Blame view

fs/exportfs/expfs.c 12.3 KB
e38f98175   Christoph Hellwig   exportfs: update ...
1
2
3
4
5
6
7
8
  /*
   * Copyright (C) Neil Brown 2002
   * Copyright (C) Christoph Hellwig 2007
   *
   * This file contains the code mapping from inodes to NFS file handles,
   * and for mapping back from file handles to dentries.
   *
   * For details on why we do all the strange and hairy things in here
dc7a08166   J. Bruce Fields   nfs: new subdir D...
9
   * take a look at Documentation/filesystems/nfs/Exporting.
e38f98175   Christoph Hellwig   exportfs: update ...
10
   */
a56942551   Christoph Hellwig   knfsd: exportfs: ...
11
  #include <linux/exportfs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
  #include <linux/fs.h>
  #include <linux/file.h>
  #include <linux/module.h>
d37065cd6   Christoph Hellwig   knfsd: exportfs: ...
15
  #include <linux/mount.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <linux/namei.h>
745ca2475   David Howells   CRED: Pass creden...
17
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18

10f11c341   Christoph Hellwig   knfsd: exportfs: ...
19
  #define dprintk(fmt, args...) do{}while(0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21

e38f98175   Christoph Hellwig   exportfs: update ...
22
  static int get_name(struct vfsmount *mnt, struct dentry *dentry, char *name,
10f11c341   Christoph Hellwig   knfsd: exportfs: ...
23
  		struct dentry *child);
e38f98175   Christoph Hellwig   exportfs: update ...
24
25
  static int exportfs_get_name(struct vfsmount *mnt, struct dentry *dir,
  		char *name, struct dentry *child)
10f11c341   Christoph Hellwig   knfsd: exportfs: ...
26
  {
396551644   Christoph Hellwig   exportfs: make st...
27
  	const struct export_operations *nop = dir->d_sb->s_export_op;
10f11c341   Christoph Hellwig   knfsd: exportfs: ...
28
29
30
31
  
  	if (nop->get_name)
  		return nop->get_name(dir, name, child);
  	else
e38f98175   Christoph Hellwig   exportfs: update ...
32
  		return get_name(mnt, dir, name, child);
10f11c341   Christoph Hellwig   knfsd: exportfs: ...
33
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

fb66a1989   Christoph Hellwig   knfsd: exportfs: ...
35
36
37
  /*
   * Check if the dentry or any of it's aliases is acceptable.
   */
e2f99018e   Christoph Hellwig   [PATCH] exportfs:...
38
39
40
41
42
43
  static struct dentry *
  find_acceptable_alias(struct dentry *result,
  		int (*acceptable)(void *context, struct dentry *dentry),
  		void *context)
  {
  	struct dentry *dentry, *toput = NULL;
873feea09   Nick Piggin   fs: dcache per-in...
44
  	struct inode *inode;
e2f99018e   Christoph Hellwig   [PATCH] exportfs:...
45

fb66a1989   Christoph Hellwig   knfsd: exportfs: ...
46
47
  	if (acceptable(context, result))
  		return result;
873feea09   Nick Piggin   fs: dcache per-in...
48
49
50
  	inode = result->d_inode;
  	spin_lock(&inode->i_lock);
  	list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
dc0474be3   Nick Piggin   fs: dcache ration...
51
  		dget(dentry);
873feea09   Nick Piggin   fs: dcache per-in...
52
  		spin_unlock(&inode->i_lock);
e2f99018e   Christoph Hellwig   [PATCH] exportfs:...
53
54
55
56
57
58
  		if (toput)
  			dput(toput);
  		if (dentry != result && acceptable(context, dentry)) {
  			dput(result);
  			return dentry;
  		}
873feea09   Nick Piggin   fs: dcache per-in...
59
  		spin_lock(&inode->i_lock);
e2f99018e   Christoph Hellwig   [PATCH] exportfs:...
60
61
  		toput = dentry;
  	}
873feea09   Nick Piggin   fs: dcache per-in...
62
  	spin_unlock(&inode->i_lock);
e2f99018e   Christoph Hellwig   [PATCH] exportfs:...
63
64
65
66
67
  
  	if (toput)
  		dput(toput);
  	return NULL;
  }
