Skip to content

Commit 18c9901

Browse files
committed
Merge tag 'fsnotify_for_v6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull fsnotify updates from Jan Kara: - Support for fanotify events returning file handles for filesystems not exportable via NFS - Improved error handling exportfs functions - Add missing FS_OPEN events when unusual open helpers are used * tag 'fsnotify_for_v6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: fsnotify: move fsnotify_open() hook into do_dentry_open() exportfs: check for error return value from exportfs_encode_*() fanotify: support reporting non-decodeable file handles exportfs: allow exporting non-decodeable file handles to userspace exportfs: add explicit flag to request non-decodeable file handles exportfs: change connectable argument to bit flags
2 parents 0a37714 + 7b8c9d7 commit 18c9901

File tree

12 files changed

+85
-37
lines changed

12 files changed

+85
-37
lines changed

Documentation/filesystems/nfs/exporting.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ are exportable by setting the s_export_op field in the struct
122122
super_block. This field must point to a "struct export_operations"
123123
struct which has the following members:
124124

125-
encode_fh (optional)
126-
Takes a dentry and creates a filehandle fragment which can later be used
125+
encode_fh (optional)
126+
Takes a dentry and creates a filehandle fragment which may later be used
127127
to find or create a dentry for the same object. The default
128128
implementation creates a filehandle fragment that encodes a 32bit inode
129129
and generation number for the inode encoded, and if necessary the

fs/exec.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,6 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
152152
path_noexec(&file->f_path)))
153153
goto exit;
154154

155-
fsnotify_open(file);
156-
157155
error = -ENOEXEC;
158156

159157
read_lock(&binfmt_lock);
@@ -940,9 +938,6 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
940938
if (err)
941939
goto exit;
942940

943-
if (name->name[0] != '\0')
944-
fsnotify_open(file);
945-
946941
out:
947942
return file;
948943

fs/exportfs/expfs.c

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,26 +381,51 @@ static int export_encode_fh(struct inode *inode, struct fid *fid,
381381
return type;
382382
}
383383

384+
/**
385+
* exportfs_encode_inode_fh - encode a file handle from inode
386+
* @inode: the object to encode
387+
* @fid: where to store the file handle fragment
388+
* @max_len: maximum length to store there
389+
* @flags: properties of the requested file handle
390+
*
391+
* Returns an enum fid_type or a negative errno.
392+
*/
384393
int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
385-
int *max_len, struct inode *parent)
394+
int *max_len, struct inode *parent, int flags)
386395
{
387396
const struct export_operations *nop = inode->i_sb->s_export_op;
388397

398+
/*
399+
* If a decodeable file handle was requested, we need to make sure that
400+
* filesystem can decode file handles.
401+
*/
402+
if (nop && !(flags & EXPORT_FH_FID) && !nop->fh_to_dentry)
403+
return -EOPNOTSUPP;
404+
389405
if (nop && nop->encode_fh)
390406
return nop->encode_fh(inode, fid->raw, max_len, parent);
391407

392408
return export_encode_fh(inode, fid, max_len, parent);
393409
}
394410
EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
395411

