}
 #endif
 
+static bool rw_hint_valid(enum rw_hint hint)
+{
+       switch (hint) {
+       case RWF_WRITE_LIFE_NOT_SET:
+       case RWH_WRITE_LIFE_NONE:
+       case RWH_WRITE_LIFE_SHORT:
+       case RWH_WRITE_LIFE_MEDIUM:
+       case RWH_WRITE_LIFE_LONG:
+       case RWH_WRITE_LIFE_EXTREME:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static long fcntl_rw_hint(struct file *file, unsigned int cmd,
+                         unsigned long arg)
+{
+       struct inode *inode = file_inode(file);
+       u64 *argp = (u64 __user *)arg;
+       enum rw_hint hint;
+
+       switch (cmd) {
+       case F_GET_FILE_RW_HINT:
+               if (put_user(file_write_hint(file), argp))
+                       return -EFAULT;
+               return 0;
+       case F_SET_FILE_RW_HINT:
+               if (get_user(hint, argp))
+                       return -EFAULT;
+               if (!rw_hint_valid(hint))
+                       return -EINVAL;
+
+               spin_lock(&file->f_lock);
+               file->f_write_hint = hint;
+               spin_unlock(&file->f_lock);
+               return 0;
+       case F_GET_RW_HINT:
+               if (put_user(inode->i_write_hint, argp))
+                       return -EFAULT;
+               return 0;
+       case F_SET_RW_HINT:
+               if (get_user(hint, argp))
+                       return -EFAULT;
+               if (!rw_hint_valid(hint))
+                       return -EINVAL;
+
+               inode_lock(inode);
+               inode->i_write_hint = hint;
+               inode_unlock(inode);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
                struct file *filp)
 {
        case F_GET_SEALS:
                err = shmem_fcntl(filp, cmd, arg);
                break;
+       case F_GET_RW_HINT:
+       case F_SET_RW_HINT:
+       case F_GET_FILE_RW_HINT:
+       case F_SET_FILE_RW_HINT:
+               err = fcntl_rw_hint(filp, cmd, arg);
+               break;
        default:
                break;
        }
 
        i_gid_write(inode, 0);
        atomic_set(&inode->i_writecount, 0);
        inode->i_size = 0;
+       inode->i_write_hint = WRITE_LIFE_NOT_SET;
        inode->i_blocks = 0;
        inode->i_bytes = 0;
        inode->i_generation = 0;
 
             likely(f->f_op->write || f->f_op->write_iter))
                f->f_mode |= FMODE_CAN_WRITE;
 
+       f->f_write_hint = WRITE_LIFE_NOT_SET;
        f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 
        file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
 
 #include <linux/rwsem.h>
 #include <linux/capability.h>
 #include <linux/semaphore.h>
+#include <linux/fcntl.h>
 #include <linux/fiemap.h>
 #include <linux/rculist_bl.h>
 #include <linux/atomic.h>
 struct address_space;
 struct writeback_control;
 
+/*
+ * Write life time hint values.
+ */
+enum rw_hint {
+       WRITE_LIFE_NOT_SET      = 0,
+       WRITE_LIFE_NONE         = RWH_WRITE_LIFE_NONE,
+       WRITE_LIFE_SHORT        = RWH_WRITE_LIFE_SHORT,
+       WRITE_LIFE_MEDIUM       = RWH_WRITE_LIFE_MEDIUM,
+       WRITE_LIFE_LONG         = RWH_WRITE_LIFE_LONG,
+       WRITE_LIFE_EXTREME      = RWH_WRITE_LIFE_EXTREME,
+};
+
 #define IOCB_EVENTFD           (1 << 0)
 #define IOCB_APPEND            (1 << 1)
 #define IOCB_DIRECT            (1 << 2)
        void (*ki_complete)(struct kiocb *iocb, long ret, long ret2);
        void                    *private;
        int                     ki_flags;
+       enum rw_hint            ki_hint;
 };
 
 static inline bool is_sync_kiocb(struct kiocb *kiocb)
        return kiocb->ki_complete == NULL;
 }
 
-static inline int iocb_flags(struct file *file);
-
-static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp)
-{
-       *kiocb = (struct kiocb) {
-               .ki_filp = filp,
-               .ki_flags = iocb_flags(filp),
-       };
-}
-
 /*
  * "descriptor" for what we're up to with a read.
  * This allows us to use the same read code yet
        spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
        unsigned short          i_bytes;
        unsigned int            i_blkbits;
+       enum rw_hint            i_write_hint;
        blkcnt_t                i_blocks;
 
 #ifdef __NEED_I_SIZE_ORDERED
         * Must not be taken from IRQ context.
         */
        spinlock_t              f_lock;
+       enum rw_hint            f_write_hint;
        atomic_long_t           f_count;
        unsigned int            f_flags;
        fmode_t                 f_mode;
 #define OFFT_OFFSET_MAX        INT_LIMIT(off_t)
 #endif
 
-#include <linux/fcntl.h>
-
 extern void send_sigio(struct fown_struct *fown, int fd, int band);
 
 /*
        return !uid_valid(inode->i_uid) || !gid_valid(inode->i_gid);
 }
 
+static inline enum rw_hint file_write_hint(struct file *file)
+{
+       if (file->f_write_hint != WRITE_LIFE_NOT_SET)
+               return file->f_write_hint;
+
+       return file_inode(file)->i_write_hint;
+}
+
+static inline int iocb_flags(struct file *file);
+
+static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp)
+{
+       *kiocb = (struct kiocb) {
+               .ki_filp = filp,
+               .ki_flags = iocb_flags(filp),
+               .ki_hint = file_write_hint(filp),
+       };
+}
+
 /*
  * Inode state bits.  Protected by inode->i_lock
  *
 
 #define F_SEAL_WRITE   0x0008  /* prevent writes */
 /* (1U << 31) is reserved for signed error codes */
 
+/*
+ * Set/Get write life time hints. {GET,SET}_RW_HINT operate on the
+ * underlying inode, while {GET,SET}_FILE_RW_HINT operate only on
+ * the specific file.
+ */
+#define F_GET_RW_HINT          (F_LINUX_SPECIFIC_BASE + 11)
+#define F_SET_RW_HINT          (F_LINUX_SPECIFIC_BASE + 12)
+#define F_GET_FILE_RW_HINT     (F_LINUX_SPECIFIC_BASE + 13)
+#define F_SET_FILE_RW_HINT     (F_LINUX_SPECIFIC_BASE + 14)
+
+/*
+ * Valid hint values for F_{GET,SET}_RW_HINT. 0 is "not set", or can be
+ * used to clear any hints previously set.
+ */
+#define RWF_WRITE_LIFE_NOT_SET 0
+#define RWH_WRITE_LIFE_NONE    1
+#define RWH_WRITE_LIFE_SHORT   2
+#define RWH_WRITE_LIFE_MEDIUM  3
+#define RWH_WRITE_LIFE_LONG    4
+#define RWH_WRITE_LIFE_EXTREME 5
+
 /*
  * Types of directory notifications that may be requested.
  */