662966ba88deb5b3d21587eec0a27b9561d60a46
[openafs.git] / src / afs / LINUX / osi_export.c
1 /*
2  * vi:set cin noet sw=4 tw=70:
3  * Copyright 2006, International Business Machines Corporation and others.
4  * All Rights Reserved.
5  * 
6  * This software has been released under the terms of the IBM Public
7  * License.  For details, see the LICENSE file in the top-level source
8  * directory or online at http://www.openafs.org/dl/license10.html
9  */
10
11 /*
12  * Filesystem export operations for Linux
13  */
14 #include <afsconfig.h>
15 #include "afs/param.h"
16
17
18 #include <linux/module.h> /* early to avoid printf->printk mapping */
19 #include <linux/fs.h>
20 #ifdef HAVE_LINUX_EXPORTFS_H
21 #include <linux/exportfs.h>
22 #endif
23 #include "afs/sysincludes.h"
24 #include "afsincludes.h"
25 #include "afs/afs_dynroot.h"
26
27 #if !defined(AFS_NONFSTRANS)
28
29 /* #define OSI_EXPORT_DEBUG */
30
31 extern struct dentry_operations afs_dentry_operations;
32 #if defined(NEW_EXPORT_OPS)
33 static struct dentry *afs_export_get_dentry(struct super_block *sb,
34                                             void *inump);
35 #endif
36
37 struct get_name_data {
38     char *name;
39     struct VenusFid fid;
40     int found;
41 };
42
43 /*
44  * Linux reserved the following filehandle types:
45  * - 0 is always the filesystem root; NFS deals with this for us
46  * - 1,2 are reserved by Linux for inode-number-based filehandles
47  * - 0xff is reserved by linux
48  *
49  * We encode filehandles for AFS files using the types defined below.
50  * Internally, our "object ID" is a VenusFid; if we get a filehandle
51  * with a more-stable cell ID, we'll turn it into a cell number in
52  * the decode_fh wrapper.
53  */
54
55 #define AFSFH_VENUSFID      0xa0 /* cell, volume, vnode, uniq           */
56 #define AFSFH_CELLFID       0xa1 /* cellhandle, volume, vnode, uniq     */
57 #define AFSFH_NET_VENUSFID  0xa2 /* net cell, volume, vnode, uniq       */
58 #define AFSFH_NET_CELLFID   0xa3 /* net cellhandle, volume, vnode, uniq */
59 #define AFSFH_DYN_RO_CELL   0xd0 /* cellhandle for RO root.cell mount   */
60 #define AFSFH_DYN_RW_CELL   0xd1 /* cellhandle for RW root.cell mount   */
61 #define AFSFH_DYN_RO_LINK   0xd2 /* cellhandle for RO root.cell symlink */
62 #define AFSFH_DYN_RW_LINK   0xd3 /* cellhandle for RW root.cell symlink */
63 #define AFSFH_DYN_MOUNT     0xd4 /* cellhandle, volume for mount point  */
64 #define AFSFH_DYN_SYMLINK   0xd5 /* hash of dynroot symlink target */
65
66 static int afs_encode_fh(struct dentry *de, __u32 *fh, int *max_len,
67                          int connectable)
68 {
69     struct vcache *tvc;
70     struct cell *tc;
71     int vntype;
72
73     if (!de->d_inode) /* encode a negative dentry?! */
74         return 255;
75     if (*max_len < 4)  /* not enough space */
76         return 255;
77
78     tvc = VTOAFS(de->d_inode);
79
80 #ifdef OSI_EXPORT_DEBUG
81     printk("afs: encode_fh(0x%08x/%d/%d.%d)\n",
82            tvc->f.fid.Cell,      tvc->f.fid.Fid.Volume,
83            tvc->f.fid.Fid.Vnode, tvc->f.fid.Fid.Unique);
84 #endif
85     if (afs_IsDynrootAnyFid(&tvc->f.fid)) {
86         vntype = VNUM_TO_VNTYPE(tvc->f.fid.Fid.Vnode);
87         switch (vntype) {
88             case 0:
89                 /* encode as a normal filehandle */
90                 break;
91
92             case VN_TYPE_MOUNT:
93                 if (*max_len < 5) {
94                     return 255;
95                 }
96                 /* fall through */
97
98             case VN_TYPE_CELL:
99             case VN_TYPE_ALIAS:
100                 AFS_GLOCK();
101                 tc = afs_GetCellByIndex(VNUM_TO_CIDX(tvc->f.fid.Fid.Vnode),
102                                         READ_LOCK);
103                 if (!tc) {
104                     AFS_GUNLOCK();
105                     return 255;
106                 }
107                 memcpy((void *)fh, tc->cellHandle, 16);
108                 afs_PutCell(tc, READ_LOCK);
109                 AFS_GUNLOCK();
110                 if (vntype == VN_TYPE_MOUNT) {
111                     fh[4] = htonl(tvc->f.fid.Fid.Unique);
112                     *max_len = 5;
113                     return AFSFH_DYN_MOUNT;
114                 }
115                 *max_len = 4;
116                 if (vntype == VN_TYPE_CELL) {
117                     return AFSFH_DYN_RO_CELL | VNUM_TO_RW(tvc->f.fid.Fid.Vnode);
118                 } else {
119                     return AFSFH_DYN_RO_LINK | VNUM_TO_RW(tvc->f.fid.Fid.Vnode);
120                 }
121
122             case VN_TYPE_SYMLINK:
123                 /* XXX fill in filehandle for dynroot symlink */
124                 /* XXX return AFSFH_DYN_SYMLINK; */
125
126             default:
127                 return 255;
128         }
129     }
130
131     if (*max_len < 7) {
132         /* not big enough for a migratable filehandle */
133         /* always encode in network order */
134         fh[0] = htonl(tvc->f.fid.Cell);
135         fh[1] = htonl(tvc->f.fid.Fid.Volume);
136         fh[2] = htonl(tvc->f.fid.Fid.Vnode);
137         fh[3] = htonl(tvc->f.fid.Fid.Unique);
138         *max_len = 4;
139         return AFSFH_NET_VENUSFID;
140     }
141
142     AFS_GLOCK();
143     tc = afs_GetCell(tvc->f.fid.Cell, READ_LOCK);
144     if (!tc) {
145         AFS_GUNLOCK();
146         return 255;
147     }
148     memcpy((void *)fh, tc->cellHandle, 16);
149     afs_PutCell(tc, READ_LOCK);
150     AFS_GUNLOCK();
151     /* always encode in network order */
152     fh[4] = htonl(tvc->f.fid.Fid.Volume);
153     fh[5] = htonl(tvc->f.fid.Fid.Vnode);
154     fh[6] = htonl(tvc->f.fid.Fid.Unique);
155
156     *max_len = 7;
157     return AFSFH_NET_CELLFID;
158 }
159
160 #if defined(NEW_EXPORT_OPS)
161 static struct dentry *afs_fh_to_dentry(struct super_block *sb, struct fid *fh_fid,
162                                     int fh_len, int fh_type)
163 #else
164 static struct dentry *afs_decode_fh(struct super_block *sb, __u32 *fh,
165                                     int fh_len, int fh_type,
166                                     int (*acceptable)(void *, struct dentry *),
167                                     void *context)
168 #endif
169 {
170     struct VenusFid fid;
171     struct cell *tc;
172     struct dentry *result;
173 #if defined(NEW_EXPORT_OPS)
174     __u32 *fh = (__u32 *)fh_fid->raw;
175 #endif
176
177
178     switch (fh_type) {
179         case AFSFH_VENUSFID:
180             if (fh_len != 4)
181                 return NULL;
182             fid.Cell       = fh[0];
183             fid.Fid.Volume = fh[1];
184             fid.Fid.Vnode  = fh[2];
185             fid.Fid.Unique = fh[3];
186             break;
187
188         case AFSFH_CELLFID:
189             if (fh_len != 7)
190                 return NULL;
191             AFS_GLOCK();
192             tc = afs_GetCellByHandle((void *)fh, READ_LOCK);
193             if (!tc) {
194                 AFS_GUNLOCK();
195                 return NULL;
196             }
197             fid.Cell       = tc->cellNum;
198             fid.Fid.Volume = fh[4];
199             fid.Fid.Vnode  = fh[5];
200             fid.Fid.Unique = fh[6];
201             afs_PutCell(tc, READ_LOCK);
202             AFS_GUNLOCK();
203             break;
204
205         case AFSFH_NET_VENUSFID:
206             fid.Cell       = ntohl(fh[0]);
207             fid.Fid.Volume = ntohl(fh[1]);
208             fid.Fid.Vnode  = ntohl(fh[2]);
209             fid.Fid.Unique = ntohl(fh[3]);
210             break;
211
212         case AFSFH_NET_CELLFID:
213             if (fh_len != 7)
214                 return NULL;
215             AFS_GLOCK();
216             tc = afs_GetCellByHandle((void *)fh, READ_LOCK);
217             if (!tc) {
218                 AFS_GUNLOCK();
219                 return NULL;
220             }
221             fid.Cell       = tc->cellNum;
222             fid.Fid.Volume = ntohl(fh[4]);
223             fid.Fid.Vnode  = ntohl(fh[5]);
224             fid.Fid.Unique = ntohl(fh[6]);
225             afs_PutCell(tc, READ_LOCK);
226             AFS_GUNLOCK();
227             break;
228
229         case AFSFH_DYN_RO_CELL:
230         case AFSFH_DYN_RW_CELL:
231             if (fh_len != 4)
232                 return NULL;
233             AFS_GLOCK();
234             tc = afs_GetCellByHandle((void *)fh, READ_LOCK);
235             if (!tc) {
236                 AFS_GUNLOCK();
237                 return NULL;
238             }
239             afs_GetDynrootFid(&fid);
240             fid.Fid.Vnode  = VNUM_FROM_CIDX_RW(tc->cellIndex, fh_type & 1);
241             fid.Fid.Unique = 1;
242             afs_PutCell(tc, READ_LOCK);
243             AFS_GUNLOCK();
244             break;
245
246         case AFSFH_DYN_RO_LINK:
247         case AFSFH_DYN_RW_LINK:
248             if (fh_len != 4)
249                 return NULL;
250             AFS_GLOCK();
251             tc = afs_GetCellByHandle((void *)fh, READ_LOCK);
252             if (!tc) {
253                 AFS_GUNLOCK();
254                 return NULL;
255             }
256             afs_GetDynrootFid(&fid);
257             fid.Fid.Vnode  = VNUM_FROM_CAIDX_RW(tc->cellIndex, fh_type & 1);
258             fid.Fid.Unique = 1;
259             afs_PutCell(tc, READ_LOCK);
260             AFS_GUNLOCK();
261             break;
262
263         case AFSFH_DYN_MOUNT:
264             if (fh_len != 5)
265                 return NULL;
266             AFS_GLOCK();
267             tc = afs_GetCellByHandle((void *)fh, READ_LOCK);
268             if (!tc) {
269                 AFS_GUNLOCK();
270                 return NULL;
271             }
272             afs_GetDynrootFid(&fid);
273             fid.Fid.Vnode  = VNUM_FROM_TYPEID(VN_TYPE_MOUNT,
274                                               tc->cellIndex << 2);
275             fid.Fid.Unique = ntohl(fh[4]);
276             afs_PutCell(tc, READ_LOCK);
277             AFS_GUNLOCK();
278             break;
279
280         case AFSFH_DYN_SYMLINK:
281             /* XXX parse dynroot symlink filehandle */
282             /* break; */
283
284         default:
285             return NULL;
286     }
287
288 #if defined(NEW_EXPORT_OPS)
289     result = afs_export_get_dentry(sb, &fid);
290 #else
291     result = sb->s_export_op->find_exported_dentry(sb, &fid, 0,
292                                                    acceptable, context);
293
294 #endif
295
296 #ifdef OSI_EXPORT_DEBUG
297     if (!result) {
298         printk("afs: decode_fh(0x%08x/%d/%d.%d): no dentry\n",
299                fid.Cell,      fid.Fid.Volume,
300                fid.Fid.Vnode, fid.Fid.Unique);
301     } else if (IS_ERR(result)) {
302         printk("afs: decode_fh(0x%08x/%d/%d.%d): error %ld\n",
303                fid.Cell,      fid.Fid.Volume,
304                fid.Fid.Vnode, fid.Fid.Unique, PTR_ERR(result));
305     }
306 #endif
307     return result;
308 }
309
310 static int update_dir_parent(struct vrequest *areq, struct vcache *adp)
311 {
312     struct VenusFid tfid;
313     struct dcache *tdc;
314     afs_size_t dirOffset, dirLen;
315     int code;
316
317 redo:
318     if (!(adp->f.states & CStatd)) {
319         if ((code = afs_VerifyVCache2(adp, areq))) {
320 #ifdef OSI_EXPORT_DEBUG
321             printk("afs: update_dir_parent(0x%08x/%d/%d.%d): VerifyVCache2: %d\n",
322                    adp->f.fid.Cell,      adp->f.fid.Fid.Volume,
323                    adp->f.fid.Fid.Vnode, adp->f.fid.Fid.Unique, code);
324 #endif
325             return code;
326         }
327     }
328
329     tdc = afs_GetDCache(adp, (afs_size_t) 0, areq, &dirOffset, &dirLen, 1);
330     if (!tdc) {
331 #ifdef OSI_EXPORT_DEBUG
332         printk("afs: update_dir_parent(0x%08x/%d/%d.%d): no dcache\n",
333                adp->f.fid.Cell,      adp->f.fid.Fid.Volume,
334                adp->f.fid.Fid.Vnode, adp->f.fid.Fid.Unique);
335 #endif
336         return EIO;
337     }
338
339     /* now we will just call dir package with appropriate inode.
340      * Dirs are always fetched in their entirety for now */
341     ObtainSharedLock(&adp->lock, 801);
342     ObtainReadLock(&tdc->lock);
343
344     /*
345      * Make sure that the data in the cache is current. There are two
346      * cases we need to worry about:
347      * 1. The cache data is being fetched by another process.
348      * 2. The cache data is no longer valid
349      */
350     while ((adp->f.states & CStatd)
351            && (tdc->dflags & DFFetching)
352            && hsame(adp->f.m.DataVersion, tdc->f.versionNo)) {
353         ReleaseReadLock(&tdc->lock);
354         ReleaseSharedLock(&adp->lock);
355         afs_osi_Sleep(&tdc->validPos);
356         ObtainSharedLock(&adp->lock, 802);
357         ObtainReadLock(&tdc->lock);
358     }
359     if (!(adp->f.states & CStatd)
360         || !hsame(adp->f.m.DataVersion, tdc->f.versionNo)) {
361         ReleaseReadLock(&tdc->lock);
362         ReleaseSharedLock(&adp->lock);
363         afs_PutDCache(tdc);
364 #ifdef OSI_EXPORT_DEBUG
365         printk("afs: update_dir_parent(0x%08x/%d/%d.%d): dir changed; retrying\n",
366                adp->f.fid.Cell,      adp->f.fid.Fid.Volume,
367                adp->f.fid.Fid.Vnode, adp->f.fid.Fid.Unique);
368 #endif
369         goto redo;
370     }
371
372     /* lookup the name in the appropriate dir, and return a cache entry
373      * on the resulting fid */
374     code = afs_dir_Lookup(tdc, "..", &tfid.Fid);
375
376     ReleaseReadLock(&tdc->lock);
377     afs_PutDCache(tdc);
378
379     if (!code) {
380         UpgradeSToWLock(&adp->lock, 803);
381         adp->f.parent.vnode  = tfid.Fid.Vnode;
382         adp->f.parent.unique = tfid.Fid.Unique;
383     }
384 #ifdef OSI_EXPORT_DEBUG
385     if (code) {
386         printk("afs: update_dir_parent(0x%08x/%d/%d.%d): afs_dir_Lookup: %d\n",
387                adp->f.fid.Cell,      adp->f.fid.Fid.Volume,
388                adp->f.fid.Fid.Vnode, adp->f.fid.Fid.Unique, code);
389     } else {
390         printk("afs: update_dir_parent(0x%08x/%d/%d.%d) => %d.%d\n",
391                adp->f.fid.Cell,      adp->f.fid.Fid.Volume,
392                adp->f.fid.Fid.Vnode, adp->f.fid.Fid.Unique,
393                adp->parent.vnode,   adp->parent.unique);
394     }
395 #endif
396     ReleaseSharedLock(&adp->lock);
397     return code;
398 }
399
400
401 static int UnEvalFakeStat(struct vrequest *areq, struct vcache **vcpp)
402 {
403     struct VenusFid tfid;
404     struct volume *tvp;
405     struct vcache *tvc;
406     int code;
407
408     if (!afs_fakestat_enable)
409         return 0;
410
411     if (*vcpp == afs_globalVp || vType(*vcpp) != VDIR || (*vcpp)->mvstat != 2)
412         return 0;
413
414     /* Figure out what FID to look for */
415     tvp = afs_GetVolume(&(*vcpp)->f.fid, 0, READ_LOCK);
416     if (!tvp) {
417 #ifdef OSI_EXPORT_DEBUG
418         printk("afs: UnEvalFakeStat(0x%08x/%d/%d.%d): no volume\n",
419                (*vcpp)->f.fid.Cell,      (*vcpp)->f.fid.Fid.Volume,
420                (*vcpp)->f.fid.Fid.Vnode, (*vcpp)->f.fid.Fid.Unique);
421 #endif
422         return ENOENT;
423     }
424     tfid = tvp->mtpoint;
425     afs_PutVolume(tvp, READ_LOCK);
426
427     tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
428     if (!tvc) {
429 #ifdef OSI_EXPORT_DEBUG
430         printk("afs: UnEvalFakeStat(0x%08x/%d/%d.%d): GetVCache(0x%08x/%d/%d.%d) failed\n",
431                (*vcpp)->f.fid.Cell,      (*vcpp)->f.fid.Fid.Volume,
432                (*vcpp)->f.fid.Fid.Vnode, (*vcpp)->f.fid.Fid.Unique,
433                tfid.Cell,          tfid.Fid.Volume,
434                tfid.Fid.Vnode,     tfid.Fid.Unique);
435 #endif
436         return ENOENT;
437     }
438
439     if (afs_fakestat_enable == 2) {
440         ObtainWriteLock(&tvc->lock, 806);
441         code = afs_HandleLink(tvc, areq);
442         if (code) {
443             ReleaseWriteLock(&tvc->lock);
444             afs_PutVCache(tvc);
445             return code;
446         }
447         if (!strchr(tvc->linkData, ':')) {
448             ReleaseWriteLock(&tvc->lock);
449             afs_PutVCache(tvc);
450             return 0;
451         }
452         ReleaseWriteLock(&tvc->lock);
453     }
454
455     afs_PutVCache(*vcpp);
456     *vcpp = tvc;
457     return 0;
458 }
459
460
461 /* 
462  * Given a FID, obtain or construct a dentry, or return an error.
463  * This should be called with the BKL and AFS_GLOCK held.
464  */
465 static struct dentry *get_dentry_from_fid(cred_t *credp, struct VenusFid *afid)
466 {
467     struct vrequest treq;
468     struct vcache *vcp;
469     struct vattr vattr;
470     struct inode *ip;
471     struct dentry *dp;
472     afs_int32 code;
473
474     code = afs_InitReq(&treq, credp);
475     if (code) {
476 #ifdef OSI_EXPORT_DEBUG
477         printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): afs_InitReq: %d\n",
478                afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique,
479                code);
480 #endif
481         return ERR_PTR(-afs_CheckCode(code, &treq, 101));
482     }
483     vcp = afs_GetVCache(afid, &treq, NULL, NULL);
484     if (vcp == NULL) {
485 #ifdef OSI_EXPORT_DEBUG
486         printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): no vcache\n",
487                afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique);
488 #endif
489         return NULL;
490     }
491
492     /* 
493      * Now, it might be that we just caused a directory vnode to
494      * spring into existence, in which case its parent FID is unset.
495      * We need to do something about that, but only because we care
496      * in our own get_parent(), below -- the common code never looks
497      * at parentVnode on directories, except for VIOCGETVCXSTATUS.
498      * So, if this fails, we don't really care very much.
499      */
500     if (vType(vcp) == VDIR && vcp->mvstat != 2 && !vcp->f.parent.vnode)
501         update_dir_parent(&treq, vcp);
502
503     /*
504      * If this is a volume root directory and fakestat is enabled,
505      * we might need to replace the directory by a mount point.
506      */
507     code = UnEvalFakeStat(&treq, &vcp);
508     if (code) {
509 #ifdef OSI_EXPORT_DEBUG
510         printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): UnEvalFakeStat: %d\n",
511                afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique,
512                code);
513 #endif
514         afs_PutVCache(vcp);
515         return ERR_PTR(-afs_CheckCode(code, &treq, 101));
516     }
517
518     ip = AFSTOV(vcp);
519     afs_getattr(vcp, &vattr, credp);
520     afs_fill_inode(ip, &vattr);
521
522     /* d_alloc_anon might block, so we shouldn't hold the glock */
523     AFS_GUNLOCK();
524     dp = d_alloc_anon(ip);
525     AFS_GLOCK();
526
527     if (!dp) {
528         iput(ip);
529 #ifdef OSI_EXPORT_DEBUG
530         printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): out of memory\n",
531                afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique);
532 #endif
533         return ERR_PTR(-ENOMEM);
534     }
535
536     dp->d_op = &afs_dentry_operations;
537     return dp;
538 }
539
540 static struct dentry *afs_export_get_dentry(struct super_block *sb,
541                                             void *inump)
542 {
543     struct dentry *dp;
544     cred_t *credp;
545
546     credp = crref();
547     AFS_GLOCK();
548
549     dp = get_dentry_from_fid(credp, inump);
550
551     AFS_GUNLOCK();
552     crfree(credp);
553
554     return dp;
555 }
556
557
558 static int get_name_hook(void *hdata, char *name,
559                          afs_int32 vnode, afs_int32 unique)
560 {
561     struct get_name_data *data = (struct get_name_data *)hdata;
562     int len;
563
564     if (vnode == data->fid.Fid.Vnode && unique == data->fid.Fid.Unique) {
565         len = strlen(name);
566         if (len > NAME_MAX) len = NAME_MAX;
567         memcpy(data->name, name, len);
568         data->name[len] = '\0';
569         data->found = 1;
570     }
571     return 0;
572 }
573
574 static int afs_export_get_name(struct dentry *parent, char *name,
575                                struct dentry *child)
576 {
577     struct afs_fakestat_state fakestate;
578     struct get_name_data data;
579     struct vrequest treq;
580     struct volume *tvp;
581     struct vcache *vcp;
582     struct dcache *tdc;
583     cred_t *credp;
584     afs_size_t dirOffset, dirLen;
585     afs_int32 code = 0;
586
587     if (!parent->d_inode) {
588 #ifdef OSI_EXPORT_DEBUG
589         /* can't lookup name in a negative dentry */
590         printk("afs: get_name(%s, %s): no parent inode\n",
591                parent->d_name.name ? (char *)parent->d_name.name : "?",
592                child->d_name.name  ? (char *)child->d_name.name  : "?");
593 #endif
594         return -EIO;
595     }
596     if (!child->d_inode) {
597 #ifdef OSI_EXPORT_DEBUG
598         /* can't find the FID of negative dentry */
599         printk("afs: get_name(%s, %s): no child inode\n",
600                parent->d_name.name ? (char *)parent->d_name.name : "?",
601                child->d_name.name  ? (char *)child->d_name.name  : "?");
602 #endif
603         return -ENOENT;
604     }
605
606     afs_InitFakeStat(&fakestate);
607
608     credp = crref();
609     AFS_GLOCK();
610
611     vcp = VTOAFS(child->d_inode);
612
613     /* special case dynamic mount directory */
614     if (afs_IsDynrootMount(vcp)) {
615 #ifdef OSI_EXPORT_DEBUG
616         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): this is the dynmount dir\n",
617                parent->d_name.name ? (char *)parent->d_name.name : "?",
618                vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
619                vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique);
620 #endif
621         data.fid = vcp->f.fid;
622         if (VTOAFS(parent->d_inode) == afs_globalVp)
623             strcpy(name, AFS_DYNROOT_MOUNTNAME);
624         else
625             code = -ENOENT;
626         goto done;
627     }
628
629     /* Figure out what FID to look for */
630     if (vcp->mvstat == 2) { /* volume root */
631         tvp = afs_GetVolume(&vcp->f.fid, 0, READ_LOCK);
632         if (!tvp) {
633 #ifdef OSI_EXPORT_DEBUG
634             printk("afs: get_name(%s, 0x%08x/%d/%d.%d): no volume for root\n",
635                    parent->d_name.name ? (char *)parent->d_name.name : "?",
636                    vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
637                    vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique);
638 #endif
639             code = ENOENT;
640             goto done;
641         }
642         data.fid = tvp->mtpoint;
643         afs_PutVolume(tvp, READ_LOCK);
644     } else {
645         data.fid = vcp->f.fid;
646     }
647
648     vcp = VTOAFS(parent->d_inode);
649 #ifdef OSI_EXPORT_DEBUG
650     printk("afs: get_name(%s, 0x%08x/%d/%d.%d): parent is 0x%08x/%d/%d.%d\n",
651            parent->d_name.name ? (char *)parent->d_name.name : "?",
652            data.fid.Cell,      data.fid.Fid.Volume,
653            data.fid.Fid.Vnode, data.fid.Fid.Unique,
654            vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
655            vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique);
656 #endif
657
658     code = afs_InitReq(&treq, credp);
659     if (code) {
660 #ifdef OSI_EXPORT_DEBUG
661         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): afs_InitReq: %d\n",
662                parent->d_name.name ? (char *)parent->d_name.name : "?",
663                data.fid.Cell,      data.fid.Fid.Volume,
664                data.fid.Fid.Vnode, data.fid.Fid.Unique, code);
665 #endif
666         goto done;
667     }
668
669     /* a dynamic mount point in the dynamic mount directory */
670     if (afs_IsDynrootMount(vcp) && afs_IsDynrootAnyFid(&data.fid)
671         && VNUM_TO_VNTYPE(data.fid.Fid.Vnode) == VN_TYPE_MOUNT) {
672 #ifdef OSI_EXPORT_DEBUG
673         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): dynamic mount point\n",
674                parent->d_name.name ? (char *)parent->d_name.name : "?",
675                data.fid.Cell,      data.fid.Fid.Volume,
676                data.fid.Fid.Vnode, data.fid.Fid.Unique);
677 #endif
678         vcp = afs_GetVCache(&data.fid, &treq, NULL, NULL);
679         if (vcp) {
680             ObtainReadLock(&vcp->lock);
681             if (strlen(vcp->linkData + 1) <= NAME_MAX)
682                 strcpy(name, vcp->linkData + 1);
683             else
684                 code = ENOENT;
685             ReleaseReadLock(&vcp->lock);
686             afs_PutVCache(vcp);
687         } else {
688 #ifdef OSI_EXPORT_DEBUG
689             printk("afs: get_name(%s, 0x%08x/%d/%d.%d): no vcache\n",
690                    parent->d_name.name ? (char *)parent->d_name.name : "?",
691                    data.fid.Cell,      data.fid.Fid.Volume,
692                    data.fid.Fid.Vnode, data.fid.Fid.Unique);
693 #endif
694             code = ENOENT;
695         }
696         goto done;
697     }
698
699     code = afs_EvalFakeStat(&vcp, &fakestate, &treq);
700     if (code)
701         goto done;
702
703     if (vcp->f.fid.Cell != data.fid.Cell ||
704         vcp->f.fid.Fid.Volume != data.fid.Fid.Volume) {
705         /* parent is not the expected cell and volume; thus it
706          * cannot possibly contain the fid we are looking for */
707 #ifdef OSI_EXPORT_DEBUG
708         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): wrong parent 0x%08x/%d\n",
709                parent->d_name.name ? (char *)parent->d_name.name : "?",
710                data.fid.Cell,      data.fid.Fid.Volume,
711                data.fid.Fid.Vnode, data.fid.Fid.Unique,
712                vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume);
713 #endif
714         code = ENOENT;
715         goto done;
716     }
717
718
719 redo:
720     if (!(vcp->f.states & CStatd)) {
721         if ((code = afs_VerifyVCache2(vcp, &treq))) {
722 #ifdef OSI_EXPORT_DEBUG
723             printk("afs: get_name(%s, 0x%08x/%d/%d.%d): VerifyVCache2(0x%08x/%d/%d.%d): %d\n",
724                    parent->d_name.name ? (char *)parent->d_name.name : "?",
725                    data.fid.Cell,      data.fid.Fid.Volume,
726                    data.fid.Fid.Vnode, data.fid.Fid.Unique,
727                    vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
728                    vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code);
729 #endif
730             goto done;
731         }
732     }
733
734     tdc = afs_GetDCache(vcp, (afs_size_t) 0, &treq, &dirOffset, &dirLen, 1);
735     if (!tdc) {
736 #ifdef OSI_EXPORT_DEBUG
737         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): GetDCache(0x%08x/%d/%d.%d): %d\n",
738                parent->d_name.name ? (char *)parent->d_name.name : "?",
739                data.fid.Cell,      data.fid.Fid.Volume,
740                data.fid.Fid.Vnode, data.fid.Fid.Unique,
741                vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
742                vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code);
743 #endif
744         code = EIO;
745         goto done;
746     }
747
748     ObtainReadLock(&vcp->lock);
749     ObtainReadLock(&tdc->lock);
750
751     /*
752      * Make sure that the data in the cache is current. There are two
753      * cases we need to worry about:
754      * 1. The cache data is being fetched by another process.
755      * 2. The cache data is no longer valid
756      */
757     while ((vcp->f.states & CStatd)
758            && (tdc->dflags & DFFetching)
759            && hsame(vcp->f.m.DataVersion, tdc->f.versionNo)) {
760         ReleaseReadLock(&tdc->lock);
761         ReleaseReadLock(&vcp->lock);
762         afs_osi_Sleep(&tdc->validPos);
763         ObtainReadLock(&vcp->lock);
764         ObtainReadLock(&tdc->lock);
765     }
766     if (!(vcp->f.states & CStatd)
767         || !hsame(vcp->f.m.DataVersion, tdc->f.versionNo)) {
768         ReleaseReadLock(&tdc->lock);
769         ReleaseReadLock(&vcp->lock);
770         afs_PutDCache(tdc);
771 #ifdef OSI_EXPORT_DEBUG
772         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): dir (0x%08x/%d/%d.%d) changed; retrying\n",
773                parent->d_name.name ? (char *)parent->d_name.name : "?",
774                data.fid.Cell,      data.fid.Fid.Volume,
775                data.fid.Fid.Vnode, data.fid.Fid.Unique,
776                vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
777                vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique);
778 #endif
779         goto redo;
780     }
781
782     data.name  = name;
783     data.found = 0;
784     code = afs_dir_EnumerateDir(tdc, get_name_hook, &data);
785     if (!code && !data.found) {
786 #ifdef OSI_EXPORT_DEBUG
787         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): not found\n",
788                parent->d_name.name ? (char *)parent->d_name.name : "?",
789                data.fid.Cell,      data.fid.Fid.Volume,
790                data.fid.Fid.Vnode, data.fid.Fid.Unique);
791 #endif
792         code = ENOENT;
793     } else if (code) {
794 #ifdef OSI_EXPORT_DEBUG
795         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): Enumeratedir(0x%08x/%d/%d.%d): %d\n",
796                parent->d_name.name ? (char *)parent->d_name.name : "?",
797                data.fid.Cell,      data.fid.Fid.Volume,
798                data.fid.Fid.Vnode, data.fid.Fid.Unique,
799                vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
800                vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code);
801 #endif
802     }
803
804     ReleaseReadLock(&tdc->lock);
805     ReleaseReadLock(&vcp->lock);
806     afs_PutDCache(tdc);
807
808 done:
809     if (!code) {
810         printk("afs: get_name(%s, 0x%08x/%d/%d.%d) => %s\n",
811                parent->d_name.name ? (char *)parent->d_name.name : "?",
812                data.fid.Cell,      data.fid.Fid.Volume,
813                data.fid.Fid.Vnode, data.fid.Fid.Unique, name);
814     }
815     afs_PutFakeStat(&fakestate);
816     AFS_GUNLOCK();
817     crfree(credp);
818     code = afs_CheckCode(code, &treq, 102);
819     return -code;
820 }
821
822
823 static struct dentry *afs_export_get_parent(struct dentry *child)
824 {
825     struct VenusFid tfid;
826     struct vrequest treq;
827     struct cell *tcell;
828     struct vcache *vcp;
829     struct dentry *dp = NULL;
830     cred_t *credp;
831     afs_uint32 cellidx;
832     int code;
833
834     if (!child->d_inode) {
835         /* can't find the parent of a negative dentry */
836 #ifdef OSI_EXPORT_DEBUG
837         printk("afs: get_parent(%s): no inode\n",
838                child->d_name.name ? (char *)child->d_name.name : "?");
839 #endif
840         return ERR_PTR(-EIO);
841     }
842
843     credp = crref();
844     AFS_GLOCK();
845
846     vcp = VTOAFS(child->d_inode);
847
848     if (afs_IsDynrootMount(vcp)) {
849         /* the dynmount directory; parent is always the AFS root */
850         tfid = afs_globalVp->f.fid;
851
852     } else if (afs_IsDynrootAny(vcp) &&
853                VNUM_TO_VNTYPE(vcp->f.fid.Fid.Vnode) == VN_TYPE_MOUNT) {
854         /* a mount point in the dynmount directory */
855         afs_GetDynrootMountFid(&tfid);
856
857     } else if (vcp->mvstat == 2) {
858         /* volume root */
859         ObtainReadLock(&vcp->lock);
860         if (vcp->mvid && vcp->mvid->Fid.Volume) {
861             tfid = *vcp->mvid;
862             ReleaseReadLock(&vcp->lock);
863         } else {
864             ReleaseReadLock(&vcp->lock);
865             tcell = afs_GetCell(vcp->f.fid.Cell, READ_LOCK);
866             if (!tcell) {
867 #ifdef OSI_EXPORT_DEBUG
868                 printk("afs: get_parent(0x%08x/%d/%d.%d): no cell\n",
869                        vcp->f.fid.Cell, vcp->f.fid.Fid.Volume,
870                        vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique);
871 #endif
872                 dp = ERR_PTR(-ENOENT);
873                 goto done;
874             }
875
876             cellidx = tcell->cellIndex;
877             afs_PutCell(tcell, READ_LOCK);
878
879             afs_GetDynrootMountFid(&tfid);
880             tfid.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, cellidx << 2);
881             tfid.Fid.Unique = vcp->f.fid.Fid.Volume;
882         }
883
884     } else {
885         /* any other vnode */
886         if (vType(vcp) == VDIR && !vcp->f.parent.vnode && vcp->mvstat != 1) {
887             code = afs_InitReq(&treq, credp);
888             if (code) {
889 #ifdef OSI_EXPORT_DEBUG
890                 printk("afs: get_parent(0x%08x/%d/%d.%d): InitReq: %d\n",
891                        vcp->f.fid.Cell, vcp->f.fid.Fid.Volume,
892                        vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code);
893 #endif
894                 dp = ERR_PTR(-ENOENT);
895                 goto done;
896             } else {
897                 code = update_dir_parent(&treq, vcp);
898                 if (code) {
899 #ifdef OSI_EXPORT_DEBUG
900                     printk("afs: get_parent(0x%08x/%d/%d.%d): update_dir_parent: %d\n",
901                            vcp->f.fid.Cell, vcp->f.fid.Fid.Volume,
902                            vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code);
903 #endif
904                     dp = ERR_PTR(-ENOENT);
905                     goto done;
906                 }
907             }
908         }
909
910         tfid.Cell       = vcp->f.fid.Cell;
911         tfid.Fid.Volume = vcp->f.fid.Fid.Volume;
912         tfid.Fid.Vnode  = vcp->f.parent.vnode;
913         tfid.Fid.Unique = vcp->f.parent.unique;
914     }
915
916 #ifdef OSI_EXPORT_DEBUG
917     printk("afs: get_parent(0x%08x/%d/%d.%d): => 0x%08x/%d/%d.%d\n",
918            vcp->f.fid.Cell, vcp->f.fid.Fid.Volume,
919            vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique,
920            tfid.Cell, tfid.Fid.Volume, tfid.Fid.Vnode, tfid.Fid.Unique);
921 #endif
922
923     dp = get_dentry_from_fid(credp, &tfid);
924     if (!dp) {
925 #ifdef OSI_EXPORT_DEBUG
926         printk("afs: get_parent(0x%08x/%d/%d.%d): no dentry\n",
927                vcp->f.fid.Cell, vcp->f.fid.Fid.Volume,
928                vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique);
929 #endif
930         dp = ERR_PTR(-ENOENT);
931     }
932
933 done:
934     AFS_GUNLOCK();
935     crfree(credp);
936
937     return dp;
938 }
939
940
941 struct export_operations afs_export_ops = {
942     .encode_fh  = afs_encode_fh,
943 #if defined(NEW_EXPORT_OPS)
944     .fh_to_dentry  = afs_fh_to_dentry,
945 #else
946     .decode_fh  = afs_decode_fh,
947     .get_dentry = afs_export_get_dentry,
948 #endif
949     .get_name   = afs_export_get_name,
950     .get_parent = afs_export_get_parent,
951 };
952
953 #endif