mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
To: Andrew Morton <akpm@osdl.org>
Cc: linux-kernel@vger.kernel.org
Subject: [PATCH 28/29] FAT: Update ->rename() path
Date: Sun, 06 Mar 2005 03:59:34 +0900	[thread overview]
Message-ID: <878y51or55.fsf_-_@devron.myhome.or.jp> (raw)
In-Reply-To: <87d5udor6b.fsf_-_@devron.myhome.or.jp> (OGAWA Hirofumi's message of "Sun, 06 Mar 2005 03:58:52 +0900")


a) If old_dir == new_dir, we don't need to update the ".." entry,
   so this doesn't touch it if unneeded.

b) old algorithm is using
         1) add a new entry (doen't point the data cluster yet).
	 2) remove a old entry.
	 3) switch the data cluster to new entry.
	 4) update a ".." entry
   this order lose the data cluster when between 2) and 3).

   Instead of above, this is using
         1) add a new entry (doen't point the data cluster yet).
	 2) switch the data cluster to new entry.
	 3) update a ".." entry if needed.
	 4) remove a old entry.
   this order would not lose the data cluster, but on disk metadata is
   corrupted on some point (later, fsck would recover this corruption
   without losing the data).

c) use synchronous update.

d) Fix the corrupted directory check created by 1 of new algorithm.
   1) Fix fat_bmap(). If directory's ->i_start == 0, fat_bmap() is
      handling it as root directory, this removes that strange behavior.
   2) On mkdir() path if directory's ->i_start == 0, returns -EIO.

Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---

 fs/fat/cache.c   |    4 -
 fs/fat/dir.c     |    9 +++-
 fs/fat/misc.c    |    2 
 fs/msdos/namei.c |  112 ++++++++++++++++++++++++++++++++++++++++++-------------
 fs/vfat/namei.c  |  101 +++++++++++++++++++++++++++++++++++--------------
 5 files changed, 170 insertions(+), 58 deletions(-)

diff -puN fs/fat/cache.c~sync08-fat_tweak8 fs/fat/cache.c
--- linux-2.6.11/fs/fat/cache.c~sync08-fat_tweak8	2005-03-06 02:37:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/cache.c	2005-03-06 02:37:32.000000000 +0900
@@ -303,9 +303,7 @@ int fat_bmap(struct inode *inode, sector
 	int cluster, offset;
 
 	*phys = 0;
-	if ((sbi->fat_bits != 32) &&
-	    (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
-	     !MSDOS_I(inode)->i_start))) {
+	if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO)) {
 		if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits))
 			*phys = sector + sbi->dir_start;
 		return 0;
diff -puN fs/fat/dir.c~sync08-fat_tweak8 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync08-fat_tweak8	2005-03-06 02:37:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:37:32.000000000 +0900
@@ -1172,8 +1172,15 @@ int fat_add_entries(struct inode *dir, v
 			free_slots = nr_bhs = 0;
 		}
 	}
-	if ((dir->i_ino == MSDOS_ROOT_INO) && (sbi->fat_bits != 32))
+	if (dir->i_ino == MSDOS_ROOT_INO) {
+		if (sbi->fat_bits != 32)
+			goto error;
+	} else if (MSDOS_I(dir)->i_start == 0) {
+		printk(KERN_ERR "FAT: Corrupted directory (i_pos %lld)\n",
+		       MSDOS_I(dir)->i_pos);
+		err = -EIO;
 		goto error;
+	}
 
 found:
 	err = 0;
diff -puN fs/fat/misc.c~sync08-fat_tweak8 fs/fat/misc.c
--- linux-2.6.11/fs/fat/misc.c~sync08-fat_tweak8	2005-03-06 02:37:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/misc.c	2005-03-06 02:37:32.000000000 +0900
@@ -33,6 +33,8 @@ void fat_fs_panic(struct super_block *s,
 	}
 }
 
+EXPORT_SYMBOL(fat_fs_panic);
+
 /* Flushes the number of free clusters on FAT32 */
 /* XXX: Need to write one per FSINFO block.  Currently only writes 1 */
 void fat_clusters_flush(struct super_block *sb)
