Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/exportfs/expfs.c
54333 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 &&
257
!name_is_dot_dotdot(name, len)) {
258
memcpy(buf->name, name, len);
259
buf->name[len] = '\0';
260
buf->found = 1;
261
return false; // no more
262
}
263
return true;
264
}
265
266
/**
267
* get_name - default export_operations->get_name function
268
* @path: the directory in which to find a name
269
* @name: a pointer to a %NAME_MAX+1 char buffer to store the name
270
* @child: the dentry for the child directory.
271
*
272
* calls readdir on the parent until it finds an entry with
273
* the same inode number as the child, and returns that.
274
*/
275
static int get_name(const struct path *path, char *name, struct dentry *child)
276
{
277
const struct cred *cred = current_cred();
278
struct inode *dir = path->dentry->d_inode;
279
int error;
280
struct file *file;
281
struct kstat stat;
282
struct path child_path = {
283
.mnt = path->mnt,
284
.dentry = child,
285
};
286
struct getdents_callback buffer = {
287
.ctx.actor = filldir_one,
288
.ctx.count = INT_MAX,
289
.name = name,
290
};
291
292
error = -ENOTDIR;
293
if (!dir || !S_ISDIR(dir->i_mode))
294
goto out;
295
error = -EINVAL;
296
if (!dir->i_fop)
297
goto out;
298
/*
299
* inode->i_ino is unsigned long, kstat->ino is u64, so the
300
* former would be insufficient on 32-bit hosts when the
301
* filesystem supports 64-bit inode numbers. So we need to
302
* actually call ->getattr, not just read i_ino:
303
*/
304
error = vfs_getattr_nosec(&child_path, &stat,
305
STATX_INO, AT_STATX_SYNC_AS_STAT);
306
if (error)
307
return error;
308
buffer.ino = stat.ino;
309
/*
310
* Open the directory ...
311
*/
312
file = dentry_open(path, O_RDONLY, cred);
313
error = PTR_ERR(file);
314
if (IS_ERR(file))
315
goto out;
316
317
error = -EINVAL;
318
if (!file->f_op->iterate_shared)
319
goto out_close;
320
321
buffer.sequence = 0;
322
while (1) {
323
int old_seq = buffer.sequence;
324
325
error = iterate_dir(file, &buffer.ctx);
326
if (buffer.found) {
327
error = 0;
328
break;
329
}
330
331
if (error < 0)
332
break;
333
334
error = -ENOENT;
335
if (old_seq == buffer.sequence)
336
break;
337
}
338
339
out_close:
340
fput(file);
341
out:
342
return error;
343
}
344
345
#define FILEID_INO64_GEN_LEN 3
346
347
/**
348
* exportfs_encode_ino64_fid - encode non-decodeable 64bit ino file id
349
* @inode: the object to encode
350
* @fid: where to store the file handle fragment
351
* @max_len: maximum length to store there (in 4 byte units)
352
*
353
* This generic function is used to encode a non-decodeable file id for
354
* fanotify for filesystems that do not support NFS export.
355
*/
356
static int exportfs_encode_ino64_fid(struct inode *inode, struct fid *fid,
357
int *max_len)
358
{
359
if (*max_len < FILEID_INO64_GEN_LEN) {
360
*max_len = FILEID_INO64_GEN_LEN;
361
return FILEID_INVALID;
362
}
363
364
fid->i64.ino = inode->i_ino;
365
fid->i64.gen = inode->i_generation;
366
*max_len = FILEID_INO64_GEN_LEN;
367
368
return FILEID_INO64_GEN;
369
}
370
371
/**
372
* exportfs_encode_inode_fh - encode a file handle from inode
373
* @inode: the object to encode
374
* @fid: where to store the file handle fragment
375
* @max_len: maximum length to store there
376
* @parent: parent directory inode, if wanted
377
* @flags: properties of the requested file handle
378
*
379
* Returns an enum fid_type or a negative errno.
380
*/
381
int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
382
int *max_len, struct inode *parent, int flags)
383
{
384
const struct export_operations *nop = inode->i_sb->s_export_op;
385
enum fid_type type;
386
387
if (!exportfs_can_encode_fh(nop, flags))
388
return -EOPNOTSUPP;
389
390
if (!nop && (flags & EXPORT_FH_FID))
391
type = exportfs_encode_ino64_fid(inode, fid, max_len);
392
else
393
type = nop->encode_fh(inode, fid->raw, max_len, parent);
394
395
if (type > 0 && FILEID_USER_FLAGS(type)) {
396
pr_warn_once("%s: unexpected fh type value 0x%x from fstype %s.\n",
397
__func__, type, inode->i_sb->s_type->name);
398
return -EINVAL;
399
}
400
401
return type;
402
403
}
404
EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
405
406
/**
407
* exportfs_encode_fh - encode a file handle from dentry
408
* @dentry: the object to encode
409
* @fid: where to store the file handle fragment
410
* @max_len: maximum length to store there
411
* @flags: properties of the requested file handle
412
*
413
* Returns an enum fid_type or a negative errno.
414
*/
415
int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
416
int flags)
417
{
418
int error;
419
struct dentry *p = NULL;
420
struct inode *inode = dentry->d_inode, *parent = NULL;
421
422
if ((flags & EXPORT_FH_CONNECTABLE) && !S_ISDIR(inode->i_mode)) {
423
p = dget_parent(dentry);
424
/*
425
* note that while p might've ceased to be our parent already,
426
* it's still pinned by and still positive.
427
*/
428
parent = p->d_inode;
429
}
430
431
error = exportfs_encode_inode_fh(inode, fid, max_len, parent, flags);
432
dput(p);
433
434
return error;
435
}
436
EXPORT_SYMBOL_GPL(exportfs_encode_fh);
437
438
struct dentry *
439
exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
440
int fileid_type, unsigned int flags,
441
int (*acceptable)(void *, struct dentry *),
442
void *context)
443
{
444
const struct export_operations *nop = mnt->mnt_sb->s_export_op;
445
struct dentry *result, *alias;
446
char nbuf[NAME_MAX+1];
447
int err;
448
449
if (fileid_type < 0 || FILEID_USER_FLAGS(fileid_type))
450
return ERR_PTR(-EINVAL);
451
452
/*
453
* Try to get any dentry for the given file handle from the filesystem.
454
*/
455
if (!exportfs_can_decode_fh(nop))
456
return ERR_PTR(-ESTALE);
457
result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
458
if (IS_ERR_OR_NULL(result))
459
return result;
460
461
if ((flags & EXPORT_FH_DIR_ONLY) && !d_is_dir(result)) {
462
err = -ENOTDIR;
463
goto err_result;
464
}
465
466
/*
467
* If no acceptance criteria was specified by caller, a disconnected
468
* dentry is also accepatable. Callers may use this mode to query if
469
* file handle is stale or to get a reference to an inode without
470
* risking the high overhead caused by directory reconnect.
471
*/
472
if (!acceptable)
473
return result;
474
475
if (d_is_dir(result)) {
476
/*
477
* This request is for a directory.
478
*
479
* On the positive side there is only one dentry for each
480
* directory inode. On the negative side this implies that we
481
* to ensure our dentry is connected all the way up to the
482
* filesystem root.
483
*/
484
if (result->d_flags & DCACHE_DISCONNECTED) {
485
err = reconnect_path(mnt, result, nbuf);
486
if (err)
487
goto err_result;
488
}
489
490
if (!acceptable(context, result)) {
491
err = -EACCES;
492
goto err_result;
493
}
494
495
return result;
496
} else {
497
/*
498
* It's not a directory. Life is a little more complicated.
499
*/
500
struct dentry *target_dir, *nresult;
501
502
/*
503
* See if either the dentry we just got from the filesystem
504
* or any alias for it is acceptable. This is always true
505
* if this filesystem is exported without the subtreecheck
506
* option. If the filesystem is exported with the subtree
507
* check option there's a fair chance we need to look at
508
* the parent directory in the file handle and make sure
509
* it's connected to the filesystem root.
510
*/
511
alias = find_acceptable_alias(result, acceptable, context);
512
if (alias)
513
return alias;
514
515
/*
516
* Try to extract a dentry for the parent directory from the
517
* file handle. If this fails we'll have to give up.
518
*/
519
err = -ESTALE;
520
if (!nop->fh_to_parent)
521
goto err_result;
522
523
target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
524
fh_len, fileid_type);
525
if (!target_dir)
526
goto err_result;
527
err = PTR_ERR(target_dir);
528
if (IS_ERR(target_dir))
529
goto err_result;
530
531
/*
532
* And as usual we need to make sure the parent directory is
533
* connected to the filesystem root. The VFS really doesn't
534
* like disconnected directories..
535
*/
536
err = reconnect_path(mnt, target_dir, nbuf);
537
if (err) {
538
dput(target_dir);
539
goto err_result;
540
}
541
542
/*
543
* Now that we've got both a well-connected parent and a
544
* dentry for the inode we're after, make sure that our
545
* inode is actually connected to the parent.
546
*/
547
err = exportfs_get_name(mnt, target_dir, nbuf, result);
548
if (err) {
549
dput(target_dir);
550
goto err_result;
551
}
552
553
nresult = lookup_one_unlocked(mnt_idmap(mnt), &QSTR(nbuf), target_dir);
554
if (!IS_ERR(nresult)) {
555
if (unlikely(nresult->d_inode != result->d_inode)) {
556
dput(nresult);
557
nresult = ERR_PTR(-ESTALE);
558
}
559
}
560
/*
561
* At this point we are done with the parent, but it's pinned
562
* by the child dentry anyway.
563
*/
564
dput(target_dir);
565
566
if (IS_ERR(nresult)) {
567
err = PTR_ERR(nresult);
568
goto err_result;
569
}
570
dput(result);
571
result = nresult;
572
573
/*
574
* And finally make sure the dentry is actually acceptable
575
* to NFSD.
576
*/
577
alias = find_acceptable_alias(result, acceptable, context);
578
if (!alias) {
579
err = -EACCES;
580
goto err_result;
581
}
582
583
return alias;
584
}
585
586
err_result:
587
dput(result);
588
return ERR_PTR(err);
589
}
590
EXPORT_SYMBOL_GPL(exportfs_decode_fh_raw);
591
592
struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
593
int fh_len, int fileid_type,
594
int (*acceptable)(void *, struct dentry *),
595
void *context)
596
{
597
struct dentry *ret;
598
599
ret = exportfs_decode_fh_raw(mnt, fid, fh_len, fileid_type, 0,
600
acceptable, context);
601
if (IS_ERR_OR_NULL(ret)) {
602
if (ret == ERR_PTR(-ENOMEM))
603
return ret;
604
return ERR_PTR(-ESTALE);
605
}
606
return ret;
607
}
608
EXPORT_SYMBOL_GPL(exportfs_decode_fh);
609
610
MODULE_DESCRIPTION("Code mapping from inodes to file handles");
611
MODULE_LICENSE("GPL");
612
613