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