diff options
Diffstat (limited to 'fs/ext4/namei.c')
| -rw-r--r-- | fs/ext4/namei.c | 480 |
1 files changed, 349 insertions, 131 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index d050e043e884..1cb84f78909e 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
| @@ -3000,6 +3000,154 @@ static struct buffer_head *ext4_get_first_dir_block(handle_t *handle, | |||
| 3000 | return ext4_get_first_inline_block(inode, parent_de, retval); | 3000 | return ext4_get_first_inline_block(inode, parent_de, retval); |
| 3001 | } | 3001 | } |
| 3002 | 3002 | ||
| 3003 | struct ext4_renament { | ||
| 3004 | struct inode *dir; | ||
| 3005 | struct dentry *dentry; | ||
| 3006 | struct inode *inode; | ||
| 3007 | bool is_dir; | ||
| 3008 | int dir_nlink_delta; | ||
| 3009 | |||
| 3010 | /* entry for "dentry" */ | ||
| 3011 | struct buffer_head *bh; | ||
| 3012 | struct ext4_dir_entry_2 *de; | ||
| 3013 | int inlined; | ||
| 3014 | |||
| 3015 | /* entry for ".." in inode if it's a directory */ | ||
| 3016 | struct buffer_head *dir_bh; | ||
| 3017 | struct ext4_dir_entry_2 *parent_de; | ||
| 3018 | int dir_inlined; | ||
| 3019 | }; | ||
| 3020 | |||
| 3021 | static int ext4_rename_dir_prepare(handle_t *handle, struct ext4_renament *ent) | ||
| 3022 | { | ||
| 3023 | int retval; | ||
| 3024 | |||
| 3025 | ent->dir_bh = ext4_get_first_dir_block(handle, ent->inode, | ||
| 3026 | &retval, &ent->parent_de, | ||
| 3027 | &ent->dir_inlined); | ||
| 3028 | if (!ent->dir_bh) | ||
| 3029 | return retval; | ||
| 3030 | if (le32_to_cpu(ent->parent_de->inode) != ent->dir->i_ino) | ||
| 3031 | return -EIO; | ||
| 3032 | BUFFER_TRACE(ent->dir_bh, "get_write_access"); | ||
| 3033 | return ext4_journal_get_write_access(handle, ent->dir_bh); | ||
| 3034 | } | ||
| 3035 | |||
| 3036 | static int ext4_rename_dir_finish(handle_t *handle, struct ext4_renament *ent, | ||
| 3037 | unsigned dir_ino) | ||
| 3038 | { | ||
| 3039 | int retval; | ||
| 3040 | |||
| 3041 | ent->parent_de->inode = cpu_to_le32(dir_ino); | ||
| 3042 | BUFFER_TRACE(ent->dir_bh, "call ext4_handle_dirty_metadata"); | ||
| 3043 | if (!ent->dir_inlined) { | ||
| 3044 | if (is_dx(ent->inode)) { | ||
| 3045 | retval = ext4_handle_dirty_dx_node(handle, | ||
| 3046 | ent->inode, | ||
| 3047 | ent->dir_bh); | ||
| 3048 | } else { | ||
| 3049 | retval = ext4_handle_dirty_dirent_node(handle, | ||
| 3050 | ent->inode, | ||
| 3051 | ent->dir_bh); | ||
| 3052 | } | ||
| 3053 | } else { | ||
| 3054 | retval = ext4_mark_inode_dirty(handle, ent->inode); | ||
| 3055 | } | ||
| 3056 | if (retval) { | ||
| 3057 | ext4_std_error(ent->dir->i_sb, retval); | ||
| 3058 | return retval; | ||
| 3059 | } | ||
| 3060 | return 0; | ||
| 3061 | } | ||
| 3062 | |||
| 3063 | static int ext4_setent(handle_t *handle, struct ext4_renament *ent, | ||
| 3064 | unsigned ino, unsigned file_type) | ||
| 3065 | { | ||
| 3066 | int retval; | ||
| 3067 | |||
| 3068 | BUFFER_TRACE(ent->bh, "get write access"); | ||
| 3069 | retval = ext4_journal_get_write_access(handle, ent->bh); | ||
| 3070 | if (retval) | ||
| 3071 | return retval; | ||
| 3072 | ent->de->inode = cpu_to_le32(ino); | ||
| 3073 | if (EXT4_HAS_INCOMPAT_FEATURE(ent->dir->i_sb, | ||
| 3074 | EXT4_FEATURE_INCOMPAT_FILETYPE)) | ||
| 3075 | ent->de->file_type = file_type; | ||
| 3076 | ent->dir->i_version++; | ||
| 3077 | ent->dir->i_ctime = ent->dir->i_mtime = | ||
| 3078 | ext4_current_time(ent->dir); | ||
| 3079 | ext4_mark_inode_dirty(handle, ent->dir); | ||
| 3080 | BUFFER_TRACE(ent->bh, "call ext4_handle_dirty_metadata"); | ||
| 3081 | if (!ent->inlined) { | ||
| 3082 | retval = ext4_handle_dirty_dirent_node(handle, | ||
| 3083 | ent->dir, ent->bh); | ||
| 3084 | if (unlikely(retval)) { | ||
| 3085 | ext4_std_error(ent->dir->i_sb, retval); | ||
| 3086 | return retval; | ||
| 3087 | } | ||
| 3088 | } | ||
| 3089 | brelse(ent->bh); | ||
| 3090 | ent->bh = NULL; | ||
| 3091 | |||
| 3092 | return 0; | ||
| 3093 | } | ||
| 3094 | |||
| 3095 | static int ext4_find_delete_entry(handle_t *handle, struct inode *dir, | ||
| 3096 | const struct qstr *d_name) | ||
| 3097 | { | ||
| 3098 | int retval = -ENOENT; | ||
| 3099 | struct buffer_head *bh; | ||
| 3100 | struct ext4_dir_entry_2 *de; | ||
| 3101 | |||
| 3102 | bh = ext4_find_entry(dir, d_name, &de, NULL); | ||
| 3103 | if (bh) { | ||
| 3104 | retval = ext4_delete_entry(handle, dir, de, bh); | ||
| 3105 | brelse(bh); | ||
| 3106 | } | ||
| 3107 | return retval; | ||
| 3108 | } | ||
| 3109 | |||
| 3110 | static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent) | ||
| 3111 | { | ||
| 3112 | int retval; | ||
| 3113 | /* | ||
| 3114 | * ent->de could have moved from under us during htree split, so make | ||
| 3115 | * sure that we are deleting the right entry. We might also be pointing | ||
| 3116 | * to a stale entry in the unused part of ent->bh so just checking inum | ||
| 3117 | * and the name isn't enough. | ||
| 3118 | */ | ||
| 3119 | if (le32_to_cpu(ent->de->inode) != ent->inode->i_ino || | ||
| 3120 | ent->de->name_len != ent->dentry->d_name.len || | ||
| 3121 | strncmp(ent->de->name, ent->dentry->d_name.name, | ||
| 3122 | ent->de->name_len)) { | ||
| 3123 | retval = ext4_find_delete_entry(handle, ent->dir, | ||
| 3124 | &ent->dentry->d_name); | ||
| 3125 | } else { | ||
| 3126 | retval = ext4_delete_entry(handle, ent->dir, ent->de, ent->bh); | ||
| 3127 | if (retval == -ENOENT) { | ||
| 3128 | retval = ext4_find_delete_entry(handle, ent->dir, | ||
| 3129 | &ent->dentry->d_name); | ||
| 3130 | } | ||
| 3131 | } | ||
| 3132 | |||
| 3133 | if (retval) { | ||
| 3134 | ext4_warning(ent->dir->i_sb, | ||
| 3135 | "Deleting old file (%lu), %d, error=%d", | ||
| 3136 | ent->dir->i_ino, ent->dir->i_nlink, retval); | ||
| 3137 | } | ||
| 3138 | } | ||
| 3139 | |||
| 3140 | static void ext4_update_dir_count(handle_t *handle, struct ext4_renament *ent) | ||
| 3141 | { | ||
| 3142 | if (ent->dir_nlink_delta) { | ||
| 3143 | if (ent->dir_nlink_delta == -1) | ||
| 3144 | ext4_dec_count(handle, ent->dir); | ||
| 3145 | else | ||
| 3146 | ext4_inc_count(handle, ent->dir); | ||
| 3147 | ext4_mark_inode_dirty(handle, ent->dir); | ||
| 3148 | } | ||
| 3149 | } | ||
| 3150 | |||
| 3003 | /* | 3151 | /* |
| 3004 | * Anybody can rename anything with this: the permission checks are left to the | 3152 | * Anybody can rename anything with this: the permission checks are left to the |
| 3005 | * higher-level routines. | 3153 | * higher-level routines. |
| @@ -3012,198 +3160,267 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 3012 | struct inode *new_dir, struct dentry *new_dentry) | 3160 | struct inode *new_dir, struct dentry *new_dentry) |
| 3013 | { | 3161 | { |
| 3014 | handle_t *handle = NULL; | 3162 | handle_t *handle = NULL; |
| 3015 | struct inode *old_inode, *new_inode; | 3163 | struct ext4_renament old = { |
| 3016 | struct buffer_head *old_bh, *new_bh, *dir_bh; | 3164 | .dir = old_dir, |
| 3017 | struct ext4_dir_entry_2 *old_de, *new_de; | 3165 | .dentry = old_dentry, |
| 3166 | .inode = old_dentry->d_inode, | ||
| 3167 | }; | ||
| 3168 | struct ext4_renament new = { | ||
| 3169 | .dir = new_dir, | ||
| 3170 | .dentry = new_dentry, | ||
| 3171 | .inode = new_dentry->d_inode, | ||
| 3172 | }; | ||
| 3018 | int retval; | 3173 | int retval; |
| 3019 | int inlined = 0, new_inlined = 0; | ||
| 3020 | struct ext4_dir_entry_2 *parent_de; | ||
| 3021 | 3174 | ||
| 3022 | dquot_initialize(old_dir); | 3175 | dquot_initialize(old.dir); |
| 3023 | dquot_initialize(new_dir); | 3176 | dquot_initialize(new.dir); |
| 3024 | |||
| 3025 | old_bh = new_bh = dir_bh = NULL; | ||
| 3026 | 3177 | ||
| 3027 | /* Initialize quotas before so that eventual writes go | 3178 | /* Initialize quotas before so that eventual writes go |
| 3028 | * in separate transaction */ | 3179 | * in separate transaction */ |
| 3029 | if (new_dentry->d_inode) | 3180 | if (new.inode) |
| 3030 | dquot_initialize(new_dentry->d_inode); | 3181 | dquot_initialize(new.inode); |
| 3031 | 3182 | ||
| 3032 | old_bh = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de, NULL); | 3183 | old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL); |
| 3033 | /* | 3184 | /* |
| 3034 | * Check for inode number is _not_ due to possible IO errors. | 3185 | * Check for inode number is _not_ due to possible IO errors. |
| 3035 | * We might rmdir the source, keep it as pwd of some process | 3186 | * We might rmdir the source, keep it as pwd of some process |
| 3036 | * and merrily kill the link to whatever was created under the | 3187 | * and merrily kill the link to whatever was created under the |
| 3037 | * same name. Goodbye sticky bit ;-< | 3188 | * same name. Goodbye sticky bit ;-< |
| 3038 | */ | 3189 | */ |
| 3039 | old_inode = old_dentry->d_inode; | ||
| 3040 | retval = -ENOENT; | 3190 | retval = -ENOENT; |
| 3041 | if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino) | 3191 | if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino) |
| 3042 | goto end_rename; | 3192 | goto end_rename; |
| 3043 | 3193 | ||
| 3044 | new_inode = new_dentry->d_inode; | 3194 | new.bh = ext4_find_entry(new.dir, &new.dentry->d_name, |
| 3045 | new_bh = ext4_find_entry(new_dir, &new_dentry->d_name, | 3195 | &new.de, &new.inlined); |
| 3046 | &new_de, &new_inlined); | 3196 | if (new.bh) { |
| 3047 | if (new_bh) { | 3197 | if (!new.inode) { |
| 3048 | if (!new_inode) { | 3198 | brelse(new.bh); |
| 3049 | brelse(new_bh); | 3199 | new.bh = NULL; |
| 3050 | new_bh = NULL; | ||
| 3051 | } | 3200 | } |
| 3052 | } | 3201 | } |
| 3053 | if (new_inode && !test_opt(new_dir->i_sb, NO_AUTO_DA_ALLOC)) | 3202 | if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC)) |
| 3054 | ext4_alloc_da_blocks(old_inode); | 3203 | ext4_alloc_da_blocks(old.inode); |
| 3055 | 3204 | ||
| 3056 | handle = ext4_journal_start(old_dir, EXT4_HT_DIR, | 3205 | handle = ext4_journal_start(old.dir, EXT4_HT_DIR, |
| 3057 | (2 * EXT4_DATA_TRANS_BLOCKS(old_dir->i_sb) + | 3206 | (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) + |
| 3058 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2)); | 3207 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2)); |
| 3059 | if (IS_ERR(handle)) | 3208 | if (IS_ERR(handle)) |
| 3060 | return PTR_ERR(handle); | 3209 | return PTR_ERR(handle); |
| 3061 | 3210 | ||
| 3062 | if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) | 3211 | if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) |
| 3063 | ext4_handle_sync(handle); | 3212 | ext4_handle_sync(handle); |
| 3064 | 3213 | ||
| 3065 | if (S_ISDIR(old_inode->i_mode)) { | 3214 | if (S_ISDIR(old.inode->i_mode)) { |
| 3066 | if (new_inode) { | 3215 | if (new.inode) { |
| 3067 | retval = -ENOTEMPTY; | 3216 | retval = -ENOTEMPTY; |
| 3068 | if (!empty_dir(new_inode)) | 3217 | if (!empty_dir(new.inode)) |
| 3218 | goto end_rename; | ||
| 3219 | } else { | ||
| 3220 | retval = -EMLINK; | ||
| 3221 | if (new.dir != old.dir && EXT4_DIR_LINK_MAX(new.dir)) | ||
| 3069 | goto end_rename; | 3222 | goto end_rename; |
| 3070 | } | 3223 | } |
| 3071 | retval = -EIO; | 3224 | retval = ext4_rename_dir_prepare(handle, &old); |
| 3072 | dir_bh = ext4_get_first_dir_block(handle, old_inode, | ||
| 3073 | &retval, &parent_de, | ||
| 3074 | &inlined); | ||
| 3075 | if (!dir_bh) | ||
| 3076 | goto end_rename; | ||
| 3077 | if (le32_to_cpu(parent_de->inode) != old_dir->i_ino) | ||
| 3078 | goto end_rename; | ||
| 3079 | retval = -EMLINK; | ||
| 3080 | if (!new_inode && new_dir != old_dir && | ||
| 3081 | EXT4_DIR_LINK_MAX(new_dir)) | ||
| 3082 | goto end_rename; | ||
| 3083 | BUFFER_TRACE(dir_bh, "get_write_access"); | ||
| 3084 | retval = ext4_journal_get_write_access(handle, dir_bh); | ||
| 3085 | if (retval) | 3225 | if (retval) |
| 3086 | goto end_rename; | 3226 | goto end_rename; |
| 3087 | } | 3227 | } |
| 3088 | if (!new_bh) { | 3228 | if (!new.bh) { |
| 3089 | retval = ext4_add_entry(handle, new_dentry, old_inode); | 3229 | retval = ext4_add_entry(handle, new.dentry, old.inode); |
| 3090 | if (retval) | 3230 | if (retval) |
| 3091 | goto end_rename; | 3231 | goto end_rename; |
| 3092 | } else { | 3232 | } else { |
| 3093 | BUFFER_TRACE(new_bh, "get write access"); | 3233 | retval = ext4_setent(handle, &new, |
| 3094 | retval = ext4_journal_get_write_access(handle, new_bh); | 3234 | old.inode->i_ino, old.de->file_type); |
| 3095 | if (retval) | 3235 | if (retval) |
| 3096 | goto end_rename; | 3236 | goto end_rename; |
| 3097 | new_de->inode = cpu_to_le32(old_inode->i_ino); | ||
| 3098 | if (EXT4_HAS_INCOMPAT_FEATURE(new_dir->i_sb, | ||
| 3099 | EXT4_FEATURE_INCOMPAT_FILETYPE)) | ||
| 3100 | new_de->file_type = old_de->file_type; | ||
| 3101 | new_dir->i_version++; | ||
| 3102 | new_dir->i_ctime = new_dir->i_mtime = | ||
| 3103 | ext4_current_time(new_dir); | ||
| 3104 | ext4_mark_inode_dirty(handle, new_dir); | ||
| 3105 | BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata"); | ||
| 3106 | if (!new_inlined) { | ||
| 3107 | retval = ext4_handle_dirty_dirent_node(handle, | ||
| 3108 | new_dir, new_bh); | ||
| 3109 | if (unlikely(retval)) { | ||
| 3110 | ext4_std_error(new_dir->i_sb, retval); | ||
| 3111 | goto end_rename; | ||
| 3112 | } | ||
| 3113 | } | ||
| 3114 | brelse(new_bh); | ||
| 3115 | new_bh = NULL; | ||
| 3116 | } | 3237 | } |
| 3117 | 3238 | ||
| 3118 | /* | 3239 | /* |
| 3119 | * Like most other Unix systems, set the ctime for inodes on a | 3240 | * Like most other Unix systems, set the ctime for inodes on a |
| 3120 | * rename. | 3241 | * rename. |
| 3121 | */ | 3242 | */ |
| 3122 | old_inode->i_ctime = ext4_current_time(old_inode); | 3243 | old.inode->i_ctime = ext4_current_time(old.inode); |
| 3123 | ext4_mark_inode_dirty(handle, old_inode); | 3244 | ext4_mark_inode_dirty(handle, old.inode); |
| 3124 | 3245 | ||
| 3125 | /* | 3246 | /* |
| 3126 | * ok, that's it | 3247 | * ok, that's it |
| 3127 | */ | 3248 | */ |
| 3128 | if (le32_to_cpu(old_de->inode) != old_inode->i_ino || | 3249 | ext4_rename_delete(handle, &old); |
| 3129 | old_de->name_len != old_dentry->d_name.len || | 3250 | |
| 3130 | strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) || | 3251 | if (new.inode) { |
| 3131 | (retval = ext4_delete_entry(handle, old_dir, | 3252 | ext4_dec_count(handle, new.inode); |
| 3132 | old_de, old_bh)) == -ENOENT) { | 3253 | new.inode->i_ctime = ext4_current_time(new.inode); |
| 3133 | /* old_de could have moved from under us during htree split, so | ||
| 3134 | * make sure that we are deleting the right entry. We might | ||
| 3135 | * also be pointing to a stale entry in the unused part of | ||
| 3136 | * old_bh so just checking inum and the name isn't enough. */ | ||
| 3137 | struct buffer_head *old_bh2; | ||
| 3138 | struct ext4_dir_entry_2 *old_de2; | ||
| 3139 | |||
| 3140 | old_bh2 = ext4_find_entry(old_dir, &old_dentry->d_name, | ||
| 3141 | &old_de2, NULL); | ||
| 3142 | if (old_bh2) { | ||
| 3143 | retval = ext4_delete_entry(handle, old_dir, | ||
| 3144 | old_de2, old_bh2); | ||
| 3145 | brelse(old_bh2); | ||
| 3146 | } | ||
| 3147 | } | 3254 | } |
| 3148 | if (retval) { | 3255 | old.dir->i_ctime = old.dir->i_mtime = ext4_current_time(old.dir); |
| 3149 | ext4_warning(old_dir->i_sb, | 3256 | ext4_update_dx_flag(old.dir); |
| 3150 | "Deleting old file (%lu), %d, error=%d", | 3257 | if (old.dir_bh) { |
| 3151 | old_dir->i_ino, old_dir->i_nlink, retval); | 3258 | retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino); |
| 3152 | } | 3259 | if (retval) |
| 3153 | |||
| 3154 | if (new_inode) { | ||
| 3155 | ext4_dec_count(handle, new_inode); | ||
| 3156 | new_inode->i_ctime = ext4_current_time(new_inode); | ||
| 3157 | } | ||
| 3158 | old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir); | ||
| 3159 | ext4_update_dx_flag(old_dir); | ||
| 3160 | if (dir_bh) { | ||
| 3161 | parent_de->inode = cpu_to_le32(new_dir->i_ino); | ||
| 3162 | BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); | ||
| 3163 | if (!inlined) { | ||
| 3164 | if (is_dx(old_inode)) { | ||
| 3165 | retval = ext4_handle_dirty_dx_node(handle, | ||
| 3166 | old_inode, | ||
| 3167 | dir_bh); | ||
| 3168 | } else { | ||
| 3169 | retval = ext4_handle_dirty_dirent_node(handle, | ||
| 3170 | old_inode, dir_bh); | ||
| 3171 | } | ||
| 3172 | } else { | ||
| 3173 | retval = ext4_mark_inode_dirty(handle, old_inode); | ||
| 3174 | } | ||
| 3175 | if (retval) { | ||
| 3176 | ext4_std_error(old_dir->i_sb, retval); | ||
| 3177 | goto end_rename; | 3260 | goto end_rename; |
| 3178 | } | 3261 | |
| 3179 | ext4_dec_count(handle, old_dir); | 3262 | ext4_dec_count(handle, old.dir); |
| 3180 | if (new_inode) { | 3263 | if (new.inode) { |
| 3181 | /* checked empty_dir above, can't have another parent, | 3264 | /* checked empty_dir above, can't have another parent, |
| 3182 | * ext4_dec_count() won't work for many-linked dirs */ | 3265 | * ext4_dec_count() won't work for many-linked dirs */ |
| 3183 | clear_nlink(new_inode); | 3266 | clear_nlink(new.inode); |
| 3184 | } else { | 3267 | } else { |
| 3185 | ext4_inc_count(handle, new_dir); | 3268 | ext4_inc_count(handle, new.dir); |
| 3186 | ext4_update_dx_flag(new_dir); | 3269 | ext4_update_dx_flag(new.dir); |
| 3187 | ext4_mark_inode_dirty(handle, new_dir); | 3270 | ext4_mark_inode_dirty(handle, new.dir); |
| 3188 | } | 3271 | } |
| 3189 | } | 3272 | } |
| 3190 | ext4_mark_inode_dirty(handle, old_dir); | 3273 | ext4_mark_inode_dirty(handle, old.dir); |
| 3191 | if (new_inode) { | 3274 | if (new.inode) { |
| 3192 | ext4_mark_inode_dirty(handle, new_inode); | 3275 | ext4_mark_inode_dirty(handle, new.inode); |
| 3193 | if (!new_inode->i_nlink) | 3276 | if (!new.inode->i_nlink) |
| 3194 | ext4_orphan_add(handle, new_inode); | 3277 | ext4_orphan_add(handle, new.inode); |
| 3195 | } | 3278 | } |
| 3196 | retval = 0; | 3279 | retval = 0; |
| 3197 | 3280 | ||
| 3198 | end_rename: | 3281 | end_rename: |
| 3199 | brelse(dir_bh); | 3282 | brelse(old.dir_bh); |
| 3200 | brelse(old_bh); | 3283 | brelse(old.bh); |
| 3201 | brelse(new_bh); | 3284 | brelse(new.bh); |
| 3202 | if (handle) | 3285 | if (handle) |
| 3203 | ext4_journal_stop(handle); | 3286 | ext4_journal_stop(handle); |
| 3204 | return retval; | 3287 | return retval; |
| 3205 | } | 3288 | } |
| 3206 | 3289 | ||
| 3290 | static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry, | ||
| 3291 | struct inode *new_dir, struct dentry *new_dentry) | ||
| 3292 | { | ||
| 3293 | handle_t *handle = NULL; | ||
| 3294 | struct ext4_renament old = { | ||
| 3295 | .dir = old_dir, | ||
| 3296 | .dentry = old_dentry, | ||
| 3297 | .inode = old_dentry->d_inode, | ||
| 3298 | }; | ||
| 3299 | struct ext4_renament new = { | ||
| 3300 | .dir = new_dir, | ||
| 3301 | .dentry = new_dentry, | ||
| 3302 | .inode = new_dentry->d_inode, | ||
| 3303 | }; | ||
| 3304 | u8 new_file_type; | ||
| 3305 | int retval; | ||
| 3306 | |||
| 3307 | dquot_initialize(old.dir); | ||
| 3308 | dquot_initialize(new.dir); | ||
| 3309 | |||
| 3310 | old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, | ||
| 3311 | &old.de, &old.inlined); | ||
| 3312 | /* | ||
| 3313 | * Check for inode number is _not_ due to possible IO errors. | ||
| 3314 | * We might rmdir the source, keep it as pwd of some process | ||
| 3315 | * and merrily kill the link to whatever was created under the | ||
| 3316 | * same name. Goodbye sticky bit ;-< | ||
| 3317 | */ | ||
| 3318 | retval = -ENOENT; | ||
| 3319 | if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino) | ||
| 3320 | goto end_rename; | ||
| 3321 | |||
| 3322 | new.bh = ext4_find_entry(new.dir, &new.dentry->d_name, | ||
| 3323 | &new.de, &new.inlined); | ||
| 3324 | |||
| 3325 | /* RENAME_EXCHANGE case: old *and* new must both exist */ | ||
| 3326 | if (!new.bh || le32_to_cpu(new.de->inode) != new.inode->i_ino) | ||
| 3327 | goto end_rename; | ||
| 3328 | |||
| 3329 | handle = ext4_journal_start(old.dir, EXT4_HT_DIR, | ||
| 3330 | (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) + | ||
| 3331 | 2 * EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2)); | ||
| 3332 | if (IS_ERR(handle)) | ||
| 3333 | return PTR_ERR(handle); | ||
| 3334 | |||
| 3335 | if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) | ||
| 3336 | ext4_handle_sync(handle); | ||
| 3337 | |||
| 3338 | if (S_ISDIR(old.inode->i_mode)) { | ||
| 3339 | old.is_dir = true; | ||
| 3340 | retval = ext4_rename_dir_prepare(handle, &old); | ||
| 3341 | if (retval) | ||
| 3342 | goto end_rename; | ||
| 3343 | } | ||
| 3344 | if (S_ISDIR(new.inode->i_mode)) { | ||
| 3345 | new.is_dir = true; | ||
| 3346 | retval = ext4_rename_dir_prepare(handle, &new); | ||
| 3347 | if (retval) | ||
| 3348 | goto end_rename; | ||
| 3349 | } | ||
| 3350 | |||
| 3351 | /* | ||
| 3352 | * Other than the special case of overwriting a directory, parents' | ||
| 3353 | * nlink only needs to be modified if this is a cross directory rename. | ||
| 3354 | */ | ||
| 3355 | if (old.dir != new.dir && old.is_dir != new.is_dir) { | ||
| 3356 | old.dir_nlink_delta = old.is_dir ? -1 : 1; | ||
| 3357 | new.dir_nlink_delta = -old.dir_nlink_delta; | ||
| 3358 | retval = -EMLINK; | ||
| 3359 | if ((old.dir_nlink_delta > 0 && EXT4_DIR_LINK_MAX(old.dir)) || | ||
| 3360 | (new.dir_nlink_delta > 0 && EXT4_DIR_LINK_MAX(new.dir))) | ||
| 3361 | goto end_rename; | ||
| 3362 | } | ||
| 3363 | |||
| 3364 | new_file_type = new.de->file_type; | ||
| 3365 | retval = ext4_setent(handle, &new, old.inode->i_ino, old.de->file_type); | ||
| 3366 | if (retval) | ||
| 3367 | goto end_rename; | ||
| 3368 | |||
| 3369 | retval = ext4_setent(handle, &old, new.inode->i_ino, new_file_type); | ||
| 3370 | if (retval) | ||
| 3371 | goto end_rename; | ||
| 3372 | |||
| 3373 | /* | ||
| 3374 | * Like most other Unix systems, set the ctime for inodes on a | ||
| 3375 | * rename. | ||
| 3376 | */ | ||
| 3377 | old.inode->i_ctime = ext4_current_time(old.inode); | ||
| 3378 | new.inode->i_ctime = ext4_current_time(new.inode); | ||
| 3379 | ext4_mark_inode_dirty(handle, old.inode); | ||
| 3380 | ext4_mark_inode_dirty(handle, new.inode); | ||
| 3381 | |||
| 3382 | if (old.dir_bh) { | ||
| 3383 | retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino); | ||
| 3384 | if (retval) | ||
| 3385 | goto end_rename; | ||
| 3386 | } | ||
| 3387 | if (new.dir_bh) { | ||
| 3388 | retval = ext4_rename_dir_finish(handle, &new, old.dir->i_ino); | ||
| 3389 | if (retval) | ||
| 3390 | goto end_rename; | ||
| 3391 | } | ||
| 3392 | ext4_update_dir_count(handle, &old); | ||
| 3393 | ext4_update_dir_count(handle, &new); | ||
| 3394 | retval = 0; | ||
| 3395 | |||
| 3396 | end_rename: | ||
| 3397 | brelse(old.dir_bh); | ||
| 3398 | brelse(new.dir_bh); | ||
| 3399 | brelse(old.bh); | ||
| 3400 | brelse(new.bh); | ||
| 3401 | if (handle) | ||
| 3402 | ext4_journal_stop(handle); | ||
| 3403 | return retval; | ||
| 3404 | } | ||
| 3405 | |||
| 3406 | static int ext4_rename2(struct inode *old_dir, struct dentry *old_dentry, | ||
| 3407 | struct inode *new_dir, struct dentry *new_dentry, | ||
| 3408 | unsigned int flags) | ||
| 3409 | { | ||
| 3410 | if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) | ||
| 3411 | return -EINVAL; | ||
| 3412 | |||
| 3413 | if (flags & RENAME_EXCHANGE) { | ||
| 3414 | return ext4_cross_rename(old_dir, old_dentry, | ||
| 3415 | new_dir, new_dentry); | ||
| 3416 | } | ||
| 3417 | /* | ||
| 3418 | * Existence checking was done by the VFS, otherwise "RENAME_NOREPLACE" | ||
| 3419 | * is equivalent to regular rename. | ||
| 3420 | */ | ||
| 3421 | return ext4_rename(old_dir, old_dentry, new_dir, new_dentry); | ||
| 3422 | } | ||
| 3423 | |||
| 3207 | /* | 3424 | /* |
| 3208 | * directories can handle most operations... | 3425 | * directories can handle most operations... |
| 3209 | */ | 3426 | */ |
| @@ -3218,6 +3435,7 @@ const struct inode_operations ext4_dir_inode_operations = { | |||
| 3218 | .mknod = ext4_mknod, | 3435 | .mknod = ext4_mknod, |
| 3219 | .tmpfile = ext4_tmpfile, | 3436 | .tmpfile = ext4_tmpfile, |
| 3220 | .rename = ext4_rename, | 3437 | .rename = ext4_rename, |
| 3438 | .rename2 = ext4_rename2, | ||
| 3221 | .setattr = ext4_setattr, | 3439 | .setattr = ext4_setattr, |
| 3222 | .setxattr = generic_setxattr, | 3440 | .setxattr = generic_setxattr, |
| 3223 | .getxattr = generic_getxattr, | 3441 | .getxattr = generic_getxattr, |
