~ubuntu-branches/ubuntu/raring/aufs/raring

« back to all changes in this revision

Viewing changes to fs/aufs25/export.c

  • Committer: Bazaar Package Importer
  • Author(s): Julian Andres Klode
  • Date: 2008-05-06 18:35:50 UTC
  • mto: This revision was merged to the branch mainline in revision 9.
  • Revision ID: james.westby@ubuntu.com-20080506183550-7y7mrzkzkh2tjlfu
Tags: upstream-0+20080506
ImportĀ upstreamĀ versionĀ 0+20080506

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2007-2008 Junjiro Okajima
 
3
 *
 
4
 * This program, aufs is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 */
 
18
 
 
19
/*
 
20
 * export via nfs
 
21
 *
 
22
 * $Id: export.c,v 1.4 2008/05/04 23:52:08 sfjro Exp $
 
23
 */
 
24
 
 
25
#include <linux/exportfs.h>
 
26
#include "aufs.h"
 
27
 
 
28
union conv {
 
29
#if BITS_PER_LONG == 32
 
30
        __u32 a[1];
 
31
#else
 
32
        __u32 a[2];
 
33
#endif
 
34
        ino_t ino;
 
35
};
 
36
 
 
37
static ino_t decode_ino(__u32 *a)
 
38
{
 
39
        union conv u;
 
40
 
 
41
        u.a[0] = a[0];
 
42
#if BITS_PER_LONG == 64
 
43
        u.a[1] = a[1];
 
44
#endif
 
45
        return u.ino;
 
46
}
 
47
 
 
48
static void encode_ino(__u32 *a, ino_t ino)
 
49
{
 
50
        union conv u;
 
51
 
 
52
        u.ino = ino;
 
53
        a[0] = u.a[0];
 
54
#if BITS_PER_LONG == 64
 
55
        a[1] = u.a[1];
 
56
#endif
 
57
}
 
58
 
 
59
/* NFS file handle */
 
60
enum {
 
61
        Fh_br_id,
 
62
        Fh_sigen,
 
63
#if BITS_PER_LONG == 64
 
64
        /* support 64bit inode number */
 
65
        Fh_ino1,
 
66
        Fh_ino2,
 
67
        Fh_dir_ino1,
 
68
        Fh_dir_ino2,
 
69
        Fh_h_ino1,
 
70
        Fh_h_ino2,
 
71
#else
 
72
        Fh_ino1,
 
73
        Fh_dir_ino1,
 
74
        Fh_h_ino1,
 
75
#endif
 
76
        Fh_h_igen,
 
77
        Fh_h_type,
 
78
        Fh_tail,
 
79
 
 
80
        Fh_ino = Fh_ino1,
 
81
        Fh_dir_ino = Fh_dir_ino1,
 
82
        Fh_h_ino = Fh_h_ino1,
 
83
};
 
84
 
 
85
static int au_test_anon(struct dentry *dentry)
 
86
{
 
87
        return !!(dentry->d_flags & DCACHE_DISCONNECTED);
 
88
}
 
89
 
 
90
/* ---------------------------------------------------------------------- */
 
91
 
 
92
static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino,
 
93
                                    ino_t dir_ino)
 
