Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 61252
b: refs/heads/master
c: f8628a1
h: refs/heads/master
v: v3
  • Loading branch information
Andreas Dilger authored and Theodore Ts'o committed Jul 18, 2007
1 parent cc02a7b commit 7a4b3f1
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 16 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6dd4ee7cab7e3a17c571aebd444f4344c8c4946e
refs/heads/master: f8628a14a27eb4512a1ede43de1d9db4d9f92bc3
60 changes: 46 additions & 14 deletions trunk/fs/ext4/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -1629,6 +1629,35 @@ static int ext4_delete_entry (handle_t *handle,
return -ENOENT;
}

/*
* DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2,
* since this indicates that nlinks count was previously 1.
*/
static void ext4_inc_count(handle_t *handle, struct inode *inode)
{
inc_nlink(inode);
if (is_dx(inode) && inode->i_nlink > 1) {
/* limit is 16-bit i_links_count */
if (inode->i_nlink >= EXT4_LINK_MAX || inode->i_nlink == 2) {
inode->i_nlink = 1;
EXT4_SET_RO_COMPAT_FEATURE(inode->i_sb,
EXT4_FEATURE_RO_COMPAT_DIR_NLINK);
}
}
}

/*
* If a directory had nlink == 1, then we should let it be 1. This indicates
* directory has >EXT4_LINK_MAX subdirs.
*/
static void ext4_dec_count(handle_t *handle, struct inode *inode)
{
drop_nlink(inode);
if (S_ISDIR(inode->i_mode) && inode->i_nlink == 0)
inc_nlink(inode);
}


static int ext4_add_nondir(handle_t *handle,
struct dentry *dentry, struct inode *inode)
{
Expand Down Expand Up @@ -1725,7 +1754,7 @@ static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
struct ext4_dir_entry_2 * de;
int err, retries = 0;

if (dir->i_nlink >= EXT4_LINK_MAX)
if (EXT4_DIR_LINK_MAX(dir))
return -EMLINK;

retry:
Expand All @@ -1748,7 +1777,7 @@ static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
dir_block = ext4_bread (handle, inode, 0, 1, &err);
if (!dir_block) {
drop_nlink(inode); /* is this nlink == 0? */
ext4_dec_count(handle, inode); /* is this nlink == 0? */
ext4_mark_inode_dirty(handle, inode);
iput (inode);
goto out_stop;
Expand Down Expand Up @@ -1780,7 +1809,7 @@ static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
iput (inode);
goto out_stop;
}
inc_nlink(dir);
ext4_inc_count(handle, dir);
ext4_update_dx_flag(dir);
ext4_mark_inode_dirty(handle, dir);
d_instantiate(dentry, inode);
Expand Down Expand Up @@ -2045,9 +2074,9 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
retval = ext4_delete_entry(handle, dir, de, bh);
if (retval)
goto end_rmdir;
if (inode->i_nlink != 2)
if (!EXT4_DIR_LINK_EMPTY(inode))
ext4_warning (inode->i_sb, "ext4_rmdir",
"empty directory has nlink!=2 (%d)",
"empty directory has too many links (%d)",
inode->i_nlink);
inode->i_version++;
clear_nlink(inode);
Expand All @@ -2058,7 +2087,7 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
ext4_orphan_add(handle, inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
drop_nlink(dir);
ext4_dec_count(handle, dir);
ext4_update_dx_flag(dir);
ext4_mark_inode_dirty(handle, dir);

Expand Down Expand Up @@ -2109,7 +2138,7 @@ static int ext4_unlink(struct inode * dir, struct dentry *dentry)
dir->i_ctime = dir->i_mtime = ext4_current_time(dir);
ext4_update_dx_flag(dir);
ext4_mark_inode_dirty(handle, dir);
drop_nlink(inode);
ext4_dec_count(handle, inode);
if (!inode->i_nlink)
ext4_orphan_add(handle, inode);
inode->i_ctime = ext4_current_time(inode);
Expand Down Expand Up @@ -2159,7 +2188,7 @@ static int ext4_symlink (struct inode * dir,
err = __page_symlink(inode, symname, l,
mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
if (err) {
drop_nlink(inode);
ext4_dec_count(handle, inode);
ext4_mark_inode_dirty(handle, inode);
iput (inode);
goto out_stop;
Expand All @@ -2185,8 +2214,9 @@ static int ext4_link (struct dentry * old_dentry,
struct inode *inode = old_dentry->d_inode;
int err, retries = 0;

if (inode->i_nlink >= EXT4_LINK_MAX)
if (EXT4_DIR_LINK_MAX(inode))
return -EMLINK;

/*
* Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing
* otherwise has the potential to corrupt the orphan inode list.
Expand All @@ -2204,7 +2234,7 @@ static int ext4_link (struct dentry * old_dentry,
handle->h_sync = 1;

inode->i_ctime = ext4_current_time(inode);
inc_nlink(inode);
ext4_inc_count(handle, inode);
atomic_inc(&inode->i_count);

err = ext4_add_nondir(handle, dentry, inode);
Expand Down Expand Up @@ -2337,7 +2367,7 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
}

if (new_inode) {
drop_nlink(new_inode);
ext4_dec_count(handle, new_inode);
new_inode->i_ctime = ext4_current_time(new_inode);
}
old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir);
Expand All @@ -2348,11 +2378,13 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata");
ext4_journal_dirty_metadata(handle, dir_bh);
drop_nlink(old_dir);
ext4_dec_count(handle, old_dir);
if (new_inode) {
drop_nlink(new_inode);
/* checked empty_dir above, can't have another parent,
* ext3_dec_count() won't work for many-linked dirs */
new_inode->i_nlink = 0;
} else {
inc_nlink(new_dir);
ext4_inc_count(handle, new_dir);
ext4_update_dx_flag(new_dir);
ext4_mark_inode_dirty(handle, new_dir);
}
Expand Down
4 changes: 3 additions & 1 deletion trunk/include/linux/ext4_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
/*
* Maximal count of links to a file
*/
#define EXT4_LINK_MAX 32000
#define EXT4_LINK_MAX 65000

/*
* Macro-instructions used to manage several block sizes
Expand Down Expand Up @@ -692,6 +692,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040

#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
Expand All @@ -710,6 +711,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
EXT4_FEATURE_INCOMPAT_64BIT)
#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
EXT4_FEATURE_RO_COMPAT_BTREE_DIR)

Expand Down

0 comments on commit 7a4b3f1

Please sign in to comment.