Author: mckusick
Date: Sat Jan 11 03:18:47 2020
New Revision: 356627
URL: https://svnweb.freebsd.org/changeset/base/356627

Log:
  When a read error occurs while fetching a directory block to delete
  or rename an entry in it, properly reset the link count of the inode
  associated with the entry that was to have been changed.
  
  Tested by: Peter Holm
  MFC after: 7 days

Modified:
  head/sys/ufs/ufs/ufs_lookup.c

Modified: head/sys/ufs/ufs/ufs_lookup.c
==============================================================================
--- head/sys/ufs/ufs/ufs_lookup.c       Sat Jan 11 03:15:12 2020        
(r356626)
+++ head/sys/ufs/ufs/ufs_lookup.c       Sat Jan 11 03:18:47 2020        
(r356627)
@@ -1169,6 +1169,7 @@ ufs_dirremove(dvp, ip, flags, isrmdir)
        struct inode *dp;
        struct direct *ep, *rep;
        struct buf *bp;
+       off_t offset;
        int error;
 
        dp = VTOI(dvp);
@@ -1187,22 +1188,32 @@ ufs_dirremove(dvp, ip, flags, isrmdir)
                        ip->i_flag |= IN_CHANGE;
                }
        }
+       if (flags & DOWHITEOUT)
+               offset = dp->i_offset;
+       else
+               offset = dp->i_offset - dp->i_count;
+       if ((error = UFS_BLKATOFF(dvp, offset, (char **)&ep, &bp)) != 0) {
+               if (ip) {
+                       ip->i_effnlink++;
+                       ip->i_flag |= IN_CHANGE;
+                       if (DOINGSOFTDEP(dvp)) {
+                               softdep_change_linkcnt(ip);
+                       } else {
+                               ip->i_nlink++;
+                               DIP_SET(ip, i_nlink, ip->i_nlink);
+                               ip->i_flag |= IN_CHANGE;
+                       }
+               }
+               return (error);
+       }
        if (flags & DOWHITEOUT) {
                /*
                 * Whiteout entry: set d_ino to UFS_WINO.
                 */
-               if ((error =
-                   UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) 
!= 0)
-                       return (error);
                ep->d_ino = UFS_WINO;
                ep->d_type = DT_WHT;
                goto out;
        }
-
-       if ((error = UFS_BLKATOFF(dvp,
-           (off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp)) != 0)
-               return (error);
-
        /* Set 'rep' to the entry being removed. */
        if (dp->i_count == 0)
                rep = ep;
@@ -1302,12 +1313,22 @@ ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir)
        }
 
        error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp);
-       if (error)
-               return (error);
-       if (ep->d_namlen == 2 && ep->d_name[1] == '.' && ep->d_name[0] == '.' &&
-           ep->d_ino != oip->i_number) {
+       if (error == 0 && ep->d_namlen == 2 && ep->d_name[1] == '.' &&
+           ep->d_name[0] == '.' && ep->d_ino != oip->i_number) {
                brelse(bp);
-               return (EIDRM);
+               error = EIDRM;
+       }
+       if (error) {
+               oip->i_effnlink++;
+               oip->i_flag |= IN_CHANGE;
+               if (DOINGSOFTDEP(vdp)) {
+                       softdep_change_linkcnt(oip);
+               } else {
+                       oip->i_nlink++;
+                       DIP_SET(oip, i_nlink, oip->i_nlink);
+                       oip->i_flag |= IN_CHANGE;
+               }
+               return (error);
        }
        ep->d_ino = newinum;
        if (!OFSFMT(vdp))
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to