94
{
 
95
        struct dentry *dentry, *parent;
 
96
        struct inode *inode;
 
97
 
 
98
        LKTRTrace("i%lu, diri%lu\n", ino, dir_ino);
 
99
 
 
100
        dentry = NULL;
 
101
        inode = ilookup(sb, ino);
 
102
        if (unlikely(!inode))
 
103
                goto out;
 
104
 
 
105
        dentry = ERR_PTR(-ESTALE);
 
106
        if (unlikely(is_bad_inode(inode)))
 
107
                goto out_iput;
 
108
 
 
109
        dentry = NULL;
 
110
        if (!S_ISDIR(inode->i_mode)) {
 
111
                struct dentry *d;
 
112
                spin_lock(&dcache_lock);
 
113
                list_for_each_entry(d, &inode->i_dentry, d_alias)
 
114
                        if (!au_test_anon(d)
 
115
                            && d->d_parent->d_inode->i_ino == dir_ino) {
 
116
                                dentry = dget_locked(d);
 
117
                                break;
 
118
                        }
 
119
                spin_unlock(&dcache_lock);
 
120
        } else {
 
121
                dentry = d_find_alias(inode);
 
122
                if (dentry && !au_test_anon(dentry)) {
 
123
                        int same_ino;
 
124
                        parent = dget_parent(dentry);
 
125
                        same_ino = (parent->d_inode->i_ino == dir_ino);
 
126
                        dput(parent);
 
127
                        if (same_ino)
 
128
                                goto out_iput; /* success */
 
129
                }
 
130
 
 
131
                dput(dentry);
 
132
                dentry = NULL;
 
133
        }
 
134
 
 
135
 out_iput:
 
136
        iput(inode);
 
137
 out:
 
138
        AuTraceErrPtr(dentry);
 
139
        return dentry;
 
140
}
 
141
 
 
142
/* ---------------------------------------------------------------------- */
 
143
 
 
144
struct find_name_by_ino {
 
145
        int called, found;
 
146
        ino_t ino;
 
147
        char *name;
 
148
        int namelen;
 
149
};
 
150
 
 
151
static int
 
152
find_name_by_ino(void *arg, const char *name, int namelen, loff_t offset,
 
153
                 u64 ino, unsigned int d_type)
 
154
{
 
155
        struct find_name_by_ino *a = arg;
 
156
 
 
157
        a->called++;
 
158
        if (a->ino != ino)
 
159
                return 0;
 
160
 
 
161
        memcpy(a->name, name, namelen);
 
162
        a->namelen = namelen;
 
163
        a->found = 1;
 
164
        return 1;
 
165
}
 
166
 
 
167
static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino,
 
168
                                        ino_t dir_ino)
 
169
{
 
170
        struct dentry *dentry, *parent;
 
171
        struct inode *dir;
 
172
        struct find_name_by_ino arg;
 
173
        struct file *file;
 
174
        int err;
 
175
 
 
176
        LKTRTrace("i%lu, diri%lu\n", ino, dir_ino);
 
177
 
 
178
        dentry = NULL;
 
179
        dir = ilookup(sb, dir_ino);
 
180
        if (unlikely(!dir))
 
181
                goto out;
 
182
 
 
183
        dentry = ERR_PTR(-ESTALE);
 
184
        if (unlikely(is_bad_inode(dir)))
 
185
                goto out_iput;
 
186
 
 
187
        dentry = NULL;
 
188
        parent = d_find_alias(dir);
 
189
        if (parent) {
 
190
                if (unlikely(au_test_anon(parent))) {
 
191
                        dput(parent);
 
192
                        goto out_iput;
 
193
                }
 
194
        } else
 
195
                goto out_iput;
 
196
 
 
197
        file = dentry_open(parent, au_mntcache_get(sb), au_dir_roflags);
 
198
        dentry = (void *)file;
 
199
        if (IS_ERR(file))
 
200
                goto out_iput;
 
201
 
 
202
        dentry = ERR_PTR(-ENOMEM);
 
203
        arg.name = __getname();
 
204
        if (unlikely(!arg.name))
 
205
                goto out_fput;
 
206
        arg.ino = ino;
 
207
        arg.found = 0;
 
208
 
 
209
        do {
 
210
                arg.called = 0;
 
211
                //smp_mb();
 
212
                err = vfsub_readdir(file, find_name_by_ino, &arg, /*dlgt*/0);
 
213
        } while (!err && !arg.found && arg.called);
 
214
        dentry = ERR_PTR(err);
 
215
        if (arg.found) {
 
216
                /* do not call au_lkup_one(), nor dlgt */
 
217
                mutex_lock(&dir->i_mutex);
 
218
                dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen);
 
219
                mutex_unlock(&dir->i_mutex);
 
220
                AuTraceErrPtr(dentry);
 
221
        }
 
222
 
 
223
        //out_putname:
 
224
        __putname(arg.name);
 
225
 out_fput:
 
226
        fput(file);
 
