diff options
Diffstat (limited to 'fs/ext4/ialloc.c')
-rw-r--r-- | fs/ext4/ialloc.c | 105 |
1 files changed, 47 insertions, 58 deletions
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 57f6eef6ccd6..45853e0d1f21 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -222,7 +222,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) | |||
222 | is_directory = S_ISDIR(inode->i_mode); | 222 | is_directory = S_ISDIR(inode->i_mode); |
223 | 223 | ||
224 | /* Do this BEFORE marking the inode not in use or returning an error */ | 224 | /* Do this BEFORE marking the inode not in use or returning an error */ |
225 | clear_inode(inode); | 225 | ext4_clear_inode(inode); |
226 | 226 | ||
227 | es = EXT4_SB(sb)->s_es; | 227 | es = EXT4_SB(sb)->s_es; |
228 | if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { | 228 | if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { |
@@ -240,56 +240,49 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) | |||
240 | if (fatal) | 240 | if (fatal) |
241 | goto error_return; | 241 | goto error_return; |
242 | 242 | ||
243 | /* Ok, now we can actually update the inode bitmaps.. */ | 243 | fatal = -ESRCH; |
244 | cleared = ext4_clear_bit_atomic(ext4_group_lock_ptr(sb, block_group), | 244 | gdp = ext4_get_group_desc(sb, block_group, &bh2); |
245 | bit, bitmap_bh->b_data); | 245 | if (gdp) { |
246 | if (!cleared) | ||
247 | ext4_error(sb, "bit already cleared for inode %lu", ino); | ||
248 | else { | ||
249 | gdp = ext4_get_group_desc(sb, block_group, &bh2); | ||
250 | |||
251 | BUFFER_TRACE(bh2, "get_write_access"); | 246 | BUFFER_TRACE(bh2, "get_write_access"); |
252 | fatal = ext4_journal_get_write_access(handle, bh2); | 247 | fatal = ext4_journal_get_write_access(handle, bh2); |
253 | if (fatal) goto error_return; | 248 | } |
254 | 249 | ext4_lock_group(sb, block_group); | |
255 | if (gdp) { | 250 | cleared = ext4_clear_bit(bit, bitmap_bh->b_data); |
256 | ext4_lock_group(sb, block_group); | 251 | if (fatal || !cleared) { |
257 | count = ext4_free_inodes_count(sb, gdp) + 1; | 252 | ext4_unlock_group(sb, block_group); |
258 | ext4_free_inodes_set(sb, gdp, count); | 253 | goto out; |
259 | if (is_directory) { | 254 | } |
260 | count = ext4_used_dirs_count(sb, gdp) - 1; | ||
261 | ext4_used_dirs_set(sb, gdp, count); | ||
262 | if (sbi->s_log_groups_per_flex) { | ||
263 | ext4_group_t f; | ||
264 | |||
265 | f = ext4_flex_group(sbi, block_group); | ||
266 | atomic_dec(&sbi->s_flex_groups[f].used_dirs); | ||
267 | } | ||
268 | 255 | ||
269 | } | 256 | count = ext4_free_inodes_count(sb, gdp) + 1; |
270 | gdp->bg_checksum = ext4_group_desc_csum(sbi, | 257 | ext4_free_inodes_set(sb, gdp, count); |
271 | block_group, gdp); | 258 | if (is_directory) { |
272 | ext4_unlock_group(sb, block_group); | 259 | count = ext4_used_dirs_count(sb, gdp) - 1; |
273 | percpu_counter_inc(&sbi->s_freeinodes_counter); | 260 | ext4_used_dirs_set(sb, gdp, count); |
274 | if (is_directory) | 261 | percpu_counter_dec(&sbi->s_dirs_counter); |
275 | percpu_counter_dec(&sbi->s_dirs_counter); | 262 | } |
276 | 263 | gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp); | |
277 | if (sbi->s_log_groups_per_flex) { | 264 | ext4_unlock_group(sb, block_group); |
278 | ext4_group_t f; | 265 | |
279 | 266 | percpu_counter_inc(&sbi->s_freeinodes_counter); | |
280 | f = ext4_flex_group(sbi, block_group); | 267 | if (sbi->s_log_groups_per_flex) { |
281 | atomic_inc(&sbi->s_flex_groups[f].free_inodes); | 268 | ext4_group_t f = ext4_flex_group(sbi, block_group); |
282 | } | 269 | |
283 | } | 270 | atomic_inc(&sbi->s_flex_groups[f].free_inodes); |
284 | BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata"); | 271 | if (is_directory) |
285 | err = ext4_handle_dirty_metadata(handle, NULL, bh2); | 272 | atomic_dec(&sbi->s_flex_groups[f].used_dirs); |
286 | if (!fatal) fatal = err; | ||
287 | } | 273 | } |
288 | BUFFER_TRACE(bitmap_bh, "call ext4_handle_dirty_metadata"); | 274 | BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata"); |
289 | err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); | 275 | fatal = ext4_handle_dirty_metadata(handle, NULL, bh2); |
290 | if (!fatal) | 276 | out: |
291 | fatal = err; | 277 | if (cleared) { |
292 | sb->s_dirt = 1; | 278 | BUFFER_TRACE(bitmap_bh, "call ext4_handle_dirty_metadata"); |
279 | err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); | ||
280 | if (!fatal) | ||
281 | fatal = err; | ||
282 | ext4_mark_super_dirty(sb); | ||
283 | } else | ||
284 | ext4_error(sb, "bit already cleared for inode %lu", ino); | ||
285 | |||
293 | error_return: | 286 | error_return: |
294 | brelse(bitmap_bh); | 287 | brelse(bitmap_bh); |
295 | ext4_std_error(sb, fatal); | 288 | ext4_std_error(sb, fatal); |
@@ -499,7 +492,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent, | |||
499 | 492 | ||
500 | if (S_ISDIR(mode) && | 493 | if (S_ISDIR(mode) && |
501 | ((parent == sb->s_root->d_inode) || | 494 | ((parent == sb->s_root->d_inode) || |
502 | (EXT4_I(parent)->i_flags & EXT4_TOPDIR_FL))) { | 495 | (ext4_test_inode_flag(parent, EXT4_INODE_TOPDIR)))) { |
503 | int best_ndir = inodes_per_group; | 496 | int best_ndir = inodes_per_group; |
504 | int ret = -1; | 497 | int ret = -1; |
505 | 498 | ||
@@ -972,23 +965,19 @@ got: | |||
972 | percpu_counter_dec(&sbi->s_freeinodes_counter); | 965 | percpu_counter_dec(&sbi->s_freeinodes_counter); |
973 | if (S_ISDIR(mode)) | 966 | if (S_ISDIR(mode)) |
974 | percpu_counter_inc(&sbi->s_dirs_counter); | 967 | percpu_counter_inc(&sbi->s_dirs_counter); |
975 | sb->s_dirt = 1; | 968 | ext4_mark_super_dirty(sb); |
976 | 969 | ||
977 | if (sbi->s_log_groups_per_flex) { | 970 | if (sbi->s_log_groups_per_flex) { |
978 | flex_group = ext4_flex_group(sbi, group); | 971 | flex_group = ext4_flex_group(sbi, group); |
979 | atomic_dec(&sbi->s_flex_groups[flex_group].free_inodes); | 972 | atomic_dec(&sbi->s_flex_groups[flex_group].free_inodes); |
980 | } | 973 | } |
981 | 974 | ||
982 | inode->i_uid = current_fsuid(); | 975 | if (test_opt(sb, GRPID)) { |
983 | if (test_opt(sb, GRPID)) | 976 | inode->i_mode = mode; |
984 | inode->i_gid = dir->i_gid; | 977 | inode->i_uid = current_fsuid(); |
985 | else if (dir->i_mode & S_ISGID) { | ||
986 | inode->i_gid = dir->i_gid; | 978 | inode->i_gid = dir->i_gid; |
987 | if (S_ISDIR(mode)) | ||
988 | mode |= S_ISGID; | ||
989 | } else | 979 | } else |
990 | inode->i_gid = current_fsgid(); | 980 | inode_init_owner(inode, dir, mode); |
991 | inode->i_mode = mode; | ||
992 | 981 | ||
993 | inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb); | 982 | inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb); |
994 | /* This is the optimal IO size (for stat), not the fs block size */ | 983 | /* This is the optimal IO size (for stat), not the fs block size */ |
@@ -1045,7 +1034,7 @@ got: | |||
1045 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) { | 1034 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) { |
1046 | /* set extent flag only for directory, file and normal symlink*/ | 1035 | /* set extent flag only for directory, file and normal symlink*/ |
1047 | if (S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) { | 1036 | if (S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) { |
1048 | EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL; | 1037 | ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS); |
1049 | ext4_ext_tree_init(handle, inode); | 1038 | ext4_ext_tree_init(handle, inode); |
1050 | } | 1039 | } |
1051 | } | 1040 | } |