dd90b5090   Christoph Hellwig   knfsd: exportfs: ...
68
69
70
71
72
73
74
  /*
   * Find root of a disconnected subtree and return a reference to it.
   */
  static struct dentry *
  find_disconnected_root(struct dentry *dentry)
  {
  	dget(dentry);
0461ee261   Christoph Hellwig   exportfs: use dge...
75
76
77
78
79
80
81
  	while (!IS_ROOT(dentry)) {
  		struct dentry *parent = dget_parent(dentry);
  
  		if (!(parent->d_flags & DCACHE_DISCONNECTED)) {
  			dput(parent);
  			break;
  		}
dd90b5090   Christoph Hellwig   knfsd: exportfs: ...
82
83
  		dput(dentry);
  		dentry = parent;
dd90b5090   Christoph Hellwig   knfsd: exportfs: ...
84
  	}
dd90b5090   Christoph Hellwig   knfsd: exportfs: ...
85
86
  	return dentry;
  }
019ab801c   Christoph Hellwig   knfsd: exportfs: ...
87
88
  /*
   * Make sure target_dir is fully connected to the dentry tree.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
   *
019ab801c   Christoph Hellwig   knfsd: exportfs: ...
90
   * It may already be, as the flag isn't always updated when connection happens.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
   */
019ab801c   Christoph Hellwig   knfsd: exportfs: ...
92
  static int
f3f8e1757   Al Viro   [PATCH] reduce th...
93
  reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
  {
019ab801c   Christoph Hellwig   knfsd: exportfs: ...
95
96
  	int noprogress = 0;
  	int err = -ESTALE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
  
  	/*
019ab801c   Christoph Hellwig   knfsd: exportfs: ...
99
  	 * It is possible that a confused file system might not let us complete
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
104
105
  	 * the path to the root.  For example, if get_parent returns a directory
  	 * in which we cannot find a name for the child.  While this implies a
  	 * very sick filesystem we don't want it to cause knfsd to spin.  Hence
  	 * the noprogress counter.  If we go through the loop 10 times (2 is
  	 * probably enough) without getting anywhere, we just give up
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  	while (target_dir->d_flags & DCACHE_DISCONNECTED && noprogress++ < 10) {
dd90b5090   Christoph Hellwig   knfsd: exportfs: ...
107
  		struct dentry *pd = find_disconnected_root(target_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
113
114
  
  		if (!IS_ROOT(pd)) {
  			/* must have found a connected parent - great */
  			spin_lock(&pd->d_lock);
  			pd->d_flags &= ~DCACHE_DISCONNECTED;
  			spin_unlock(&pd->d_lock);
  			noprogress = 0;
e38f98175   Christoph Hellwig   exportfs: update ...
115
  		} else if (pd == mnt->mnt_sb->s_root) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
