diff -Nur orig/fs/ext3/namei.c patch/fs/ext3/namei.c --- orig/fs/ext3/namei.c 2005-10-12 13:58:19.000000000 -0700 +++ patch/fs/ext3/namei.c 2005-10-12 14:00:33.000000000 -0700 @@ -1603,11 +1603,17 @@ static inline void ext3_inc_count(handle_t *handle, struct inode *inode) { inode->i_nlink++; + if (is_dx(inode) && inode->i_nlink > 1) { + /* limit is 16-bit i_links_count */ + if (inode->i_nlink >= EXT3_LINK_MAX || inode->i_nlink == 2) + inode->i_nlink = 1; + } } static inline void ext3_dec_count(handle_t *handle, struct inode *inode) { - inode->i_nlink--; + if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2) + inode->i_nlink--; } static int ext3_add_nondir(handle_t *handle, @@ -1706,7 +1712,7 @@ static int ext3_add_nondir(handle_t struct ext3_dir_entry_2 * de; int err, retries = 0; - if (dir->i_nlink >= EXT3_LINK_MAX) + if (EXT3_DIR_LINK_MAX(dir)) return -EMLINK; retry: @@ -1729,7 +1735,7 @@ static int ext3_mkdir(struct inode inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize; dir_block = ext3_bread (handle, inode, 0, 1, &err); if (!dir_block) { - inode->i_nlink--; /* is this nlink == 0? */ + ext3_dec_count(handle, inode); /* is this nlink == 0? */ ext3_mark_inode_dirty(handle, inode); iput (inode); goto out_stop; @@ -1761,7 +1767,7 @@ static int ext3_mkdir(struct inode iput (inode); goto out_stop; } - dir->i_nlink++; + ext3_inc_count(handle, dir); ext3_update_dx_flag(dir); ext3_mark_inode_dirty(handle, dir); d_instantiate(dentry, inode); @@ -2026,10 +2032,10 @@ static int ext3_rmdir (struct inode retval = ext3_delete_entry(handle, dir, de, bh); if (retval) goto end_rmdir; - if (inode->i_nlink != 2) - ext3_warning (inode->i_sb, "ext3_rmdir", - "empty directory has nlink!=2 (%d)", - inode->i_nlink); + if (!EXT3_DIR_LINK_EMPTY(inode)) + ext3_warning(inode->i_sb, "ext3_rmdir", + "empty directory has too many links (%d)", + inode->i_nlink); inode->i_version++; inode->i_nlink = 0; /* There's no need to set i_disksize: the fact that i_nlink is @@ -2039,7 +2045,7 @@ static int ext3_rmdir (struct inode ext3_orphan_add(handle, inode); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; ext3_mark_inode_dirty(handle, inode); - dir->i_nlink--; + ext3_dec_count(handle, dir); ext3_update_dx_flag(dir); ext3_mark_inode_dirty(handle, dir); @@ -2090,7 +2096,7 @@ static int ext3_unlink(struct inode dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; ext3_update_dx_flag(dir); ext3_mark_inode_dirty(handle, dir); - inode->i_nlink--; + ext3_dec_count(handle, inode); if (!inode->i_nlink) ext3_orphan_add(handle, inode); inode->i_ctime = dir->i_ctime; @@ -2165,7 +2171,7 @@ static int ext3_link (struct dentry struct inode *inode = old_dentry->d_inode; int err, retries = 0; - if (inode->i_nlink >= EXT3_LINK_MAX) + if (EXT3_DIR_LINK_MAX(inode)) return -EMLINK; retry: @@ -2252,8 +2258,8 @@ static int ext3_rename (struct inode if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino) goto end_rename; retval = -EMLINK; - if (!new_inode && new_dir!=old_dir && - new_dir->i_nlink >= EXT3_LINK_MAX) + if (!new_inode && new_dir != old_dir && + EXT3_DIR_LINK_MAX(new_dir)) goto end_rename; } if (!new_bh) { @@ -2310,7 +2316,7 @@ static int ext3_rename (struct inode } if (new_inode) { - new_inode->i_nlink--; + ext3_dec_count(handle, new_inode); new_inode->i_ctime = CURRENT_TIME_SEC; } old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; @@ -2321,11 +2327,13 @@ static int ext3_rename (struct inode PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino); BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata"); ext3_journal_dirty_metadata(handle, dir_bh); - old_dir->i_nlink--; + ext3_dec_count(handle, old_dir); if (new_inode) { - new_inode->i_nlink--; + /* 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 { - new_dir->i_nlink++; + ext3_inc_count(handle, new_dir); ext3_update_dx_flag(new_dir); ext3_mark_inode_dirty(handle, new_dir); } Index: linux-2.6.7/include/linux/ext3_fs.h =================================================================== --- linux-2.6.7.orig/include/linux/ext3_fs.h 2004-06-15 23:19:36.000000000 -0600 +++ linux-2.6.7/include/linux/ext3_fs.h 2004-08-20 17:41:27.000000000 -0600 @@ -79,7 +81,7 @@ /* * Maximal count of links to a file */ -#define EXT3_LINK_MAX 32000 +#define EXT3_LINK_MAX 65000 /* * Macro-instructions used to manage several block sizes