Loading Documentation/filesystems/vfs.txt +3 −0 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading include/linux/fs.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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 */ mm/fadvise.c +45 −33 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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); Loading @@ -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; } } /* /* Loading @@ -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! */ Loading @@ -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; Loading Loading @@ -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; } return 0; } } out: 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; } } Loading Loading
Documentation/filesystems/vfs.txt +3 −0 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading
include/linux/fs.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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 */
mm/fadvise.c +45 −33 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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); Loading @@ -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; } } /* /* Loading @@ -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! */ Loading @@ -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; Loading Loading @@ -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; } return 0; } } out: 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; } } Loading