Index: linux-2.6.5-7.283/fs/ext3/namei.c
===================================================================
--- linux-2.6.5-7.283.orig/fs/ext3/namei.c
+++ linux-2.6.5-7.283/fs/ext3/namei.c
@@ -1613,11 +1613,17 @@ static int ext3_delete_entry (handle_t *
 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,
@@ -1730,7 +1736,7 @@ static int ext3_mkdir(struct inode * dir
 	int retries = 0;
 	int err;
 
-	if (dir->i_nlink >= EXT3_LINK_MAX)
+	if (EXT3_DIR_LINK_MAX(dir))
 		return -EMLINK;
 
 retry:
@@ -1752,7 +1758,7 @@ retry:
 	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;
@@ -1784,7 +1790,7 @@ retry:
 		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);
@@ -2042,16 +2048,16 @@ static int ext3_rmdir (struct inode * di
 	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;
 	ext3_orphan_add(handle, inode);
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	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);
 
@@ -2100,7 +2106,7 @@ static int ext3_unlink(struct inode * di
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	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;
@@ -2191,7 +2197,7 @@ static int ext3_link (struct dentry * ol
 	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:
@@ -2277,8 +2283,8 @@ static int ext3_rename (struct inode * o
 		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) {
@@ -2335,7 +2341,7 @@ static int ext3_rename (struct inode * o
 	}
 
 	if (new_inode) {
-		new_inode->i_nlink--;
+		ext3_dec_count(handle, new_inode);
 		new_inode->i_ctime = CURRENT_TIME;
 	}
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
@@ -2346,11 +2352,13 @@ static int ext3_rename (struct inode * o
 		PARENT_INO(dir_bh->b_data) = le32_to_cpu(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.5-7.283/include/linux/ext3_fs.h
===================================================================
--- linux-2.6.5-7.283.orig/include/linux/ext3_fs.h
+++ linux-2.6.5-7.283/include/linux/ext3_fs.h
@@ -86,7 +86,7 @@ struct statfs;
 /*
  * 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
@@ -538,6 +538,7 @@ static inline struct ext3_inode_info *EX
 #define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
 #define EXT3_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
 #define EXT3_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK	0x0020
 
 #define EXT3_FEATURE_INCOMPAT_COMPRESSION	0x0001
 #define EXT3_FEATURE_INCOMPAT_FILETYPE		0x0002
@@ -553,6 +554,7 @@ static inline struct ext3_inode_info *EX
 					 EXT3_FEATURE_INCOMPAT_EXTENTS)
 #define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
 					 EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
+					 EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
 					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
 
 /*