Import Upstream version 1.8.5
[hcoop/debian/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 != AFS_MVSTAT_ROOT)
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, 104));
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 != AFS_MVSTAT_ROOT && !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 == AFS_MVSTAT_ROOT) { /* 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 == AFS_MVSTAT_ROOT) {
873 /* volume root */
874 ObtainReadLock(&vcp->lock);
875 if (vcp->mvid.parent && vcp->mvid.parent->Fid.Volume) {
876 tfid = *vcp->mvid.parent;
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 != AFS_MVSTAT_MTPT) {
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