Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -885,6 +885,7 @@ struct file_operations {
	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 (*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
@@ -965,6 +966,8 @@ otherwise noted.
  dedupe_file_range: called by the ioctl(2) system call for FIDEDUPERANGE
	command.

  fadvise: possibly called by the fadvise64() system call.

Note that the file operations are implemented by the specific
filesystem in which the inode resides. When opening a device node
(character or block special) most filesystems will call special
+5 −0
Original line number Diff line number Diff line
@@ -1763,6 +1763,7 @@ struct file_operations {
			u64);
	int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t,
			u64);
	int (*fadvise)(struct file *, loff_t, loff_t, int);
} __randomize_layout;

struct inode_operations {
@@ -3459,4 +3460,8 @@ static inline bool dir_relax_shared(struct inode *inode)
extern bool path_noexec(const struct path *path);
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 */
+45 −33
Original line number Diff line number Diff line
@@ -27,9 +27,9 @@
 * 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 address_space *mapping;
	struct backing_dev_info *bdi;
@@ -37,22 +37,14 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
	pgoff_t start_index;
	pgoff_t end_index;
	unsigned long nrpages;
	int ret = 0;

	if (!f.file)
		return -EBADF;
	inode = file_inode(file);
	if (S_ISFIFO(inode->i_mode))
		return -ESPIPE;

	inode = file_inode(f.file);
	if (S_ISFIFO(inode->i_mode)) {
		ret = -ESPIPE;
		goto out;
	}

	mapping = f.file->f_mapping;
	if (!mapping || len < 0) {
		ret = -EINVAL;
		goto out;
	}
	mapping = file->f_mapping;
	if (!mapping || len < 0)
		return -EINVAL;

	bdi = inode_to_bdi(mapping->host);

@@ -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 */
			break;
		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)

	switch (advice) {
	case POSIX_FADV_NORMAL:
		f.file->f_ra.ra_pages = bdi->ra_pages;
		spin_lock(&f.file->f_lock);
		f.file->f_mode &= ~FMODE_RANDOM;
		spin_unlock(&f.file->f_lock);
		file->f_ra.ra_pages = bdi->ra_pages;
		spin_lock(&file->f_lock);
		file->f_mode &= ~FMODE_RANDOM;
		spin_unlock(&file->f_lock);
		break;
	case POSIX_FADV_RANDOM:
		spin_lock(&f.file->f_lock);
		f.file->f_mode |= FMODE_RANDOM;
		spin_unlock(&f.file->f_lock);
		spin_lock(&file->f_lock);
		file->f_mode |= FMODE_RANDOM;
		spin_unlock(&file->f_lock);
		break;
	case POSIX_FADV_SEQUENTIAL:
		f.file->f_ra.ra_pages = bdi->ra_pages * 2;
		spin_lock(&f.file->f_lock);
		f.file->f_mode &= ~FMODE_RANDOM;
		spin_unlock(&f.file->f_lock);
		file->f_ra.ra_pages = bdi->ra_pages * 2;
		spin_lock(&file->f_lock);
		file->f_mode &= ~FMODE_RANDOM;
		spin_unlock(&file->f_lock);
		break;
	case POSIX_FADV_WILLNEED:
		/* First and last PARTIAL page! */
@@ -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
		 * success even if filesystem can't retrieve a hint,
		 */
		force_page_cache_readahead(mapping, f.file, start_index,
					   nrpages);
		force_page_cache_readahead(mapping, file, start_index, nrpages);
		break;
	case POSIX_FADV_NOREUSE:
		break;
@@ -183,9 +174,30 @@ int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
		}
		break;
	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);
	return ret;
}