We have a pwritev2(2) interface based on passing in flags. Add an
fcntl interface for querying these flags, and also for setting them
as well:

F_GET_RW_HINT           Returns the read/write hint set. Right now it
                        will be one of the WRITE_LIFE_* values.

F_SET_RW_HINT           Pass in rw_hint type to set the read/write hint.
                        Only WRITE_LIFE_* hints are currently supported.
                        Returns 0 on succes, -1 otherwise.

Sample program testing/implementing basic setting/getting of write
hints is below.

/*
 * writehint.c: check or set a file/inode write hint
 */

static char *str[] = { "WRITE_LIFE_NONE", "WRITE_LIFE_SHORT",
                        "WRITE_LIFE_MEDIUM", "WRITE_LIFE_LONG",
                        "WRITE_LIFE_EXTREME" };

int main(int argc, char *argv[])
{
        int hint = -1, fd, ret;

        if (argc < 2) {
                fprintf(stderr, "%s: dev <hint>\n", argv[0]);
                return 1;
        }

        fd = open(argv[1], O_RDONLY);
        if (fd < 0) {
                perror("open");
                return 2;
        }

        if (argc > 2)
                hint = atoi(argv[2]);

        if (hint == -1) {
                ret = fcntl(fd, F_GET_RW_HINT);
                if (ret < 0) {
                        perror("fcntl: F_GET_RW_HINT");
                        return 3;
                }
                hint = ret;
        } else {
                ret = fcntl(fd, F_SET_RW_HINT, hint);
                if (ret < 0) {
                        perror("fcntl: F_SET_RW_HINT");
                        return 4;
                }
        }

        printf("%s: %shint %s\n", argv[1], hint != -1 ? "set " : "", str[hint]);
        close(fd);
        return 0;
}

Signed-off-by: Jens Axboe <ax...@kernel.dk>
---
 fs/fcntl.c                 | 38 ++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/fcntl.h |  6 ++++++
 2 files changed, 44 insertions(+)

diff --git a/fs/fcntl.c b/fs/fcntl.c
index f4e7267d117f..417ce336c875 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -243,6 +243,40 @@ static int f_getowner_uids(struct file *filp, unsigned 
long arg)
 }
 #endif
 
+long fcntl_rw_hint(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct inode *inode = file_inode(file);
+       long ret;
+
+       switch (cmd) {
+       case F_GET_RW_HINT:
+               ret = mask_to_write_hint(inode->i_flags, S_WRITE_LIFE_SHIFT);
+               break;
+       case F_SET_RW_HINT: {
+               enum rw_hint hint = arg;
+
+               switch (hint) {
+               case WRITE_LIFE_NONE:
+               case WRITE_LIFE_SHORT:
+               case WRITE_LIFE_MEDIUM:
+               case WRITE_LIFE_LONG:
+               case WRITE_LIFE_EXTREME:
+                       inode_set_write_hint(inode, hint);
+                       ret = 0;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+               break;
+               }
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
 static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
                struct file *filp)
 {
@@ -337,6 +371,10 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned 
long arg,
        case F_GET_SEALS:
                err = shmem_fcntl(filp, cmd, arg);
                break;
+       case F_GET_RW_HINT:
+       case F_SET_RW_HINT:
+               err = fcntl_rw_hint(filp, cmd, arg);
+               break;
        default:
                break;
        }
diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
index 813afd6eee71..f1a0fbc5bff1 100644
--- a/include/uapi/linux/fcntl.h
+++ b/include/uapi/linux/fcntl.h
@@ -43,6 +43,12 @@
 /* (1U << 31) is reserved for signed error codes */
 
 /*
+ * Set/Get write life time hints
+ */
+#define F_GET_RW_HINT          (F_LINUX_SPECIFIC_BASE + 11)
+#define F_SET_RW_HINT          (F_LINUX_SPECIFIC_BASE + 12)
+
+/*
  * Types of directory notifications that may be requested.
  */
 #define DN_ACCESS      0x00000001      /* File accessed */
-- 
2.7.4

Reply via email to