All of lore.kernel.org
 help / color / mirror / Atom feed
From: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	bug-track@fisher-privat.net
Subject: [PATCH 2/2] fat: mark fs as dirty on mount and clean on umount
Date: Fri, 28 Dec 2012 02:20:20 +0900	[thread overview]
Message-ID: <87han7za23.fsf@devron.myhome.or.jp> (raw)
In-Reply-To: <87pq1vza3y.fsf@devron.myhome.or.jp> (OGAWA Hirofumi's message of "Fri, 28 Dec 2012 02:19:13 +0900")


From: Oleksij Rempel <bug-track@fisher-privat.net>

There is no documented methods to mark FAT as dirty. Unofficially MS
started to use reserved Byte in boot sector for this purpose,
at least since Win 2000. With Win 7 user is warned if fs is dirty
and asked to clean it.
Different versions of Win, handle it in different ways,
but always have same meaning:
- Win 2000 and XP, set it on write operations and
  remove it after operation was finnished
- Win 7, set dirty flag on first write and remove it on umount.

We will do it as fallow:
- set dirty flag on mount. If fs was initially dirty, warn user,
  remember it and do not do any changes to boot sector.
- clean it on umount. If fs was initially dirty, leave it dirty.
- do not do any thing if fs mounted read-only.
- TODO: leave fs dirty if we found some error after mount.

patch history:
- v2. do not warn on read-only. Some style fixes.
- v3. make fat_set_state static.
- v4. add "force" variable to fat_set_state and use it on remount ro to rw.

Signed-off-by: Oleksij Rempel <bug-track@fisher-privat.net>
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---

 fs/fat/fat.h                  |    2 +
 fs/fat/inode.c                |   66 +++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/msdos_fs.h |    2 +
 3 files changed, 70 insertions(+)

diff -puN fs/fat/fat.h~fat-check-dirty-2 fs/fat/fat.h
--- linux/fs/fat/fat.h~fat-check-dirty-2	2012-12-28 02:17:42.000000000 +0900
+++ linux-hirofumi/fs/fat/fat.h	2012-12-28 02:17:42.000000000 +0900
@@ -95,6 +95,8 @@ struct msdos_sb_info {
 
 	spinlock_t dir_hash_lock;
 	struct hlist_head dir_hashtable[FAT_HASH_SIZE];
+
+	unsigned int dirty;           /* fs state before mount */
 };
 
 #define FAT_CACHE_VALID	0	/* special case for valid cache */
diff -puN fs/fat/inode.c~fat-check-dirty-2 fs/fat/inode.c
--- linux/fs/fat/inode.c~fat-check-dirty-2	2012-12-28 02:17:42.000000000 +0900
+++ linux-hirofumi/fs/fat/inode.c	2012-12-28 02:17:42.000000000 +0900
@@ -488,10 +488,59 @@ static void fat_evict_inode(struct inode
 	fat_detach(inode);
 }
 
+static void fat_set_state(struct super_block *sb,
+			unsigned int set, unsigned int force)
+{
+	struct buffer_head *bh;
+	struct fat_boot_sector *b;
+	struct msdos_sb_info *sbi = sb->s_fs_info;
+
+	/* do not change any thing if mounted read only */
+	if ((sb->s_flags & MS_RDONLY) && !force)
+		return;
+
+	/* do not change state if fs was dirty */
+	if (sbi->dirty) {
+		/* warn only on set (mount). */
+		if (set)
+			fat_msg(sb, KERN_WARNING, "Volume was not properly "
+				"unmounted. Some data may be corrupt. "
+				"Please run fsck.");
+		return;
+	}
+
+	bh = sb_bread(sb, 0);
+	if (bh == NULL) {
+		fat_msg(sb, KERN_ERR, "unable to read boot sector "
+			"to mark fs as dirty");
+		return;
+	}
+
+	b = (struct fat_boot_sector *) bh->b_data;
+
+	if (sbi->fat_bits == 32) {
+		if (set)
+			b->fat32.state |= FAT_STATE_DIRTY;
+		else
+			b->fat32.state &= ~FAT_STATE_DIRTY;
+	} else /* fat 16 and 12 */ {
+		if (set)
+			b->fat16.state |= FAT_STATE_DIRTY;
+		else
+			b->fat16.state &= ~FAT_STATE_DIRTY;
+	}
+
+	mark_buffer_dirty(bh);
+	sync_dirty_buffer(bh);
+	brelse(bh);
+}
+
 static void fat_put_super(struct super_block *sb)
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 
+	fat_set_state(sb, 0, 0);
+
 	iput(sbi->fsinfo_inode);
 	iput(sbi->fat_inode);
 
@@ -566,8 +615,18 @@ static void __exit fat_destroy_inodecach
 
 static int fat_remount(struct super_block *sb, int *flags, char *data)
 {
+	int new_rdonly;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	*flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME);
+
+	/* make sure we update state on remount. */
+	new_rdonly = *flags & MS_RDONLY;
+	if (new_rdonly != (sb->s_flags & MS_RDONLY)) {
+		if (new_rdonly)
+			fat_set_state(sb, 0, 0);
+		else
+			fat_set_state(sb, 1, 1);
+	}
 	return 0;
 }
 
@@ -1362,6 +1421,12 @@ int fat_fill_super(struct super_block *s
 	if (sbi->fat_bits != 32)
 		sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12;
 
+	/* some OSes set FAT_STATE_DIRTY and clean it on unmount. */
+	if (sbi->fat_bits == 32)
+		sbi->dirty = b->fat32.state & FAT_STATE_DIRTY;
+	else /* fat 16 or 12 */
+		sbi->dirty = b->fat16.state & FAT_STATE_DIRTY;
+
 	/* check that FAT table does not overflow */
 	fat_clusters = sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits;
 	total_clusters = min(total_clusters, fat_clusters - FAT_START_ENT);
@@ -1456,6 +1521,7 @@ int fat_fill_super(struct super_block *s
 					"the device does not support discard");
 	}
 
+	fat_set_state(sb, 1, 0);
 	return 0;
 
 out_invalid:
diff -puN include/uapi/linux/msdos_fs.h~fat-check-dirty-2 include/uapi/linux/msdos_fs.h
--- linux/include/uapi/linux/msdos_fs.h~fat-check-dirty-2	2012-12-28 02:17:42.000000000 +0900
+++ linux-hirofumi/include/uapi/linux/msdos_fs.h	2012-12-28 02:17:42.000000000 +0900
@@ -87,6 +87,8 @@
 #define IS_FSINFO(x)	(le32_to_cpu((x)->signature1) == FAT_FSINFO_SIG1 \
 			 && le32_to_cpu((x)->signature2) == FAT_FSINFO_SIG2)
 
+#define FAT_STATE_DIRTY 0x01
+
 struct __fat_dirent {
 	long		d_ino;
 	__kernel_off_t	d_off;
_

-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

  reply	other threads:[~2012-12-27 17:20 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-12-27 17:19 [PATCH 1/2] fat: add extended fileds to struct fat_boot_sector OGAWA Hirofumi
2012-12-27 17:20 ` OGAWA Hirofumi [this message]
2013-01-02 23:44   ` [PATCH 2/2] fat: mark fs as dirty on mount and clean on umount Andrew Morton
2013-01-03  8:46     ` Oleksij Rempel

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=87han7za23.fsf@devron.myhome.or.jp \
    --to=hirofumi@mail.parknet.co.jp \
    --cc=akpm@linux-foundation.org \
    --cc=bug-track@fisher-privat.net \
    --cc=linux-fsdevel@vger.kernel.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.