227
 out_iput:
 
228
        iput(dir);
 
229
 out:
 
230
        AuTraceErrPtr(dentry);
 
231
        return dentry;
 
232
}
 
233
 
 
234
/* ---------------------------------------------------------------------- */
 
235
 
 
236
struct append_name {
 
237
        int found, called, len;
 
238
        char *h_path;
 
239
        ino_t h_ino;
 
240
};
 
241
 
 
242
static int append_name(void *arg, const char *name, int len, loff_t pos,
 
243
                       u64 ino, unsigned int d_type)
 
244
{
 
245
        struct append_name *a = arg;
 
246
        char *p;
 
247
 
 
248
        a->called++;
 
249
        if (ino != a->h_ino)
 
250
                return 0;
 
251
 
 
252
        AuDebugOn(len == 1 && *name == '.');
 
253
        AuDebugOn(len == 2 && name[0] == '.' && name[1] == '.');
 
254
        a->len = strlen(a->h_path);
 
255
        memmove(a->h_path - len - 1, a->h_path, a->len);
 
256
        a->h_path -= len + 1;
 
257
        p = a->h_path + a->len;
 
258
        *p++ = '/';
 
259
        memcpy(p, name, len);
 
260
        a->len += 1 + len;
 
261
        a->found++;
 
262
        return 1;
 
263
}
 
264
 
 
265
static int h_acceptable(void *expv, struct dentry *dentry)
 
266
{
 
267
        return 1;
 
268
}
 
269
 
 
270
static char *au_build_path(struct super_block *sb, __u32 *fh, char *path,
 
271
                             struct vfsmount *h_mnt, struct dentry *h_root,
 
272
                             struct dentry *h_parent)
 
273
{
 
274
        char *ret;
 
275
        int err, len;
 
276
        struct file *h_file;
 
277
        struct append_name arg;
 
278
        struct path dm_path = {
 
279
                .mnt    = h_mnt,
 
280
                .dentry = h_root
 
281
        };
 
282
 
 
283
        AuTraceEnter();
 
284
 
 
285
        arg.h_path = d_path(&dm_path, path, PATH_MAX);
 
286
        ret = arg.h_path;
 
287
        if (unlikely(!arg.h_path || IS_ERR(arg.h_path)))
 
288
                goto out;
 
289
 
 
290
        len = strlen(arg.h_path);
 
291
        dm_path.dentry = h_parent;
 
292
        arg.h_path = d_path(&dm_path, path, PATH_MAX);
 
293
        ret = arg.h_path;
 
294
        if (unlikely(!arg.h_path || IS_ERR(arg.h_path)))
 
295
                goto out;
 
296
        LKTRTrace("%s\n", arg.h_path);
 
297
        if (len != 1)
 
298
                arg.h_path += len;
 
299
        LKTRTrace("%p, %s, %ld\n",
 
300
                  arg.h_path, arg.h_path, (long)(arg.h_path - path));
 
301
 
 
302
        /* cf. fs/exportfs/expfs.c */
 
303
        h_file = dentry_open(dget(h_parent), mntget(h_mnt), au_dir_roflags);
 
304
        ret = (void *)h_file;
 
305
        if (IS_ERR(h_file))
 
306
                goto out;
 
307
 
 
308
        arg.found = 0;
 
309
        arg.h_ino = decode_ino(fh + Fh_h_ino);
 
310
        do {
 
311
                arg.called = 0;
 
312
                err = vfsub_readdir(h_file, append_name, &arg, /*dlgt*/0);
 
313
        } while (!err && !arg.found && arg.called);
 
314
        LKTRTrace("%p, %s, %d\n", arg.h_path, arg.h_path, arg.len);
 
315
        fput(h_file);
 
316
        ret = ERR_PTR(err);
 
317
        if (unlikely(err))
 
318
                goto out;
 
319
 
 
320
        dm_path.mnt = au_mntcache_get(sb);
 
321
        dm_path.dentry = sb->s_root;
 
322
        ret = d_path(&dm_path, path, PATH_MAX - arg.len);
 
323
        mntput(dm_path.mnt);
 
324
        if (unlikely(!ret || IS_ERR(ret)))
 
325
                goto out;
 
326
        ret[strlen(ret)] = '/';
 
327
        LKTRTrace("%s\n", ret);
 
328
 
 
329
 out:
 
330
        AuTraceErrPtr(ret);
 
331
        return ret;
 
332
}
 
