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