412+
/**
413+
* exportfs_encode_fh - encode a file handle from dentry
414+
* @dentry: the object to encode
415+
* @fid: where to store the file handle fragment
416+
* @max_len: maximum length to store there
417+
* @flags: properties of the requested file handle
418+
*
419+
* Returns an enum fid_type or a negative errno.
420+
*/
396421
int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
397-
int connectable)
422+
int flags)
398423
{
399424
int error;
400425
struct dentry *p = NULL;
401426
struct inode *inode = dentry->d_inode, *parent = NULL;
402427

403-
if (connectable && !S_ISDIR(inode->i_mode)) {
428+
if ((flags & EXPORT_FH_CONNECTABLE) && !S_ISDIR(inode->i_mode)) {
404429
p = dget_parent(dentry);
405430
/*
406431
* note that while p might've ceased to be our parent already,
@@ -409,7 +434,7 @@ int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
409434
parent = p->d_inode;
410435
}
411436

412-
error = exportfs_encode_inode_fh(inode, fid, max_len, parent);
437+
error = exportfs_encode_inode_fh(inode, fid, max_len, parent, flags);
413438
dput(p);
414439

415440
return error;

fs/fhandle.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,22 @@
1616

1717
static long do_sys_name_to_handle(const struct path *path,
1818
struct file_handle __user *ufh,
19-
int __user *mnt_id)
19+
int __user *mnt_id, int fh_flags)
2020
{
2121
long retval;
2222
struct file_handle f_handle;
2323
int handle_dwords, handle_bytes;
2424
struct file_handle *handle = NULL;
2525

2626
/*
27-
* We need to make sure whether the file system
28-
* support decoding of the file handle
27+
* We need to make sure whether the file system support decoding of
28+
* the file handle if decodeable file handle was requested.
29+
* Otherwise, even empty export_operations are sufficient to opt-in
30+
* to encoding FIDs.
2931
*/
3032
if (!path->dentry->d_sb->s_export_op ||
31-
!path->dentry->d_sb->s_export_op->fh_to_dentry)
33+
(!(fh_flags & EXPORT_FH_FID) &&
34+
!path->dentry->d_sb->s_export_op->fh_to_dentry))
3235
return -EOPNOTSUPP;
3336

3437
if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
@@ -45,27 +48,28 @@ static long do_sys_name_to_handle(const struct path *path,
4548
/* convert handle size to multiple of sizeof(u32) */
4649
handle_dwords = f_handle.handle_bytes >> 2;
4750

48-
/* we ask for a non connected handle */
51+
/* we ask for a non connectable maybe decodeable file handle */
4952
retval = exportfs_encode_fh(path->dentry,
5053
(struct fid *)handle->f_handle,
51-
&handle_dwords, 0);
54+
&handle_dwords, fh_flags);
5255
handle->handle_type = retval;
5356
/* convert handle size to bytes */
5457
handle_bytes = handle_dwords * sizeof(u32);
5558
handle->handle_bytes = handle_bytes;
5659
if ((handle->handle_bytes > f_handle.handle_bytes) ||
57-
(retval == FILEID_INVALID) || (retval == -ENOSPC)) {
60+
(retval == FILEID_INVALID) || (retval < 0)) {
5861
/* As per old exportfs_encode_fh documentation
5962
* we could return ENOSPC to indicate overflow
6063
* But file system returned 255 always. So handle
6164
* both the values
6265
*/
66+
if (retval == FILEID_INVALID || retval == -ENOSPC)
67+
retval = -EOVERFLOW;
6368
/*
6469
* set the handle size to zero so we copy only
6570
* non variable part of the file_handle
6671
*/
6772
handle_bytes = 0;
68-
retval = -EOVERFLOW;
6973
} else
7074
retval = 0;
7175
/* copy the mount id */
@@ -84,6 +88,7 @@ static long do_sys_name_to_handle(const struct path *path,
8488
* @handle: resulting file handle
8589
* @mnt_id: mount id of the file system containing the file
8690
* @flag: flag value to indicate whether to follow symlink or not
91+
* and whether a decodable file handle is required.
8792
*
8893
* @handle->handle_size indicate the space available to store the
8994
* variable part of the file handle in bytes. If there is not
@@ -96,17 +101,19 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
96101
{
97102
struct path path;
98103
int lookup_flags;
104+
int fh_flags;
99105
int err;
100106

101-
if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
107+
if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID))
102108
return -EINVAL;
103109

104110
lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
111+
fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0;
105112
if (flag & AT_EMPTY_PATH)
106113
lookup_flags |= LOOKUP_EMPTY;
107114
err = user_path_at(dfd, name, lookup_flags, &path);
108115
if (!err) {
109-
err = do_sys_name_to_handle(&path, handle, mnt_id);
116+
err = do_sys_name_to_handle(&path, handle, mnt_id, fh_flags);
110117
path_put(&path);
111118
}
112119
return err;
@@ -235,7 +242,6 @@ static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
235242
retval = PTR_ERR(file);
236243
} else {
237244
retval = fd;
238-
fsnotify_open(file);
239245
fd_install(fd, file);
240246
}
241247
path_put(&path);

fs/nfsd/nfsfh.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,10 +414,13 @@ static void _fh_update(struct svc_fh *fhp, struct svc_export *exp,
414414
struct fid *fid = (struct fid *)
415415
(fhp->fh_handle.fh_fsid + fhp->fh_handle.fh_size/4 - 1);
416416
int maxsize = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
417-
int subtreecheck = !(exp->ex_flags & NFSEXP_NOSUBTREECHECK);
417+
int fh_flags = (exp->ex_flags & NFSEXP_NOSUBTREECHECK) ? 0 :
418+
EXPORT_FH_CONNECTABLE;
419+
int fileid_type =
420+
exportfs_encode_fh(dentry, fid, &maxsize, fh_flags);
418421

419422
fhp->fh_handle.fh_fileid_type =
420-
exportfs_encode_fh(dentry, fid, &maxsize, subtreecheck);
423+
fileid_type > 0 ? fileid_type : FILEID_INVALID;
421424
fhp->fh_handle.fh_size += maxsize * 4;
422425
} else {
423426
fhp->fh_handle.fh_fileid_type = FILEID_ROOT;

fs/notify/fanotify/fanotify.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ static int fanotify_encode_fh_len(struct inode *inode)
380380
if (!inode)
381381
return 0;
382382

383-
exportfs_encode_inode_fh(inode, NULL, &dwords, NULL);
383+
exportfs_encode_fid(inode, NULL, &dwords);
384384
fh_len = dwords << 2;
385385

386386
/*
@@ -443,9 +443,9 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
443443
}
444444

445445
dwords = fh_len >> 2;
446-
type = exportfs_encode_inode_fh(inode, buf, &dwords, NULL);
446+
type = exportfs_encode_fid(inode, buf, &dwords);
447447
err = -EINVAL;
448-
if (!type || type == FILEID_INVALID || fh_len != dwords << 2)
448+
if (type <= 0 || type == FILEID_INVALID || fh_len != dwords << 2)
449449
goto out_err;
450450

451451
fh->type = type;

fs/notify/fanotify/fanotify_user.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,11 +1591,10 @@ static int fanotify_test_fid(struct dentry *dentry)
15911591
* We need to make sure that the file system supports at least
15921592
* encoding a file handle so user can use name_to_handle_at() to
15931593
* compare fid returned with event to the file handle of watched
1594-
* objects. However, name_to_handle_at() requires that the
1595-
* filesystem also supports decoding file handles.
1594+
* objects. However, even the relaxed AT_HANDLE_FID flag requires
1595+
* at least empty export_operations for ecoding unique file ids.
15961596
*/
1597-
if (!dentry->d_sb->s_export_op ||
1598-
!dentry->d_sb->s_export_op->fh_to_dentry)
1597+
if (!dentry->d_sb->s_export_op)
15991598
return -EOPNOTSUPP;
16001599

16011600
return 0;

fs/notify/fdinfo.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ static void show_mark_fhandle(struct seq_file *m, struct inode *inode)
5050
f.handle.handle_bytes = sizeof(f.pad);
5151
size = f.handle.handle_bytes >> 2;
5252

53-
ret = exportfs_encode_inode_fh(inode, (struct fid *)f.handle.f_handle, &size, NULL);
53+
ret = exportfs_encode_fid(inode, (struct fid *)f.handle.f_handle, &size);
5454
if ((ret == FILEID_INVALID) || (ret < 0)) {
5555
WARN_ONCE(1, "Can't encode file handler for inotify: %d\n", ret);
5656
return;

fs/open.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,11 @@ static int do_dentry_open(struct file *f,
963963
}
964964
}
965965

966+
/*
967+
* Once we return a file with FMODE_OPENED, __fput() will call
968+
* fsnotify_close(), so we need fsnotify_open() here for symmetry.
969+
*/
970+
fsnotify_open(f);
966971
return 0;
967972

968973
cleanup_all:
@@ -1404,7 +1409,6 @@ static long do_sys_openat2(int dfd, const char __user *filename,
14041409
put_unused_fd(fd);
14051410
fd = PTR_ERR(f);
14061411
} else {
1407-
fsnotify_open(f);
14081412
fd_install(fd, f);
14091413
}
14101414
}

include/linux/exportfs.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ struct fid {
135135
};
136136
};
137137

