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