#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>
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
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)
.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,