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