]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/f2fs/namei.c
Merge tag 'tag-chrome-platform-for-v5.6' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / fs / f2fs / namei.c
index a1c507b0b4ac4b293b4e086675b2a3669f76d177..2aa035422c0fac63a51e60d1a5dce93a37482dc6 100644 (file)
@@ -119,6 +119,13 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
        if (F2FS_I(inode)->i_flags & F2FS_PROJINHERIT_FL)
                set_inode_flag(inode, FI_PROJ_INHERIT);
 
+       if (f2fs_sb_has_compression(sbi)) {
+               /* Inherit the compression flag in directory */
+               if ((F2FS_I(dir)->i_flags & F2FS_COMPR_FL) &&
+                                       f2fs_may_compress(inode))
+                       set_compress_context(inode);
+       }
+
        f2fs_set_inode_flags(inode);
 
        trace_f2fs_new_inode(inode, 0);
@@ -149,6 +156,9 @@ static inline int is_extension_exist(const unsigned char *s, const char *sub)
        size_t sublen = strlen(sub);
        int i;
 
+       if (sublen == 1 && *sub == '*')
+               return 1;
+
        /*
         * filename format of multimedia file should be defined as:
         * "filename + '.' + extension + (optional: '.' + temp extension)".
@@ -262,6 +272,45 @@ int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name,
        return 0;
 }
 
+static void set_compress_inode(struct f2fs_sb_info *sbi, struct inode *inode,
+                                               const unsigned char *name)
+{
+       __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
+       unsigned char (*ext)[F2FS_EXTENSION_LEN];
+       unsigned int ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
+       int i, cold_count, hot_count;
+
+       if (!f2fs_sb_has_compression(sbi) ||
+                       is_inode_flag_set(inode, FI_COMPRESSED_FILE) ||
+                       F2FS_I(inode)->i_flags & F2FS_NOCOMP_FL ||
+                       !f2fs_may_compress(inode))
+               return;
+
+       down_read(&sbi->sb_lock);
+
+       cold_count = le32_to_cpu(sbi->raw_super->extension_count);
+       hot_count = sbi->raw_super->hot_ext_count;
+
+       for (i = cold_count; i < cold_count + hot_count; i++) {
+               if (is_extension_exist(name, extlist[i])) {
+                       up_read(&sbi->sb_lock);
+                       return;
+               }
+       }
+
+       up_read(&sbi->sb_lock);
+
+       ext = F2FS_OPTION(sbi).extensions;
+
+       for (i = 0; i < ext_cnt; i++) {
+               if (!is_extension_exist(name, ext[i]))
+                       continue;
+
+               set_compress_context(inode);
+               return;
+       }
+}
+
 static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                                                bool excl)
 {
@@ -286,6 +335,8 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        if (!test_opt(sbi, DISABLE_EXT_IDENTIFY))
                set_file_temperature(sbi, inode, dentry->d_name.name);
 
+       set_compress_inode(sbi, inode, dentry->d_name.name);
+
        inode->i_op = &f2fs_file_inode_operations;
        inode->i_fop = &f2fs_file_operations;
        inode->i_mapping->a_ops = &f2fs_dblock_aops;
@@ -797,6 +848,7 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
 
        if (whiteout) {
                f2fs_i_links_write(inode, false);
+               inode->i_state |= I_LINKABLE;
                *whiteout = inode;
        } else {
                d_tmpfile(dentry, inode);
@@ -849,12 +901,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct inode *old_inode = d_inode(old_dentry);
        struct inode *new_inode = d_inode(new_dentry);
        struct inode *whiteout = NULL;
-       struct page *old_dir_page;
+       struct page *old_dir_page = NULL;
        struct page *old_page, *new_page = NULL;
        struct f2fs_dir_entry *old_dir_entry = NULL;
        struct f2fs_dir_entry *old_entry;
        struct f2fs_dir_entry *new_entry;
-       bool is_old_inline = f2fs_has_inline_dentry(old_dir);
        int err;
 
        if (unlikely(f2fs_cp_error(sbi)))
@@ -867,6 +918,26 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        F2FS_I(old_dentry->d_inode)->i_projid)))
                return -EXDEV;
 
+       /*
+        * If new_inode is null, the below renaming flow will
+        * add a link in old_dir which can conver inline_dir.
+        * After then, if we failed to get the entry due to other
+        * reasons like ENOMEM, we had to remove the new entry.
+        * Instead of adding such the error handling routine, let's
+        * simply convert first here.
+        */
+       if (old_dir == new_dir && !new_inode) {
+               err = f2fs_try_convert_inline_dir(old_dir, new_dentry);
+               if (err)
+                       return err;
+       }
+
+       if (flags & RENAME_WHITEOUT) {
+               err = f2fs_create_whiteout(old_dir, &whiteout);
+               if (err)
+                       return err;
+       }
+
        err = dquot_initialize(old_dir);
        if (err)
                goto out;
