aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2018-08-27 08:56:02 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2018-08-30 11:08:35 -0400
commit45cd0faae3715e305bc46e23b34c5ed4d185ceb8 (patch)
treebe01e26c488ebd3cb7943136a0805563e311d117
parent17ef445f9befdc5c9adac270b18240ad24ee50ec (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.txt3
-rw-r--r--include/linux/fs.h5
-rw-r--r--mm/fadvise.c78
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
890Again, all methods are called without any locks being held, unless 891Again, 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
968Note that the file operations are implemented by the specific 971Note that the file operations are implemented by the specific
969filesystem in which the inode resides. When opening a device node 972filesystem 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
1768struct inode_operations { 1769struct inode_operations {
@@ -3459,4 +3460,8 @@ static inline bool dir_relax_shared(struct inode *inode)
3459extern bool path_noexec(const struct path *path); 3460extern bool path_noexec(const struct path *path);
3460extern void inode_nohighmem(struct inode *inode); 3461extern void inode_nohighmem(struct inode *inode);
3461 3462
3463/* mm/fadvise.c */
3464extern 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
30int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) 30static 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 }
188out: 179 return 0;
180}
181
182int 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}
189EXPORT_SYMBOL(vfs_fadvise);
190
191int 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}