]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/ext4/namei.c
ext4: fix dir_nlink behaviour
[karo-tx-linux.git] / fs / ext4 / namei.c
index 13f0cadb1238e61983629e02cda233a60b84f6d1..cc986b8241817aea5ba782edc24fe1033d508ea0 100644 (file)
@@ -2395,19 +2395,22 @@ out:
 }
 
 /*
- * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2,
- * since this indicates that nlinks count was previously 1.
+ * Set directory link count to 1 if nlinks > EXT4_LINK_MAX, or if nlinks == 2
+ * since this indicates that nlinks count was previously 1 to avoid overflowing
+ * the 16-bit i_links_count field on disk.  Directories with i_nlink == 1 mean
+ * that subdirectory link counts are not being maintained accurately.
+ *
+ * The caller has already checked for i_nlink overflow in case the DIR_LINK
+ * feature is not enabled and returned -EMLINK.  The is_dx() check is a proxy
+ * for checking S_ISDIR(inode) (since the INODE_INDEX feature will not be set
+ * on regular files) and to avoid creating huge/slow non-HTREE directories.
  */
 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) {
-                       set_nlink(inode, 1);
-                       ext4_set_feature_dir_nlink(inode->i_sb);
-               }
-       }
+       if (is_dx(inode) &&
+           (inode->i_nlink > EXT4_LINK_MAX || inode->i_nlink == 2))
+               set_nlink(inode, 1);
 }
 
 /*