Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/exportfs/expfs.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) Neil Brown 2002
4
* Copyright (C) Christoph Hellwig 2007
5
*
6
* This file contains the code mapping from inodes to NFS file handles,
7
* and for mapping back from file handles to dentries.
8
*
9
* For details on why we do all the strange and hairy things in here
10
* take a look at Documentation/filesystems/nfs/exporting.rst.
11
*/
12
#include <linux/exportfs.h>
13
#include <linux/fs.h>
14
#include <linux/file.h>
15
#include <linux/module.h>
16
#include <linux/mount.h>
17
#include <linux/namei.h>
18
#include <linux/sched.h>
19
#include <linux/cred.h>
20
21
#define dprintk(fmt, args...) pr_debug(fmt, ##args)
22
23
24
static int get_name(const struct path *path, char *name, struct dentry *child);
25
26
27
static int exportfs_get_name(struct vfsmount *mnt, struct dentry *dir,
28
char *name, struct dentry *child)
29
{
30
const struct export_operations *nop = dir->d_sb->s_export_op;
31
struct path path = {.mnt = mnt, .dentry = dir};
32
33
if (nop->get_name)
34
return nop->get_name(dir, name, child);
35
else
36
return get_name(&path, name, child);
37
}
38
39
/*
40
* Check if the dentry or any of it's aliases is acceptable.
41
*/
42
static struct dentry *
43
find_acceptable_alias(struct dentry *result,
44
int (*acceptable)(void *context, struct dentry *dentry),
45
void *context)
46
{
47
struct dentry *dentry, *toput = NULL;
48
struct inode *inode;
49
50
if (acceptable(context, result))
51
return result;
52
53
inode = result->d_inode;
54
spin_lock(&inode->i_lock);
55
hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
56
dget(dentry);
57
spin_unlock(&inode->i_lock);
58
if (toput)
59
dput(toput);
60
if (dentry != result && acceptable(context, dentry)) {
61
dput(result);
62
return dentry;
63
}
64
spin_lock(&inode->i_lock);
65
toput = dentry;
66
}
67
spin_unlock(&inode->i_lock);
68
69
if (toput)
70
dput(toput);
71
return NULL;
72
}
73
74
static bool dentry_connected(struct dentry *dentry)
75
{
76
dget(dentry);
77
while (dentry->d_flags & DCACHE_DISCONNECTED) {
78
struct dentry *parent = dget_parent(dentry);
79
80
dput(dentry);
81
if (dentry == parent) {
82
dput(parent);
83
return false;
84
}
85
dentry = parent;
86
}
87
dput(dentry);
88
return true;
89
}
90
91
static void clear_disconnected(struct dentry *dentry)
92
{
93
dget(dentry);
94
while (dentry->d_flags & DCACHE_DISCONNECTED) {
95
struct dentry *parent = dget_parent(dentry);
96
97
WARN_ON_ONCE(IS_ROOT(dentry));
98
99
spin_lock(&dentry->d_lock);
100
dentry->d_flags &= ~DCACHE_DISCONNECTED;
101
spin_unlock(&dentry->d_lock);
102
103
dput(dentry);
104
dentry = parent;
105
}
106
dput(dentry);
107
}
108
109
/*
110
* Reconnect a directory dentry with its parent.
111
*
112
* This can return a dentry, or NULL, or an error.
113
*
114
* In the first case the returned dentry is the parent of the given
115
* dentry, and may itself need to be reconnected to its parent.
116
*
117
* In the NULL case, a concurrent VFS operation has either renamed or
118
* removed this directory. The concurrent operation has reconnected our
119
* dentry, so we no longer need to.
120
*/
121
static struct dentry *reconnect_one(struct vfsmount *mnt,
122
struct dentry *dentry, char *nbuf)
123
{
124
struct dentry *parent;
125
struct dentry *tmp;
126
int err;
127
128
parent = ERR_PTR(-EACCES);
129
if (mnt->mnt_sb->s_export_op->get_parent)
130
parent = mnt->mnt_sb->s_export_op->get_parent(dentry);
131
132
if (IS_ERR(parent)) {
133
dprintk("get_parent of %lu failed, err %ld\n",
134
dentry->d_inode->i_ino, PTR_ERR(parent));
135
return parent;
136
}
137
138
dprintk("%s: find name of %lu in %lu\n", __func__,
139
dentry->d_inode->i_ino, parent->d_inode->i_ino);
140
err = exportfs_get_name(mnt, parent, nbuf, dentry);
141
if (err == -ENOENT)
142
goto out_reconnected;
143
if (err)
144
goto out_err;
145
dprintk("%s: found name: %s\n", __func__, nbuf);
146
tmp = lookup_one_unlocked(mnt_idmap(mnt), &QSTR(nbuf), parent);
147
if (IS_ERR(tmp)) {
148
dprintk("lookup failed: %ld\n", PTR_ERR(tmp));
149
err = PTR_ERR(tmp);
150
goto out_err;
151
}
152
if (tmp != dentry) {
153
/*
154
* Somebody has renamed it since exportfs_get_name();
155
* great, since it could've only been renamed if it
156
* got looked up and thus connected, and it would
157
* remain connected afterwards. We are done.
158
*/
159
dput(tmp);
160
goto out_reconnected;
161
}
162
dput(tmp);
163
if (IS_ROOT(dentry)) {
164
err = -ESTALE;
165
goto out_err;
166
}
167
return parent;
168
169
out_err:
170
dput(parent);
171
return ERR_PTR(err);
172
out_reconnected:
173
dput(parent);
174
/*
175
* Someone must have renamed our entry into another parent, in
176
* which case it has been reconnected by the rename.
177
*
178
* Or someone removed it entirely, in which case filehandle
179
* lookup will succeed but the directory is now IS_DEAD and
180
* subsequent operations on it will fail.
181
*
182
* Alternatively, maybe there was no race at all, and the
183
* filesystem is just corrupt and gave us a parent that doesn't
184
* actually contain any entry pointing to this inode. So,
185
* double check that this worked and return -ESTALE if not:
186
*/
187
if (!dentry_connected(dentry))
188
return ERR_PTR(-ESTALE);
189
return NULL;
190
}
191
192
/*
193
* Make sure target_dir is fully connected to the dentry tree.
194
*
195
* On successful return, DCACHE_DISCONNECTED will be cleared on
196
* target_dir, and target_dir->d_parent->...->d_parent will reach the
197
* root of the filesystem.
198
*
199
* Whenever DCACHE_DISCONNECTED is unset, target_dir is fully connected.
200
* But the converse is not true: target_dir may have DCACHE_DISCONNECTED
201
* set but already be connected. In that case we'll verify the
202
* connection to root and then clear the flag.
203
*
204
* Note that target_dir could be removed by a concurrent operation. In
205
* that case reconnect_path may still succeed with target_dir fully
206
* connected, but further operations using the filehandle will fail when
207
* necessary (due to S_DEAD being set on the directory).
208
*/
209
static int
210
reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf)
211
{
212
struct dentry *dentry, *parent;
213
214
dentry = dget(target_dir);
215
216
while (dentry->d_flags & DCACHE_DISCONNECTED) {
217
BUG_ON(dentry == mnt->mnt_sb->s_root);
218
219
if (IS_ROOT(dentry))
220
parent = reconnect_one(mnt, dentry, nbuf);
221
else
222
parent = dget_parent(dentry);
223
224
if (!parent)
225
break;
226
dput(dentry);
227
if (IS_ERR(parent))
228
return PTR_ERR(parent);
229
dentry = parent;
230
}
231
dput(dentry);
232
clear_disconnected(target_dir);
233
return 0;
234
}
235
236
struct getdents_callback {
237
struct dir_context ctx;
238
char *name; /* name that was found. It already points to a
239
buffer NAME_MAX+1 is size */
240
u64 ino; /* the inum we are looking for */
241
int found; /* inode matched? */
242
int sequence; /* sequence counter */
243
};
244
245
/*
246
* A rather strange filldir function to capture
247
* the name matching the specified inode number.
248
*/
249
static bool filldir_one(struct dir_context *ctx, const char *name, int len,
250
loff_t pos, u64 ino, unsigned int d_type)
251
{
252
struct getdents_callback *buf =
253
container_of(ctx, struct getdents_callback, ctx);
254
255
buf->sequence++;
256
if (buf->ino == ino && len <= NAME_MAX && !is_dot_dotdot(name, len)) {
257
memcpy(buf->name, name, len);
258
buf->name[len] = '\0';
259
buf->found = 1;
260
return false; // no more
261
}
262
return true;
263
}
264
265
/**
266
* get_name - default export_operations->get_name function
267
* @path: the directory in which to find a name
268
* @name: a pointer to a %NAME_MAX+1 char buffer to store the name
269
* @child: the dentry for the child directory.
270
*
271
* calls readdir on the parent until it finds an entry with
272
* the same inode number as the child, and returns that.
273
*/
274
static int get_name(const struct path *path, char *name, struct dentry *child)
275
{
276
const struct cred *cred = current_cred();
277
struct inode *dir = path->dentry->d_inode;
278
int error;
279
struct file *file;
280
struct kstat stat;
281
struct path child_path = {
282
.mnt = path->mnt,
283
.dentry = child,
284
};
285
struct getdents_callback buffer = {
286
.ctx.actor = filldir_one,
287
.ctx.count = INT_MAX,
288
.name = name,
289
};
290
291
error = -ENOTDIR;
292
if (!dir || !S_ISDIR(dir->i_mode))
293
goto out;
294
error = -EINVAL;
295
if (!dir->i_fop)
296
goto out;
297
/*
298
* inode->i_ino is unsigned long, kstat->ino is u64, so the
299
* former would be insufficient on 32-bit hosts when the
300
* filesystem supports 64-bit inode numbers. So we need to
301
* actually call ->getattr, not just read i_ino:
302
*/
303
error = vfs_getattr_nosec(&child_path, &stat,
304
STATX_INO, AT_STATX_SYNC_AS_STAT);
305
if (error)
306
return error;
307
buffer.ino = stat.ino;
308
/*
309
* Open the directory ...
310
*/
311
file = dentry_open(path, O_RDONLY, cred);
312
error = PTR_ERR(file);
313
if (IS_ERR(file))
314
goto out;
315
316
error = -EINVAL;
317
if (!file->f_op->iterate_shared)
318
goto out_close;
319
320
buffer.sequence = 0;
321
while (1) {
322
int old_seq = buffer.sequence;
323
324
error = iterate_dir(file, &buffer.ctx);
325
if (buffer.found) {
326
error = 0;
327
break;
328
}
329
330
if (error < 0)
331
break;
332
333
error = -ENOENT;
334
if (old_seq == buffer.sequence)
335
break;
336
}
337
338
out_close:
339
fput(file);
340
out:
341
return error;
342
}
343
344
#define FILEID_INO64_GEN_LEN 3
345
346
/**
347
* exportfs_encode_ino64_fid - encode non-decodeable 64bit ino file id
348
* @inode: the object to encode
349
* @fid: where to store the file handle fragment
350
* @max_len: maximum length to store there (in 4 byte units)
351
*
352
* This generic function is used to encode a non-decodeable file id for
353
* fanotify for filesystems that do not support NFS export.
354
*/
355
static int exportfs_encode_ino64_fid(struct inode *inode, struct fid *fid,
356
int *max_len)
357
{
358
if (*max_len < FILEID_INO64_GEN_LEN) {
359
*max_len = FILEID_INO64_GEN_LEN;
360
return FILEID_INVALID;
361
}
362
363
fid->i64.ino = inode->i_ino;
364
fid->i64.gen = inode->i_generation;
365
*max_len = FILEID_INO64_GEN_LEN;
366
367
return FILEID_INO64_GEN;
368
}
369
370
/**
371
* exportfs_encode_inode_fh - encode a file handle from inode
372
* @inode: the object to encode
373
* @fid: where to store the file handle fragment
374
* @max_len: maximum length to store there
375
* @parent: parent directory inode, if wanted
376
* @flags: properties of the requested file handle
377
*
378
* Returns an enum fid_type or a negative errno.
379
*/
380
int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
381
int *max_len, struct inode *parent, int flags)
382
{
383
const struct export_operations *nop = inode->i_sb->s_export_op;
384
enum fid_type type;
385
386
if (!exportfs_can_encode_fh(nop, flags))
387
return -EOPNOTSUPP;
388
389
if (!nop && (flags & EXPORT_FH_FID))
390
type = exportfs_encode_ino64_fid(inode, fid, max_len);
391
else
392
type = nop->encode_fh(inode, fid->raw, max_len, parent);
393
394
if (type > 0 && FILEID_USER_FLAGS(type)) {
395
pr_warn_once("%s: unexpected fh type value 0x%x from fstype %s.\n",
396
__func__, type, inode->i_sb->s_type->name);
397
return -EINVAL;
398
}
399
400
return type;
401
402
}
403
EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
404
405
/**
406
* exportfs_encode_fh - encode a file handle from dentry
407
* @dentry: the object to encode
408
* @fid: where to store the file handle fragment
409
* @max_len: maximum length to store there
410
* @flags: properties of the requested file handle
411
*
412
* Returns an enum fid_type or a negative errno.
413
*/
414
int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
415
int flags)
416
{
417
int error;
418
struct dentry *p = NULL;
419
struct inode *inode = dentry->d_inode, *parent = NULL;
420
421
if ((flags & EXPORT_FH_CONNECTABLE) && !S_ISDIR(inode->i_mode)) {
422
p = dget_parent(dentry);
423
/*
424
* note that while p might've ceased to be our parent already,
425
* it's still pinned by and still positive.
426
*/
427
parent = p->d_inode;
428
}
429
430
error = exportfs_encode_inode_fh(inode, fid, max_len, parent, flags);
431
dput(p);
432
433
return error;
434
}
435
EXPORT_SYMBOL_GPL(exportfs_encode_fh);
436
437
struct dentry *
438
exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
439
int fileid_type, unsigned int flags,
440
int (*acceptable)(void *, struct dentry *),
441
void *context)
442
{
443
const struct export_operations *nop = mnt->mnt_sb->s_export_op;
444
struct dentry *result, *alias;
445
char nbuf[NAME_MAX+1];
446
int err;
447
448
if (fileid_type < 0 || FILEID_USER_FLAGS(fileid_type))
449
return ERR_PTR(-EINVAL);
450
451
/*
452
* Try to get any dentry for the given file handle from the filesystem.
453
*/
454
if (!exportfs_can_decode_fh(nop))
455
return ERR_PTR(-ESTALE);
456
result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
457
if (IS_ERR_OR_NULL(result))
458
return result;
459
460
if ((flags & EXPORT_FH_DIR_ONLY) && !d_is_dir(result)) {
461
err = -ENOTDIR;
462
goto err_result;
463
}
464
465
/*
466
* If no acceptance criteria was specified by caller, a disconnected
467
* dentry is also accepatable. Callers may use this mode to query if
468
* file handle is stale or to get a reference to an inode without
469
* risking the high overhead caused by directory reconnect.
470
*/
471
if (!acceptable)
472
return result;
473
474
if (d_is_dir(result)) {
475
/*
476
* This request is for a directory.
477
*
478
* On the positive side there is only one dentry for each
479
* directory inode. On the negative side this implies that we
480
* to ensure our dentry is connected all the way up to the
481
* filesystem root.
482
*/
483
if (result->d_flags & DCACHE_DISCONNECTED) {
484
err = reconnect_path(mnt, result, nbuf);
485
if (err)
486
goto err_result;
487
}
488
489
if (!acceptable(context, result)) {
490
err = -EACCES;
491
goto err_result;
492
}
493
494
return result;
495
} else {
496
/*
497
* It's not a directory. Life is a little more complicated.
498
*/
499
struct dentry *target_dir, *nresult;
500
501
/*
502
* See if either the dentry we just got from the filesystem
503
* or any alias for it is acceptable. This is always true
504
* if this filesystem is exported without the subtreecheck
505
* option. If the filesystem is exported with the subtree
506
* check option there's a fair chance we need to look at
507
* the parent directory in the file handle and make sure
508
* it's connected to the filesystem root.
509
*/
510
alias = find_acceptable_alias(result, acceptable, context);
511
if (alias)
512
return alias;
513
514
/*
515
* Try to extract a dentry for the parent directory from the
516
* file handle. If this fails we'll have to give up.
517
*/
518
err = -ESTALE;
519
if (!nop->fh_to_parent)
520
goto err_result;
521
522
target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
523
fh_len, fileid_type);
524
if (!target_dir)
525
goto err_result;
526
err = PTR_ERR(target_dir);
527
if (IS_ERR(target_dir))
528
goto err_result;
529
530
/*
531
* And as usual we need to make sure the parent directory is
532
* connected to the filesystem root. The VFS really doesn't
533
* like disconnected directories..
534
*/
535
err = reconnect_path(mnt, target_dir, nbuf);
536
if (err) {
537
dput(target_dir);
538
goto err_result;
539
}
540
541
/*
542
* Now that we've got both a well-connected parent and a
543
* dentry for the inode we're after, make sure that our
544
* inode is actually connected to the parent.
545
*/
546
err = exportfs_get_name(mnt, target_dir, nbuf, result);
547
if (err) {
548
dput(target_dir);
549
goto err_result;
550
}
551
552
nresult = lookup_one_unlocked(mnt_idmap(mnt), &QSTR(nbuf), target_dir);
553
if (!IS_ERR(nresult)) {
554
if (unlikely(nresult->d_inode != result->d_inode)) {
555
dput(nresult);
556
nresult = ERR_PTR(-ESTALE);
557
}
558
}
559
/*
560
* At this point we are done with the parent, but it's pinned
561
* by the child dentry anyway.
562
*/
563
dput(target_dir);
564
565
if (IS_ERR(nresult)) {
566
err = PTR_ERR(nresult);
567
goto err_result;
568
}
569
dput(result);
570
result = nresult;
571
572
/*
573
* And finally make sure the dentry is actually acceptable
574
* to NFSD.
575
*/
576
alias = find_acceptable_alias(result, acceptable, context);
577
if (!alias) {
578
err = -EACCES;
579
goto err_result;
580
}
581
582
return alias;
583
}
584
585
err_result:
586
dput(result);
587
return ERR_PTR(err);
588
}
589
EXPORT_SYMBOL_GPL(exportfs_decode_fh_raw);
590
591
struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
592
int fh_len, int fileid_type,
593
int (*acceptable)(void *, struct dentry *),
594
void *context)
595
{
596
struct dentry *ret;
597
598
ret = exportfs_decode_fh_raw(mnt, fid, fh_len, fileid_type, 0,
599
acceptable, context);
600
if (IS_ERR_OR_NULL(ret)) {
601
if (ret == ERR_PTR(-ENOMEM))
602
return ret;
603
return ERR_PTR(-ESTALE);
604
}
605
return ret;
606
}
607
EXPORT_SYMBOL_GPL(exportfs_decode_fh);
608
609
MODULE_DESCRIPTION("Code mapping from inodes to file handles");
610
MODULE_LICENSE("GPL");
611
612