summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2017-06-16 11:13:28 -0600
committerJens Axboe <axboe@fb.com>2017-06-17 13:54:22 -0600
commitf3d8911e36b289a9330125c27b05bd4838d62cb6 (patch)
tree05c8a5f1d0accd72671e09e40574bc0c6b0010eb
parentb610abd212c30234156bce75ea66d2b9efbbb440 (diff)
fs: add fcntl() interface for setting/getting write life time hints
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 <axboe@kernel.dk>
-rw-r--r--fs/fcntl.c38
-rw-r--r--include/uapi/linux/fcntl.h6
2 files changed, 44 insertions, 0 deletions
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 */