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