333
 
 
334
static struct dentry *
 
335
decode_by_path(struct super_block *sb, aufs_bindex_t bindex, __u32 *fh,
 
336
               int fh_len, void *context)
 
337
{
 
338
        struct dentry *dentry, *h_parent, *root, *h_root;
 
339
        struct super_block *h_sb;
 
340
        char *path, *p;
 
341
        struct vfsmount *h_mnt;
 
342
        int err;
 
343
        struct nameidata nd;
 
344
        struct au_branch *br;
 
345
 
 
346
        LKTRTrace("b%d\n", bindex);
 
347
        SiMustAnyLock(sb);
 
348
 
 
349
        br = au_sbr(sb, bindex);
 
350
        /* au_br_get(br); */
 
351
        h_mnt = br->br_mnt;
 
352
        h_sb = h_mnt->mnt_sb;
 
353
        LKTRTrace("%s, h_decode_fh\n", au_sbtype(h_sb));
 
354
        /* in linux-2.6.24, it takes struct fid * as file handle */
 
355
        //todo: call lower fh_to_dentry()? fh_to_parent()?
 
356
        h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail),
 
357
                                      fh_len - Fh_tail, fh[Fh_h_type],
 
358
                                      h_acceptable, /*context*/NULL);
 
359
        dentry = h_parent;
 
360
        if (unlikely(!h_parent || IS_ERR(h_parent))) {
 
361
                AuWarn1("%s decode_fh failed\n", au_sbtype(h_sb));
 
362
                goto out;
 
363
        }
 
364
        dentry = NULL;
 
365
        if (unlikely(au_test_anon(h_parent))) {
 
366
                AuWarn1("%s decode_fh returned a disconnected dentry\n",
 
367
                        au_sbtype(h_sb));
 
368
                dput(h_parent);
 
369
                goto out;
 
370
        }
 
371
 
 
372
        dentry = ERR_PTR(-ENOMEM);
 
373
        path = __getname();
 
374
        if (unlikely(!path)) {
 
375
                dput(h_parent);
 
376
                goto out;
 
377
        }
 
378
 
 
379
        root = sb->s_root;
 
380
        di_read_lock_parent(root, !AuLock_IR);
 
381
        h_root = au_h_dptr(root, bindex);
 
382
        di_read_unlock(root, !AuLock_IR);
 
383
        p = au_build_path(sb, fh, path, h_mnt, h_root, h_parent);
 
384
        dput(h_parent);
 
385
        if (IS_ERR(p))
 
386
                goto out_putname;
 
387
 
 
388
        err = vfsub_path_lookup(p, LOOKUP_FOLLOW, &nd);
 
389
        dentry = ERR_PTR(err);
 
390
        if (!err) {
 
391
                dentry = dget(nd.path.dentry);
 
392
                if (unlikely(au_test_anon(dentry))) {
 
393
                        dput(dentry);
 
394
                        dentry = ERR_PTR(-ESTALE);
 
395
                }
 
396
                path_put(&nd.path);
 
397
        }
 
398
 
 
399
 out_putname:
 
400
        __putname(path);
 
401
 out:
 
402
        /* au_br_put(br); */
 
403
        AuTraceErrPtr(dentry);
 
404
        return dentry;
 
405
}
 
406
 
 
407
/* ---------------------------------------------------------------------- */
 
408
 
 
409
static noinline_for_stack struct dentry *
 
410
aufs_decode_fh(struct super_block *sb, __u32 *fh, int fh_len, int fh_type,
 
411
               int (*acceptable)(void *context, struct dentry *de),
 
412
               void *context)
 
