]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/os/linux/zfs/zpl_file.c
Add Linux posix_fadvise support
[mirror_zfs.git] / module / os / linux / zfs / zpl_file.c
index 43b7fb60a99708d4f790834248602c75933b6388..b0d9f37a3ec0a22fe80e2b5298c5ace8f70ead99 100644 (file)
@@ -27,6 +27,7 @@
 #ifdef CONFIG_COMPAT
 #include <linux/compat.h>
 #endif
+#include <linux/fs.h>
 #include <sys/file.h>
 #include <sys/dmu_objset.h>
 #include <sys/zfs_znode.h>
@@ -37,6 +38,9 @@
     defined(HAVE_VFS_FILEMAP_DIRTY_FOLIO)
 #include <linux/pagemap.h>
 #endif
+#ifdef HAVE_FILE_FADVISE
+#include <linux/fadvise.h>
+#endif
 #ifdef HAVE_VFS_FILEMAP_DIRTY_FOLIO
 #include <linux/writeback.h>
 #endif
@@ -906,6 +910,61 @@ zpl_ioctl_getversion(struct file *filp, void __user *arg)
        return (copy_to_user(arg, &generation, sizeof (generation)));
 }
 
+#ifdef HAVE_FILE_FADVISE
+static int
+zpl_fadvise(struct file *filp, loff_t offset, loff_t len, int advice)
+{
+       struct inode *ip = file_inode(filp);
+       znode_t *zp = ITOZ(ip);
+       zfsvfs_t *zfsvfs = ITOZSB(ip);
+       objset_t *os = zfsvfs->z_os;
+       int error = 0;
+
+       if (S_ISFIFO(ip->i_mode))
+               return (-ESPIPE);
+
+       if (offset < 0 || len < 0)
+               return (-EINVAL);
+
+       ZFS_ENTER(zfsvfs);
+       ZFS_VERIFY_ZP(zp);
+
+       switch (advice) {
+       case POSIX_FADV_SEQUENTIAL:
+       case POSIX_FADV_WILLNEED:
+#ifdef HAVE_GENERIC_FADVISE
+               if (zn_has_cached_data(zp))
+                       error = generic_fadvise(filp, offset, len, advice);
+#endif
+               /*
+                * Pass on the caller's size directly, but note that
+                * dmu_prefetch_max will effectively cap it.  If there
+                * really is a larger sequential access pattern, perhaps
+                * dmu_zfetch will detect it.
+                */
+               if (len == 0)
+                       len = i_size_read(ip) - offset;
+
+               dmu_prefetch(os, zp->z_id, 0, offset, len,
+                   ZIO_PRIORITY_ASYNC_READ);
+               break;
+       case POSIX_FADV_NORMAL:
+       case POSIX_FADV_RANDOM:
+       case POSIX_FADV_DONTNEED:
+       case POSIX_FADV_NOREUSE:
+               /* ignored for now */
+               break;
+       default:
+               error = -EINVAL;
+               break;
+       }
+
+       ZFS_EXIT(zfsvfs);
+
+       return (error);
+}
+#endif /* HAVE_FILE_FADVISE */
+
 #define        ZFS_FL_USER_VISIBLE     (FS_FL_USER_VISIBLE | ZFS_PROJINHERIT_FL)
 #define        ZFS_FL_USER_MODIFIABLE  (FS_FL_USER_MODIFIABLE | ZFS_PROJINHERIT_FL)
 
@@ -1259,6 +1318,9 @@ const struct file_operations zpl_file_operations = {
        .aio_fsync      = zpl_aio_fsync,
 #endif
        .fallocate      = zpl_fallocate,
+#ifdef HAVE_FILE_FADVISE
+       .fadvise        = zpl_fadvise,
+#endif
        .unlocked_ioctl = zpl_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = zpl_compat_ioctl,