summaryrefslogtreecommitdiffstats
path: root/fs/fcntl.c
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2017-06-27 13:47:04 -0400
committerJens Axboe <axboe@kernel.dk>2017-06-27 14:05:22 -0400
commitc75b1d9421f80f4143e389d2d50ddfc8a28c8c35 (patch)
tree6fe665d5e9f8cfab50b764d418e732617a5d5129 /fs/fcntl.c
parent12e9a6d62236dacb87a6b2dd84dd9c29bb5be1de (diff)
fs: add fcntl() interface for setting/getting write life time hints
Define a set of write life time hints: RWH_WRITE_LIFE_NOT_SET No hint information set RWH_WRITE_LIFE_NONE No hints about write life time RWH_WRITE_LIFE_SHORT Data written has a short life time RWH_WRITE_LIFE_MEDIUM Data written has a medium life time RWH_WRITE_LIFE_LONG Data written has a long life time RWH_WRITE_LIFE_EXTREME Data written has an extremely long life time The intent is for these values to be relative to each other, no absolute meaning should be attached to these flag names. 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 on the underlying inode. F_SET_RW_HINT Set one of the above write hints on the underlying inode. F_GET_FILE_RW_HINT Returns the read/write hint set on the file descriptor. F_SET_FILE_RW_HINT Set one of the above write hints on the file descriptor. The user passes in a 64-bit pointer to get/set these values, and the interface returns 0/-1 on success/error. Sample program testing/implementing basic setting/getting of write hints is below. Add support for storing the write life time hint in the inode flags and in struct file as well, and pass them to the kiocb flags. If both a file and its corresponding inode has a write hint, then we use the one in the file, if available. The file hint can be used for sync/direct IO, for buffered writeback only the inode hint is available. This is in preparation for utilizing these hints in the block layer, to guide on-media data placement. /* * writehint.c: get or set an inode write hint */ #include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <stdbool.h> #include <inttypes.h> #ifndef F_GET_RW_HINT #define F_LINUX_SPECIFIC_BASE 1024 #define F_GET_RW_HINT (F_LINUX_SPECIFIC_BASE + 11) #define F_SET_RW_HINT (F_LINUX_SPECIFIC_BASE + 12) #endif static char *str[] = { "RWF_WRITE_LIFE_NOT_SET", "RWH_WRITE_LIFE_NONE", "RWH_WRITE_LIFE_SHORT", "RWH_WRITE_LIFE_MEDIUM", "RWH_WRITE_LIFE_LONG", "RWH_WRITE_LIFE_EXTREME" }; int main(int argc, char *argv[]) { uint64_t hint; int fd, ret; if (argc < 2) { fprintf(stderr, "%s: file <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]); ret = fcntl(fd, F_SET_RW_HINT, &hint); if (ret < 0) { perror("fcntl: F_SET_RW_HINT"); return 4; } } ret = fcntl(fd, F_GET_RW_HINT, &hint); if (ret < 0) { perror("fcntl: F_GET_RW_HINT"); return 3; } printf("%s: hint %s\n", argv[1], str[hint]); close(fd); return 0; } Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r--fs/fcntl.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c
index f4e7267d117f..67bdc6e8ccad 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -243,6 +243,62 @@ static int f_getowner_uids(struct file *filp, unsigned long arg)
243} 243}
244#endif 244#endif
245 245
246static bool rw_hint_valid(enum rw_hint hint)
247{
248 switch (hint) {
249 case RWF_WRITE_LIFE_NOT_SET:
250 case RWH_WRITE_LIFE_NONE:
251 case RWH_WRITE_LIFE_SHORT:
252 case RWH_WRITE_LIFE_MEDIUM:
253 case RWH_WRITE_LIFE_LONG:
254 case RWH_WRITE_LIFE_EXTREME:
255 return true;
256 default:
257 return false;
258 }
259}
260
261static long fcntl_rw_hint(struct file *file, unsigned int cmd,
262 unsigned long arg)
263{
264 struct inode *inode = file_inode(file);
265 u64 *argp = (u64 __user *)arg;
266 enum rw_hint hint;
267
268 switch (cmd) {
269 case F_GET_FILE_RW_HINT:
270 if (put_user(file_write_hint(file), argp))
271 return -EFAULT;
272 return 0;
273 case F_SET_FILE_RW_HINT:
274 if (get_user(hint, argp))
275 return -EFAULT;
276 if (!rw_hint_valid(hint))
277 return -EINVAL;
278
279 spin_lock(&file->f_lock);
280 file->f_write_hint = hint;
281 spin_unlock(&file->f_lock);
282 return 0;
283 case F_GET_RW_HINT:
284 if (put_user(inode->i_write_hint, argp))
285 return -EFAULT;
286 return 0;
287 case F_SET_RW_HINT:
288 if (get_user(hint, argp))
289 return -EFAULT;
290 if (!rw_hint_valid(hint))
291 return -EINVAL;
292
293 inode_lock(inode);
294 inode->i_write_hint = hint;
295 inode_unlock(inode);
296 return 0;
297 default:
298 return -EINVAL;
299 }
300}
301
246static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, 302static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
247 struct file *filp) 303 struct file *filp)
248{ 304{
@@ -337,6 +393,12 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
337 case F_GET_SEALS: 393 case F_GET_SEALS:
338 err = shmem_fcntl(filp, cmd, arg); 394 err = shmem_fcntl(filp, cmd, arg);
339 break; 395 break;
396 case F_GET_RW_HINT:
397 case F_SET_RW_HINT:
398 case F_GET_FILE_RW_HINT:
399 case F_SET_FILE_RW_HINT:
400 err = fcntl_rw_hint(filp, cmd, arg);
401 break;
340 default: 402 default:
341 break; 403 break;
342 } 404 }