413
{
 
414
        struct dentry *dentry;
 
415
        ino_t ino, dir_ino;
 
416
        aufs_bindex_t bindex, br_id;
 
417
        struct inode *inode, *h_inode;
 
418
        au_gen_t sigen;
 
419
 
 
420
        //au_debug_on();
 
421
        LKTRTrace("%d, fh{i%u, br_id %u, sigen %u, hi%u}\n",
 
422
                  fh_type, fh[Fh_ino], fh[Fh_br_id], fh[Fh_sigen],
 
423
                  fh[Fh_h_ino]);
 
424
        AuDebugOn(fh_len < Fh_tail);
 
425
 
 
426
        si_read_lock(sb, AuLock_FLUSH);
 
427
        lockdep_off();
 
428
 
 
429
        /* branch id may be wrapped around */
 
430
        dentry = ERR_PTR(-ESTALE);
 
431
        br_id = fh[Fh_br_id];
 
432
        sigen = fh[Fh_sigen];
 
433
        bindex = au_br_index(sb, br_id);
 
434
        if (unlikely(bindex < 0 || sigen + AUFS_BRANCH_MAX <= au_sigen(sb)))
 
435
                goto out;
 
436
 
 
437
        /* is this inode still cached? */
 
438
        ino = decode_ino(fh + Fh_ino);
 
439
        dir_ino = decode_ino(fh + Fh_dir_ino);
 
440
        dentry = decode_by_ino(sb, ino, dir_ino);
 
441
        if (IS_ERR(dentry))
 
442
                goto out;
 
443
        if (dentry)
 
444
                goto accept;
 
445
 
 
446
        /* is the parent dir cached? */
 
447
        dentry = decode_by_dir_ino(sb, ino, dir_ino);
 
448
        if (IS_ERR(dentry))
 
449
                goto out;
 
450
        if (dentry)
 
451
                goto accept;
 
452
 
 
453
        /* lookup path */
 
454
        dentry = decode_by_path(sb, bindex, fh, fh_len, context);
 
455
        if (IS_ERR(dentry))
 
456
                goto out;
 
457
        if (unlikely(!dentry))
 
458
                goto out_stale;
 
459
        if (unlikely(dentry->d_inode->i_ino != ino))
 
460
                goto out_dput;
 
461
 
 
462
 accept:
 
463
        inode = dentry->d_inode;
 
464
        h_inode = NULL;
 
465
        ii_read_lock_child(inode);
 
466
        if (au_ibstart(inode) <= bindex && bindex <= au_ibend(inode))
 
467
                h_inode = au_h_iptr(inode, bindex);
 
468
        ii_read_unlock(inode);
 
469
        if (h_inode
 
470
            && h_inode->i_generation == fh[Fh_h_igen]
 
471
            && acceptable(context, dentry))
 
472
                goto out; /* success */
 
473
 out_dput:
 
474
        dput(dentry);
 
475
 out_stale:
 
476
        dentry = ERR_PTR(-ESTALE);
 
477
 out:
 
478
        lockdep_on();
 
479
        si_read_unlock(sb);
 
480
        AuTraceErrPtr(dentry);
 
481
        //au_debug_off();
 
482
        return dentry;
 
483
}
 
484
 
 
485
static struct dentry *
 
486
aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
 
487
                  int fh_type)
 
488
{
 
489
        return aufs_decode_fh(sb, fid->raw, fh_len, fh_type, h_acceptable,
 
490
                              /*context*/NULL);
 
491
}
 
492
 
 
493
#if 0
 
494
/* support subtreecheck option */
 
495
static struct dentry *au_fh_to_parent(struct super_block *sb, struct fid *fid,
 
496
                                      int fh_len, int fh_type)
 
497
{
 
498
}
 
499
#endif
 
500
 
 
501
/* ---------------------------------------------------------------------- */
 
502
 
 
503
static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
 
504
                          int connectable)
 
505
{
 
506
        int err;
 
507
        struct super_block *sb, *h_sb;
 
508
        struct inode *inode, *h_inode, *dir;
 
509
        aufs_bindex_t bindex;
 
510
        union conv u;
 
511
        struct dentry *parent, *h_parent;
 
512
 
 
513
        //au_debug_on();
 
514
        BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a));
 