@@ -898,17 +969,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                }
        }
 
-       if (flags & RENAME_WHITEOUT) {
-               err = f2fs_create_whiteout(old_dir, &whiteout);
-               if (err)
-                       goto out_dir;
-       }
-
        if (new_inode) {
 
                err = -ENOTEMPTY;
                if (old_dir_entry && !f2fs_empty_dir(new_inode))
-                       goto out_whiteout;
+                       goto out_dir;
 
                err = -ENOENT;
                new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,
@@ -916,7 +981,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (!new_entry) {
                        if (IS_ERR(new_page))
                                err = PTR_ERR(new_page);
-                       goto out_whiteout;
+                       goto out_dir;
                }
 
                f2fs_balance_fs(sbi, true);
@@ -928,6 +993,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        goto put_out_dir;
 
                f2fs_set_link(new_dir, new_entry, new_page, old_inode);
+               new_page = NULL;
 
                new_inode->i_ctime = current_time(new_inode);
                down_write(&F2FS_I(new_inode)->i_sem);
@@ -948,33 +1014,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                err = f2fs_add_link(new_dentry, old_inode);
                if (err) {
                        f2fs_unlock_op(sbi);
-                       goto out_whiteout;
+                       goto out_dir;
                }
 
                if (old_dir_entry)
                        f2fs_i_links_write(new_dir, true);
-
-               /*
-                * old entry and new entry can locate in the same inline
-                * dentry in inode, when attaching new entry in inline dentry,
-                * it could force inline dentry conversion, after that,
-                * old_entry and old_page will point to wrong address, in
-                * order to avoid this, let's do the check and update here.
-                */
-               if (is_old_inline && !f2fs_has_inline_dentry(old_dir)) {
-                       f2fs_put_page(old_page, 0);
-                       old_page = NULL;
-
-                       old_entry = f2fs_find_entry(old_dir,
-                                               &old_dentry->d_name, &old_page);
-                       if (!old_entry) {
-                               err = -ENOENT;
-                               if (IS_ERR(old_page))
-                                       err = PTR_ERR(old_page);
-                               f2fs_unlock_op(sbi);
-                               goto out_whiteout;
-                       }
-               }
        }
 
        down_write(&F2FS_I(old_inode)->i_sem);
@@ -989,9 +1033,9 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
        f2fs_mark_inode_dirty_sync(old_inode, false);
 
        f2fs_delete_entry(old_entry, old_page, old_dir, NULL);
+       old_page = NULL;
 
        if (whiteout) {
-               whiteout->i_state |= I_LINKABLE;
                set_inode_flag(whiteout, FI_INC_LINK);
                err = f2fs_add_link(old_dentry, whiteout);
                if (err)
@@ -1025,17 +1069,15 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 put_out_dir:
        f2fs_unlock_op(sbi);
-       if (new_page)
-               f2fs_put_page(new_page, 0);
-out_whiteout:
-       if (whiteout)
-               iput(whiteout);
+       f2fs_put_page(new_page, 0);
 out_dir:
        if (old_dir_entry)
                f2fs_put_page(old_dir_page, 0);
 out_old:
        f2fs_put_page(old_page, 0);
 out:
+       if (whiteout)
+               iput(whiteout);
        return err;
 }