121
122
  			printk(KERN_ERR "export: Eeek filesystem root is not connected, impossible
  ");
  			spin_lock(&pd->d_lock);
  			pd->d_flags &= ~DCACHE_DISCONNECTED;
  			spin_unlock(&pd->d_lock);
  			noprogress = 0;
  		} else {
10f11c341   Christoph Hellwig   knfsd: exportfs: ...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  			/*
  			 * We have hit the top of a disconnected path, try to
  			 * find parent and connect.
  			 *
  			 * Racing with some other process renaming a directory
  			 * isn't much of a problem here.  If someone renames
  			 * the directory, it will end up properly connected,
  			 * which is what we want
  			 *
  			 * Getting the parent can't be supported generically,
  			 * the locking is too icky.
  			 *
  			 * Instead we just return EACCES.  If server reboots
  			 * or inodes get flushed, you lose
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  			 */
10f11c341   Christoph Hellwig   knfsd: exportfs: ...
138
  			struct dentry *ppd = ERR_PTR(-EACCES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  			struct dentry *npd;
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
140
  			mutex_lock(&pd->d_inode->i_mutex);
e38f98175   Christoph Hellwig   exportfs: update ...
141
142
  			if (mnt->mnt_sb->s_export_op->get_parent)
  				ppd = mnt->mnt_sb->s_export_op->get_parent(pd);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
143
  			mutex_unlock(&pd->d_inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
  
  			if (IS_ERR(ppd)) {
  				err = PTR_ERR(ppd);
019ab801c   Christoph Hellwig   knfsd: exportfs: ...
147
148
  				dprintk("%s: get_parent of %ld failed, err %d
  ",
8e24eea72   Harvey Harrison   fs: replace remai...
149
  					__func__, pd->d_inode->i_ino, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
  				dput(pd);
  				break;
  			}
019ab801c   Christoph Hellwig   knfsd: exportfs: ...
153

8e24eea72   Harvey Harrison   fs: replace remai...
154
155
  			dprintk("%s: find name of %lu in %lu
  ", __func__,
019ab801c   Christoph Hellwig   knfsd: exportfs: ...
156
  				pd->d_inode->i_ino, ppd->d_inode->i_ino);
e38f98175   Christoph Hellwig   exportfs: update ...
157
  			err = exportfs_get_name(mnt, ppd, nbuf, pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
160
161
162
163
164
165
166
167
  			if (err) {
  				dput(ppd);
  				dput(pd);
  				if (err == -ENOENT)
  					/* some race between get_parent and
  					 * get_name?  just try again
  					 */
  					continue;
  				break;
  			}
8e24eea72   Harvey Harrison   fs: replace remai...
168
169
  			dprintk("%s: found name: %s
  ", __func__, nbuf);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
170
  			mutex_lock(&ppd->d_inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  			npd = lookup_one_len(nbuf, ppd, strlen(nbuf));
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
172
  			mutex_unlock(&ppd->d_inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
  			if (IS_ERR(npd)) {
  				err = PTR_ERR(npd);
019ab801c   Christoph Hellwig   knfsd: exportfs: ...
175
176
  				dprintk("%s: lookup failed: %d
  ",
8e24eea72   Harvey Harrison   fs: replace remai...
177
  					__func__, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
180
181
182
183
184
185
186
187
188
189
  				dput(ppd);
  				dput(pd);
  				break;
  			}
  			/* we didn't really want npd, we really wanted
  			 * a side-effect of the lookup.
  			 * hopefully, npd == pd, though it isn't really
  			 * a problem if it isn't
  			 */
  			if (npd == pd)
  				noprogress = 0;
  			else
8e24eea72   Harvey Harrison   fs: replace remai...
190
191
  				printk("%s: npd != pd
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  			dput(npd);
  			dput(ppd);
  			if (IS_ROOT(pd)) {
  				/* something went wrong, we have to give up */
  				dput(pd);
  				break;
  			}
  		}
  		dput(pd);
  	}
  
  	if (target_dir->d_flags & DCACHE_DISCONNECTED) {
  		/* something went wrong - oh-well */
  		if (!err)
  			err = -ESTALE;
019ab801c   Christoph Hellwig   knfsd: exportfs: ...
207
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  	}
019ab801c   Christoph Hellwig   knfsd: exportfs: ...
209
210
211
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
217
218
219
220
221
222
223
224
  struct getdents_callback {
  	char *name;		/* name that was found. It already points to a
  				   buffer NAME_MAX+1 is size */
  	unsigned long ino;	/* the inum we are looking for */
  	int found;		/* inode matched? */
  	int sequence;		/* sequence counter */
  };
  
  /*
   * A rather strange filldir function to capture
   * the name matching the specified inode number.
   */
  static int filldir_one(void * __buf, const char * name, int len,
afefdbb28   David Howells   [PATCH] VFS: Make...
225
  			loff_t pos, u64 ino, unsigned int d_type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  {
  	struct getdents_callback *buf = __buf;
  	int result = 0;
  
  	buf->sequence++;
  	if (buf->ino == ino) {
  		memcpy(buf->name, name, len);
  		buf->name[len] = '\0';
  		buf->found = 1;
  		result = -1;
  	}
  	return result;
  }
  
  /**
   * get_name - default export_operations->get_name function
   * @dentry: the directory in which to find a name
   * @name:   a pointer to a %NAME_MAX+1 char buffer to store the name
   * @child:  the dentry for the child directory.
   *
   * calls readdir on the parent until it finds an entry with
   * the same inode number as the child, and returns that.
   */
e38f98175   Christoph Hellwig   exportfs: update ...
249
250
  static int get_name(struct vfsmount *mnt, struct dentry *dentry,
  		char *name, struct dentry *child)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  {
745ca2475   David Howells   CRED: Pass creden...
252
  	const struct cred *cred = current_cred();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  	struct inode *dir = dentry->d_inode;
  	int error;
  	struct file *file;
  	struct getdents_callback buffer;
  
  	error = -ENOTDIR;
  	if (!dir || !S_ISDIR(dir->i_mode))
  		goto out;
  	error = -EINVAL;
  	if (!dir->i_fop)
  		goto out;
  	/*
  	 * Open the directory ...
  	 */
745ca2475   David Howells   CRED: Pass creden...
267
  	file = dentry_open(dget(dentry), mntget(mnt), O_RDONLY, cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  	error = PTR_ERR(file);
  	if (IS_ERR(file))
  		goto out;
  
  	error = -EINVAL;
  	if (!file->f_op->readdir)
  		goto out_close;
  
  	buffer.name = name;
  	buffer.ino = child->d_inode->i_ino;
  	buffer.found = 0;
  	buffer.sequence = 0;
  	while (1) {
  		int old_seq = buffer.sequence;
  
  		error = vfs_readdir(file, filldir_one, &buffer);
53c9c5c0e   Al Viro   [PATCH] prepare v...
284
285
286
287
  		if (buffer.found) {
  			error = 0;
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
  
  		if (error < 0)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
295
296
297
298
299
300
  		error = -ENOENT;
  		if (old_seq == buffer.sequence)
  			break;
  	}
  
  out_close:
  	fput(file);
  out:
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
305
306
307
308
309
310
311
312
  /**
   * export_encode_fh - default export_operations->encode_fh function
   * @dentry:  the dentry to encode
   * @fh:      where to store the file handle fragment
   * @max_len: maximum length to store there
   * @connectable: whether to store parent information
   *
   * This default encode_fh function assumes that the 32 inode number
   * is suitable for locating an inode, and that the generation number
   * can be used to check that it is still valid.  It places them in the
   * filehandle fragment where export_decode_fh expects to find them.
   */
6e91ea2bb   Christoph Hellwig   exportfs: add fid...
313
314
  static int export_encode_fh(struct dentry *dentry, struct fid *fid,
  		int *max_len, int connectable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
317
  {
  	struct inode * inode = dentry->d_inode;
  	int len = *max_len;
6e91ea2bb   Christoph Hellwig   exportfs: add fid...
318
  	int type = FILEID_INO32_GEN;
5fe0c2378   Aneesh Kumar K.V   exportfs: Return ...
319
320
321
322
323
324
  
  	if (connectable && (len < 4)) {
  		*max_len = 4;
  		return 255;
  	} else if (len < 2) {
  		*max_len = 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  		return 255;
5fe0c2378   Aneesh Kumar K.V   exportfs: Return ...
326
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
  
  	len = 2;
6e91ea2bb   Christoph Hellwig   exportfs: add fid...
329
330
  	fid->i32.ino = inode->i_ino;
  	fid->i32.gen = inode->i_generation;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
334
335
  	if (connectable && !S_ISDIR(inode->i_mode)) {
  		struct inode *parent;
  
  		spin_lock(&dentry->d_lock);
  		parent = dentry->d_parent->d_inode;
6e91ea2bb   Christoph Hellwig   exportfs: add fid...
336
337
  		fid->i32.parent_ino = parent->i_ino;
  		fid->i32.parent_gen = parent->i_generation;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
  		spin_unlock(&dentry->d_lock);
  		len = 4;
6e91ea2bb   Christoph Hellwig   exportfs: add fid...
340
  		type = FILEID_INO32_GEN_PARENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
344
  	}
  	*max_len = len;
  	return type;
  }
6e91ea2bb   Christoph Hellwig   exportfs: add fid...
345
  int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
d37065cd6   Christoph Hellwig   knfsd: exportfs: ...
346
347
  		int connectable)
  {
396551644   Christoph Hellwig   exportfs: make st...
348
  	const struct export_operations *nop = dentry->d_sb->s_export_op;
10f11c341   Christoph Hellwig   knfsd: exportfs: ...
349
  	int error;
d37065cd6   Christoph Hellwig   knfsd: exportfs: ...
350

10f11c341   Christoph Hellwig   knfsd: exportfs: ...
351
  	if (nop->encode_fh)
6e91ea2bb   Christoph Hellwig   exportfs: add fid...
352
  		error = nop->encode_fh(dentry, fid->raw, max_len, connectable);
10f11c341   Christoph Hellwig   knfsd: exportfs: ...
353
  	else
6e91ea2bb   Christoph Hellwig   exportfs: add fid...
354
  		error = export_encode_fh(dentry, fid, max_len, connectable);
10f11c341   Christoph Hellwig   knfsd: exportfs: ...
355
356
  
  	return error;
d37065cd6   Christoph Hellwig   knfsd: exportfs: ...
357
358
  }
  EXPORT_SYMBOL_GPL(exportfs_encode_fh);
6e91ea2bb   Christoph Hellwig   exportfs: add fid...
359
360
361
  struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
  		int fh_len, int fileid_type,
  		int (*acceptable)(void *, struct dentry *), void *context)
d37065cd6   Christoph Hellwig   knfsd: exportfs: ...
362
  {
396551644   Christoph Hellwig   exportfs: make st...
363
  	const struct export_operations *nop = mnt->mnt_sb->s_export_op;
2596110a3   Christoph Hellwig   exportfs: add new...
364
  	struct dentry *result, *alias;
f3f8e1757   Al Viro   [PATCH] reduce th...
365
  	char nbuf[NAME_MAX+1];
2596110a3   Christoph Hellwig   exportfs: add new...
366
  	int err;
d37065cd6   Christoph Hellwig   knfsd: exportfs: ...
367

2596110a3   Christoph Hellwig   exportfs: add new...
368
  	/*
2596110a3   Christoph Hellwig   exportfs: add new...
369
370
  	 * Try to get any dentry for the given file handle from the filesystem.
  	 */
becfd1f37   Aneesh Kumar K.V   vfs: Add open by ...
371
372
  	if (!nop || !nop->fh_to_dentry)
  		return ERR_PTR(-ESTALE);
2596110a3   Christoph Hellwig   exportfs: add new...
373
  	result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
a4f4d6df5   J. Bruce Fields   EXPORTFS: handle ...
374
375
  	if (!result)
  		result = ERR_PTR(-ESTALE);
2596110a3   Christoph Hellwig   exportfs: add new...
376
377
378
379
380
381
382
383
384
385
386
387
388
  	if (IS_ERR(result))
  		return result;
  
  	if (S_ISDIR(result->d_inode->i_mode)) {
  		/*
  		 * This request is for a directory.
  		 *
  		 * On the positive side there is only one dentry for each
  		 * directory inode.  On the negative side this implies that we
  		 * to ensure our dentry is connected all the way up to the
  		 * filesystem root.
  		 */
  		if (result->d_flags & DCACHE_DISCONNECTED) {
f3f8e1757   Al Viro   [PATCH] reduce th...
389
  			err = reconnect_path(mnt, result, nbuf);
2596110a3   Christoph Hellwig   exportfs: add new...
390
391
392
393
394
395
396
397
398
399
  			if (err)
  				goto err_result;
  		}
  
  		if (!acceptable(context, result)) {
  			err = -EACCES;
  			goto err_result;
  		}
  
  		return result;
10f11c341   Christoph Hellwig   knfsd: exportfs: ...
400
  	} else {
2596110a3   Christoph Hellwig   exportfs: add new...
401
402
403
404
  		/*
  		 * It's not a directory.  Life is a little more complicated.
  		 */
  		struct dentry *target_dir, *nresult;
2596110a3   Christoph Hellwig   exportfs: add new...
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
  
  		/*
  		 * See if either the dentry we just got from the filesystem
  		 * or any alias for it is acceptable.  This is always true
  		 * if this filesystem is exported without the subtreecheck
  		 * option.  If the filesystem is exported with the subtree
  		 * check option there's a fair chance we need to look at
  		 * the parent directory in the file handle and make sure
  		 * it's connected to the filesystem root.
  		 */
  		alias = find_acceptable_alias(result, acceptable, context);
  		if (alias)
  			return alias;
  
  		/*
  		 * Try to extract a dentry for the parent directory from the
  		 * file handle.  If this fails we'll have to give up.
  		 */
  		err = -ESTALE;
  		if (!nop->fh_to_parent)
  			goto err_result;
  
  		target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
  				fh_len, fileid_type);
a4f4d6df5   J. Bruce Fields   EXPORTFS: handle ...
429
430
  		if (!target_dir)
  			goto err_result;
2596110a3   Christoph Hellwig   exportfs: add new...
431
432
433
434
435
436
437
438
439
  		err = PTR_ERR(target_dir);
  		if (IS_ERR(target_dir))
  			goto err_result;
  
  		/*
  		 * And as usual we need to make sure the parent directory is
  		 * connected to the filesystem root.  The VFS really doesn't
  		 * like disconnected directories..
  		 */
f3f8e1757   Al Viro   [PATCH] reduce th...
440
  		err = reconnect_path(mnt, target_dir, nbuf);
2596110a3   Christoph Hellwig   exportfs: add new...
441
442
443
444
445
446
447
448
449
450
  		if (err) {
  			dput(target_dir);
  			goto err_result;
  		}
  
  		/*
  		 * Now that we've got both a well-connected parent and a
  		 * dentry for the inode we're after, make sure that our
  		 * inode is actually connected to the parent.
  		 */
e38f98175   Christoph Hellwig   exportfs: update ...
451
  		err = exportfs_get_name(mnt, target_dir, nbuf, result);
2596110a3   Christoph Hellwig   exportfs: add new...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
  		if (!err) {
  			mutex_lock(&target_dir->d_inode->i_mutex);
  			nresult = lookup_one_len(nbuf, target_dir,
  						 strlen(nbuf));
  			mutex_unlock(&target_dir->d_inode->i_mutex);
  			if (!IS_ERR(nresult)) {
  				if (nresult->d_inode) {
  					dput(result);
  					result = nresult;
  				} else
  					dput(nresult);
  			}
  		}
  
  		/*
  		 * At this point we are done with the parent, but it's pinned
  		 * by the child dentry anyway.
  		 */
  		dput(target_dir);
  
  		/*
  		 * And finally make sure the dentry is actually acceptable
  		 * to NFSD.
  		 */
  		alias = find_acceptable_alias(result, acceptable, context);
  		if (!alias) {
  			err = -EACCES;
  			goto err_result;
  		}
  
  		return alias;
10f11c341   Christoph Hellwig   knfsd: exportfs: ...
483
  	}
2596110a3   Christoph Hellwig   exportfs: add new...
484
485
486
   err_result:
  	dput(result);
  	return ERR_PTR(err);
d37065cd6   Christoph Hellwig   knfsd: exportfs: ...
487
488
  }
  EXPORT_SYMBOL_GPL(exportfs_decode_fh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  MODULE_LICENSE("GPL");