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