VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   32 Branches   54 Tags
author: Russell King <rmk+kernel@armlinux.org.uk> 2019-12-09 11:10:01 +0000 committer: Al Viro <viro@zeniv.linux.org.uk> 2020-01-20 20:12:41 -0500 commit: f6075c79074378910e131bbebc9d1dab53fd9986 parent: ae5df41390eb1c40b9a5c220673d8c31a4cb57db
Commit Summary:
fs/adfs: dir: improve update failure handling
Diffstat:
1 file changed, 31 insertions, 11 deletions
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index ff9c921be31c..5e5d344bae7c 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -64,12 +64,8 @@ int adfs_dir_copyto(struct adfs_dir *dir, unsigned int offset, const void *src,
 	return 0;
 }
 
-void adfs_dir_relse(struct adfs_dir *dir)
+static void __adfs_dir_cleanup(struct adfs_dir *dir)
 {
-	unsigned int i;
-
-	for (i = 0; i < dir->nr_buffers; i++)
-		brelse(dir->bhs[i]);
 	dir->nr_buffers = 0;
 
 	if (dir->bhs != dir->bh)
@@ -78,6 +74,26 @@ void adfs_dir_relse(struct adfs_dir *dir)
 	dir->sb = NULL;
 }
 
+void adfs_dir_relse(struct adfs_dir *dir)
+{
+	unsigned int i;
+
+	for (i = 0; i < dir->nr_buffers; i++)
+		brelse(dir->bhs[i]);
+
+	__adfs_dir_cleanup(dir);
+}
+
+static void adfs_dir_forget(struct adfs_dir *dir)
+{
+	unsigned int i;
+
+	for (i = 0; i < dir->nr_buffers; i++)
+		bforget(dir->bhs[i]);
+
+	__adfs_dir_cleanup(dir);
+}
+
 int adfs_dir_read_buffers(struct super_block *sb, u32 indaddr,
 			  unsigned int size, struct adfs_dir *dir)
 {
@@ -288,20 +304,28 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
 		goto unlock;
 
 	ret = ops->update(&dir, obj);
+	if (ret)
+		goto forget;
 	up_write(&adfs_dir_rwsem);
 
-	if (ret == 0)
-		adfs_dir_mark_dirty(&dir);
+	adfs_dir_mark_dirty(&dir);
 
-	if (wait) {
-		int err = adfs_dir_sync(&dir);
-		if (!ret)
-			ret = err;
-	}
+	if (wait)
+		ret = adfs_dir_sync(&dir);
 
 	adfs_dir_relse(&dir);
 	return ret;
 
+	/*
+	 * If the updated failed because the entry wasn't found, we can
+	 * just release the buffers. If it was any other error, forget
+	 * the dirtied buffers so they aren't written back to the media.
+	 */
+forget:
+	if (ret == -ENOENT)
+		adfs_dir_relse(&dir);
+	else
+		adfs_dir_forget(&dir);
 unlock:
 	up_write(&adfs_dir_rwsem);
 #endif