diff -puN fs/msdos/namei.c~sync08-fat_tweak8 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync08-fat_tweak8	2005-03-06 02:37:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c	2005-03-06 02:37:32.000000000 +0900
@@ -456,9 +456,9 @@ static int do_msdos_rename(struct inode 
 	struct inode *old_inode, *new_inode;
 	struct fat_slot_info old_sinfo, sinfo;
 	struct timespec ts;
-	int err, is_dir;
+	int err, old_attrs, is_dir, update_dotdot, corrupt = 0;
 
-	old_sinfo.bh = dotdot_bh = NULL;
+	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
 	old_inode = old_dentry->d_inode;
 	new_inode = new_dentry->d_inode;
 
@@ -469,7 +469,8 @@ static int do_msdos_rename(struct inode 
 	}
 
 	is_dir = S_ISDIR(old_inode->i_mode);
-	if (is_dir) {
+	update_dotdot = (is_dir && old_dir != new_dir);
+	if (update_dotdot) {
 		if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
 					 &dotdot_i_pos) < 0) {
 			err = -EIO;
@@ -477,9 +478,9 @@ static int do_msdos_rename(struct inode 
 		}
 	}
 
+	old_attrs = MSDOS_I(old_inode)->i_attrs;
 	err = fat_scan(new_dir, new_name, &sinfo);
 	if (!err) {
-		brelse(sinfo.bh);
 		if (!new_inode) {
 			/* "foo" -> ".foo" case. just change the ATTR_HIDDEN */
 			if (sinfo.de != old_sinfo.de) {
@@ -490,11 +491,21 @@ static int do_msdos_rename(struct inode 
 				MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
 			else
 				MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
-			mark_inode_dirty(old_inode);
+			if (IS_DIRSYNC(old_dir)) {
+				err = fat_sync_inode(old_inode);
+				if (err) {
+					MSDOS_I(old_inode)->i_attrs = old_attrs;
+					goto out;
+				}
+			} else
+				mark_inode_dirty(old_inode);
 
 			old_dir->i_version++;
 			old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
-			mark_inode_dirty(old_dir);
+			if (IS_DIRSYNC(old_dir))
+				(void)fat_sync_inode(old_dir);
+			else
+				mark_inode_dirty(old_dir);
 			goto out;
 		}
 	}
@@ -520,47 +531,96 @@ static int do_msdos_rename(struct inode 
 				      &ts, &sinfo);
 		if (err)
 			goto out;
-		brelse(sinfo.bh);
 	}
 	new_dir->i_version++;
 
-	err = fat_remove_entries(old_dir, &old_sinfo);	/* and releases bh */
-	old_sinfo.bh = NULL;
-	if (err)
-		goto out;
-	if (is_dir)
-		old_dir->i_nlink--;
 	fat_detach(old_inode);
 	fat_attach(old_inode, sinfo.i_pos);
 	if (is_hid)
 		MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
 	else
 		MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
-	mark_inode_dirty(old_inode);
-
-	old_dir->i_version++;
-	old_dir->i_ctime = old_dir->i_mtime = ts;
-	mark_inode_dirty(old_dir);
+	if (IS_DIRSYNC(new_dir)) {
+		err = fat_sync_inode(old_inode);
+		if (err)
+			goto error_inode;
+	} else
+		mark_inode_dirty(old_inode);
 
-	if (new_inode) {
-		new_inode->i_nlink--;
-		new_inode->i_ctime = ts;
-	}
-	if (is_dir) {
+	if (update_dotdot) {
 		int start = MSDOS_I(new_dir)->i_logstart;
 		dotdot_de->start = cpu_to_le16(start);
 		dotdot_de->starthi = cpu_to_le16(start >> 16);
 		mark_buffer_dirty(dotdot_bh);
+		if (IS_DIRSYNC(new_dir)) {
+			err = sync_dirty_buffer(dotdot_bh);
+			if (err)
+				goto error_dotdot;
+		}
+		old_dir->i_nlink--;
+		if (!new_inode)
+			new_dir->i_nlink++;
+	}
 
-		if (new_inode)
-			new_inode->i_nlink--;
+	err = fat_remove_entries(old_dir, &old_sinfo);	/* and releases bh */
+	old_sinfo.bh = NULL;
+	if (err)
+		goto error_dotdot;
+	old_dir->i_version++;
+	old_dir->i_ctime = old_dir->i_mtime = ts;
+	if (IS_DIRSYNC(old_dir))
+		(void)fat_sync_inode(old_dir);
+	else
+		mark_inode_dirty(old_dir);
+
+	if (new_inode) {
+		if (is_dir)
+			new_inode->i_nlink -= 2;
 		else
-			new_dir->i_nlink++;
+			new_inode->i_nlink--;
+		new_inode->i_ctime = ts;
 	}
 out:
+	brelse(sinfo.bh);
 	brelse(dotdot_bh);
 	brelse(old_sinfo.bh);
 	return err;
+
+error_dotdot:
+	/* data cluster is shared, serious corruption */
+	corrupt = 1;
+
+	if (update_dotdot) {
+		int start = MSDOS_I(old_dir)->i_logstart;
+		dotdot_de->start = cpu_to_le16(start);
+		dotdot_de->starthi = cpu_to_le16(start >> 16);
+		mark_buffer_dirty(dotdot_bh);
+		corrupt |= sync_dirty_buffer(dotdot_bh);
+	}
+error_inode:
+	fat_detach(old_inode);
+	fat_attach(old_inode, old_sinfo.i_pos);
+	MSDOS_I(old_inode)->i_attrs = old_attrs;
+	if (new_inode) {
+		fat_attach(new_inode, sinfo.i_pos);
+		if (corrupt)
+			corrupt |= fat_sync_inode(new_inode);
+	} else {
+		/*
+		 * If new entry was not sharing the data cluster, it
+		 * shouldn't be serious corruption.
+		 */
+		int err2 = fat_remove_entries(new_dir, &sinfo);
+		if (corrupt)
+			corrupt |= err2;
+		sinfo.bh = NULL;
+	}
+	if (corrupt < 0) {
+		fat_fs_panic(new_dir->i_sb,
+			     "%s: Filesystem corrupted (i_pos %lld)",
+			     __FUNCTION__, sinfo.i_pos);
+	}
+	goto out;
 }
 
 /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
diff -puN fs/vfat/namei.c~sync08-fat_tweak8 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync08-fat_tweak8	2005-03-06 02:37:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:37:32.000000000 +0900
@@ -890,11 +890,11 @@ static int vfat_rename(struct inode *old
 	struct msdos_dir_entry *dotdot_de;
 	loff_t dotdot_i_pos;
 	struct inode *old_inode, *new_inode;
-	int err, is_dir;
 	struct fat_slot_info old_sinfo, sinfo;
 	struct timespec ts;
+	int err, is_dir, update_dotdot, corrupt = 0;
 
-	old_sinfo.bh = dotdot_bh = NULL;
+	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
 	old_inode = old_dentry->d_inode;
 	new_inode = new_dentry->d_inode;
 	lock_kernel();
@@ -903,7 +903,8 @@ static int vfat_rename(struct inode *old
 		goto out;
 
 	is_dir = S_ISDIR(old_inode->i_mode);
-	if (is_dir) {
+	update_dotdot = (is_dir && old_dir != new_dir);
+	if (update_dotdot) {
 		if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
 					 &dotdot_i_pos) < 0) {
 			err = -EIO;
@@ -912,11 +913,10 @@ static int vfat_rename(struct inode *old
 	}
 
 	ts = CURRENT_TIME_SEC;
-	if (new_dentry->d_inode) {
+	if (new_inode) {
 		err = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
 		if (err)
 			goto out;
-		brelse(sinfo.bh);
 		if (MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
 			/* WTF??? Cry and fail. */
 			printk(KERN_WARNING "vfat_rename: fs corrupted\n");
@@ -934,48 +934,93 @@ static int vfat_rename(struct inode *old
 				     &ts, &sinfo);
 		if (err)
 			goto out;
-		brelse(sinfo.bh);
 	}
 	new_dir->i_version++;
 
-	err = fat_remove_entries(old_dir, &old_sinfo);	/* and releases bh */
-	old_sinfo.bh = NULL;
-	if (err)
-		goto out;
-	if (is_dir)
-		old_dir->i_nlink--;
 	fat_detach(old_inode);
 	fat_attach(old_inode, sinfo.i_pos);
-	mark_inode_dirty(old_inode);
-
-	old_dir->i_version++;
-	old_dir->i_ctime = old_dir->i_mtime = ts;
-	mark_inode_dirty(old_dir);
-
-	if (new_inode) {
-		new_inode->i_nlink--;
-		new_inode->i_ctime = ts;
-	}
+	if (IS_DIRSYNC(new_dir)) {
+		err = fat_sync_inode(old_inode);
+		if (err)
+			goto error_inode;
+	} else
+		mark_inode_dirty(old_inode);
 
-	if (is_dir) {
+	if (update_dotdot) {
 		int start = MSDOS_I(new_dir)->i_logstart;
 		dotdot_de->start = cpu_to_le16(start);
 		dotdot_de->starthi = cpu_to_le16(start >> 16);
 		mark_buffer_dirty(dotdot_bh);
-		if (new_dir->i_sb->s_flags & MS_SYNCHRONOUS)
-			sync_dirty_buffer(dotdot_bh);
+		if (IS_DIRSYNC(new_dir)) {
+			err = sync_dirty_buffer(dotdot_bh);
+			if (err)
+				goto error_dotdot;
+		}
+		old_dir->i_nlink--;
+		if (!new_inode)
+ 			new_dir->i_nlink++;
+	}
 
-		if (new_inode)
-			new_inode->i_nlink--;
+	err = fat_remove_entries(old_dir, &old_sinfo);	/* and releases bh */
+	old_sinfo.bh = NULL;
+	if (err)
+		goto error_dotdot;
+	old_dir->i_version++;
+	old_dir->i_ctime = old_dir->i_mtime = ts;
+	if (IS_DIRSYNC(old_dir))
+		(void)fat_sync_inode(old_dir);
+	else
+		mark_inode_dirty(old_dir);
+
+	if (new_inode) {
+		if (is_dir)
+			new_inode->i_nlink -= 2;
 		else
-			new_dir->i_nlink++;
+			new_inode->i_nlink--;
+		new_inode->i_ctime = ts;
 	}
 out:
+	brelse(sinfo.bh);
 	brelse(dotdot_bh);
 	brelse(old_sinfo.bh);
 	unlock_kernel();
 
 	return err;
+
+error_dotdot:
+	/* data cluster is shared, serious corruption */
+	corrupt = 1;
+
+	if (update_dotdot) {
+		int start = MSDOS_I(old_dir)->i_logstart;
+		dotdot_de->start = cpu_to_le16(start);
+		dotdot_de->starthi = cpu_to_le16(start >> 16);
+		mark_buffer_dirty(dotdot_bh);
+		corrupt |= sync_dirty_buffer(dotdot_bh);
+	}
+error_inode:
+	fat_detach(old_inode);
+	fat_attach(old_inode, old_sinfo.i_pos);
+	if (new_inode) {
+		fat_attach(new_inode, sinfo.i_pos);
+		if (corrupt)
+			corrupt |= fat_sync_inode(new_inode);
+	} else {
+		/*
+		 * If new entry was not sharing the data cluster, it
+		 * shouldn't be serious corruption.
+		 */
+		int err2 = fat_remove_entries(new_dir, &sinfo);
+		if (corrupt)
+			corrupt |= err2;
+		sinfo.bh = NULL;
+	}
+	if (corrupt < 0) {
+		fat_fs_panic(new_dir->i_sb,
+			     "%s: Filesystem corrupted (i_pos %lld)",
+			     __FUNCTION__, sinfo.i_pos);
+	}
+	goto out;
 }
 
 static struct inode_operations vfat_dir_inode_operations = {
_

  reply	other threads:[~2005-03-05 19:59 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <87ll92rl6a.fsf@devron.myhome.or.jp>
2005-03-05 18:41 ` [PATCH 1/29] fat: fix writev(), add aio support OGAWA Hirofumi
2005-03-05 18:42   ` [PATCH 2/29] FAT: Updated FAT attributes patch OGAWA Hirofumi
2005-03-05 18:43     ` [PATCH 3/29] FAT: fat_readdirx() with dotOK=yes fix OGAWA Hirofumi
2005-03-05 18:43       ` [PATCH 4/29] let fat handle MS_SYNCHRONOUS flag OGAWA Hirofumi
2005-03-06 22:38         ` Christoph Hellwig
2005-03-07 14:56           ` OGAWA Hirofumi
2005-03-05 18:44       ` [PATCH 5/29] FAT: Rewrite the FAT (File Allocation Table) access stuff OGAWA Hirofumi
2005-03-05 18:45         ` [PATCH 6/29] FAT: add debugging code to fatent.c OGAWA Hirofumi
2005-03-05 18:47           ` [PATCH 7/29] FAT: Use "unsigned int" for ->free_clusters and ->prev_free OGAWA Hirofumi
2005-03-05 18:47             ` [PATCH 8/29] FAT: "struct vfat_slot_info" cleanup OGAWA Hirofumi
2005-03-05 18:48               ` [PATCH 9/29] FAT: Use "struct fat_slot_info" for fat_search_long() OGAWA Hirofumi
2005-03-05 18:49                 ` [PATCH 10/29] FAT: Add fat_remove_entries() OGAWA Hirofumi
2005-03-05 18:49                   ` [PATCH 11/29] FAT: fat_build_inode() cleanup OGAWA Hirofumi
2005-03-05 18:50                     ` [PATCH 12/29] FAT: Use "struct fat_slot_info" for fat_scan() OGAWA Hirofumi
2005-03-05 18:50                       ` [PATCH 13/29] FAT: Use "struct fat_slot_info" for msdos_find() OGAWA Hirofumi
2005-03-05 18:51                         ` [PATCH 14/29] FAT: vfat_build_slots() cleanup OGAWA Hirofumi
2005-03-05 18:52                           ` [PATCH 15/29] FAT: Use a same timestamp on some operations path OGAWA Hirofumi
2005-03-05 18:52                             ` [PATCH 16/29] FAT: msdos_rename() cleanup OGAWA Hirofumi
2005-03-05 18:53                               ` [PATCH 17/29] FAT: msdos_add_entry() cleanup OGAWA Hirofumi
2005-03-05 18:53                                 ` [PATCH 18/29] FAT: Allocate the cluster before adding the directory entry OGAWA Hirofumi
2005-03-05 18:54                                   ` [PATCH 19/29] FAT: Rewrite fat_add_entries() OGAWA Hirofumi
2005-03-05 18:55                                     ` [PATCH 20/29] FAT: Use fat_remove_entries() for msdos OGAWA Hirofumi
2005-03-05 18:55                                       ` [PATCH 21/29] FAT: make the fat_get_entry()/fat__get_entry() the static OGAWA Hirofumi
2005-03-05 18:56                                         ` [PATCH 22/29] FAT: "i_pos" cleanup OGAWA Hirofumi
2005-03-05 18:56                                           ` [PATCH 23/29] FAT: Remove the multiple MSDOS_SB() call OGAWA Hirofumi
2005-03-05 18:57                                             ` [PATCH 24/29] FAT: Remove unneed mark_inode_dirty() OGAWA Hirofumi
2005-03-05 18:57                                               ` [PATCH 25/29] FAT: Fix fat_truncate() OGAWA Hirofumi
2005-03-05 18:58                                                 ` [PATCH 26/29] FAT: Fix fat_write_inode() OGAWA Hirofumi
2005-03-05 18:58                                                   ` [PATCH 27/29] FAT: Use synchronous update for {vfat,msdos}_add_entry() OGAWA Hirofumi
2005-03-05 18:59                                                     ` OGAWA Hirofumi [this message]
2005-03-05 19:00                                                       ` [PATCH 29/29] FAT: Fix typo OGAWA Hirofumi
2005-03-06 22:44                                             ` [PATCH 23/29] FAT: Remove the multiple MSDOS_SB() call Christoph Hellwig
2005-03-07 22:01                                             ` Adrian Bunk
2005-03-08 13:48                                               ` OGAWA Hirofumi
2005-03-06 15:53     ` [PATCH 2/29] FAT: Updated FAT attributes patch Michael Geng
2005-03-06 17:02       ` OGAWA Hirofumi
2005-03-06 22:45       ` Christoph Hellwig
2005-03-06  0:07   ` [PATCH] FAT: Support synchronous updates OGAWA Hirofumi
2005-03-07  1:10 ` [PATCH] FAT: Support synchronous update Andrew Morton
2005-03-07 15:02   ` OGAWA Hirofumi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=878y51or55.fsf_-_@devron.myhome.or.jp \
    --to=hirofumi@mail.parknet.co.jp \
    --cc=akpm@osdl.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome