@@ -66,6 +66,8 @@ ssize_t zuf_rw_read_iter(struct super_block *sb, struct inode *inode,
ssize_t zuf_rw_write_iter(struct super_block *sb, struct inode *inode,
struct kiocb *kiocb, struct iov_iter *ii);
int zuf_trim_edge(struct inode *inode, ulong filepos, uint len);
+int zuf_fadvise(struct super_block *sb, struct inode *inode,
+ loff_t offset, loff_t len, int advise, bool rand);
int zuf_iom_execute_sync(struct super_block *sb, struct inode *inode,
__u64 *iom_e, uint iom_n);
int zuf_iom_execute_async(struct super_block *sb, struct zus_iomap_build *iomb,
@@ -238,6 +238,29 @@ static int _ioc_setversion(struct inode *inode, uint __user *parg)
return err;
}
+static int _ioc_fadvise(struct file *file, ulong arg)
+{
+ struct inode *inode = file_inode(file);
+ struct zuf_inode_info *zii = ZUII(inode);
+ struct zufs_ioc_fadvise iof = {};
+ int err;
+
+ if (!S_ISREG(inode->i_mode))
+ return -EINVAL;
+
+ if (arg && copy_from_user(&iof, (void __user *)arg, sizeof(iof)))
+ return -EFAULT;
+
+ zuf_r_lock(zii);
+
+ err = zuf_fadvise(inode->i_sb, inode, iof.offset, iof.length,
+ iof.advise, file->f_mode & FMODE_RANDOM);
+
+ zuf_r_unlock(zii);
+
+ return err;
+}
+
long zuf_ioctl(struct file *filp, unsigned int cmd, ulong arg)
{
struct inode *inode = filp->f_inode;
@@ -252,6 +275,8 @@ long zuf_ioctl(struct file *filp, unsigned int cmd, ulong arg)
return put_user(inode->i_generation, (int __user *)arg);
case FS_IOC_SETVERSION:
return _ioc_setversion(inode, parg);
+ case ZUFS_IOC_FADVISE:
+ return _ioc_fadvise(filp, arg);
default:
return _ioctl_dispatch(inode, cmd, arg);
}
@@ -315,6 +315,60 @@ ssize_t zuf_rw_write_iter(struct super_block *sb, struct inode *inode,
return ret;
}
+static int _fadv_willneed(struct super_block *sb, struct inode *inode,
+ loff_t offset, loff_t len, bool rand)
+{
+ struct zufs_ioc_IO io = {};
+ struct __zufs_ra ra = {
+ .start = md_o2p(offset),
+ .ra_pages = md_o2p_up(len),
+ .prev_pos = offset - 1,
+ };
+ int err;
+
+ io.ra.start = ra.start;
+ io.ra.ra_pages = ra.ra_pages;
+ io.ra.prev_pos = ra.prev_pos;
+ io.flags = rand ? ZUFS_IO_RAND : 0;
+
+ err = _IO_dispatch(SBI(sb), &io, ZUII(inode), ZUFS_OP_PRE_READ, 0,
+ NULL, 0, offset, 0);
+ return err;
+}
+
+static int _fadv_dontneed(struct super_block *sb, struct inode *inode,
+ loff_t offset, loff_t len)
+{
+ struct zufs_ioc_range ioc_range = {
+ .hdr.in_len = sizeof(ioc_range),
+ .hdr.operation = ZUFS_OP_SYNC,
+ .zus_ii = ZUII(inode)->zus_ii,
+ .offset = offset,
+ .length = len,
+ .ioc_flags = ZUFS_RF_DONTNEED,
+ };
+
+ return zufc_dispatch(ZUF_ROOT(SBI(sb)), &ioc_range.hdr, NULL, 0);
+}
+
+int zuf_fadvise(struct super_block *sb, struct inode *inode,
+ loff_t offset, loff_t len, int advise, bool rand)
+{
+ switch (advise) {
+ case POSIX_FADV_WILLNEED:
+ return _fadv_willneed(sb, inode, offset, len, rand);
+ case POSIX_FADV_DONTNEED:
+ return _fadv_dontneed(sb, inode, offset, len);
+ case POSIX_FADV_NOREUSE: /* TODO */
+ case POSIX_FADV_SEQUENTIAL: /* TODO: turn off random */
+ case POSIX_FADV_NORMAL:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
/* ~~~~ iom_dec.c ~~~ */
/* for now here (at rw.c) looks logical */
@@ -778,6 +778,7 @@ const char *zuf_op_name(enum e_zufs_operation op)
CASE_ENUM_NAME(ZUFS_OP_CLONE );
CASE_ENUM_NAME(ZUFS_OP_COPY );
CASE_ENUM_NAME(ZUFS_OP_READ );
+ CASE_ENUM_NAME(ZUFS_OP_PRE_READ );
CASE_ENUM_NAME(ZUFS_OP_WRITE );
CASE_ENUM_NAME(ZUFS_OP_GET_BLOCK );
CASE_ENUM_NAME(ZUFS_OP_PUT_BLOCK );
@@ -159,6 +159,19 @@ struct zus_inode {
/* Total ZUFS_INODE_SIZE bytes always */
};
+/* ~~~~~ vfs extension ioctl commands ~~~~~ */
+
+/* TODO: This one needs to be an FS vector called from
+ * the fadvise() system call. (Future patch)
+ */
+struct zufs_ioc_fadvise {
+ __u64 offset;
+ __u64 length; /* if 0 all file */
+ __u64 advise;
+} __packed;
+
+#define ZUFS_IOC_FADVISE _IOW('S', 2, struct zufs_ioc_fadvise)
+
/* ~~~~~ ZUFS API ioctl commands ~~~~~ */
enum {
ZUS_API_MAP_MAX_PAGES = 1024,
@@ -341,6 +354,7 @@ enum e_zufs_operation {
ZUFS_OP_COPY,
ZUFS_OP_READ,
+ ZUFS_OP_PRE_READ,
ZUFS_OP_WRITE,
ZUFS_OP_GET_BLOCK,
ZUFS_OP_PUT_BLOCK,