138+
#define EXPORT_FH_CONNECTABLE 0x1 /* Encode file handle with parent */
139+
#define EXPORT_FH_FID 0x2 /* File handle may be non-decodeable */
140+
138141
/**
139142
* struct export_operations - for nfsd to communicate with file systems
140143
* @encode_fh: encode a file handle fragment from a dentry
@@ -150,7 +153,7 @@ struct fid {
150153
* encode_fh:
151154
* @encode_fh should store in the file handle fragment @fh (using at most
152155
* @max_len bytes) information that can be used by @decode_fh to recover the
153-
* file referred to by the &struct dentry @de. If the @connectable flag is
156+
* file referred to by the &struct dentry @de. If @flag has CONNECTABLE bit
154157
* set, the encode_fh() should store sufficient information so that a good
155158
* attempt can be made to find not only the file but also it's place in the
156159
* filesystem. This typically means storing a reference to de->d_parent in
@@ -225,9 +228,18 @@ struct export_operations {
225228
};
226229

227230
extern int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
228-
int *max_len, struct inode *parent);
231+
int *max_len, struct inode *parent,
232+
int flags);
229233
extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
230-
int *max_len, int connectable);
234+
int *max_len, int flags);
235+
236+
static inline int exportfs_encode_fid(struct inode *inode, struct fid *fid,
237+
int *max_len)
238+
{
239+
return exportfs_encode_inode_fh(inode, fid, max_len, NULL,
240+
EXPORT_FH_FID);
241+
}
242+
231243
extern struct dentry *exportfs_decode_fh_raw(struct vfsmount *mnt,
232244
struct fid *fid, int fh_len,
233245
int fileid_type,

0 commit comments

Comments
 (0)