515
        LKTRTrace("%.*s, max %d, conn %d\n",
 
516
                  AuDLNPair(dentry), *max_len, connectable);
 
517
        AuDebugOn(au_test_anon(dentry));
 
518
        inode = dentry->d_inode;
 
519
        AuDebugOn(!inode);
 
520
        parent = dget_parent(dentry);
 
521
        AuDebugOn(au_test_anon(parent));
 
522
 
 
523
        err = -ENOSPC;
 
524
        if (unlikely(*max_len <= Fh_tail)) {
 
525
                AuWarn1("NFSv2 client (max_len %d)?\n", *max_len);
 
526
                goto out;
 
527
        }
 
528
 
 
529
        sb = dentry->d_sb;
 
530
        si_read_lock(sb, AuLock_FLUSH);
 
531
        di_read_lock_child(dentry, AuLock_IR);
 
532
        di_read_lock_parent(parent, AuLock_IR);
 
533
#ifdef CONFIG_AUFS_DEBUG
 
534
        if (unlikely(!au_opt_test(au_mntflags(sb), XINO)))
 
535
                AuWarn1("NFS-exporting requires xino\n");
 
536
#if 0 // temp
 
537
        if (unlikely(au_opt_test(au_mntflags(sb), UDBA_INOTIFY)))
 
538
                AuWarn1("udba=inotify is not recommended when exporting\n");
 
539
#endif
 
540
#endif
 
541
 
 
542
        err = -EPERM;
 
543
        bindex = au_dbstart(dentry);
 
544
        h_sb = au_sbr_sb(sb, bindex);
 
545
        if (unlikely(!h_sb->s_export_op)) {
 
546
                AuErr1("%s branch is not exportable\n", au_sbtype(h_sb));
 
547
                goto out_unlock;
 
548
        }
 
549
 
 
550
#if 0 //def CONFIG_AUFS_ROBR
 
551
        if (unlikely(au_test_aufs(h_sb))) {
 
552
                AuErr1("aufs branch is not supported\n");
 
553
                goto out_unlock;
 
554
        }
 
555
#endif
 
556
 
 
557
        fh[Fh_br_id] = au_sbr_id(sb, bindex);
 
558
        fh[Fh_sigen] = au_sigen(sb);
 
559
        encode_ino(fh + Fh_ino, inode->i_ino);
 
560
        dir = parent->d_inode;
 
561
        encode_ino(fh + Fh_dir_ino, dir->i_ino);
 
562
        h_inode = au_h_dptr(dentry, bindex)->d_inode;
 
563
        encode_ino(fh + Fh_h_ino, h_inode->i_ino);
 
564
        fh[Fh_h_igen] = h_inode->i_generation;
 
565
 
 
566
        *max_len -= Fh_tail;
 
567
        //LKTRTrace("Fh_tail %d, max_len %d\n", Fh_tail, *max_len);
 
568
        h_parent = au_h_dptr(parent, bindex);
 
569
        AuDebugOn(au_test_anon(h_parent));
 
570
        /* in linux-2.6.24, it takes struct fid * as file handle */
 
571
        fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail),
 
572
                                           max_len, connectable);
 
573
        err = fh[Fh_h_type];
 
574
        *max_len += Fh_tail;
 
575
        if (err != 255)
 
576
                err = 2; //??
 
577
        else
 
578
                AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb));
 
579
 
 
580
 out_unlock:
 
581
        di_read_unlock(parent, AuLock_IR);
 
582
        aufs_read_unlock(dentry, AuLock_IR);
 
583
 out:
 
584
        dput(parent);
 
585
        AuTraceErr(err);
 
586
        //au_debug_off();
 
587
        if (unlikely(err < 0))
 
588
                err = 255;
 
589
        return err;
 
590
}
 
591
 
 
592
/* ---------------------------------------------------------------------- */
 
593
 
 
594
struct export_operations aufs_export_op = {
 
595
        .fh_to_dentry   = aufs_fh_to_dentry,
 
596
        .encode_fh      = aufs_encode_fh
 
597
};