Message ID | 1497729594-4707-6-git-send-email-axboe@kernel.dk (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Sat, Jun 17, 2017 at 01:59:48PM -0600, Jens Axboe wrote: > 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> > --- > 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) The unsigned long arg is a little annoying because it will de different size for 32-bit vs 64-vit architectures. How about just doing a get_user and use a fixed-size 64-bit value?
On 06/19/2017 12:28 AM, Christoph Hellwig wrote: > On Sat, Jun 17, 2017 at 01:59:48PM -0600, Jens Axboe wrote: >> 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> >> --- >> 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) > > The unsigned long arg is a little annoying because it will de different > size for 32-bit vs 64-vit architectures. > > How about just doing a get_user and use a fixed-size 64-bit value? It's just passing it in from fcnt(), my intent was for it to be a u32 on the uapi side. But we can make it a 64-bit type, since we're going away from the enum and making it a proper type.
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 */
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> --- fs/fcntl.c | 38 ++++++++++++++++++++++++++++++++++++++ include/uapi/linux/fcntl.h | 6 ++++++ 2 files changed, 44 insertions(+)