diff options
author | Amir Goldstein <amir73il@gmail.com> | 2018-08-27 08:56:02 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2018-08-30 11:08:35 -0400 |
commit | 45cd0faae3715e305bc46e23b34c5ed4d185ceb8 (patch) | |
tree | be01e26c488ebd3cb7943136a0805563e311d117 | |
parent | 17ef445f9befdc5c9adac270b18240ad24ee50ec (diff) |
vfs: add the fadvise() file operation
This is going to be used by overlayfs and possibly useful
for other filesystems.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r-- | Documentation/filesystems/vfs.txt | 3 | ||||
-rw-r--r-- | include/linux/fs.h | 5 | ||||
-rw-r--r-- | mm/fadvise.c | 78 |
3 files changed, 53 insertions, 33 deletions
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index ec2142c8dbd3..a6c6a8af48a2 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt | |||
@@ -885,6 +885,7 @@ struct file_operations { | |||
885 | ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int); | 885 | ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int); |
886 | int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t, u64); | 886 | int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t, u64); |
887 | int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t, u64); | 887 | int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t, u64); |
888 | int (*fadvise)(struct file *, loff_t, loff_t, int); | ||
888 | }; | 889 | }; |
889 | 890 | ||
890 | Again, all methods are called without any locks being held, unless | 891 | Again, all methods are called without any locks being held, unless |
@@ -965,6 +966,8 @@ otherwise noted. | |||
965 | dedupe_file_range: called by the ioctl(2) system call for FIDEDUPERANGE | 966 | dedupe_file_range: called by the ioctl(2) system call for FIDEDUPERANGE |
966 | command. | 967 | command. |
967 | 968 | ||
969 | fadvise: possibly called by the fadvise64() system call. | ||
970 | |||
968 | Note that the file operations are implemented by the specific | 971 | Note that the file operations are implemented by the specific |
969 | filesystem in which the inode resides. When opening a device node | 972 | filesystem in which the inode resides. When opening a device node |
970 | (character or block special) most filesystems will call special | 973 | (character or block special) most filesystems will call special |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 33322702c910..6c0b4a1c22ff 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1763,6 +1763,7 @@ struct file_operations { | |||
1763 | u64); | 1763 | u64); |
1764 | int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t, | 1764 | int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t, |
1765 | u64); | 1765 | u64); |
1766 | int (*fadvise)(struct file *, loff_t, loff_t, int); | ||
1766 | } __randomize_layout; | 1767 | } __randomize_layout; |
1767 | 1768 | ||
1768 | struct inode_operations { | 1769 | struct inode_operations { |
@@ -3459,4 +3460,8 @@ static inline bool dir_relax_shared(struct inode *inode) | |||
3459 | extern bool path_noexec(const struct path *path); | 3460 | extern bool path_noexec(const struct path *path); |
3460 | extern void inode_nohighmem(struct inode *inode); | 3461 | extern void inode_nohighmem(struct inode *inode); |
3461 | 3462 | ||
3463 | /* mm/fadvise.c */ | ||
3464 | extern int vfs_fadvise(struct file *file, loff_t offset, loff_t len, | ||
3465 | int advice); | ||
3466 | |||
3462 | #endif /* _LINUX_FS_H */ | 3467 | #endif /* _LINUX_FS_H */ |
diff --git a/mm/fadvise.c b/mm/fadvise.c index 2d8376e3c640..2f59bac1cb77 100644 --- a/mm/fadvise.c +++ b/mm/fadvise.c | |||
@@ -27,9 +27,9 @@ | |||
27 | * deactivate the pages and clear PG_Referenced. | 27 | * deactivate the pages and clear PG_Referenced. |
28 | */ | 28 | */ |
29 | 29 | ||
30 | int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) | 30 | static int generic_fadvise(struct file *file, loff_t offset, loff_t len, |
31 | int advice) | ||
31 | { | 32 | { |
32 | struct fd f = fdget(fd); | ||
33 | struct inode *inode; | 33 | struct inode *inode; |
34 | struct address_space *mapping; | 34 | struct address_space *mapping; |
35 | struct backing_dev_info *bdi; | 35 | struct backing_dev_info *bdi; |
@@ -37,22 +37,14 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) | |||
37 | pgoff_t start_index; | 37 | pgoff_t start_index; |
38 | pgoff_t end_index; | 38 | pgoff_t end_index; |
39 | unsigned long nrpages; | 39 | unsigned long nrpages; |
40 | int ret = 0; | ||
41 | 40 | ||
42 | if (!f.file) | 41 | inode = file_inode(file); |
43 | return -EBADF; | 42 | if (S_ISFIFO(inode->i_mode)) |
43 | return -ESPIPE; | ||
44 | 44 | ||
45 | inode = file_inode(f.file); | 45 | mapping = file->f_mapping; |
46 | if (S_ISFIFO(inode->i_mode)) { | 46 | if (!mapping || len < 0) |
47 | ret = -ESPIPE; | 47 | return -EINVAL; |
48 | goto out; | ||
49 | } | ||
50 | |||
51 | mapping = f.file->f_mapping; | ||
52 | if (!mapping || len < 0) { | ||
53 | ret = -EINVAL; | ||
54 | goto out; | ||
55 | } | ||
56 | 48 | ||
57 | bdi = inode_to_bdi(mapping->host); | 49 | bdi = inode_to_bdi(mapping->host); |
58 | 50 | ||
@@ -67,9 +59,9 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) | |||
67 | /* no bad return value, but ignore advice */ | 59 | /* no bad return value, but ignore advice */ |
68 | break; | 60 | break; |
69 | default: | 61 | default: |
70 | ret = -EINVAL; | 62 | return -EINVAL; |
71 | } | 63 | } |
72 | goto out; | 64 | return 0; |
73 | } | 65 | } |
74 | 66 | ||
75 | /* | 67 | /* |
@@ -85,21 +77,21 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) | |||
85 | 77 | ||
86 | switch (advice) { | 78 | switch (advice) { |
87 | case POSIX_FADV_NORMAL: | 79 | case POSIX_FADV_NORMAL: |
88 | f.file->f_ra.ra_pages = bdi->ra_pages; | 80 | file->f_ra.ra_pages = bdi->ra_pages; |
89 | spin_lock(&f.file->f_lock); | 81 | spin_lock(&file->f_lock); |
90 | f.file->f_mode &= ~FMODE_RANDOM; | 82 | file->f_mode &= ~FMODE_RANDOM; |
91 | spin_unlock(&f.file->f_lock); | 83 | spin_unlock(&file->f_lock); |
92 | break; | 84 | break; |
93 | case POSIX_FADV_RANDOM: | 85 | case POSIX_FADV_RANDOM: |
94 | spin_lock(&f.file->f_lock); | 86 | spin_lock(&file->f_lock); |
95 | f.file->f_mode |= FMODE_RANDOM; | 87 | file->f_mode |= FMODE_RANDOM; |
96 | spin_unlock(&f.file->f_lock); | 88 | spin_unlock(&file->f_lock); |
97 | break; | 89 | break; |
98 | case POSIX_FADV_SEQUENTIAL: | 90 | case POSIX_FADV_SEQUENTIAL: |
99 | f.file->f_ra.ra_pages = bdi->ra_pages * 2; | 91 | file->f_ra.ra_pages = bdi->ra_pages * 2; |
100 | spin_lock(&f.file->f_lock); | 92 | spin_lock(&file->f_lock); |
101 | f.file->f_mode &= ~FMODE_RANDOM; | 93 | file->f_mode &= ~FMODE_RANDOM; |
102 | spin_unlock(&f.file->f_lock); | 94 | spin_unlock(&file->f_lock); |
103 | break; | 95 | break; |
104 | case POSIX_FADV_WILLNEED: | 96 | case POSIX_FADV_WILLNEED: |
105 | /* First and last PARTIAL page! */ | 97 | /* First and last PARTIAL page! */ |
@@ -115,8 +107,7 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) | |||
115 | * Ignore return value because fadvise() shall return | 107 | * Ignore return value because fadvise() shall return |
116 | * success even if filesystem can't retrieve a hint, | 108 | * success even if filesystem can't retrieve a hint, |
117 | */ | 109 | */ |
118 | force_page_cache_readahead(mapping, f.file, start_index, | 110 | force_page_cache_readahead(mapping, file, start_index, nrpages); |
119 | nrpages); | ||
120 | break; | 111 | break; |
121 | case POSIX_FADV_NOREUSE: | 112 | case POSIX_FADV_NOREUSE: |
122 | break; | 113 | break; |
@@ -183,9 +174,30 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) | |||
183 | } | 174 | } |
184 | break; | 175 | break; |
185 | default: | 176 | default: |
186 | ret = -EINVAL; | 177 | return -EINVAL; |
187 | } | 178 | } |
188 | out: | 179 | return 0; |
180 | } | ||
181 | |||
182 | int vfs_fadvise(struct file *file, loff_t offset, loff_t len, int advice) | ||
183 | { | ||
184 | if (file->f_op->fadvise) | ||
185 | return file->f_op->fadvise(file, offset, len, advice); | ||
186 | |||
187 | return generic_fadvise(file, offset, len, advice); | ||
188 | } | ||
189 | EXPORT_SYMBOL(vfs_fadvise); | ||
190 | |||
191 | int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) | ||
192 | { | ||
193 | struct fd f = fdget(fd); | ||
194 | int ret; | ||
195 | |||
196 | if (!f.file) | ||
197 | return -EBADF; | ||
198 | |||
199 | ret = vfs_fadvise(f.file, offset, len, advice); | ||
200 | |||
189 | fdput(f); | 201 | fdput(f); |
190 | return ret; | 202 | return ret; |
191 | } | 203 | } |