Commit 45cd0faa authored by Amir Goldstein's avatar Amir Goldstein Committed by Miklos Szeredi

vfs: add the fadvise() file operation

This is going to be used by overlayfs and possibly useful
for other filesystems.
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 17ef445f
...@@ -885,6 +885,7 @@ struct file_operations { ...@@ -885,6 +885,7 @@ struct file_operations {
ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int); ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int);
int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t, u64); int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t, u64);
int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t, u64); int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t, u64);
int (*fadvise)(struct file *, loff_t, loff_t, int);
}; };
Again, all methods are called without any locks being held, unless Again, all methods are called without any locks being held, unless
...@@ -965,6 +966,8 @@ otherwise noted. ...@@ -965,6 +966,8 @@ otherwise noted.
dedupe_file_range: called by the ioctl(2) system call for FIDEDUPERANGE dedupe_file_range: called by the ioctl(2) system call for FIDEDUPERANGE
command. command.
fadvise: possibly called by the fadvise64() system call.
Note that the file operations are implemented by the specific Note that the file operations are implemented by the specific
filesystem in which the inode resides. When opening a device node filesystem in which the inode resides. When opening a device node
(character or block special) most filesystems will call special (character or block special) most filesystems will call special
......
...@@ -1763,6 +1763,7 @@ struct file_operations { ...@@ -1763,6 +1763,7 @@ struct file_operations {
u64); u64);
int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t, int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t,
u64); u64);
int (*fadvise)(struct file *, loff_t, loff_t, int);
} __randomize_layout; } __randomize_layout;
struct inode_operations { struct inode_operations {
...@@ -3459,4 +3460,8 @@ static inline bool dir_relax_shared(struct inode *inode) ...@@ -3459,4 +3460,8 @@ static inline bool dir_relax_shared(struct inode *inode)
extern bool path_noexec(const struct path *path); extern bool path_noexec(const struct path *path);
extern void inode_nohighmem(struct inode *inode); extern void inode_nohighmem(struct inode *inode);
/* mm/fadvise.c */
extern int vfs_fadvise(struct file *file, loff_t offset, loff_t len,
int advice);
#endif /* _LINUX_FS_H */ #endif /* _LINUX_FS_H */
...@@ -27,9 +27,9 @@ ...@@ -27,9 +27,9 @@
* deactivate the pages and clear PG_Referenced. * deactivate the pages and clear PG_Referenced.
*/ */
int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) static int generic_fadvise(struct file *file, loff_t offset, loff_t len,
int advice)
{ {
struct fd f = fdget(fd);
struct inode *inode; struct inode *inode;
struct address_space *mapping; struct address_space *mapping;
struct backing_dev_info *bdi; struct backing_dev_info *bdi;
...@@ -37,22 +37,14 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) ...@@ -37,22 +37,14 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
pgoff_t start_index; pgoff_t start_index;
pgoff_t end_index; pgoff_t end_index;
unsigned long nrpages; unsigned long nrpages;
int ret = 0;
if (!f.file) inode = file_inode(file);
return -EBADF; if (S_ISFIFO(inode->i_mode))
return -ESPIPE;
inode = file_inode(f.file); mapping = file->f_mapping;
if (S_ISFIFO(inode->i_mode)) { if (!mapping || len < 0)
ret = -ESPIPE; return -EINVAL;
goto out;
}
mapping = f.file->f_mapping;
if (!mapping || len < 0) {
ret = -EINVAL;
goto out;
}
bdi = inode_to_bdi(mapping->host); bdi = inode_to_bdi(mapping->host);
...@@ -67,9 +59,9 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) ...@@ -67,9 +59,9 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
/* no bad return value, but ignore advice */ /* no bad return value, but ignore advice */
break; break;
default: default:
ret = -EINVAL; return -EINVAL;
} }
goto out; return 0;
} }
/* /*
...@@ -85,21 +77,21 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) ...@@ -85,21 +77,21 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
switch (advice) { switch (advice) {
case POSIX_FADV_NORMAL: case POSIX_FADV_NORMAL:
f.file->f_ra.ra_pages = bdi->ra_pages; file->f_ra.ra_pages = bdi->ra_pages;
spin_lock(&f.file->f_lock); spin_lock(&file->f_lock);
f.file->f_mode &= ~FMODE_RANDOM; file->f_mode &= ~FMODE_RANDOM;
spin_unlock(&f.file->f_lock); spin_unlock(&file->f_lock);
break; break;
case POSIX_FADV_RANDOM: case POSIX_FADV_RANDOM:
spin_lock(&f.file->f_lock); spin_lock(&file->f_lock);
f.file->f_mode |= FMODE_RANDOM; file->f_mode |= FMODE_RANDOM;
spin_unlock(&f.file->f_lock); spin_unlock(&file->f_lock);
break; break;
case POSIX_FADV_SEQUENTIAL: case POSIX_FADV_SEQUENTIAL:
f.file->f_ra.ra_pages = bdi->ra_pages * 2; file->f_ra.ra_pages = bdi->ra_pages * 2;
spin_lock(&f.file->f_lock); spin_lock(&file->f_lock);
f.file->f_mode &= ~FMODE_RANDOM; file->f_mode &= ~FMODE_RANDOM;
spin_unlock(&f.file->f_lock); spin_unlock(&file->f_lock);
break; break;
case POSIX_FADV_WILLNEED: case POSIX_FADV_WILLNEED:
/* First and last PARTIAL page! */ /* First and last PARTIAL page! */
...@@ -115,8 +107,7 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) ...@@ -115,8 +107,7 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
* Ignore return value because fadvise() shall return * Ignore return value because fadvise() shall return
* success even if filesystem can't retrieve a hint, * success even if filesystem can't retrieve a hint,
*/ */
force_page_cache_readahead(mapping, f.file, start_index, force_page_cache_readahead(mapping, file, start_index, nrpages);
nrpages);
break; break;
case POSIX_FADV_NOREUSE: case POSIX_FADV_NOREUSE:
break; break;
...@@ -183,9 +174,30 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) ...@@ -183,9 +174,30 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
} }
break; break;
default: default:
ret = -EINVAL; return -EINVAL;
} }
out: return 0;
}
int vfs_fadvise(struct file *file, loff_t offset, loff_t len, int advice)
{
if (file->f_op->fadvise)
return file->f_op->fadvise(file, offset, len, advice);
return generic_fadvise(file, offset, len, advice);
}
EXPORT_SYMBOL(vfs_fadvise);
int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
{
struct fd f = fdget(fd);
int ret;
if (!f.file)
return -EBADF;
ret = vfs_fadvise(f.file, offset, len, advice);
fdput(f); fdput(f);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment