libafs: reduce stack space in LINUX
[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 = NULL;
468     struct vcache *vcp;
469     struct vattr vattr;
470     struct inode *ip;
471     struct dentry *dp;
472     afs_int32 code;
473
474     code = afs_CreateReq(&treq, credp);
475     if (code) {
476 #ifdef OSI_EXPORT_DEBUG
477         printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): afs_CreateReq: %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, NULL, 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         afs_DestroyReq(treq);
490         return NULL;
491     }
492
493     /* 
494      * Now, it might be that we just caused a directory vnode to
495      * spring into existence, in which case its parent FID is unset.
496      * We need to do something about that, but only because we care
497      * in our own get_parent(), below -- the common code never looks
498      * at parentVnode on directories, except for VIOCGETVCXSTATUS.
499      * So, if this fails, we don't really care very much.
500      */
501     if (vType(vcp) == VDIR && vcp->mvstat != 2 && !vcp->f.parent.vnode)
502         update_dir_parent(treq, vcp);
503
504     /*
505      * If this is a volume root directory and fakestat is enabled,
506      * we might need to replace the directory by a mount point.
507      */
508     code = UnEvalFakeStat(treq, &vcp);
509     if (code) {
510 #ifdef OSI_EXPORT_DEBUG
511         printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): UnEvalFakeStat: %d\n",
512                afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique,
513                code);
514 #endif
515         afs_PutVCache(vcp);
516         code = afs_CheckCode(code, treq, 103);
517         afs_DestroyReq(treq);
518         return ERR_PTR(-code);
519     }
520
521     ip = AFSTOV(vcp);
522     afs_getattr(vcp, &vattr, credp);
523     afs_fill_inode(ip, &vattr);
524
525     /* d_alloc_anon might block, so we shouldn't hold the glock */
526     AFS_GUNLOCK();
527     dp = d_alloc_anon(ip);
528     AFS_GLOCK();
529
530     if (!dp) {
531         iput(ip);
532 #ifdef OSI_EXPORT_DEBUG
533         printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): out of memory\n",
534                afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique);
535 #endif
536         afs_DestroyReq(treq);
537         return ERR_PTR(-ENOMEM);
538     }
539
540     dp->d_op = &afs_dentry_operations;
541     afs_DestroyReq(treq);
542     return dp;
543 }
544
545 static struct dentry *afs_export_get_dentry(struct super_block *sb,
546                                             void *inump)
547 {
548     struct dentry *dp;
549     cred_t *credp;
550
551     credp = crref();
552     AFS_GLOCK();
553
554     dp = get_dentry_from_fid(credp, inump);
555
556     AFS_GUNLOCK();
557     crfree(credp);
558
559     return dp;
560 }
561
562
563 static int get_name_hook(void *hdata, char *name,
564                          afs_int32 vnode, afs_int32 unique)
565 {
566     struct get_name_data *data = (struct get_name_data *)hdata;
567     int len;
568
569     if (vnode == data->fid.Fid.Vnode && unique == data->fid.Fid.Unique) {
570         len = strlen(name);
571         if (len > NAME_MAX) len = NAME_MAX;
572         memcpy(data->name, name, len);
573         data->name[len] = '\0';
574         data->found = 1;
575     }
576     return 0;
577 }
578
579 static int afs_export_get_name(struct dentry *parent, char *name,
580                                struct dentry *child)
581 {
582     struct afs_fakestat_state fakestate;
583     struct get_name_data data;
584     struct vrequest *treq = NULL;
585     struct volume *tvp;
586     struct vcache *vcp;
587     struct dcache *tdc;
588     cred_t *credp;
589     afs_size_t dirOffset, dirLen;
590     afs_int32 code = 0;
591
592     if (!parent->d_inode) {
593 #ifdef OSI_EXPORT_DEBUG
594         /* can't lookup name in a negative dentry */
595         printk("afs: get_name(%s, %s): no parent inode\n",
596                parent->d_name.name ? (char *)parent->d_name.name : "?",
597                child->d_name.name  ? (char *)child->d_name.name  : "?");
598 #endif
599         return -EIO;
600     }
601     if (!child->d_inode) {
602 #ifdef OSI_EXPORT_DEBUG
603         /* can't find the FID of negative dentry */
604         printk("afs: get_name(%s, %s): no child inode\n",
605                parent->d_name.name ? (char *)parent->d_name.name : "?",
606                child->d_name.name  ? (char *)child->d_name.name  : "?");
607 #endif
608         return -ENOENT;
609     }
610
611     afs_InitFakeStat(&fakestate);
612
613     credp = crref();
614     AFS_GLOCK();
615
616     vcp = VTOAFS(child->d_inode);
617
618     /* special case dynamic mount directory */
619     if (afs_IsDynrootMount(vcp)) {
620 #ifdef OSI_EXPORT_DEBUG
621         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): this is the dynmount dir\n",
622                parent->d_name.name ? (char *)parent->d_name.name : "?",
623                vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
624                vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique);
625 #endif
626         data.fid = vcp->f.fid;
627         if (VTOAFS(parent->d_inode) == afs_globalVp)
628             strcpy(name, AFS_DYNROOT_MOUNTNAME);
629         else
630             code = -ENOENT;
631         goto done;
632     }
633
634     /* Figure out what FID to look for */
635     if (vcp->mvstat == 2) { /* volume root */
636         tvp = afs_GetVolume(&vcp->f.fid, 0, READ_LOCK);
637         if (!tvp) {
638 #ifdef OSI_EXPORT_DEBUG
639             printk("afs: get_name(%s, 0x%08x/%d/%d.%d): no volume for root\n",
640                    parent->d_name.name ? (char *)parent->d_name.name : "?",
641                    vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
642                    vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique);
643 #endif
644             code = ENOENT;
645             goto done;
646         }
647         data.fid = tvp->mtpoint;
648         afs_PutVolume(tvp, READ_LOCK);
649     } else {
650         data.fid = vcp->f.fid;
651     }
652
653     vcp = VTOAFS(parent->d_inode);
654 #ifdef OSI_EXPORT_DEBUG
655     printk("afs: get_name(%s, 0x%08x/%d/%d.%d): parent is 0x%08x/%d/%d.%d\n",
656            parent->d_name.name ? (char *)parent->d_name.name : "?",
657            data.fid.Cell,      data.fid.Fid.Volume,
658            data.fid.Fid.Vnode, data.fid.Fid.Unique,
659            vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
660            vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique);
661 #endif
662     code = afs_CreateReq(&treq, credp);
663     if (code) {
664 #ifdef OSI_EXPORT_DEBUG
665         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): afs_CreateReq: %d\n",
666                parent->d_name.name ? (char *)parent->d_name.name : "?",
667                data.fid.Cell,      data.fid.Fid.Volume,
668                data.fid.Fid.Vnode, data.fid.Fid.Unique, code);
669 #endif
670         goto done;
671     }
672
673     /* a dynamic mount point in the dynamic mount directory */
674     if (afs_IsDynrootMount(vcp) && afs_IsDynrootAnyFid(&data.fid)
675         && VNUM_TO_VNTYPE(data.fid.Fid.Vnode) == VN_TYPE_MOUNT) {
676 #ifdef OSI_EXPORT_DEBUG
677         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): dynamic mount point\n",
678                parent->d_name.name ? (char *)parent->d_name.name : "?",
679                data.fid.Cell,      data.fid.Fid.Volume,
680                data.fid.Fid.Vnode, data.fid.Fid.Unique);
681 #endif
682         vcp = afs_GetVCache(&data.fid, treq, NULL, NULL);
683         if (vcp) {
684             ObtainReadLock(&vcp->lock);
685             if (strlen(vcp->linkData + 1) <= NAME_MAX)
686                 strcpy(name, vcp->linkData + 1);
687             else
688                 code = ENOENT;
689             ReleaseReadLock(&vcp->lock);
690             afs_PutVCache(vcp);
691         } else {
692 #ifdef OSI_EXPORT_DEBUG
693             printk("afs: get_name(%s, 0x%08x/%d/%d.%d): no vcache\n",
694                    parent->d_name.name ? (char *)parent->d_name.name : "?",
695                    data.fid.Cell,      data.fid.Fid.Volume,
696                    data.fid.Fid.Vnode, data.fid.Fid.Unique);
697 #endif
698             code = ENOENT;
699         }
700         goto done;
701     }
702
703     code = afs_EvalFakeStat(&vcp, &fakestate, treq);
704     if (code)
705         goto done;
706
707     if (vcp->f.fid.Cell != data.fid.Cell ||
708         vcp->f.fid.Fid.Volume != data.fid.Fid.Volume) {
709         /* parent is not the expected cell and volume; thus it
710          * cannot possibly contain the fid we are looking for */
711 #ifdef OSI_EXPORT_DEBUG
712         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): wrong parent 0x%08x/%d\n",
713                parent->d_name.name ? (char *)parent->d_name.name : "?",
714                data.fid.Cell,      data.fid.Fid.Volume,
715                data.fid.Fid.Vnode, data.fid.Fid.Unique,
716                vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume);
717 #endif
718         code = ENOENT;
719         goto done;
720     }
721
722
723 redo:
724     if (!(vcp->f.states & CStatd)) {
725         if ((code = afs_VerifyVCache2(vcp, treq))) {
726 #ifdef OSI_EXPORT_DEBUG
727             printk("afs: get_name(%s, 0x%08x/%d/%d.%d): VerifyVCache2(0x%08x/%d/%d.%d): %d\n",
728                    parent->d_name.name ? (char *)parent->d_name.name : "?",
729                    data.fid.Cell,      data.fid.Fid.Volume,
730                    data.fid.Fid.Vnode, data.fid.Fid.Unique,
731                    vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
732                    vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code);
733 #endif
734             goto done;
735         }
736     }
737
738     tdc = afs_GetDCache(vcp, (afs_size_t) 0, treq, &dirOffset, &dirLen, 1);
739     if (!tdc) {
740 #ifdef OSI_EXPORT_DEBUG
741         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): GetDCache(0x%08x/%d/%d.%d): %d\n",
742                parent->d_name.name ? (char *)parent->d_name.name : "?",
743                data.fid.Cell,      data.fid.Fid.Volume,
744                data.fid.Fid.Vnode, data.fid.Fid.Unique,
745                vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
746                vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code);
747 #endif
748         code = EIO;
749         goto done;
750     }
751
752     ObtainReadLock(&vcp->lock);
753     ObtainReadLock(&tdc->lock);
754
755     /*
756      * Make sure that the data in the cache is current. There are two
757      * cases we need to worry about:
758      * 1. The cache data is being fetched by another process.
759      * 2. The cache data is no longer valid
760      */
761     while ((vcp->f.states & CStatd)
762            && (tdc->dflags & DFFetching)
763            && hsame(vcp->f.m.DataVersion, tdc->f.versionNo)) {
764         ReleaseReadLock(&tdc->lock);
765         ReleaseReadLock(&vcp->lock);
766         afs_osi_Sleep(&tdc->validPos);
767         ObtainReadLock(&vcp->lock);
768         ObtainReadLock(&tdc->lock);
769     }
770     if (!(vcp->f.states & CStatd)
771         || !hsame(vcp->f.m.DataVersion, tdc->f.versionNo)) {
772         ReleaseReadLock(&tdc->lock);
773         ReleaseReadLock(&vcp->lock);
774         afs_PutDCache(tdc);
775 #ifdef OSI_EXPORT_DEBUG
776         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): dir (0x%08x/%d/%d.%d) changed; retrying\n",
777                parent->d_name.name ? (char *)parent->d_name.name : "?",
778                data.fid.Cell,      data.fid.Fid.Volume,
779                data.fid.Fid.Vnode, data.fid.Fid.Unique,
780                vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
781                vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique);
782 #endif
783         goto redo;
784     }
785
786     data.name  = name;
787     data.found = 0;
788     code = afs_dir_EnumerateDir(tdc, get_name_hook, &data);
789     if (!code && !data.found) {
790 #ifdef OSI_EXPORT_DEBUG
791         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): not found\n",
792                parent->d_name.name ? (char *)parent->d_name.name : "?",
793                data.fid.Cell,      data.fid.Fid.Volume,
794                data.fid.Fid.Vnode, data.fid.Fid.Unique);
795 #endif
796         code = ENOENT;
797     } else if (code) {
798 #ifdef OSI_EXPORT_DEBUG
799         printk("afs: get_name(%s, 0x%08x/%d/%d.%d): Enumeratedir(0x%08x/%d/%d.%d): %d\n",
800                parent->d_name.name ? (char *)parent->d_name.name : "?",
801                data.fid.Cell,      data.fid.Fid.Volume,
802                data.fid.Fid.Vnode, data.fid.Fid.Unique,
803                vcp->f.fid.Cell,      vcp->f.fid.Fid.Volume,
804                vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code);
805 #endif
806     }
807
808     ReleaseReadLock(&tdc->lock);
809     ReleaseReadLock(&vcp->lock);
810     afs_PutDCache(tdc);
811
812 done:
813     if (!code) {
814         printk("afs: get_name(%s, 0x%08x/%d/%d.%d) => %s\n",
815                parent->d_name.name ? (char *)parent->d_name.name : "?",
816                data.fid.Cell,      data.fid.Fid.Volume,
817                data.fid.Fid.Vnode, data.fid.Fid.Unique, name);
818     }
819     afs_PutFakeStat(&fakestate);
820     code = afs_CheckCode(code, treq, 102);
821     afs_DestroyReq(treq);
822     AFS_GUNLOCK();
823     crfree(credp);
824     return -code;
825 }
826
827
828 static struct dentry *afs_export_get_parent(struct dentry *child)
829 {
830     struct VenusFid tfid;
831     struct vrequest *treq = NULL;
832     struct cell *tcell;
833     struct vcache *vcp;
834     struct dentry *dp = NULL;
835     cred_t *credp;
836     afs_uint32 cellidx;
837     int code;
838
839     if (!child->d_inode) {
840         /* can't find the parent of a negative dentry */
841 #ifdef OSI_EXPORT_DEBUG
842         printk("afs: get_parent(%s): no inode\n",
843                child->d_name.name ? (char *)child->d_name.name : "?");
844 #endif
845         return ERR_PTR(-EIO);
846     }
847
848     credp = crref();
849     AFS_GLOCK();
850
851     vcp = VTOAFS(child->d_inode);
852
853     if (afs_IsDynrootMount(vcp)) {
854         /* the dynmount directory; parent is always the AFS root */
855         tfid = afs_globalVp->f.fid;
856
857     } else if (afs_IsDynrootAny(vcp) &&
858                VNUM_TO_VNTYPE(vcp->f.fid.Fid.Vnode) == VN_TYPE_MOUNT) {
859         /* a mount point in the dynmount directory */
860         afs_GetDynrootMountFid(&tfid);
861
862     } else if (vcp->mvstat == 2) {
863         /* volume root */
864         ObtainReadLock(&vcp->lock);
865         if (vcp->mvid && vcp->mvid->Fid.Volume) {
866             tfid = *vcp->mvid;
867             ReleaseReadLock(&vcp->lock);
868         } else {
869             ReleaseReadLock(&vcp->lock);
870             tcell = afs_GetCell(vcp->f.fid.Cell, READ_LOCK);
871             if (!tcell) {
872 #ifdef OSI_EXPORT_DEBUG
873                 printk("afs: get_parent(0x%08x/%d/%d.%d): no cell\n",
874                        vcp->f.fid.Cell, vcp->f.fid.Fid.Volume,
875                        vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique);
876 #endif
877                 dp = ERR_PTR(-ENOENT);
878                 goto done;
879             }
880
881             cellidx = tcell->cellIndex;
882             afs_PutCell(tcell, READ_LOCK);
883
884             afs_GetDynrootMountFid(&tfid);
885             tfid.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, cellidx << 2);
886             tfid.Fid.Unique = vcp->f.fid.Fid.Volume;
887         }
888
889     } else {
890         /* any other vnode */
891         if (vType(vcp) == VDIR && !vcp->f.parent.vnode && vcp->mvstat != 1) {
892             code = afs_CreateReq(&treq, credp);
893             if (code) {
894 #ifdef OSI_EXPORT_DEBUG
895                 printk("afs: get_parent(0x%08x/%d/%d.%d): afs_CreateReq: %d\n",
896                        vcp->f.fid.Cell, vcp->f.fid.Fid.Volume,
897                        vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code);
898 #endif
899                 dp = ERR_PTR(-ENOENT);
900                 goto done;
901             } else {
902                 code = update_dir_parent(treq, vcp);
903                 if (code) {
904 #ifdef OSI_EXPORT_DEBUG
905                     printk("afs: get_parent(0x%08x/%d/%d.%d): update_dir_parent: %d\n",
906                            vcp->f.fid.Cell, vcp->f.fid.Fid.Volume,
907                            vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code);
908 #endif
909                     dp = ERR_PTR(-ENOENT);
910                     goto done;
911                 }
912             }
913         }
914
915         tfid.Cell       = vcp->f.fid.Cell;
916         tfid.Fid.Volume = vcp->f.fid.Fid.Volume;
917         tfid.Fid.Vnode  = vcp->f.parent.vnode;
918         tfid.Fid.Unique = vcp->f.parent.unique;
919     }
920
921 #ifdef OSI_EXPORT_DEBUG
922     printk("afs: get_parent(0x%08x/%d/%d.%d): => 0x%08x/%d/%d.%d\n",
923            vcp->f.fid.Cell, vcp->f.fid.Fid.Volume,
924            vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique,
925            tfid.Cell, tfid.Fid.Volume, tfid.Fid.Vnode, tfid.Fid.Unique);
926 #endif
927
928     dp = get_dentry_from_fid(credp, &tfid);
929     if (!dp) {
930 #ifdef OSI_EXPORT_DEBUG
931         printk("afs: get_parent(0x%08x/%d/%d.%d): no dentry\n",
932                vcp->f.fid.Cell, vcp->f.fid.Fid.Volume,
933                vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique);
934 #endif
935         dp = ERR_PTR(-ENOENT);
936     }
937
938 done:
939     afs_DestroyReq(treq);
940     AFS_GUNLOCK();
941     crfree(credp);
942
943     return dp;
944 }
945
946
947 struct export_operations afs_export_ops = {
948     .encode_fh  = afs_encode_fh,
949 #if defined(NEW_EXPORT_OPS)
950     .fh_to_dentry  = afs_fh_to_dentry,
951 #else
952     .decode_fh  = afs_decode_fh,
953     .get_dentry = afs_export_get_dentry,
954 #endif
955     .get_name   = afs_export_get_name,
956     .get_parent = afs_export_get_parent,
957 };
958
959 #endif