We don't always undo the link increases in error cases.
Added logic the undo the changes to link count if an
error occurred in those cases.
---
 libdiskfs/dir-rename.c  | 12 ++++++++++--
 libdiskfs/dir-renamed.c | 29 +++++++++++++++++++++++++++--
 2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/libdiskfs/dir-rename.c b/libdiskfs/dir-rename.c
index c8bb0dad..7953132b 100644
--- a/libdiskfs/dir-rename.c
+++ b/libdiskfs/dir-rename.c
@@ -188,12 +188,20 @@ diskfs_S_dir_rename (struct protid *fromcred,
     diskfs_node_update (tdp, 1);
 
   pthread_mutex_unlock (&tdp->lock);
-  pthread_mutex_unlock (&fnp->lock);
   if (err)
     {
-      diskfs_nrele (fnp);
+      if (fnp->dn_stat.st_nlink > 0)
+       {
+         fnp->dn_stat.st_nlink--;
+         fnp->dn_set_ctime = 1;
+         if (diskfs_synchronous)
+           diskfs_node_update (fnp, 1);
+       }
+      diskfs_drop_dirstat (tdp, ds);
+      diskfs_nput (fnp);
       return err;
     }
+  pthread_mutex_unlock (&fnp->lock);
 
   /* We now hold no locks */
 
diff --git a/libdiskfs/dir-renamed.c b/libdiskfs/dir-renamed.c
index 1f3f3de4..532ff998 100644
--- a/libdiskfs/dir-renamed.c
+++ b/libdiskfs/dir-renamed.c
@@ -159,6 +159,13 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, 
const char *fromname,
       assert_backtrace (err != ENOENT);
       if (err)
        {
+         if (tdp->dn_stat.st_nlink > 0)
+           {
+             tdp->dn_stat.st_nlink--;
+             tdp->dn_set_ctime = 1;
+             if (diskfs_synchronous)
+               diskfs_node_update (tdp, 1);
+           }
          diskfs_drop_dirstat (fnp, tmpds);
          goto out;
        }
@@ -168,7 +175,16 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, 
const char *fromname,
       if (diskfs_synchronous)
        diskfs_file_update (fnp, 1);
       if (err)
-       goto out;
+       {
+         if (tdp->dn_stat.st_nlink > 0)
+           {
+             tdp->dn_stat.st_nlink--;
+             tdp->dn_set_ctime = 1;
+             if (diskfs_synchronous)
+               diskfs_node_update (tdp, 1);
+           }
+         goto out;
+       }
 
       fdp->dn_stat.st_nlink--;
       fdp->dn_set_ctime = 1;
@@ -213,7 +229,16 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, 
const char *fromname,
     }
 
   if (err)
-    goto out;
+    {
+      if (fnp->dn_stat.st_nlink > 0)
+       {
+         fnp->dn_stat.st_nlink--;
+         fnp->dn_set_ctime = 1;
+         if (diskfs_synchronous)
+           diskfs_node_update (fnp, 1);
+       }
+      goto out;
+    }
 
   /* 4: Remove the entry in fdp. */
   ds = buf;
-- 
2.52.0


Reply via email to