linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/29] fat: fix writev(), add aio support
       [not found] <87ll92rl6a.fsf@devron.myhome.or.jp>
@ 2005-03-05 18:41 ` OGAWA Hirofumi
  2005-03-05 18:42   ` [PATCH 2/29] FAT: Updated FAT attributes patch OGAWA Hirofumi
  2005-03-06  0:07   ` [PATCH] FAT: Support synchronous updates OGAWA Hirofumi
  2005-03-07  1:10 ` [PATCH] FAT: Support synchronous update Andrew Morton
  1 sibling, 2 replies; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:41 UTC (permalink / raw)
  To: linux-kernel, Andrew Morton


This patch fixes vectored write support on fat to do the nessecary
non-standard action done in write() aswell.

Also adds aio support and makes read/write wrappers around the aio
version.

 From: Christoph Hellwig <hch@lst.de>

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

 fs/fat/file.c |   31 ++++++++++++++++++++++++-------
 1 files changed, 24 insertions(+), 7 deletions(-)

diff -puN fs/fat/file.c~fat_support-aio fs/fat/file.c
--- linux-2.6.11/fs/fat/file.c~fat_support-aio	2005-03-06 02:17:05.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/file.c	2005-03-06 02:35:38.000000000 +0900
@@ -12,13 +12,28 @@
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 
-static ssize_t fat_file_write(struct file *filp, const char __user *buf,
-			      size_t count, loff_t *ppos)
+static ssize_t fat_file_aio_write(struct kiocb *iocb, const char __user *buf,
+				  size_t count, loff_t pos)
+{
+	struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
+	int retval;
+
+	retval = generic_file_aio_write(iocb, buf, count, pos);
+	if (retval > 0) {
+		inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+		MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+		mark_inode_dirty(inode);
+	}
+	return retval;
+}
+
+static ssize_t fat_file_writev(struct file *filp, const struct iovec *iov,
+			       unsigned long nr_segs, loff_t *ppos)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	int retval;
 
-	retval = generic_file_write(filp, buf, count, ppos);
+	retval = generic_file_writev(filp, iov, nr_segs, ppos);
 	if (retval > 0) {
 		inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
 		MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
@@ -29,12 +44,14 @@ static ssize_t fat_file_write(struct fil
 
 struct file_operations fat_file_operations = {
 	.llseek		= generic_file_llseek,
-	.read		= generic_file_read,
-	.write		= fat_file_write,
+	.read		= do_sync_read,
+	.write		= do_sync_write,
+	.readv		= generic_file_readv,
+	.writev		= fat_file_writev,
+	.aio_read	= generic_file_aio_read,
+	.aio_write	= fat_file_aio_write,
 	.mmap		= generic_file_mmap,
 	.fsync		= file_fsync,
-	.readv		= generic_file_readv,
-	.writev		= generic_file_writev,
 	.sendfile	= generic_file_sendfile,
 };
 
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 2/29] FAT: Updated FAT attributes patch
  2005-03-05 18:41 ` [PATCH 1/29] fat: fix writev(), add aio support OGAWA Hirofumi
@ 2005-03-05 18:42   ` OGAWA Hirofumi
  2005-03-05 18:43     ` [PATCH 3/29] FAT: fat_readdirx() with dotOK=yes fix OGAWA Hirofumi
  2005-03-06 15:53     ` [PATCH 2/29] FAT: Updated FAT attributes patch Michael Geng
  2005-03-06  0:07   ` [PATCH] FAT: Support synchronous updates OGAWA Hirofumi
  1 sibling, 2 replies; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:42 UTC (permalink / raw)
  To: linux-kernel, Andrew Morton


This updates the FAT attributes as well as (hopefully) corrects the 
handling of VFAT ctime.  The FAT attributes are implemented as a 32-bit 
ioctl, per the previous discussions.

Signed-Off-By: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---

 fs/fat/dir.c             |    2 
 fs/fat/file.c            |   99 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/fat/inode.c           |   38 ++++++++----------
 fs/vfat/namei.c          |    2 
 include/linux/msdos_fs.h |   22 +++++++---
 5 files changed, 135 insertions(+), 28 deletions(-)

diff -puN fs/fat/dir.c~fat_attribute-ioctl fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~fat_attribute-ioctl	2005-03-06 02:36:02.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:36:02.000000000 +0900
@@ -639,7 +639,7 @@ static int fat_dir_ioctl(struct inode * 
 		both = 1;
 		break;
 	default:
-		return -EINVAL;
+		return fat_generic_ioctl(inode, filp, cmd, arg);
 	}
 
 	d1 = (struct dirent __user *)arg;
diff -puN fs/fat/file.c~fat_attribute-ioctl fs/fat/file.c
--- linux-2.6.11/fs/fat/file.c~fat_attribute-ioctl	2005-03-06 02:36:02.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/file.c	2005-03-06 02:36:02.000000000 +0900
@@ -42,6 +42,104 @@ static ssize_t fat_file_writev(struct fi
 	return retval;
 }
 
+int fat_generic_ioctl(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+	u32 __user *user_attr = (u32 __user *)arg;
+
+	switch (cmd) {
+	case FAT_IOCTL_GET_ATTRIBUTES:
+	{
+		u32 attr;
+
+		if (inode->i_ino == MSDOS_ROOT_INO)
+			attr = ATTR_DIR;
+		else
+			attr = fat_attr(inode);
+
+		return put_user(attr, user_attr);
+	}
+	case FAT_IOCTL_SET_ATTRIBUTES:
+	{
+		u32 attr, oldattr;
+		int err, is_dir = S_ISDIR(inode->i_mode);
+		struct iattr ia;
+
+		err = get_user(attr, user_attr);
+		if (err)
+			return err;
+
+		down(&inode->i_sem);
+
+		if (IS_RDONLY(inode)) {
+			err = -EROFS;
+			goto up;
+		}
+
+		/*
+		 * ATTR_VOLUME and ATTR_DIR cannot be changed; this also
+		 * prevents the user from turning us into a VFAT
+		 * longname entry.  Also, we obviously can't set
+		 * any of the NTFS attributes in the high 24 bits.
+		 */
+		attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR);
+		/* Merge in ATTR_VOLUME and ATTR_DIR */
+		attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) |
+			(is_dir ? ATTR_DIR : 0);
+		oldattr = fat_attr(inode);
+
+		/* Equivalent to a chmod() */
+		ia.ia_valid = ATTR_MODE | ATTR_CTIME;
+		if (is_dir) {
+			ia.ia_mode = MSDOS_MKMODE(attr,
+				S_IRWXUGO & ~sbi->options.fs_dmask)
+				| S_IFDIR;
+		} else {
+			ia.ia_mode = MSDOS_MKMODE(attr,
+				(S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO))
+				& ~sbi->options.fs_fmask)
+				| S_IFREG;
+		}
+
+		/* The root directory has no attributes */
+		if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) {
+			err = -EINVAL;
+			goto up;
+		}
+
+		if (sbi->options.sys_immutable) {
+			if ((attr | oldattr) & ATTR_SYS) {
+				if (!capable(CAP_LINUX_IMMUTABLE)) {
+					err = -EPERM;
+					goto up;
+				}
+			}
+		}
+
+		/* This MUST be done before doing anything irreversible... */
+		err = notify_change(filp->f_dentry, &ia);
+		if (err)
+			goto up;
+
+		if (sbi->options.sys_immutable) {
+			if (attr & ATTR_SYS)
+				inode->i_flags |= S_IMMUTABLE;
+			else
+				inode->i_flags &= S_IMMUTABLE;
+		}
+
+		MSDOS_I(inode)->i_attrs = attr & ATTR_UNUSED;
+		mark_inode_dirty(inode);
+	up:
+		up(&inode->i_sem);
+		return err;
+	}
+	default:
+		return -ENOTTY;	/* Inappropriate ioctl for device */
+	}
+}
+
 struct file_operations fat_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= do_sync_read,
@@ -51,6 +149,7 @@ struct file_operations fat_file_operatio
 	.aio_read	= generic_file_aio_read,
 	.aio_write	= fat_file_aio_write,
 	.mmap		= generic_file_mmap,
+	.ioctl		= fat_generic_ioctl,
 	.fsync		= file_fsync,
 	.sendfile	= generic_file_sendfile,
 };
diff -puN fs/fat/inode.c~fat_attribute-ioctl fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~fat_attribute-ioctl	2005-03-06 02:36:02.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c	2005-03-06 02:36:02.000000000 +0900
@@ -220,8 +220,7 @@ static int fat_calc_dir_size(struct inod
 /* doesn't deal with root inode */
 static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
 {
-	struct super_block *sb = inode->i_sb;
-	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
 	int error;
 
 	MSDOS_I(inode)->i_pos = 0;
@@ -266,9 +265,10 @@ static int fat_fill_inode(struct inode *
 		inode->i_mapping->a_ops = &fat_aops;
 		MSDOS_I(inode)->mmu_private = inode->i_size;
 	}
-	if(de->attr & ATTR_SYS)
+	if (de->attr & ATTR_SYS) {
 		if (sbi->options.sys_immutable)
 			inode->i_flags |= S_IMMUTABLE;
+	}
 	MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
 	/* this is as close to the truth as we can get ... */
 	inode->i_blksize = sbi->cluster_size;
@@ -277,12 +277,15 @@ static int fat_fill_inode(struct inode *
 	inode->i_mtime.tv_sec = inode->i_atime.tv_sec =
 		date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date));
 	inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = 0;
-	inode->i_ctime.tv_sec =
-		MSDOS_SB(sb)->options.isvfat
-		? date_dos2unix(le16_to_cpu(de->ctime), le16_to_cpu(de->cdate))
-		: inode->i_mtime.tv_sec;
-	inode->i_ctime.tv_nsec = de->ctime_ms * 1000000;
-	MSDOS_I(inode)->i_ctime_ms = de->ctime_ms;
+	if (sbi->options.isvfat) {
+		int secs = de->ctime_cs / 100;
+		int csecs = de->ctime_cs % 100;
+		inode->i_ctime.tv_sec  =
+			date_dos2unix(le16_to_cpu(de->ctime),
+				      le16_to_cpu(de->cdate)) + secs;
+		inode->i_ctime.tv_nsec = csecs * 10000000;
+	} else
+		inode->i_ctime = inode->i_mtime;
 
 	return 0;
 }
@@ -483,22 +486,18 @@ retry:
 
 	raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
 	    [i_pos & (sbi->dir_per_block - 1)];
-	if (S_ISDIR(inode->i_mode)) {
-		raw_entry->attr = ATTR_DIR;
+	if (S_ISDIR(inode->i_mode))
 		raw_entry->size = 0;
-	}
-	else {
-		raw_entry->attr = ATTR_NONE;
+	else
 		raw_entry->size = cpu_to_le32(inode->i_size);
-	}
-	raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) |
-	    MSDOS_I(inode)->i_attrs;
+	raw_entry->attr = fat_attr(inode);
 	raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart);
 	raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16);
 	fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, &raw_entry->date);
 	if (sbi->options.isvfat) {
 		fat_date_unix2dos(inode->i_ctime.tv_sec,&raw_entry->ctime,&raw_entry->cdate);
-		raw_entry->ctime_ms = MSDOS_I(inode)->i_ctime_ms; /* use i_ctime.tv_nsec? */
+		raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 +
+			inode->i_ctime.tv_nsec / 10000000;
 	}
 	spin_unlock(&sbi->inode_hash_lock);
 	mark_buffer_dirty(bh);
@@ -1026,10 +1025,9 @@ static int fat_read_root(struct inode *i
 	MSDOS_I(inode)->i_logstart = 0;
 	MSDOS_I(inode)->mmu_private = inode->i_size;
 
-	MSDOS_I(inode)->i_attrs = 0;
+	MSDOS_I(inode)->i_attrs = ATTR_NONE;
 	inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0;
 	inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0;
-	MSDOS_I(inode)->i_ctime_ms = 0;
 	inode->i_nlink = fat_subdirs(inode)+2;
 
 	return 0;
diff -puN fs/vfat/namei.c~fat_attribute-ioctl fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~fat_attribute-ioctl	2005-03-06 02:36:02.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:36:02.000000000 +0900
@@ -649,7 +649,7 @@ shortname:
 	de->lcase = lcase;
 	de->adate = de->cdate = de->date = 0;
 	de->ctime = de->time = 0;
-	de->ctime_ms = 0;
+	de->ctime_cs = 0;
 	de->start = 0;
 	de->starthi = 0;
 	de->size = 0;
diff -puN include/linux/msdos_fs.h~fat_attribute-ioctl include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~fat_attribute-ioctl	2005-03-06 02:36:02.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:36:02.000000000 +0900
@@ -50,8 +50,6 @@
 #define MSDOS_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)
 /* Convert attribute bits and a mask to the UNIX mode. */
 #define MSDOS_MKMODE(a, m) (m & (a & ATTR_RO ? S_IRUGO|S_IXUGO : S_IRWXUGO))
-/* Convert the UNIX mode to MS-DOS attribute bits. */
-#define MSDOS_MKATTR(m)	((m & S_IWUGO) ? ATTR_NONE : ATTR_RO)
 
 #define MSDOS_NAME	11	/* maximum name length */
 #define MSDOS_LONGNAME	256	/* maximum name length */
@@ -100,8 +98,11 @@
 /*
  * ioctl commands
  */
-#define	VFAT_IOCTL_READDIR_BOTH		_IOR('r', 1, struct dirent [2])
-#define	VFAT_IOCTL_READDIR_SHORT	_IOR('r', 2, struct dirent [2])
+#define VFAT_IOCTL_READDIR_BOTH		_IOR('r', 1, struct dirent [2])
+#define VFAT_IOCTL_READDIR_SHORT	_IOR('r', 2, struct dirent [2])
+/* <linux/videotext.h> has used 0x72 ('r') in collision, so skip a few */
+#define FAT_IOCTL_GET_ATTRIBUTES	_IOR('r', 0x10, __u32)
+#define FAT_IOCTL_SET_ATTRIBUTES	_IOW('r', 0x11, __u32)
 
 /*
  * vfat shortname flags
@@ -152,7 +153,7 @@ struct msdos_dir_entry {
 	__u8	name[8],ext[3];	/* name and extension */
 	__u8	attr;		/* attribute bits */
 	__u8    lcase;		/* Case for base and extension */
-	__u8	ctime_ms;	/* Creation time, milliseconds */
+	__u8	ctime_cs;	/* Creation time, centiseconds (0-199) */
 	__le16	ctime;		/* Creation time */
 	__le16	cdate;		/* Creation date */
 	__le16	adate;		/* Last access date */
@@ -257,7 +258,6 @@ struct msdos_inode_info {
 	int i_start;		/* first cluster or 0 */
 	int i_logstart;		/* logical first cluster */
 	int i_attrs;		/* unused attribute bits */
-	int i_ctime_ms;		/* unused change time in milliseconds */
 	loff_t i_pos;		/* on-disk position of directory entry or 0 */
 	struct hlist_node i_fat_hash;	/* hash by i_location */
 	struct inode vfs_inode;
@@ -273,6 +273,14 @@ static inline struct msdos_inode_info *M
 	return container_of(inode, struct msdos_inode_info, vfs_inode);
 }
 
+/* Return the FAT attribute byte for this inode */
+static inline u8 fat_attr(struct inode *inode)
+{
+	return ((inode->i_mode & S_IWUGO) ? ATTR_NONE : ATTR_RO) |
+		(S_ISDIR(inode->i_mode) ? ATTR_DIR : ATTR_NONE) |
+		MSDOS_I(inode)->i_attrs;
+}
+
 static inline sector_t fat_clus_to_blknr(struct msdos_sb_info *sbi, int clus)
 {
 	return ((sector_t)clus - FAT_START_ENT) * sbi->sec_per_clus
@@ -328,6 +336,8 @@ extern int fat_scan(struct inode *dir, c
 		    struct msdos_dir_entry **res_de, loff_t *i_pos);
 
 /* fat/file.c */
+extern int fat_generic_ioctl(struct inode *inode, struct file *filp,
+			     unsigned int cmd, unsigned long arg);
 extern struct file_operations fat_file_operations;
 extern struct inode_operations fat_file_inode_operations;
 extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 3/29] FAT: fat_readdirx() with dotOK=yes fix
  2005-03-05 18:42   ` [PATCH 2/29] FAT: Updated FAT attributes patch OGAWA Hirofumi
@ 2005-03-05 18:43     ` OGAWA Hirofumi
  2005-03-05 18:43       ` [PATCH 4/29] let fat handle MS_SYNCHRONOUS flag OGAWA Hirofumi
  2005-03-05 18:44       ` [PATCH 5/29] FAT: Rewrite the FAT (File Allocation Table) access stuff OGAWA Hirofumi
  2005-03-06 15:53     ` [PATCH 2/29] FAT: Updated FAT attributes patch Michael Geng
  1 sibling, 2 replies; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:43 UTC (permalink / raw)
  To: linux-kernel, Andrew Morton


In the case of dotsOK, re-initialization of "ptname" pointer is needed,
otherwise, "ptname" is pointing the previous start position.

This fixes it.

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

 fs/fat/dir.c |   10 +++++++---
 1 files changed, 7 insertions(+), 3 deletions(-)

diff -puN fs/fat/dir.c~fat_readdirx-fix fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~fat_readdirx-fix	2005-03-06 02:36:05.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:36:05.000000000 +0900
@@ -442,9 +442,13 @@ ParseLong:
 			long_slots = 0;
 	}
 
-	if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
-		*ptname++ = '.';
-		dotoffset = 1;
+	if (MSDOS_SB(sb)->options.dotsOK) {
+		ptname = bufname;
+		dotoffset = 0;
+		if (de->attr & ATTR_HIDDEN) {
+			*ptname++ = '.';
+			dotoffset = 1;
+		}
 	}
 
 	memcpy(work, de->name, sizeof(de->name));
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 4/29] let fat handle MS_SYNCHRONOUS flag
  2005-03-05 18:43     ` [PATCH 3/29] FAT: fat_readdirx() with dotOK=yes fix OGAWA Hirofumi
@ 2005-03-05 18:43       ` OGAWA Hirofumi
  2005-03-06 22:38         ` Christoph Hellwig
  2005-03-05 18:44       ` [PATCH 5/29] FAT: Rewrite the FAT (File Allocation Table) access stuff OGAWA Hirofumi
  1 sibling, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:43 UTC (permalink / raw)
  To: linux-kernel, Andrew Morton


Adds MS_SYNCHRONOUS flag support.

Signed-off-by: Colin Leroy <colin@colino.net>
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---

 fs/fat/cache.c           |    8 ++++++++
 fs/fat/dir.c             |   26 +++++++++++++++++---------
 fs/fat/file.c            |    5 +++++
 fs/fat/inode.c           |   10 ++++++++++
 fs/fat/misc.c            |    2 ++
 fs/vfat/namei.c          |   31 ++++++++++++++++++++++++-------
 include/linux/msdos_fs.h |    1 +
 7 files changed, 67 insertions(+), 16 deletions(-)

diff -puN fs/fat/cache.c~sync03-fat_sync00 fs/fat/cache.c
--- linux-2.6.11/fs/fat/cache.c~sync03-fat_sync00	2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/cache.c	2005-03-06 02:36:08.000000000 +0900
@@ -269,8 +269,12 @@ static int __fat_access(struct super_blo
 				*p_last = (*p_last & 0xf0) | (new_value >> 8);
 			}
 			mark_buffer_dirty(bh2);
+			if (sb->s_flags & MS_SYNCHRONOUS)
+				sync_dirty_buffer(bh2);
 		}
 		mark_buffer_dirty(bh);
+		if (sb->s_flags & MS_SYNCHRONOUS)
+			sync_dirty_buffer(bh);
 		for (copy = 1; copy < sbi->fats; copy++) {
 			b = sbi->fat_start + (first >> sb->s_blocksize_bits)
 				+ sbi->fat_length * copy;
@@ -283,10 +287,14 @@ static int __fat_access(struct super_blo
 				}
 				memcpy(c_bh2->b_data, bh2->b_data, sb->s_blocksize);
 				mark_buffer_dirty(c_bh2);
+				if (sb->s_flags & MS_SYNCHRONOUS)
+					sync_dirty_buffer(c_bh2);
 				brelse(c_bh2);
 			}
 			memcpy(c_bh->b_data, bh->b_data, sb->s_blocksize);
 			mark_buffer_dirty(c_bh);
+			if (sb->s_flags & MS_SYNCHRONOUS)
+				sync_dirty_buffer(c_bh);
 			brelse(c_bh);
 		}
 	}
diff -puN fs/fat/dir.c~sync03-fat_sync00 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync03-fat_sync00	2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:36:08.000000000 +0900
@@ -778,6 +778,8 @@ static struct buffer_head *fat_extend_di
 			memset(bh->b_data, 0, sb->s_blocksize);
 			set_buffer_uptodate(bh);
 			mark_buffer_dirty(bh);
+			if (sb->s_flags & MS_SYNCHRONOUS)
+				sync_dirty_buffer(bh);
 			if (!res)
 				res = bh;
 			else
@@ -842,6 +844,7 @@ EXPORT_SYMBOL(fat_add_entries);
 
 int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
 {
+	struct super_block *sb = dir->i_sb;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 	__le16 date, time;
@@ -851,26 +854,31 @@ int fat_new_dir(struct inode *dir, struc
 		return PTR_ERR(bh);
 
 	/* zeroed out, so... */
-	fat_date_unix2dos(dir->i_mtime.tv_sec,&time,&date);
-	de = (struct msdos_dir_entry*)&bh->b_data[0];
-	memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
-	memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
+	fat_date_unix2dos(dir->i_mtime.tv_sec, &time, &date);
+	de = (struct msdos_dir_entry *)bh->b_data;
+	memcpy(de[0].name, MSDOS_DOT, MSDOS_NAME);
+	memcpy(de[1].name, MSDOS_DOTDOT, MSDOS_NAME);
 	de[0].attr = de[1].attr = ATTR_DIR;
 	de[0].time = de[1].time = time;
 	de[0].date = de[1].date = date;
-	if (is_vfat) {	/* extra timestamps */
+	if (is_vfat) {
+		/* extra timestamps */
 		de[0].ctime = de[1].ctime = time;
-		de[0].adate = de[0].cdate =
-			de[1].adate = de[1].cdate = date;
+		de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date;
 	}
 	de[0].start = cpu_to_le16(MSDOS_I(dir)->i_logstart);
-	de[0].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart>>16);
+	de[0].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart >> 16);
 	de[1].start = cpu_to_le16(MSDOS_I(parent)->i_logstart);
-	de[1].starthi = cpu_to_le16(MSDOS_I(parent)->i_logstart>>16);
+	de[1].starthi = cpu_to_le16(MSDOS_I(parent)->i_logstart >> 16);
 	mark_buffer_dirty(bh);
+	if (sb->s_flags & MS_SYNCHRONOUS)
+		sync_dirty_buffer(bh);
 	brelse(bh);
+
 	dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
 	mark_inode_dirty(dir);
+	if (IS_SYNC(dir))
+		fat_sync_inode(dir);
 
 	return 0;
 }
diff -puN fs/fat/file.c~sync03-fat_sync00 fs/fat/file.c
--- linux-2.6.11/fs/fat/file.c~sync03-fat_sync00	2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/file.c	2005-03-06 02:36:08.000000000 +0900
@@ -23,6 +23,9 @@ static ssize_t fat_file_aio_write(struct
 		inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
 		MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 		mark_inode_dirty(inode);
+//		check the locking rules
+//		if (IS_SYNC(inode))
+//			fat_sync_inode(inode);
 	}
 	return retval;
 }
@@ -288,6 +291,8 @@ void fat_truncate(struct inode *inode)
 	unlock_kernel();
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
 	mark_inode_dirty(inode);
+	if (IS_SYNC(inode))
+		fat_sync_inode(inode);
 }
 
 struct inode_operations fat_file_inode_operations = {
diff -puN fs/fat/inode.c~sync03-fat_sync00 fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~sync03-fat_sync00	2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c	2005-03-06 02:36:08.000000000 +0900
@@ -501,11 +501,21 @@ retry:
 	}
 	spin_unlock(&sbi->inode_hash_lock);
 	mark_buffer_dirty(bh);
+	if (wait)
+		sync_dirty_buffer(bh);
 	brelse(bh);
 	unlock_kernel();
+
 	return 0;
 }
 
+int fat_sync_inode(struct inode *inode)
+{
+	return fat_write_inode(inode, 1);
+}
+
+EXPORT_SYMBOL(fat_sync_inode);
+
 static int fat_show_options(struct seq_file *m, struct vfsmount *mnt);
 static struct super_operations fat_sops = {
 	.alloc_inode	= fat_alloc_inode,
diff -puN fs/fat/misc.c~sync03-fat_sync00 fs/fat/misc.c
--- linux-2.6.11/fs/fat/misc.c~sync03-fat_sync00	2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/misc.c	2005-03-06 02:36:08.000000000 +0900
@@ -75,6 +75,8 @@ void fat_clusters_flush(struct super_blo
 		if (sbi->prev_free != -1)
 			fsinfo->next_cluster = cpu_to_le32(sbi->prev_free);
 		mark_buffer_dirty(bh);
+		if (sb->s_flags & MS_SYNCHRONOUS)
+			sync_dirty_buffer(bh);
 	}
 	brelse(bh);
 }
diff -puN fs/vfat/namei.c~sync03-fat_sync00 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync03-fat_sync00	2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:36:08.000000000 +0900
@@ -663,6 +663,7 @@ static int vfat_add_entry(struct inode *
 			  int is_dir, struct vfat_slot_info *sinfo_out,
 			  struct buffer_head **bh, struct msdos_dir_entry **de)
 {
+	struct super_block *sb = dir->i_sb;
 	struct msdos_dir_slot *dir_slots;
 	loff_t offset;
 	int res, slots, slot;
@@ -702,6 +703,8 @@ static int vfat_add_entry(struct inode *
 		}
 		memcpy(*de, dir_slots + slot, sizeof(struct msdos_dir_slot));
 		mark_buffer_dirty(*bh);
+		if (sb->s_flags & MS_SYNCHRONOUS)
+			sync_dirty_buffer(*bh);
 	}
 
 	res = 0;
@@ -713,8 +716,9 @@ static int vfat_add_entry(struct inode *
 	dir->i_mtime.tv_nsec = 0;
 	(*de)->ctime = (*de)->time;
 	(*de)->adate = (*de)->cdate = (*de)->date;
-
 	mark_buffer_dirty(*bh);
+	if (sb->s_flags & MS_SYNCHRONOUS)
+		sync_dirty_buffer(*bh);
 
 	/* slots can't be less than 1 */
 	sinfo_out->long_slots = slots - 1;
@@ -820,9 +824,12 @@ static int vfat_create(struct inode *dir
 	if (!inode)
 		goto out;
 	res = 0;
+	inode->i_version++;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
 	mark_inode_dirty(inode);
-	inode->i_version++;
+	if (IS_SYNC(inode))
+		fat_sync_inode(inode);
+
 	dir->i_version++;
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry, inode);
@@ -835,15 +842,20 @@ static void vfat_remove_entry(struct ino
 			      struct buffer_head *bh,
 			      struct msdos_dir_entry *de)
 {
+	struct super_block *sb = dir->i_sb;
 	loff_t offset, i_pos;
 	int i;
 
-	/* remove the shortname */
 	dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
 	dir->i_version++;
 	mark_inode_dirty(dir);
+
+	/* remove the shortname */
 	de->name[0] = DELETED_FLAG;
 	mark_buffer_dirty(bh);
+	if (sb->s_flags & MS_SYNCHRONOUS)
+		sync_dirty_buffer(bh);
+
 	/* remove the longname */
 	offset = sinfo->longname_offset;
 	de = NULL;
@@ -853,6 +865,8 @@ static void vfat_remove_entry(struct ino
 		de->name[0] = DELETED_FLAG;
 		de->attr = ATTR_NONE;
 		mark_buffer_dirty(bh);
+		if (sb->s_flags & MS_SYNCHRONOUS)
+			sync_dirty_buffer(bh);
 	}
 	brelse(bh);
 }
@@ -879,7 +893,7 @@ static int vfat_rmdir(struct inode *dir,
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 	mark_inode_dirty(inode);
-	/* releases bh */
+	/* releases bh and syncs it if necessary */
 	vfat_remove_entry(dir, &sinfo, bh, de);
 	dir->i_nlink--;
 out:
@@ -903,7 +917,7 @@ static int vfat_unlink(struct inode *dir
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 	mark_inode_dirty(inode);
-	/* releases bh */
+	/* releases bh and syncs it if necessary */
 	vfat_remove_entry(dir, &sinfo, bh, de);
 out:
 	unlock_kernel();
@@ -949,7 +963,7 @@ mkdir_failed:
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 	mark_inode_dirty(inode);
-	/* releases bh */
+	/* releases bh ands syncs if necessary */
 	vfat_remove_entry(dir, &sinfo, bh, de);
 	iput(inode);
 	dir->i_nlink--;
@@ -1027,8 +1041,11 @@ static int vfat_rename(struct inode *old
 	if (is_dir) {
 		int start = MSDOS_I(new_dir)->i_logstart;
 		dotdot_de->start = cpu_to_le16(start);
-		dotdot_de->starthi = cpu_to_le16(start>>16);
+		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);
+
 		old_dir->i_nlink--;
 		if (new_inode) {
 			new_inode->i_nlink--;
diff -puN include/linux/msdos_fs.h~sync03-fat_sync00 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync03-fat_sync00	2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:36:08.000000000 +0900
@@ -349,6 +349,7 @@ extern void fat_detach(struct inode *ino
 extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos);
 extern struct inode *fat_build_inode(struct super_block *sb,
 			struct msdos_dir_entry *de, loff_t i_pos, int *res);
+extern int fat_sync_inode(struct inode *inode);
 int fat_fill_super(struct super_block *sb, void *data, int silent,
 		   struct inode_operations *fs_dir_inode_ops, int isvfat);
 
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 5/29] FAT: Rewrite the FAT (File Allocation Table) access stuff
  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-05 18:44       ` OGAWA Hirofumi
  2005-03-05 18:45         ` [PATCH 6/29] FAT: add debugging code to fatent.c OGAWA Hirofumi
  1 sibling, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:44 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


In order not to write the same block repeatedly, rewrite the FAT entry
access stuff.

And this separates the "allocate the cluster" and "link to cluster
chain" operations for expanding the file/dir safely.
(fat_alloc_clusters() allocates the cluster, and fat_chain_add() links
allocated cluster to the chain which inode has.)

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

 fs/fat/Makefile          |    2 
 fs/fat/cache.c           |  145 +----------
 fs/fat/dir.c             |   15 -
 fs/fat/fatent.c          |  590 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/fat/file.c            |   69 ++---
 fs/fat/inode.c           |   60 ++--
 fs/fat/misc.c            |  122 ++++-----
 include/linux/msdos_fs.h |   57 +++-
 8 files changed, 781 insertions(+), 279 deletions(-)

diff -puN fs/fat/Makefile~sync05-fat_dep-fatent fs/fat/Makefile
--- linux-2.6.11/fs/fat/Makefile~sync05-fat_dep-fatent	2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/Makefile	2005-03-06 02:36:12.000000000 +0900
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_FAT_FS) += fat.o
 
-fat-objs := cache.o dir.o file.o inode.o misc.o
+fat-objs := cache.o dir.o fatent.o file.o inode.o misc.o
diff -puN fs/fat/cache.c~sync05-fat_dep-fatent fs/fat/cache.c
--- linux-2.6.11/fs/fat/cache.c~sync05-fat_dep-fatent	2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/cache.c	2005-03-06 02:36:12.000000000 +0900
@@ -203,132 +203,6 @@ void fat_cache_inval_inode(struct inode 
 	spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
 }
 
-static int __fat_access(struct super_block *sb, int nr, int new_value)
-{
-	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	struct buffer_head *bh, *bh2, *c_bh, *c_bh2;
-	unsigned char *p_first, *p_last;
-	int copy, first, last, next, b;
-
-	if (sbi->fat_bits == 32) {
-		first = last = nr*4;
-	} else if (sbi->fat_bits == 16) {
-		first = last = nr*2;
-	} else {
-		first = nr*3/2;
-		last = first+1;
-	}
-	b = sbi->fat_start + (first >> sb->s_blocksize_bits);
-	if (!(bh = sb_bread(sb, b))) {
-		printk(KERN_ERR "FAT: bread(block %d) in"
-		       " fat_access failed\n", b);
-		return -EIO;
-	}
-	if ((first >> sb->s_blocksize_bits) == (last >> sb->s_blocksize_bits)) {
-		bh2 = bh;
-	} else {
-		if (!(bh2 = sb_bread(sb, b + 1))) {
-			brelse(bh);
-			printk(KERN_ERR "FAT: bread(block %d) in"
-			       " fat_access failed\n", b + 1);
-			return -EIO;
-		}
-	}
-	if (sbi->fat_bits == 32) {
-		p_first = p_last = NULL; /* GCC needs that stuff */
-		next = le32_to_cpu(((__le32 *) bh->b_data)[(first &
-		    (sb->s_blocksize - 1)) >> 2]);
-		/* Fscking Microsoft marketing department. Their "32" is 28. */
-		next &= 0x0fffffff;
-	} else if (sbi->fat_bits == 16) {
-		p_first = p_last = NULL; /* GCC needs that stuff */
-		next = le16_to_cpu(((__le16 *) bh->b_data)[(first &
-		    (sb->s_blocksize - 1)) >> 1]);
-	} else {
-		p_first = &((__u8 *)bh->b_data)[first & (sb->s_blocksize - 1)];
-		p_last = &((__u8 *)bh2->b_data)[(first + 1) & (sb->s_blocksize - 1)];
-		if (nr & 1)
-			next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff;
-		else
-			next = (*p_first+(*p_last << 8)) & 0xfff;
-	}
-	if (new_value != -1) {
-		if (sbi->fat_bits == 32) {
-			((__le32 *)bh->b_data)[(first & (sb->s_blocksize - 1)) >> 2]
-				= cpu_to_le32(new_value);
-		} else if (sbi->fat_bits == 16) {
-			((__le16 *)bh->b_data)[(first & (sb->s_blocksize - 1)) >> 1]
-				= cpu_to_le16(new_value);
-		} else {
-			if (nr & 1) {
-				*p_first = (*p_first & 0xf) | (new_value << 4);
-				*p_last = new_value >> 4;
-			}
-			else {
-				*p_first = new_value & 0xff;
-				*p_last = (*p_last & 0xf0) | (new_value >> 8);
-			}
-			mark_buffer_dirty(bh2);
-			if (sb->s_flags & MS_SYNCHRONOUS)
-				sync_dirty_buffer(bh2);
-		}
-		mark_buffer_dirty(bh);
-		if (sb->s_flags & MS_SYNCHRONOUS)
-			sync_dirty_buffer(bh);
-		for (copy = 1; copy < sbi->fats; copy++) {
-			b = sbi->fat_start + (first >> sb->s_blocksize_bits)
-				+ sbi->fat_length * copy;
-			if (!(c_bh = sb_bread(sb, b)))
-				break;
-			if (bh != bh2) {
-				if (!(c_bh2 = sb_bread(sb, b+1))) {
-					brelse(c_bh);
-					break;
-				}
-				memcpy(c_bh2->b_data, bh2->b_data, sb->s_blocksize);
-				mark_buffer_dirty(c_bh2);
-				if (sb->s_flags & MS_SYNCHRONOUS)
-					sync_dirty_buffer(c_bh2);
-				brelse(c_bh2);
-			}
-			memcpy(c_bh->b_data, bh->b_data, sb->s_blocksize);
-			mark_buffer_dirty(c_bh);
-			if (sb->s_flags & MS_SYNCHRONOUS)
-				sync_dirty_buffer(c_bh);
-			brelse(c_bh);
-		}
-	}
-	brelse(bh);
-	if (bh != bh2)
-		brelse(bh2);
-	return next;
-}
-
-/*
- * Returns the this'th FAT entry, -1 if it is an end-of-file entry. If
- * new_value is != -1, that FAT entry is replaced by it.
- */
-int fat_access(struct super_block *sb, int nr, int new_value)
-{
-	int next;
-
-	next = -EIO;
-	if (nr < FAT_START_ENT || MSDOS_SB(sb)->max_cluster <= nr) {
-		fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", nr);
-		goto out;
-	}
-	if (new_value == FAT_ENT_EOF)
-		new_value = EOF_FAT(sb);
-
-	next = __fat_access(sb, nr, new_value);
-	if (next < 0)
-		goto out;
-	if (next >= BAD_FAT(sb))
-		next = FAT_ENT_EOF;
-out:
-	return next;
-}
-
 static inline int cache_contiguous(struct fat_cache_id *cid, int dclus)
 {
 	cid->nr_contig++;
@@ -347,6 +221,7 @@ int fat_get_cluster(struct inode *inode,
 {
 	struct super_block *sb = inode->i_sb;
 	const int limit = sb->s_maxbytes >> MSDOS_SB(sb)->cluster_bits;
+	struct fat_entry fatent;
 	struct fat_cache_id cid;
 	int nr;
 
@@ -365,34 +240,40 @@ int fat_get_cluster(struct inode *inode,
 		cache_init(&cid, -1, -1);
 	}
 
+	fatent_init(&fatent);
 	while (*fclus < cluster) {
 		/* prevent the infinite loop of cluster chain */
 		if (*fclus > limit) {
 			fat_fs_panic(sb, "%s: detected the cluster chain loop"
 				     " (i_pos %lld)", __FUNCTION__,
 				     MSDOS_I(inode)->i_pos);
-			return -EIO;
+			nr = -EIO;
+			goto out;
 		}
 
-		nr = fat_access(sb, *dclus, -1);
+		nr = fat_ent_read(inode, &fatent, *dclus);
 		if (nr < 0)
-			return nr;
+			goto out;
 		else if (nr == FAT_ENT_FREE) {
 			fat_fs_panic(sb, "%s: invalid cluster chain"
 				     " (i_pos %lld)", __FUNCTION__,
 				     MSDOS_I(inode)->i_pos);
-			return -EIO;
+			nr = -EIO;
+			goto out;
 		} else if (nr == FAT_ENT_EOF) {
 			fat_cache_add(inode, &cid);
-			return FAT_ENT_EOF;
+			goto out;
 		}
 		(*fclus)++;
 		*dclus = nr;
 		if (!cache_contiguous(&cid, *dclus))
 			cache_init(&cid, *fclus, *dclus);
 	}
+	nr = 0;
 	fat_cache_add(inode, &cid);
-	return 0;
+out:
+	fatent_brelse(&fatent);
+	return nr;
 }
 
 static int fat_bmap_cluster(struct inode *inode, int cluster)
diff -puN fs/fat/dir.c~sync05-fat_dep-fatent fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync05-fat_dep-fatent	2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:36:12.000000000 +0900
@@ -759,7 +759,7 @@ static struct buffer_head *fat_extend_di
 {
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *bh, *res = NULL;
-	int nr, sec_per_clus = MSDOS_SB(sb)->sec_per_clus;
+	int err, cluster, sec_per_clus = MSDOS_SB(sb)->sec_per_clus;
 	sector_t sector, last_sector;
 
 	if (MSDOS_SB(sb)->fat_bits != 32) {
@@ -767,11 +767,16 @@ static struct buffer_head *fat_extend_di
 			return ERR_PTR(-ENOSPC);
 	}
 
-	nr = fat_add_cluster(inode);
-	if (nr < 0)
-		return ERR_PTR(nr);
+	err = fat_alloc_clusters(inode, &cluster, 1);
+	if (err)
+		return ERR_PTR(err);
+	err = fat_chain_add(inode, cluster, 1);
+	if (err) {
+		fat_free_clusters(inode, cluster);
+		return ERR_PTR(err);
+	}
 
-	sector = fat_clus_to_blknr(MSDOS_SB(sb), nr);
+	sector = fat_clus_to_blknr(MSDOS_SB(sb), cluster);
 	last_sector = sector + sec_per_clus;
 	for ( ; sector < last_sector; sector++) {
 		if ((bh = sb_getblk(sb, sector))) {
diff -puN /dev/null fs/fat/fatent.c
--- /dev/null	2004-09-13 22:36:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/fatent.c	2005-03-06 02:36:12.000000000 +0900
@@ -0,0 +1,590 @@
+/*
+ * Copyright (C) 2004, OGAWA Hirofumi
+ * Released under GPL v2.
+ */
+
+#include <linux/fs.h>
+#include <linux/msdos_fs.h>
+
+struct fatent_operations {
+	void (*ent_blocknr)(struct super_block *, int, int *, sector_t *);
+	void (*ent_set_ptr)(struct fat_entry *, int);
+	int (*ent_bread)(struct super_block *, struct fat_entry *,
+			 int, sector_t);
+	int (*ent_get)(struct fat_entry *);
+	void (*ent_put)(struct fat_entry *, int);
+	int (*ent_next)(struct fat_entry *);
+};
+
+static void fat12_ent_blocknr(struct super_block *sb, int entry,
+			      int *offset, sector_t *blocknr)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	int bytes = entry + (entry >> 1);
+	*offset = bytes & (sb->s_blocksize - 1);
+	*blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
+}
+
+static void fat_ent_blocknr(struct super_block *sb, int entry,
+			    int *offset, sector_t *blocknr)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	int bytes = (entry << sbi->fatent_shift);
+	*offset = bytes & (sb->s_blocksize - 1);
+	*blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
+}
+
+static void fat12_ent_set_ptr(struct fat_entry *fatent, int offset)
+{
+	struct buffer_head **bhs = fatent->bhs;
+	if (fatent->nr_bhs == 1) {
+		fatent->u.ent12_p[0] = bhs[0]->b_data + offset;
+		fatent->u.ent12_p[1] = bhs[0]->b_data + (offset + 1);
+	} else {
+		fatent->u.ent12_p[0] = bhs[0]->b_data + offset;
+		fatent->u.ent12_p[1] = bhs[1]->b_data;
+	}
+}
+
+static void fat16_ent_set_ptr(struct fat_entry *fatent, int offset)
+{
+	fatent->u.ent16_p = (__le16 *)(fatent->bhs[0]->b_data + offset);
+}
+
+static void fat32_ent_set_ptr(struct fat_entry *fatent, int offset)
+{
+	fatent->u.ent32_p = (__le32 *)(fatent->bhs[0]->b_data + offset);
+}
+
+static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent,
+			   int offset, sector_t blocknr)
+{
+	struct buffer_head **bhs = fatent->bhs;
+
+	bhs[0] = sb_bread(sb, blocknr);
+	if (!bhs[0])
+		goto err;
+
+	if ((offset + 1) < sb->s_blocksize)
+		fatent->nr_bhs = 1;
+	else {
+		/* This entry is block boundary, it needs the next block */
+		blocknr++;
+		bhs[1] = sb_bread(sb, blocknr);
+		if (!bhs[1])
+			goto err_brelse;
+		fatent->nr_bhs = 2;
+	}
+	fat12_ent_set_ptr(fatent, offset);
+	return 0;
+
+err_brelse:
+	brelse(bhs[0]);
+err:
+	printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n",
+	       (unsigned long long)blocknr);
+	return -EIO;
+}
+
+static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent,
+			 int offset, sector_t blocknr)
+{
+	struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+
+	fatent->bhs[0] = sb_bread(sb, blocknr);
+	if (!fatent->bhs[0]) {
+		printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n",
+		       (unsigned long long)blocknr);
+		return -EIO;
+	}
+	fatent->nr_bhs = 1;
+	ops->ent_set_ptr(fatent, offset);
+	return 0;
+}
+
+static int fat12_ent_get(struct fat_entry *fatent)
+{
+	u8 **ent12_p = fatent->u.ent12_p;
+	int next;
+
+	if (fatent->entry & 1)
+		next = (*ent12_p[0] >> 4) | (*ent12_p[1] << 4);
+	else
+		next = (*ent12_p[1] << 8) | *ent12_p[0];
+	next &= 0x0fff;
+	if (next >= BAD_FAT12)
+		next = FAT_ENT_EOF;
+	return next;
+}
+
+static int fat16_ent_get(struct fat_entry *fatent)
+{
+	int next = le16_to_cpu(*fatent->u.ent16_p);
+	if (next >= BAD_FAT16)
+		next = FAT_ENT_EOF;
+	return next;
+}
+
+static int fat32_ent_get(struct fat_entry *fatent)
+{
+	int next = le32_to_cpu(*fatent->u.ent32_p) & 0x0fffffff;
+	if (next >= BAD_FAT32)
+		next = FAT_ENT_EOF;
+	return next;
+}
+
+static void fat12_ent_put(struct fat_entry *fatent, int new)
+{
+	u8 **ent12_p = fatent->u.ent12_p;
+
+	if (new == FAT_ENT_EOF)
+		new = EOF_FAT12;
+
+	if (fatent->entry & 1) {
+		*ent12_p[0] = (new << 4) | (*ent12_p[0] & 0x0f);
+		*ent12_p[1] = new >> 4;
+	} else {
+		*ent12_p[0] = new & 0xff;
+		*ent12_p[1] = (*ent12_p[1] & 0xf0) | (new >> 8);
+	}
+
+	mark_buffer_dirty(fatent->bhs[0]);
+	if (fatent->nr_bhs == 2)
+		mark_buffer_dirty(fatent->bhs[1]);
+}
+
+static void fat16_ent_put(struct fat_entry *fatent, int new)
+{
+	if (new == FAT_ENT_EOF)
+		new = EOF_FAT16;
+
+	*fatent->u.ent16_p = cpu_to_le16(new);
+	mark_buffer_dirty(fatent->bhs[0]);
+}
+
+static void fat32_ent_put(struct fat_entry *fatent, int new)
+{
+	if (new == FAT_ENT_EOF)
+		new = EOF_FAT32;
+
+	new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff;
+	*fatent->u.ent32_p = cpu_to_le32(new);
+	mark_buffer_dirty(fatent->bhs[0]);
+}
+
+static int fat12_ent_next(struct fat_entry *fatent)
+{
+	u8 **ent12_p = fatent->u.ent12_p;
+	struct buffer_head **bhs = fatent->bhs;
+	u8 *nextp = ent12_p[1] + 1 + (fatent->entry & 1);
+
+	fatent->entry++;
+	if (fatent->nr_bhs == 1) {
+		if (nextp < (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))) {
+			ent12_p[0] = nextp - 1;
+			ent12_p[1] = nextp;
+			return 1;
+		}
+	} else {
+		ent12_p[0] = nextp - 1;
+		ent12_p[1] = nextp;
+		brelse(bhs[0]);
+		bhs[0] = bhs[1];
+		fatent->nr_bhs = 1;
+		return 1;
+	}
+	return 0;
+}
+
+static int fat16_ent_next(struct fat_entry *fatent)
+{
+	const struct buffer_head *bh = fatent->bhs[0];
+	fatent->entry++;
+	if (fatent->u.ent16_p < (__le16 *)(bh->b_data + (bh->b_size - 2))) {
+		fatent->u.ent16_p++;
+		return 1;
+	}
+	return 0;
+}
+
+static int fat32_ent_next(struct fat_entry *fatent)
+{
+	const struct buffer_head *bh = fatent->bhs[0];
+	fatent->entry++;
+	if (fatent->u.ent32_p < (__le32 *)(bh->b_data + (bh->b_size - 4))) {
+		fatent->u.ent32_p++;
+		return 1;
+	}
+	return 0;
+}
+
+static struct fatent_operations fat12_ops = {
+	.ent_blocknr	= fat12_ent_blocknr,
+	.ent_set_ptr	= fat12_ent_set_ptr,
+	.ent_bread	= fat12_ent_bread,
+	.ent_get	= fat12_ent_get,
+	.ent_put	= fat12_ent_put,
+	.ent_next	= fat12_ent_next,
+};
+
+static struct fatent_operations fat16_ops = {
+	.ent_blocknr	= fat_ent_blocknr,
+	.ent_set_ptr	= fat16_ent_set_ptr,
+	.ent_bread	= fat_ent_bread,
+	.ent_get	= fat16_ent_get,
+	.ent_put	= fat16_ent_put,
+	.ent_next	= fat16_ent_next,
+};
+
+static struct fatent_operations fat32_ops = {
+	.ent_blocknr	= fat_ent_blocknr,
+	.ent_set_ptr	= fat32_ent_set_ptr,
+	.ent_bread	= fat_ent_bread,
+	.ent_get	= fat32_ent_get,
+	.ent_put	= fat32_ent_put,
+	.ent_next	= fat32_ent_next,
+};
+
+static inline void lock_fat(struct msdos_sb_info *sbi)
+{
+	down(&sbi->fat_lock);
+}
+
+static inline void unlock_fat(struct msdos_sb_info *sbi)
+{
+	up(&sbi->fat_lock);
+}
+
+void fat_ent_access_init(struct super_block *sb)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+
+	init_MUTEX(&sbi->fat_lock);
+
+	switch (sbi->fat_bits) {
+	case 32:
+		sbi->fatent_shift = 2;
+		sbi->fatent_ops = &fat32_ops;
+		break;
+	case 16:
+		sbi->fatent_shift = 1;
+		sbi->fatent_ops = &fat16_ops;
+		break;
+	case 12:
+		sbi->fatent_shift = -1;
+		sbi->fatent_ops = &fat12_ops;
+		break;
+	}
+}
+
+static inline int fat_ent_update_ptr(struct super_block *sb,
+				     struct fat_entry *fatent,
+				     int offset, sector_t blocknr)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct fatent_operations *ops = sbi->fatent_ops;
+	struct buffer_head **bhs = fatent->bhs;
+
+	/* Is this fatent's blocks including this entry? */
+	if (!fatent->nr_bhs || bhs[0]->b_blocknr != blocknr)
+		return 0;
+	/* Does this entry need the next block? */
+	if (sbi->fat_bits == 12 && (offset + 1) >= sb->s_blocksize) {
+		if (fatent->nr_bhs != 2 || bhs[1]->b_blocknr != (blocknr + 1))
+			return 0;
+	}
+	ops->ent_set_ptr(fatent, offset);
+	return 1;
+}
+
+int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry)
+{
+	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+	struct fatent_operations *ops = sbi->fatent_ops;
+	int err, offset;
+	sector_t blocknr;
+
+	if (entry < FAT_START_ENT || sbi->max_cluster <= entry) {
+		fatent_brelse(fatent);
+		fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", entry);
+		return -EIO;
+	}
+
+	fatent_set_entry(fatent, entry);
+	ops->ent_blocknr(sb, entry, &offset, &blocknr);
+
+	if (!fat_ent_update_ptr(sb, fatent, offset, blocknr)) {
+		fatent_brelse(fatent);
+		err = ops->ent_bread(sb, fatent, offset, blocknr);
+		if (err)
+			return err;
+	}
+	return ops->ent_get(fatent);
+}
+
+static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs,
+			  int nr_bhs)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct buffer_head *c_bh;
+	int err, n, copy;
+
+	err = 0;
+	for (copy = 1; copy < sbi->fats; copy++) {
+		sector_t backup_fat = sbi->fat_length * copy;
+
+		for (n = 0; n < nr_bhs; n++) {
+			c_bh = sb_getblk(sb, backup_fat + bhs[n]->b_blocknr);
+			if (!c_bh) {
+				err = -ENOMEM;
+				goto error;
+			}
+			memcpy(c_bh->b_data, bhs[n]->b_data, sb->s_blocksize);
+			set_buffer_uptodate(c_bh);
+			mark_buffer_dirty(c_bh);
+			if (sb->s_flags & MS_SYNCHRONOUS)
+				err = sync_dirty_buffer(c_bh);
+			brelse(c_bh);
+			if (err)
+				goto error;
+		}
+	}
+error:
+	return err;
+}
+
+int fat_ent_write(struct inode *inode, struct fat_entry *fatent,
+		  int new, int wait)
+{
+	struct super_block *sb = inode->i_sb;
+	struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+	int err;
+
+	ops->ent_put(fatent, new);
+	if (wait) {
+		err = fat_sync_bhs(fatent->bhs, fatent->nr_bhs);
+		if (err)
+			return err;
+	}
+	return fat_mirror_bhs(sb, fatent->bhs, fatent->nr_bhs);
+}
+
+static inline int fat_ent_next(struct msdos_sb_info *sbi,
+			       struct fat_entry *fatent)
+{
+	if (sbi->fatent_ops->ent_next(fatent)) {
+		if (fatent->entry < sbi->max_cluster)
+			return 1;
+	}
+	return 0;
+}
+
+static inline int fat_ent_read_block(struct super_block *sb,
+				     struct fat_entry *fatent)
+{
+	struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+	sector_t blocknr;
+	int offset;
+
+	fatent_brelse(fatent);
+	ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr);
+	return ops->ent_bread(sb, fatent, offset, blocknr);
+}
+
+static void fat_collect_bhs(struct buffer_head **bhs, int *nr_bhs,
+			    struct fat_entry *fatent)
+{
+	int n, i;
+
+	for (n = 0; n < fatent->nr_bhs; n++) {
+		for (i = 0; i < *nr_bhs; i++) {
+			if (fatent->bhs[n] == bhs[i])
+				break;
+		}
+		if (i == *nr_bhs) {
+			get_bh(fatent->bhs[n]);
+			bhs[i] = fatent->bhs[n];
+			(*nr_bhs)++;
+		}
+	}
+}
+
+int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
+{
+	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct fatent_operations *ops = sbi->fatent_ops;
+	struct fat_entry fatent, prev_ent;
+	struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+	int i, count, err, nr_bhs, idx_clus;
+
+	BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2));	/* fixed limit */
+
+	lock_fat(sbi);
+	if (sbi->free_clusters != -1 && sbi->free_clusters < nr_cluster) {
+		unlock_fat(sbi);
+		return -ENOSPC;
+	}
+
+	err = nr_bhs = idx_clus = 0;
+	count = FAT_START_ENT;
+	fatent_init(&prev_ent);
+	fatent_init(&fatent);
+	fatent_set_entry(&fatent, sbi->prev_free + 1);
+	while (count < sbi->max_cluster) {
+		fatent.entry %= sbi->max_cluster;
+		if (fatent.entry < FAT_START_ENT)
+			fatent.entry = FAT_START_ENT;
+		fatent_set_entry(&fatent, fatent.entry);
+		err = fat_ent_read_block(sb, &fatent);
+		if (err)
+			goto out;
+
+		/* Find the free entries in a block */
+		do {
+			if (ops->ent_get(&fatent) == FAT_ENT_FREE) {
+				int entry = fatent.entry;
+
+				/* make the cluster chain */
+				ops->ent_put(&fatent, FAT_ENT_EOF);
+				if (prev_ent.nr_bhs)
+					ops->ent_put(&prev_ent, entry);
+
+				fat_collect_bhs(bhs, &nr_bhs, &fatent);
+
+				sbi->prev_free = entry;
+				if (sbi->free_clusters != -1)
+					sbi->free_clusters--;
+
+				cluster[idx_clus] = entry;
+				idx_clus++;
+				if (idx_clus == nr_cluster)
+					goto out;
+
+				/*
+				 * fat_collect_bhs() gets ref-count of bhs,
+				 * so we can still use the prev_ent.
+				 */
+				prev_ent = fatent;
+			}
+			count++;
+			if (count == sbi->max_cluster)
+				break;
+		} while (fat_ent_next(sbi, &fatent));
+	}
+
+	/* Couldn't allocate the free entries */
+	sbi->free_clusters = 0;
+	err = -ENOSPC;
+
+out:
+	unlock_fat(sbi);
+	fatent_brelse(&fatent);
+	if (!err) {
+		if (inode_needs_sync(inode))
+			err = fat_sync_bhs(bhs, nr_bhs);
+		if (!err)
+			err = fat_mirror_bhs(sb, bhs, nr_bhs);
+	}
+	for (i = 0; i < nr_bhs; i++)
+		brelse(bhs[i]);
+	fat_clusters_flush(sb);
+
+	if (err && idx_clus)
+		fat_free_clusters(inode, cluster[0]);
+
+	return err;
+}
+
+int fat_free_clusters(struct inode *inode, int cluster)
+{
+	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct fatent_operations *ops = sbi->fatent_ops;
+	struct fat_entry fatent;
+	struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+	int i, err, nr_bhs;
+
+	nr_bhs = 0;
+	fatent_init(&fatent);
+	lock_fat(sbi);
+	do {
+		cluster = fat_ent_read(inode, &fatent, cluster);
+		if (cluster < 0) {
+			err = cluster;
+			goto error;
+		} else if (cluster == FAT_ENT_FREE) {
+			fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF",
+				     __FUNCTION__);
+			err = -EIO;
+			goto error;
+		}
+
+		ops->ent_put(&fatent, FAT_ENT_FREE);
+		if (sbi->free_clusters != -1)
+			sbi->free_clusters++;
+
+		if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) {
+			if (sb->s_flags & MS_SYNCHRONOUS) {
+				err = fat_sync_bhs(bhs, nr_bhs);
+				if (err)
+					goto error;
+			}
+			err = fat_mirror_bhs(sb, bhs, nr_bhs);
+			if (err)
+				goto error;
+			for (i = 0; i < nr_bhs; i++)
+				brelse(bhs[i]);
+			nr_bhs = 0;
+		}
+		fat_collect_bhs(bhs, &nr_bhs, &fatent);
+	} while (cluster != FAT_ENT_EOF);
+
+	if (sb->s_flags & MS_SYNCHRONOUS) {
+		err = fat_sync_bhs(bhs, nr_bhs);
+		if (err)
+			goto error;
+	}
+	err = fat_mirror_bhs(sb, bhs, nr_bhs);
+error:
+	fatent_brelse(&fatent);
+	for (i = 0; i < nr_bhs; i++)
+		brelse(bhs[i]);
+	unlock_fat(sbi);
+
+	fat_clusters_flush(sb);
+
+	return err;
+}
+
+int fat_count_free_clusters(struct super_block *sb)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct fatent_operations *ops = sbi->fatent_ops;
+	struct fat_entry fatent;
+	int err = 0, free;
+
+	lock_fat(sbi);
+	if (sbi->free_clusters != -1)
+		goto out;
+
+	free = 0;
+	fatent_init(&fatent);
+	fatent_set_entry(&fatent, FAT_START_ENT);
+	while (fatent.entry < sbi->max_cluster) {
+		err = fat_ent_read_block(sb, &fatent);
+		if (err)
+			goto out;
+
+		do {
+			if (ops->ent_get(&fatent) == FAT_ENT_FREE)
+				free++;
+		} while (fat_ent_next(sbi, &fatent));
+	}
+	sbi->free_clusters = free;
+	fatent_brelse(&fatent);
+out:
+	unlock_fat(sbi);
+	return err;
+}
diff -puN fs/fat/file.c~sync05-fat_dep-fatent fs/fat/file.c
--- linux-2.6.11/fs/fat/file.c~sync05-fat_dep-fatent	2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/file.c	2005-03-06 02:36:12.000000000 +0900
@@ -212,62 +212,63 @@ EXPORT_SYMBOL(fat_notify_change);
 static int fat_free(struct inode *inode, int skip)
 {
 	struct super_block *sb = inode->i_sb;
-	int nr, ret, fclus, dclus;
+	int ret, wait;
 
 	if (MSDOS_I(inode)->i_start == 0)
 		return 0;
 
+	/*
+	 * Write a new EOF, and get the remaining cluster chain for freeing.
+	 */
+	wait = IS_DIRSYNC(inode);
 	if (skip) {
+		struct fat_entry fatent;
+		int fclus, dclus;
+
 		ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus);
 		if (ret < 0)
 			return ret;
 		else if (ret == FAT_ENT_EOF)
 			return 0;
 
-		nr = fat_access(sb, dclus, -1);
-		if (nr == FAT_ENT_EOF)
+		fatent_init(&fatent);
+		ret = fat_ent_read(inode, &fatent, dclus);
+		if (ret == FAT_ENT_EOF) {
+			fatent_brelse(&fatent);
 			return 0;
-		else if (nr > 0) {
-			/*
-			 * write a new EOF, and get the remaining cluster
-			 * chain for freeing.
-			 */
-			nr = fat_access(sb, dclus, FAT_ENT_EOF);
+		} else if (ret == FAT_ENT_FREE) {
+			fat_fs_panic(sb,
+				     "%s: invalid cluster chain (i_pos %lld)",
+				     __FUNCTION__, MSDOS_I(inode)->i_pos);
+			ret = -EIO;
+		} else if (ret > 0) {
+			int err = fat_ent_write(inode, &fatent, FAT_ENT_EOF,
+						wait);
+			if (err)
+				ret = err;
 		}
-		if (nr < 0)
-			return nr;
+		fatent_brelse(&fatent);
+		if (ret < 0)
+			return ret;
 
 		fat_cache_inval_inode(inode);
 	} else {
 		fat_cache_inval_inode(inode);
 
-		nr = MSDOS_I(inode)->i_start;
+		ret = MSDOS_I(inode)->i_start;
 		MSDOS_I(inode)->i_start = 0;
 		MSDOS_I(inode)->i_logstart = 0;
-		mark_inode_dirty(inode);
+		if (wait) {
+			int err = fat_sync_inode(inode);
+			if (err)
+				return err;
+		} else
+			mark_inode_dirty(inode);
 	}
+	inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);
 
-	lock_fat(sb);
-	do {
-		nr = fat_access(sb, nr, FAT_ENT_FREE);
-		if (nr < 0)
-			goto error;
-		else if (nr == FAT_ENT_FREE) {
-			fat_fs_panic(sb, "%s: deleting beyond EOF (i_pos %lld)",
-				     __FUNCTION__, MSDOS_I(inode)->i_pos);
-			nr = -EIO;
-			goto error;
-		}
-		if (MSDOS_SB(sb)->free_clusters != -1)
-			MSDOS_SB(sb)->free_clusters++;
-		inode->i_blocks -= MSDOS_SB(sb)->cluster_size >> 9;
-	} while (nr != FAT_ENT_EOF);
-	fat_clusters_flush(sb);
-	nr = 0;
-error:
-	unlock_fat(sb);
-
-	return nr;
+	/* Freeing the remained cluster chain */
+	return fat_free_clusters(inode, ret);
 }
 
 void fat_truncate(struct inode *inode)
diff -puN fs/fat/inode.c~sync05-fat_dep-fatent fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~sync05-fat_dep-fatent	2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c	2005-03-06 02:36:12.000000000 +0900
@@ -33,6 +33,21 @@ static int fat_default_codepage = CONFIG
 static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET;
 
 
+static int fat_add_cluster(struct inode *inode)
+{
+	int err, cluster;
+
+	err = fat_alloc_clusters(inode, &cluster, 1);
+	if (err)
+		return err;
+	/* FIXME: this cluster should be added after data of this
+	 * cluster is writed */
+	err = fat_chain_add(inode, cluster, 1);
+	if (err)
+		fat_free_clusters(inode, cluster);
+	return err;
+}
+
 static int fat_get_block(struct inode *inode, sector_t iblock,
 			 struct buffer_head *bh_result, int create)
 {
@@ -55,11 +70,9 @@ static int fat_get_block(struct inode *i
 		return -EIO;
 	}
 	if (!((unsigned long)iblock & (MSDOS_SB(sb)->sec_per_clus - 1))) {
-		int error;
-
-		error = fat_add_cluster(inode);
-		if (error < 0)
-			return error;
+		err = fat_add_cluster(inode);
+		if (err)
+			return err;
 	}
 	MSDOS_I(inode)->mmu_private += sb->s_blocksize;
 	err = fat_bmap(inode, iblock, &phys);
@@ -423,34 +436,19 @@ static int fat_remount(struct super_bloc
 static int fat_statfs(struct super_block *sb, struct kstatfs *buf)
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	int free, nr, ret;
 
-	if (sbi->free_clusters != -1)
-		free = sbi->free_clusters;
-	else {
-		lock_fat(sb);
-		if (sbi->free_clusters != -1)
-			free = sbi->free_clusters;
-		else {
-			free = 0;
-			for (nr = FAT_START_ENT; nr < sbi->max_cluster; nr++) {
-				ret = fat_access(sb, nr, -1);
-				if (ret < 0) {
-					unlock_fat(sb);
-					return ret;
-				} else if (ret == FAT_ENT_FREE)
-					free++;
-			}
-			sbi->free_clusters = free;
-		}
-		unlock_fat(sb);
+	/* If the count of free cluster is still unknown, counts it here. */
+	if (sbi->free_clusters == -1) {
+		int err = fat_count_free_clusters(sb);
+		if (err)
+			return err;
 	}
 
 	buf->f_type = sb->s_magic;
 	buf->f_bsize = sbi->cluster_size;
 	buf->f_blocks = sbi->max_cluster - FAT_START_ENT;
-	buf->f_bfree = free;
-	buf->f_bavail = free;
+	buf->f_bfree = sbi->free_clusters;
+	buf->f_bavail = sbi->free_clusters;
 	buf->f_namelen = sbi->options.isvfat ? 260 : 12;
 
 	return 0;
@@ -1076,10 +1074,6 @@ int fat_fill_super(struct super_block *s
 	if (error)
 		goto out_fail;
 
-	/* set up enough so that it can read an inode */
-	fat_hash_init(sb);
-	init_MUTEX(&sbi->fat_lock);
-
 	error = -EIO;
 	sb_min_blocksize(sb, 512);
 	bh = sb_bread(sb, 0);
@@ -1256,6 +1250,10 @@ int fat_fill_super(struct super_block *s
 
 	brelse(bh);
 
+	/* set up enough so that it can read an inode */
+	fat_hash_init(sb);
+	fat_ent_access_init(sb);
+
 	/*
 	 * The low byte of FAT's first entry must have same value with
 	 * media-field.  But in real world, too many devices is
diff -puN fs/fat/misc.c~sync05-fat_dep-fatent fs/fat/misc.c
--- linux-2.6.11/fs/fat/misc.c~sync05-fat_dep-fatent	2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/misc.c	2005-03-06 02:36:12.000000000 +0900
@@ -33,16 +33,6 @@ void fat_fs_panic(struct super_block *s,
 	}
 }
 
-void lock_fat(struct super_block *sb)
-{
-	down(&(MSDOS_SB(sb)->fat_lock));
-}
-
-void unlock_fat(struct super_block *sb)
-{
-	up(&(MSDOS_SB(sb)->fat_lock));
-}
-
 /* 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)
@@ -82,26 +72,22 @@ void fat_clusters_flush(struct super_blo
 }
 
 /*
- * fat_add_cluster tries to allocate a new cluster and adds it to the
- * file represented by inode.
+ * fat_chain_add() adds a new cluster to the chain of clusters represented
+ * by inode.
  */
-int fat_add_cluster(struct inode *inode)
+int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
 {
 	struct super_block *sb = inode->i_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	int ret, count, limit, new_dclus, new_fclus, last;
-	int cluster_bits = sbi->cluster_bits;
+	int ret, new_fclus, last;
 
 	/*
 	 * We must locate the last cluster of the file to add this new
 	 * one (new_dclus) to the end of the link list (the FAT).
-	 *
-	 * In order to confirm that the cluster chain is valid, we
-	 * find out EOF first.
 	 */
 	last = new_fclus = 0;
 	if (MSDOS_I(inode)->i_start) {
-		int ret, fclus, dclus;
+		int fclus, dclus;
 
 		ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus);
 		if (ret < 0)
@@ -110,66 +96,42 @@ int fat_add_cluster(struct inode *inode)
 		last = dclus;
 	}
 
-	/* find free FAT entry */
-	lock_fat(sb);
-
-	if (sbi->free_clusters == 0) {
-		unlock_fat(sb);
-		return -ENOSPC;
-	}
-
-	limit = sbi->max_cluster;
-	new_dclus = sbi->prev_free + 1;
-	for (count = FAT_START_ENT; count < limit; count++, new_dclus++) {
-		new_dclus = new_dclus % limit;
-		if (new_dclus < FAT_START_ENT)
-			new_dclus = FAT_START_ENT;
-
-		ret = fat_access(sb, new_dclus, -1);
-		if (ret < 0) {
-			unlock_fat(sb);
-			return ret;
-		} else if (ret == FAT_ENT_FREE)
-			break;
-	}
-	if (count >= limit) {
-		sbi->free_clusters = 0;
-		unlock_fat(sb);
-		return -ENOSPC;
-	}
-
-	ret = fat_access(sb, new_dclus, FAT_ENT_EOF);
-	if (ret < 0) {
-		unlock_fat(sb);
-		return ret;
-	}
-
-	sbi->prev_free = new_dclus;
-	if (sbi->free_clusters != -1)
-		sbi->free_clusters--;
-	fat_clusters_flush(sb);
-
-	unlock_fat(sb);
-
 	/* add new one to the last of the cluster chain */
 	if (last) {
-		ret = fat_access(sb, last, new_dclus);
+		struct fat_entry fatent;
+
+		fatent_init(&fatent);
+		ret = fat_ent_read(inode, &fatent, last);
+		if (ret >= 0) {
+			int wait = inode_needs_sync(inode);
+			ret = fat_ent_write(inode, &fatent, new_dclus, wait);
+			fatent_brelse(&fatent);
+		}
 		if (ret < 0)
 			return ret;
 //		fat_cache_add(inode, new_fclus, new_dclus);
 	} else {
 		MSDOS_I(inode)->i_start = new_dclus;
 		MSDOS_I(inode)->i_logstart = new_dclus;
-		mark_inode_dirty(inode);
+		/*
+		 * Since generic_osync_inode() synchronize later if
+		 * this is not directory, we don't here.
+		 */
+		if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) {
+			ret = fat_sync_inode(inode);
+			if (ret)
+				return ret;
+		} else
+			mark_inode_dirty(inode);
 	}
-	if (new_fclus != (inode->i_blocks >> (cluster_bits - 9))) {
+	if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) {
 		fat_fs_panic(sb, "clusters badly computed (%d != %lu)",
-			new_fclus, inode->i_blocks >> (cluster_bits - 9));
+			new_fclus, inode->i_blocks >> (sbi->cluster_bits - 9));
 		fat_cache_inval_inode(inode);
 	}
-	inode->i_blocks += sbi->cluster_size >> 9;
+	inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9);
 
-	return new_dclus;
+	return 0;
 }
 
 extern struct timezone sys_tz;
@@ -281,3 +243,31 @@ next:
 }
 
 EXPORT_SYMBOL(fat__get_entry);
+
+int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
+{
+	int i, e, err = 0;
+
+	for (i = 0; i < nr_bhs; i++) {
+		lock_buffer(bhs[i]);
+		if (test_clear_buffer_dirty(bhs[i])) {
+			get_bh(bhs[i]);
+			bhs[i]->b_end_io = end_buffer_write_sync;
+			e = submit_bh(WRITE, bhs[i]);
+			if (!err && e)
+				err = e;
+		} else
+			unlock_buffer(bhs[i]);
+	}
+	for (i = 0; i < nr_bhs; i++) {
+		wait_on_buffer(bhs[i]);
+		if (buffer_eopnotsupp(bhs[i])) {
+			clear_buffer_eopnotsupp(bhs[i]);
+			err = -EOPNOTSUPP;
+		} else if (!err && !buffer_uptodate(bhs[i]))
+			err = -EIO;
+	}
+	return err;
+}
+
+EXPORT_SYMBOL(fat_sync_bhs);
diff -puN include/linux/msdos_fs.h~sync05-fat_dep-fatent include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync05-fat_dep-fatent	2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:36:12.000000000 +0900
@@ -76,15 +76,11 @@
 #define BAD_FAT12	0xFF7
 #define BAD_FAT16	0xFFF7
 #define BAD_FAT32	0x0FFFFFF7
-#define BAD_FAT(s)	(MSDOS_SB(s)->fat_bits == 32 ? BAD_FAT32 : \
-	MSDOS_SB(s)->fat_bits == 16 ? BAD_FAT16 : BAD_FAT12)
 
 /* standard EOF */
 #define EOF_FAT12	0xFFF
 #define EOF_FAT16	0xFFFF
 #define EOF_FAT32	0x0FFFFFFF
-#define EOF_FAT(s)	(MSDOS_SB(s)->fat_bits == 32 ? EOF_FAT32 : \
-	MSDOS_SB(s)->fat_bits == 16 ? EOF_FAT16 : EOF_FAT12)
 
 #define FAT_ENT_FREE	(0)
 #define FAT_ENT_BAD	(BAD_FAT32)
@@ -238,6 +234,9 @@ struct msdos_sb_info {
 	int dir_per_block;	     /* dir entries per block */
 	int dir_per_block_bits;	     /* log2(dir_per_block) */
 
+	int fatent_shift;
+	struct fatent_operations *fatent_ops;
+
 	spinlock_t inode_hash_lock;
 	struct hlist_head inode_hashtable[FAT_HASH_SIZE];
 };
@@ -315,7 +314,6 @@ static inline void fatwchar_to16(__u8 *d
 
 /* fat/cache.c */
 extern void fat_cache_inval_inode(struct inode *inode);
-extern int fat_access(struct super_block *sb, int nr, int new_value);
 extern int fat_get_cluster(struct inode *inode, int cluster,
 			   int *fclus, int *dclus);
 extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys);
@@ -335,6 +333,46 @@ extern int fat_scan(struct inode *dir, c
 		    struct buffer_head **res_bh,
 		    struct msdos_dir_entry **res_de, loff_t *i_pos);
 
+/* fat/fatent.c */
+struct fat_entry {
+	int entry;
+	union {
+		u8 *ent12_p[2];
+		__le16 *ent16_p;
+		__le32 *ent32_p;
+	} u;
+	int nr_bhs;
+	struct buffer_head *bhs[2];
+};
+
+static inline void fatent_init(struct fat_entry *fatent)
+{
+	fatent->nr_bhs = 0;
+}
+
+static inline void fatent_set_entry(struct fat_entry *fatent, int entry)
+{
+	fatent->entry = entry;
+}
+
+static inline void fatent_brelse(struct fat_entry *fatent)
+{
+	int i;
+	for (i = 0; i < fatent->nr_bhs; i++)
+		brelse(fatent->bhs[i]);
+	fatent->nr_bhs = 0;
+}
+
+extern void fat_ent_access_init(struct super_block *sb);
+extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent,
+			int entry);
+extern int fat_ent_write(struct inode *inode, struct fat_entry *fatent,
+			 int new, int wait);
+extern int fat_alloc_clusters(struct inode *inode, int *cluster,
+			      int nr_cluster);
+extern int fat_free_clusters(struct inode *inode, int cluster);
+extern int fat_count_free_clusters(struct super_block *sb);
+
 /* fat/file.c */
 extern int fat_generic_ioctl(struct inode *inode, struct file *filp,
 			     unsigned int cmd, unsigned long arg);
@@ -350,15 +388,13 @@ extern struct inode *fat_iget(struct sup
 extern struct inode *fat_build_inode(struct super_block *sb,
 			struct msdos_dir_entry *de, loff_t i_pos, int *res);
 extern int fat_sync_inode(struct inode *inode);
-int fat_fill_super(struct super_block *sb, void *data, int silent,
-		   struct inode_operations *fs_dir_inode_ops, int isvfat);
+extern int fat_fill_super(struct super_block *sb, void *data, int silent,
+			struct inode_operations *fs_dir_inode_ops, int isvfat);
 
 /* fat/misc.c */
 extern void fat_fs_panic(struct super_block *s, const char *fmt, ...);
-extern void lock_fat(struct super_block *sb);
-extern void unlock_fat(struct super_block *sb);
 extern void fat_clusters_flush(struct super_block *sb);
-extern int fat_add_cluster(struct inode *inode);
+extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
 extern int date_dos2unix(unsigned short time, unsigned short date);
 extern void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date);
 extern int fat__get_entry(struct inode *dir, loff_t *pos,
@@ -378,6 +414,7 @@ static __inline__ int fat_get_entry(stru
 	}
 	return fat__get_entry(dir, pos, bh, de, i_pos);
 }
+extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
 
 #endif /* __KERNEL__ */
 
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 6/29] FAT: add debugging code to fatent.c
  2005-03-05 18:44       ` [PATCH 5/29] FAT: Rewrite the FAT (File Allocation Table) access stuff OGAWA Hirofumi
@ 2005-03-05 18:45         ` OGAWA Hirofumi
  2005-03-05 18:47           ` [PATCH 7/29] FAT: Use "unsigned int" for ->free_clusters and ->prev_free OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:45 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


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

 fs/fat/fatent.c          |   20 ++++++++++++++++++++
 include/linux/msdos_fs.h |    6 ++++++
 2 files changed, 26 insertions(+)

diff -puN fs/fat/fatent.c~sync05-fat_dep-fatent-debug fs/fat/fatent.c
--- linux-2.6.11/fs/fat/fatent.c~sync05-fat_dep-fatent-debug	2005-03-06 02:36:16.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/fatent.c	2005-03-06 02:36:16.000000000 +0900
@@ -21,6 +21,7 @@ static void fat12_ent_blocknr(struct sup
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	int bytes = entry + (entry >> 1);
+	WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry);
 	*offset = bytes & (sb->s_blocksize - 1);
 	*blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
 }
@@ -30,6 +31,7 @@ static void fat_ent_blocknr(struct super
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	int bytes = (entry << sbi->fatent_shift);
+	WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry);
 	*offset = bytes & (sb->s_blocksize - 1);
 	*blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
 }
@@ -38,9 +40,11 @@ static void fat12_ent_set_ptr(struct fat
 {
 	struct buffer_head **bhs = fatent->bhs;
 	if (fatent->nr_bhs == 1) {
+		WARN_ON(offset >= (bhs[0]->b_size - 1));
 		fatent->u.ent12_p[0] = bhs[0]->b_data + offset;
 		fatent->u.ent12_p[1] = bhs[0]->b_data + (offset + 1);
 	} else {
+		WARN_ON(offset != (bhs[0]->b_size - 1));
 		fatent->u.ent12_p[0] = bhs[0]->b_data + offset;
 		fatent->u.ent12_p[1] = bhs[1]->b_data;
 	}
@@ -48,11 +52,13 @@ static void fat12_ent_set_ptr(struct fat
 
 static void fat16_ent_set_ptr(struct fat_entry *fatent, int offset)
 {
+	WARN_ON(offset & (2 - 1));
 	fatent->u.ent16_p = (__le16 *)(fatent->bhs[0]->b_data + offset);
 }
 
 static void fat32_ent_set_ptr(struct fat_entry *fatent, int offset)
 {
+	WARN_ON(offset & (4 - 1));
 	fatent->u.ent32_p = (__le32 *)(fatent->bhs[0]->b_data + offset);
 }
 
@@ -61,6 +67,7 @@ static int fat12_ent_bread(struct super_
 {
 	struct buffer_head **bhs = fatent->bhs;
 
+	WARN_ON(blocknr < MSDOS_SB(sb)->fat_start);
 	bhs[0] = sb_bread(sb, blocknr);
 	if (!bhs[0])
 		goto err;
@@ -91,6 +98,7 @@ static int fat_ent_bread(struct super_bl
 {
 	struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
 
+	WARN_ON(blocknr < MSDOS_SB(sb)->fat_start);
 	fatent->bhs[0] = sb_bread(sb, blocknr);
 	if (!fatent->bhs[0]) {
 		printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n",
@@ -120,6 +128,7 @@ static int fat12_ent_get(struct fat_entr
 static int fat16_ent_get(struct fat_entry *fatent)
 {
 	int next = le16_to_cpu(*fatent->u.ent16_p);
+	WARN_ON((unsigned long)fatent->u.ent16_p & (2 - 1));
 	if (next >= BAD_FAT16)
 		next = FAT_ENT_EOF;
 	return next;
@@ -128,6 +137,7 @@ static int fat16_ent_get(struct fat_entr
 static int fat32_ent_get(struct fat_entry *fatent)
 {
 	int next = le32_to_cpu(*fatent->u.ent32_p) & 0x0fffffff;
+	WARN_ON((unsigned long)fatent->u.ent32_p & (4 - 1));
 	if (next >= BAD_FAT32)
 		next = FAT_ENT_EOF;
 	return next;
@@ -167,6 +177,7 @@ static void fat32_ent_put(struct fat_ent
 	if (new == FAT_ENT_EOF)
 		new = EOF_FAT32;
 
+	WARN_ON(new & 0xf0000000);
 	new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff;
 	*fatent->u.ent32_p = cpu_to_le32(new);
 	mark_buffer_dirty(fatent->bhs[0]);
@@ -180,12 +191,16 @@ static int fat12_ent_next(struct fat_ent
 
 	fatent->entry++;
 	if (fatent->nr_bhs == 1) {
+		WARN_ON(ent12_p[0] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 2)));
+		WARN_ON(ent12_p[1] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1)));
 		if (nextp < (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))) {
 			ent12_p[0] = nextp - 1;
 			ent12_p[1] = nextp;
 			return 1;
 		}
 	} else {
+		WARN_ON(ent12_p[0] != (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1)));
+		WARN_ON(ent12_p[1] != (u8 *)bhs[1]->b_data);
 		ent12_p[0] = nextp - 1;
 		ent12_p[1] = nextp;
 		brelse(bhs[0]);
@@ -193,6 +208,8 @@ static int fat12_ent_next(struct fat_ent
 		fatent->nr_bhs = 1;
 		return 1;
 	}
+	ent12_p[0] = NULL;
+	ent12_p[1] = NULL;
 	return 0;
 }
 
@@ -204,6 +221,7 @@ static int fat16_ent_next(struct fat_ent
 		fatent->u.ent16_p++;
 		return 1;
 	}
+	fatent->u.ent16_p = NULL;
 	return 0;
 }
 
@@ -215,6 +233,7 @@ static int fat32_ent_next(struct fat_ent
 		fatent->u.ent32_p++;
 		return 1;
 	}
+	fatent->u.ent32_p = NULL;
 	return 0;
 }
 
@@ -323,6 +342,7 @@ int fat_ent_read(struct inode *inode, st
 	return ops->ent_get(fatent);
 }
 
+/* FIXME: We can write the blocks as more big chunk. */
 static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs,
 			  int nr_bhs)
 {
diff -puN include/linux/msdos_fs.h~sync05-fat_dep-fatent-debug include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync05-fat_dep-fatent-debug	2005-03-06 02:36:16.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:36:16.000000000 +0900
@@ -348,19 +348,25 @@ struct fat_entry {
 static inline void fatent_init(struct fat_entry *fatent)
 {
 	fatent->nr_bhs = 0;
+	fatent->entry = 0;
+	fatent->u.ent32_p = NULL;
+	fatent->bhs[0] = fatent->bhs[1] = NULL;
 }
 
 static inline void fatent_set_entry(struct fat_entry *fatent, int entry)
 {
 	fatent->entry = entry;
+	fatent->u.ent32_p = NULL;
 }
 
 static inline void fatent_brelse(struct fat_entry *fatent)
 {
 	int i;
+	fatent->u.ent32_p = NULL;
 	for (i = 0; i < fatent->nr_bhs; i++)
 		brelse(fatent->bhs[i]);
 	fatent->nr_bhs = 0;
+	fatent->bhs[0] = fatent->bhs[1] = NULL;
 }
 
 extern void fat_ent_access_init(struct super_block *sb);
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 7/29] FAT: Use "unsigned int" for ->free_clusters and ->prev_free
  2005-03-05 18:45         ` [PATCH 6/29] FAT: add debugging code to fatent.c OGAWA Hirofumi
@ 2005-03-05 18:47           ` OGAWA Hirofumi
  2005-03-05 18:47             ` [PATCH 8/29] FAT: "struct vfat_slot_info" cleanup OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:47 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


This changes ->free_clusters and ->prev_free from "int" to "unsigned int".
These value should be never negative value (but it's using 0xffffffff(-1)
as undefined state).

With this changes, fatfs would handle the corruption of free_clusters
more proper.

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

 fs/fat/fatent.c          |    3 +--
 fs/fat/inode.c           |    6 +++++-
 include/linux/msdos_fs.h |    4 ++--
 3 files changed, 8 insertions(+), 5 deletions(-)

diff -puN fs/fat/fatent.c~sync05-fat_free-unsigned fs/fat/fatent.c
--- linux-2.6.11/fs/fat/fatent.c~sync05-fat_free-unsigned	2005-03-06 02:36:19.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/fatent.c	2005-03-06 02:36:19.000000000 +0900
@@ -453,8 +453,7 @@ int fat_alloc_clusters(struct inode *ino
 	fatent_init(&fatent);
 	fatent_set_entry(&fatent, sbi->prev_free + 1);
 	while (count < sbi->max_cluster) {
-		fatent.entry %= sbi->max_cluster;
-		if (fatent.entry < FAT_START_ENT)
+		if (fatent.entry >= sbi->max_cluster)
 			fatent.entry = FAT_START_ENT;
 		fatent_set_entry(&fatent, fatent.entry);
 		err = fat_ent_read_block(sb, &fatent);
diff -puN fs/fat/inode.c~sync05-fat_free-unsigned fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~sync05-fat_free-unsigned	2005-03-06 02:36:19.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c	2005-03-06 02:36:19.000000000 +0900
@@ -1163,7 +1163,7 @@ int fat_fill_super(struct super_block *s
 	sbi->fat_length = le16_to_cpu(b->fat_length);
 	sbi->root_cluster = 0;
 	sbi->free_clusters = -1;	/* Don't know yet */
-	sbi->prev_free = -1;
+	sbi->prev_free = FAT_START_ENT;
 
 	if (!sbi->fat_length && b->fat32_length) {
 		struct fat_boot_fsinfo *fsinfo;
@@ -1247,6 +1247,10 @@ int fat_fill_super(struct super_block *s
 	/* check the free_clusters, it's not necessarily correct */
 	if (sbi->free_clusters != -1 && sbi->free_clusters > total_clusters)
 		sbi->free_clusters = -1;
+	/* check the prev_free, it's not necessarily correct */
+	sbi->prev_free %= sbi->max_cluster;
+	if (sbi->prev_free < FAT_START_ENT)
+		sbi->prev_free = FAT_START_ENT;
 
 	brelse(bh);
 
diff -puN include/linux/msdos_fs.h~sync05-fat_free-unsigned include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync05-fat_free-unsigned	2005-03-06 02:36:19.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:36:19.000000000 +0900
@@ -225,8 +225,8 @@ struct msdos_sb_info {
 	unsigned long root_cluster;  /* first cluster of the root directory */
 	unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */
 	struct semaphore fat_lock;
-	int prev_free;               /* previously allocated cluster number */
-	int free_clusters;           /* -1 if undefined */
+	unsigned int prev_free;      /* previously allocated cluster number */
+	unsigned int free_clusters;  /* -1 if undefined */
 	struct fat_mount_options options;
 	struct nls_table *nls_disk;  /* Codepage used on disk */
 	struct nls_table *nls_io;    /* Charset used for input and display */
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 8/29] FAT: "struct vfat_slot_info" cleanup
  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             ` OGAWA Hirofumi
  2005-03-05 18:48               ` [PATCH 9/29] FAT: Use "struct fat_slot_info" for fat_search_long() OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:47 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


Add "struct fat_slot_info" for updating data of the directory entries.

 1) Rename "struct vfat_slot_info" to "struct fat_slot_info"
 2) Add "de" and "bh" to fat_slot_info instead of using argument.
 3) Replace the "vfat_slot_info + de + bh" by new fat_slot_info

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

 fs/vfat/namei.c          |  126 ++++++++++++++++++++---------------------------
 include/linux/msdos_fs.h |    8 +-
 2 files changed, 61 insertions(+), 73 deletions(-)

diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync06-fat_dir-cleanup	2005-03-06 02:36:22.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:36:22.000000000 +0900
@@ -660,16 +660,15 @@ out_free:
 }
 
 static int vfat_add_entry(struct inode *dir, struct qstr *qname,
-			  int is_dir, struct vfat_slot_info *sinfo_out,
-			  struct buffer_head **bh, struct msdos_dir_entry **de)
+			  int is_dir, struct fat_slot_info *sinfo)
 {
 	struct super_block *sb = dir->i_sb;
 	struct msdos_dir_slot *dir_slots;
 	loff_t offset;
 	int res, slots, slot;
 	unsigned int len;
-	struct msdos_dir_entry *dummy_de;
-	struct buffer_head *dummy_bh;
+	struct msdos_dir_entry *de, *dummy_de;
+	struct buffer_head *bh, *dummy_bh;
 	loff_t dummy_i_pos;
 
 	len = vfat_striptail_len(qname);
@@ -695,16 +694,16 @@ static int vfat_add_entry(struct inode *
 	brelse(dummy_bh);
 
 	/* Now create the new entry */
-	*bh = NULL;
+	bh = NULL;
 	for (slot = 0; slot < slots; slot++) {
-		if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->i_pos) < 0) {
+		if (fat_get_entry(dir, &offset, &bh, &de, &sinfo->i_pos) < 0) {
 			res = -EIO;
 			goto cleanup;
 		}
-		memcpy(*de, dir_slots + slot, sizeof(struct msdos_dir_slot));
-		mark_buffer_dirty(*bh);
+		memcpy(de, dir_slots + slot, sizeof(struct msdos_dir_slot));
+		mark_buffer_dirty(bh);
 		if (sb->s_flags & MS_SYNCHRONOUS)
-			sync_dirty_buffer(*bh);
+			sync_dirty_buffer(bh);
 	}
 
 	res = 0;
@@ -712,18 +711,19 @@ static int vfat_add_entry(struct inode *
 	dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
 	mark_inode_dirty(dir);
 
-	fat_date_unix2dos(dir->i_mtime.tv_sec, &(*de)->time, &(*de)->date);
+	fat_date_unix2dos(dir->i_mtime.tv_sec, &de->time, &de->date);
 	dir->i_mtime.tv_nsec = 0;
-	(*de)->ctime = (*de)->time;
-	(*de)->adate = (*de)->cdate = (*de)->date;
-	mark_buffer_dirty(*bh);
+	de->ctime = de->time;
+	de->adate = de->cdate = de->date;
+	mark_buffer_dirty(bh);
 	if (sb->s_flags & MS_SYNCHRONOUS)
-		sync_dirty_buffer(*bh);
+		sync_dirty_buffer(bh);
 
 	/* slots can't be less than 1 */
-	sinfo_out->long_slots = slots - 1;
-	sinfo_out->longname_offset =
-		offset - sizeof(struct msdos_dir_slot) * slots;
+	sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * slots;
+	sinfo->nr_slots = slots - 1;
+	sinfo->de = de;
+	sinfo->bh = bh;
 
 cleanup:
 	kfree(dir_slots);
@@ -731,8 +731,7 @@ cleanup:
 }
 
 static int vfat_find(struct inode *dir, struct qstr *qname,
-		     struct vfat_slot_info *sinfo, struct buffer_head **last_bh,
-		     struct msdos_dir_entry **last_de)
+		     struct fat_slot_info *sinfo)
 {
 	struct super_block *sb = dir->i_sb;
 	loff_t offset;
@@ -745,10 +744,10 @@ static int vfat_find(struct inode *dir, 
 
 	res = fat_search_long(dir, qname->name, len,
 			      (MSDOS_SB(sb)->options.name_check != 's'),
-			      &offset, &sinfo->longname_offset);
+			      &offset, &sinfo->slot_off);
 	if (res > 0) {
-		sinfo->long_slots = res - 1;
-		if (fat_get_entry(dir, &offset, last_bh, last_de, &sinfo->i_pos) >= 0)
+		sinfo->nr_slots = res - 1;
+		if (fat_get_entry(dir, &offset, &sinfo->bh, &sinfo->de, &sinfo->i_pos) >= 0)
 			return 0;
 		res = -EIO;
 	}
@@ -759,11 +758,9 @@ static struct dentry *vfat_lookup(struct
 				  struct nameidata *nd)
 {
 	int res;
-	struct vfat_slot_info sinfo;
+	struct fat_slot_info sinfo;
 	struct inode *inode;
 	struct dentry *alias;
-	struct buffer_head *bh = NULL;
-	struct msdos_dir_entry *de;
 	int table;
 
 	lock_kernel();
@@ -771,13 +768,13 @@ static struct dentry *vfat_lookup(struct
 	dentry->d_op = &vfat_dentry_ops[table];
 
 	inode = NULL;
-	res = vfat_find(dir, &dentry->d_name, &sinfo, &bh, &de);
+	res = vfat_find(dir, &dentry->d_name, &sinfo);
 	if (res < 0) {
 		table++;
 		goto error;
 	}
-	inode = fat_build_inode(dir->i_sb, de, sinfo.i_pos, &res);
-	brelse(bh);
+	inode = fat_build_inode(dir->i_sb, sinfo.de, sinfo.i_pos, &res);
+	brelse(sinfo.bh);
 	if (res) {
 		unlock_kernel();
 		return ERR_PTR(res);
@@ -810,17 +807,15 @@ static int vfat_create(struct inode *dir
 {
 	struct super_block *sb = dir->i_sb;
 	struct inode *inode = NULL;
-	struct buffer_head *bh = NULL;
-	struct msdos_dir_entry *de;
-	struct vfat_slot_info sinfo;
+	struct fat_slot_info sinfo;
 	int res;
 
 	lock_kernel();
-	res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo, &bh, &de);
+	res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo);
 	if (res < 0)
 		goto out;
-	inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
-	brelse(bh);
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos, &res);
+	brelse(sinfo.bh);
 	if (!inode)
 		goto out;
 	res = 0;
@@ -838,11 +833,11 @@ out:
 	return res;
 }
 
-static void vfat_remove_entry(struct inode *dir, struct vfat_slot_info *sinfo,
-			      struct buffer_head *bh,
-			      struct msdos_dir_entry *de)
+static void vfat_remove_entry(struct inode *dir, struct fat_slot_info *sinfo)
 {
 	struct super_block *sb = dir->i_sb;
+	struct msdos_dir_entry *de = sinfo->de;
+	struct buffer_head *bh = sinfo->bh;
 	loff_t offset, i_pos;
 	int i;
 
@@ -857,9 +852,9 @@ static void vfat_remove_entry(struct ino
 		sync_dirty_buffer(bh);
 
 	/* remove the longname */
-	offset = sinfo->longname_offset;
+	offset = sinfo->slot_off;
 	de = NULL;
-	for (i = sinfo->long_slots; i > 0; --i) {
+	for (i = sinfo->nr_slots; i > 0; --i) {
 		if (fat_get_entry(dir, &offset, &bh, &de, &i_pos) < 0)
 			continue;
 		de->name[0] = DELETED_FLAG;
@@ -874,9 +869,7 @@ static void vfat_remove_entry(struct ino
 static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	struct vfat_slot_info sinfo;
-	struct buffer_head *bh = NULL;
-	struct msdos_dir_entry *de;
+	struct fat_slot_info sinfo;
 	int res;
 
 	lock_kernel();
@@ -884,7 +877,7 @@ static int vfat_rmdir(struct inode *dir,
 	if (res)
 		goto out;
 
-	res = vfat_find(dir, &dentry->d_name, &sinfo, &bh, &de);
+	res = vfat_find(dir, &dentry->d_name, &sinfo);
 	if (res < 0)
 		goto out;
 
@@ -894,7 +887,7 @@ static int vfat_rmdir(struct inode *dir,
 	fat_detach(inode);
 	mark_inode_dirty(inode);
 	/* releases bh and syncs it if necessary */
-	vfat_remove_entry(dir, &sinfo, bh, de);
+	vfat_remove_entry(dir, &sinfo);
 	dir->i_nlink--;
 out:
 	unlock_kernel();
@@ -904,13 +897,11 @@ out:
 static int vfat_unlink(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	struct vfat_slot_info sinfo;
-	struct buffer_head *bh = NULL;
-	struct msdos_dir_entry *de;
+	struct fat_slot_info sinfo;
 	int res;
 
 	lock_kernel();
-	res = vfat_find(dir, &dentry->d_name, &sinfo, &bh, &de);
+	res = vfat_find(dir, &dentry->d_name, &sinfo);
 	if (res < 0)
 		goto out;
 	inode->i_nlink = 0;
@@ -918,7 +909,7 @@ static int vfat_unlink(struct inode *dir
 	fat_detach(inode);
 	mark_inode_dirty(inode);
 	/* releases bh and syncs it if necessary */
-	vfat_remove_entry(dir, &sinfo, bh, de);
+	vfat_remove_entry(dir, &sinfo);
 out:
 	unlock_kernel();
 
@@ -929,16 +920,14 @@ static int vfat_mkdir(struct inode *dir,
 {
 	struct super_block *sb = dir->i_sb;
 	struct inode *inode = NULL;
-	struct vfat_slot_info sinfo;
-	struct buffer_head *bh = NULL;
-	struct msdos_dir_entry *de;
+	struct fat_slot_info sinfo;
 	int res;
 
 	lock_kernel();
-	res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo, &bh, &de);
+	res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo);
 	if (res < 0)
 		goto out;
-	inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos, &res);
 	if (!inode)
 		goto out_brelse;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
@@ -953,7 +942,7 @@ static int vfat_mkdir(struct inode *dir,
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry, inode);
 out_brelse:
-	brelse(bh);
+	brelse(sinfo.bh);
 out:
 	unlock_kernel();
 	return res;
@@ -964,7 +953,7 @@ mkdir_failed:
 	fat_detach(inode);
 	mark_inode_dirty(inode);
 	/* releases bh ands syncs if necessary */
-	vfat_remove_entry(dir, &sinfo, bh, de);
+	vfat_remove_entry(dir, &sinfo);
 	iput(inode);
 	dir->i_nlink--;
 	goto out;
@@ -973,24 +962,22 @@ mkdir_failed:
 static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
 		       struct inode *new_dir, struct dentry *new_dentry)
 {
-	struct buffer_head *old_bh, *new_bh, *dotdot_bh;
-	struct msdos_dir_entry *old_de, *new_de, *dotdot_de;
+	struct buffer_head *dotdot_bh;
+	struct msdos_dir_entry *dotdot_de;
 	loff_t dotdot_i_pos;
 	struct inode *old_inode, *new_inode;
 	int res, is_dir;
-	struct vfat_slot_info old_sinfo, sinfo;
+	struct fat_slot_info old_sinfo, sinfo;
 
-	old_bh = new_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();
-	res = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo, &old_bh,
-			&old_de);
+	res = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
 	if (res < 0)
 		goto rename_done;
 
 	is_dir = S_ISDIR(old_inode->i_mode);
-
 	if (is_dir) {
 		if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
 			     &dotdot_de, &dotdot_i_pos) < 0) {
@@ -1000,8 +987,7 @@ static int vfat_rename(struct inode *old
 	}
 
 	if (new_dentry->d_inode) {
-		res = vfat_find(new_dir, &new_dentry->d_name, &sinfo, &new_bh,
-				&new_de);
+		res = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
 		if (res < 0 || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
 			/* WTF??? Cry and fail. */
 			printk(KERN_WARNING "vfat_rename: fs corrupted\n");
@@ -1016,7 +1002,7 @@ static int vfat_rename(struct inode *old
 		fat_detach(new_inode);
 	} else {
 		res = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
-				     &sinfo, &new_bh, &new_de);
+				     &sinfo);
 		if (res < 0)
 			goto rename_done;
 	}
@@ -1024,8 +1010,8 @@ static int vfat_rename(struct inode *old
 	new_dir->i_version++;
 
 	/* releases old_bh */
-	vfat_remove_entry(old_dir, &old_sinfo, old_bh, old_de);
-	old_bh = NULL;
+	vfat_remove_entry(old_dir, &old_sinfo);
+	old_sinfo.bh = NULL;
 	fat_detach(old_inode);
 	fat_attach(old_inode, sinfo.i_pos);
 	mark_inode_dirty(old_inode);
@@ -1057,8 +1043,8 @@ static int vfat_rename(struct inode *old
 
 rename_done:
 	brelse(dotdot_bh);
-	brelse(old_bh);
-	brelse(new_bh);
+	brelse(old_sinfo.bh);
+	brelse(sinfo.bh);
 	unlock_kernel();
 	return res;
 }
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync06-fat_dir-cleanup	2005-03-06 02:36:22.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:36:22.000000000 +0900
@@ -170,10 +170,12 @@ struct msdos_dir_slot {
 	__u8    name11_12[4];	/* last 2 characters in name */
 };
 
-struct vfat_slot_info {
-	int long_slots;		/* number of long slots in filename */
-	loff_t longname_offset;	/* dir offset for longname start */
+struct fat_slot_info {
 	loff_t i_pos;		/* on-disk position of directory entry */
+	loff_t slot_off;	/* offset for slot or de start */
+	int nr_slots;		/* number of slots + 1(de) in filename */
+	struct msdos_dir_entry *de;
+	struct buffer_head *bh;
 };
 
 #ifdef __KERNEL__
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 9/29] FAT: Use "struct fat_slot_info" for fat_search_long()
  2005-03-05 18:47             ` [PATCH 8/29] FAT: "struct vfat_slot_info" cleanup OGAWA Hirofumi
@ 2005-03-05 18:48               ` OGAWA Hirofumi
  2005-03-05 18:49                 ` [PATCH 10/29] FAT: Add fat_remove_entries() OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:48 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


The fat_search_long() provide the "struct fat_slot_info" by this
change.  So, vfat_find() became to be enough simple, and it just
returns 0 or error.

And the error check of vfat_find() is also simplify.

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

 fs/fat/dir.c             |   26 +++++++------
 fs/vfat/namei.c          |   89 ++++++++++++++++++++---------------------------
 include/linux/msdos_fs.h |    3 -
 3 files changed, 54 insertions(+), 64 deletions(-)

diff -puN fs/fat/dir.c~sync06-fat_dir-cleanup2 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync06-fat_dir-cleanup2	2005-03-06 02:36:25.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:36:25.000000000 +0900
@@ -136,7 +136,7 @@ fat_shortname2uni(struct nls_table *nls,
  * value is the total amount of slots, including the shortname entry.
  */
 int fat_search_long(struct inode *inode, const unsigned char *name,
-		    int name_len, int anycase, loff_t *spos, loff_t *lpos)
+		    int name_len, struct fat_slot_info *sinfo)
 {
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *bh = NULL;
@@ -149,12 +149,14 @@ int fat_search_long(struct inode *inode,
 	unsigned char work[8], bufname[260];	/* 256 + 4 */
 	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
 	int utf8 = MSDOS_SB(sb)->options.utf8;
+	int anycase = (MSDOS_SB(sb)->options.name_check != 's');
 	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
-	int chl, i, j, last_u, res = 0;
+	int chl, i, j, last_u, err;
 	loff_t i_pos, cpos = 0;
 
+	err = -ENOENT;
 	while(1) {
-		if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
+		if (fat_get_entry(inode, &cpos, &bh, &de, &i_pos) == -1)
 			goto EODir;
 parse_record:
 		long_slots = 0;
@@ -288,15 +290,17 @@ parse_long:
 	}
 
 Found:
-	res = long_slots + 1;
-	*spos = cpos - sizeof(struct msdos_dir_entry);
-	*lpos = cpos - res*sizeof(struct msdos_dir_entry);
+	sinfo->i_pos = i_pos;
+	sinfo->slot_off = cpos - (long_slots + 1) * sizeof(*de);
+	sinfo->nr_slots = long_slots;
+	sinfo->de = de;
+	sinfo->bh = bh;
+	err = 0;
 EODir:
-	brelse(bh);
-	if (unicode) {
-		free_page((unsigned long) unicode);
-	}
-	return res;
+	if (unicode)
+		free_page((unsigned long)unicode);
+
+	return err;
 }
 
 EXPORT_SYMBOL(fat_search_long);
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup2 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync06-fat_dir-cleanup2	2005-03-06 02:36:25.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:36:25.000000000 +0900
@@ -733,51 +733,35 @@ cleanup:
 static int vfat_find(struct inode *dir, struct qstr *qname,
 		     struct fat_slot_info *sinfo)
 {
-	struct super_block *sb = dir->i_sb;
-	loff_t offset;
-	unsigned int len;
-	int res;
-
-	len = vfat_striptail_len(qname);
+	unsigned int len = vfat_striptail_len(qname);
 	if (len == 0)
 		return -ENOENT;
-
-	res = fat_search_long(dir, qname->name, len,
-			      (MSDOS_SB(sb)->options.name_check != 's'),
-			      &offset, &sinfo->slot_off);
-	if (res > 0) {
-		sinfo->nr_slots = res - 1;
-		if (fat_get_entry(dir, &offset, &sinfo->bh, &sinfo->de, &sinfo->i_pos) >= 0)
-			return 0;
-		res = -EIO;
-	}
-	return res ? res : -ENOENT;
+	return fat_search_long(dir, qname->name, len, sinfo);
 }
 
 static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
 				  struct nameidata *nd)
 {
-	int res;
+	struct super_block *sb = dir->i_sb;
 	struct fat_slot_info sinfo;
-	struct inode *inode;
+	struct inode *inode = NULL;
 	struct dentry *alias;
-	int table;
+	int err, table;
 
 	lock_kernel();
-	table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0;
+	table = (MSDOS_SB(sb)->options.name_check == 's') ? 2 : 0;
 	dentry->d_op = &vfat_dentry_ops[table];
 
-	inode = NULL;
-	res = vfat_find(dir, &dentry->d_name, &sinfo);
-	if (res < 0) {
+	err = vfat_find(dir, &dentry->d_name, &sinfo);
+	if (err) {
 		table++;
 		goto error;
 	}
-	inode = fat_build_inode(dir->i_sb, sinfo.de, sinfo.i_pos, &res);
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos, &err);
 	brelse(sinfo.bh);
-	if (res) {
+	if (err) {
 		unlock_kernel();
-		return ERR_PTR(res);
+		return ERR_PTR(err);
 	}
 	alias = d_find_alias(inode);
 	if (alias) {
@@ -870,40 +854,43 @@ static int vfat_rmdir(struct inode *dir,
 {
 	struct inode *inode = dentry->d_inode;
 	struct fat_slot_info sinfo;
-	int res;
+	int err;
 
 	lock_kernel();
-	res = fat_dir_empty(inode);
-	if (res)
-		goto out;
 
-	res = vfat_find(dir, &dentry->d_name, &sinfo);
-	if (res < 0)
+	err = fat_dir_empty(inode);
+	if (err)
+		goto out;
+	err = vfat_find(dir, &dentry->d_name, &sinfo);
+	if (err)
 		goto out;
 
-	res = 0;
 	inode->i_nlink = 0;
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 	mark_inode_dirty(inode);
 	/* releases bh and syncs it if necessary */
 	vfat_remove_entry(dir, &sinfo);
+
 	dir->i_nlink--;
 out:
 	unlock_kernel();
-	return res;
+
+	return err;
 }
 
 static int vfat_unlink(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
 	struct fat_slot_info sinfo;
-	int res;
+	int err;
 
 	lock_kernel();
-	res = vfat_find(dir, &dentry->d_name, &sinfo);
-	if (res < 0)
+
+	err = vfat_find(dir, &dentry->d_name, &sinfo);
+	if (err)
 		goto out;
+
 	inode->i_nlink = 0;
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
@@ -913,7 +900,7 @@ static int vfat_unlink(struct inode *dir
 out:
 	unlock_kernel();
 
-	return res;
+	return err;
 }
 
 static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
@@ -966,44 +953,44 @@ 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 res, is_dir;
+	int err, is_dir;
 	struct fat_slot_info old_sinfo, sinfo;
 
 	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
 	old_inode = old_dentry->d_inode;
 	new_inode = new_dentry->d_inode;
 	lock_kernel();
-	res = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
-	if (res < 0)
+	err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
+	if (err)
 		goto rename_done;
 
 	is_dir = S_ISDIR(old_inode->i_mode);
 	if (is_dir) {
 		if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
 			     &dotdot_de, &dotdot_i_pos) < 0) {
-			res = -EIO;
+			err = -EIO;
 			goto rename_done;
 		}
 	}
 
 	if (new_dentry->d_inode) {
-		res = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
-		if (res < 0 || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
+		err = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
+		if (err || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
 			/* WTF??? Cry and fail. */
 			printk(KERN_WARNING "vfat_rename: fs corrupted\n");
 			goto rename_done;
 		}
 
 		if (is_dir) {
-			res = fat_dir_empty(new_inode);
-			if (res)
+			err = fat_dir_empty(new_inode);
+			if (err)
 				goto rename_done;
 		}
 		fat_detach(new_inode);
 	} else {
-		res = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
+		err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
 				     &sinfo);
-		if (res < 0)
+		if (err)
 			goto rename_done;
 	}
 
@@ -1040,13 +1027,13 @@ static int vfat_rename(struct inode *old
 			mark_inode_dirty(new_dir);
 		}
 	}
-
 rename_done:
 	brelse(dotdot_bh);
 	brelse(old_sinfo.bh);
 	brelse(sinfo.bh);
 	unlock_kernel();
-	return res;
+
+	return err;
 }
 
 static struct inode_operations vfat_dir_inode_operations = {
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup2 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync06-fat_dir-cleanup2	2005-03-06 02:36:25.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:36:25.000000000 +0900
@@ -323,8 +323,7 @@ extern int fat_bmap(struct inode *inode,
 /* fat/dir.c */
 extern struct file_operations fat_dir_operations;
 extern int fat_search_long(struct inode *inode, const unsigned char *name,
-			   int name_len, int anycase,
-			   loff_t *spos, loff_t *lpos);
+			   int name_len, struct fat_slot_info *sinfo);
 extern int fat_add_entries(struct inode *dir, int slots,
 			   struct buffer_head **bh,
 			   struct msdos_dir_entry **de, loff_t *i_pos);
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 10/29] FAT: Add fat_remove_entries()
  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                 ` OGAWA Hirofumi
  2005-03-05 18:49                   ` [PATCH 11/29] FAT: fat_build_inode() cleanup OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:49 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


This changes the fat_slot_info->nr_slot, now it's total counts which
include a shortname entry.  And this adds a fat_remove_entries()
which use the ->nr_slots.

In order not to write out the same block repeatedly,
fat_remove_entries() was rewritten from vfat_remove_entries().

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

 fs/fat/dir.c             |  103 +++++++++++++++++++++++++++++++++++++++++++----
 fs/vfat/namei.c          |   81 ++++++++++++------------------------
 include/linux/msdos_fs.h |    1 
 3 files changed, 124 insertions(+), 61 deletions(-)

diff -puN fs/fat/dir.c~sync06-fat_dir-cleanup3 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync06-fat_dir-cleanup3	2005-03-06 02:36:28.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:36:29.000000000 +0900
@@ -144,7 +144,7 @@ int fat_search_long(struct inode *inode,
 	struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
 	struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
 	wchar_t bufuname[14];
-	unsigned char xlate_len, long_slots;
+	unsigned char xlate_len, nr_slots;
 	wchar_t *unicode = NULL;
 	unsigned char work[8], bufname[260];	/* 256 + 4 */
 	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
@@ -159,7 +159,7 @@ int fat_search_long(struct inode *inode,
 		if (fat_get_entry(inode, &cpos, &bh, &de, &i_pos) == -1)
 			goto EODir;
 parse_record:
-		long_slots = 0;
+		nr_slots = 0;
 		if (de->name[0] == DELETED_FLAG)
 			continue;
 		if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
@@ -191,7 +191,7 @@ parse_long:
 			slots = id & ~0x40;
 			if (slots > 20 || !slots)	/* ceil(256 * 2 / 26) */
 				continue;
-			long_slots = slots;
+			nr_slots = slots;
 			alias_checksum = ds->alias_checksum;
 
 			slot = slots;
@@ -228,7 +228,7 @@ parse_long:
 			for (sum = 0, i = 0; i < 11; i++)
 				sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
 			if (sum != alias_checksum)
-				long_slots = 0;
+				nr_slots = 0;
 		}
 
 		memcpy(work, de->name, sizeof(de->name));
@@ -276,7 +276,7 @@ parse_long:
 								xlate_len)))
 				goto Found;
 
-		if (long_slots) {
+		if (nr_slots) {
 			xlate_len = utf8
 				?utf8_wcstombs(bufname, unicode, sizeof(bufname))
 				:uni16_to_x8(bufname, unicode, uni_xlate, nls_io);
@@ -290,9 +290,10 @@ parse_long:
 	}
 
 Found:
+	nr_slots++;	/* include the de */
 	sinfo->i_pos = i_pos;
-	sinfo->slot_off = cpos - (long_slots + 1) * sizeof(*de);
-	sinfo->nr_slots = long_slots;
+	sinfo->slot_off = cpos - nr_slots * sizeof(*de);
+	sinfo->nr_slots = nr_slots;
 	sinfo->de = de;
 	sinfo->bh = bh;
 	err = 0;
@@ -759,6 +760,94 @@ int fat_scan(struct inode *dir, const un
 
 EXPORT_SYMBOL(fat_scan);
 
+static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots)
+{
+	struct super_block *sb = dir->i_sb;
+	struct buffer_head *bh;
+	struct msdos_dir_entry *de, *endp;
+	loff_t i_pos;
+	int err = 0, orig_slots;
+
+	while (nr_slots) {
+		bh = NULL;
+		if (fat_get_entry(dir, &pos, &bh, &de, &i_pos) < 0) {
+			err = -EIO;
+			break;
+		}
+
+		orig_slots = nr_slots;
+		endp = (struct msdos_dir_entry *)(bh->b_data + sb->s_blocksize);
+		while (nr_slots && de < endp) {
+			de->name[0] = DELETED_FLAG;
+			de++;
+			nr_slots--;
+		}
+		mark_buffer_dirty(bh);
+		if (IS_DIRSYNC(dir))
+			err = sync_dirty_buffer(bh);
+		brelse(bh);
+		if (err)
+			break;
+
+		/* pos is *next* de's position, so this does `- sizeof(de)' */
+		pos += ((orig_slots - nr_slots) * sizeof(*de)) - sizeof(*de);
+	}
+
+	return err;
+}
+
+int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo)
+{
+	struct msdos_dir_entry *de;
+	struct buffer_head *bh;
+	int err = 0, nr_slots;
+
+	/*
+	 * First stage: Remove the shortname. By this, the directory
+	 * entry is removed.
+	 */
+	nr_slots = sinfo->nr_slots;
+	de = sinfo->de;
+	sinfo->de = NULL;
+	bh = sinfo->bh;
+	sinfo->bh = NULL;
+	while (nr_slots && de >= (struct msdos_dir_entry *)bh->b_data) {
+		de->name[0] = DELETED_FLAG;
+		de--;
+		nr_slots--;
+	}
+	mark_buffer_dirty(bh);
+	if (IS_DIRSYNC(dir))
+		err = sync_dirty_buffer(bh);
+	brelse(bh);
+	if (err)
+		return err;
+	dir->i_version++;
+
+	if (nr_slots) {
+		/*
+		 * Second stage: remove the remaining longname slots.
+		 * (This directory entry is already removed, and so return
+		 * the success)
+		 */
+		err = __fat_remove_entries(dir, sinfo->slot_off, nr_slots);
+		if (err) {
+			printk(KERN_WARNING
+			       "FAT: Couldn't remove the long name slots\n");
+		}
+	}
+
+	dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
+	if (IS_DIRSYNC(dir))
+		(void)fat_sync_inode(dir);
+	else
+		mark_inode_dirty(dir);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(fat_remove_entries);
+
 static struct buffer_head *fat_extend_dir(struct inode *inode)
 {
 	struct super_block *sb = inode->i_sb;
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup3 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync06-fat_dir-cleanup3	2005-03-06 02:36:28.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:36:29.000000000 +0900
@@ -721,7 +721,7 @@ static int vfat_add_entry(struct inode *
 
 	/* slots can't be less than 1 */
 	sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * slots;
-	sinfo->nr_slots = slots - 1;
+	sinfo->nr_slots = slots;
 	sinfo->de = de;
 	sinfo->bh = bh;
 
@@ -817,39 +817,6 @@ out:
 	return res;
 }
 
-static void vfat_remove_entry(struct inode *dir, struct fat_slot_info *sinfo)
-{
-	struct super_block *sb = dir->i_sb;
-	struct msdos_dir_entry *de = sinfo->de;
-	struct buffer_head *bh = sinfo->bh;
-	loff_t offset, i_pos;
-	int i;
-
-	dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
-	dir->i_version++;
-	mark_inode_dirty(dir);
-
-	/* remove the shortname */
-	de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(bh);
-	if (sb->s_flags & MS_SYNCHRONOUS)
-		sync_dirty_buffer(bh);
-
-	/* remove the longname */
-	offset = sinfo->slot_off;
-	de = NULL;
-	for (i = sinfo->nr_slots; i > 0; --i) {
-		if (fat_get_entry(dir, &offset, &bh, &de, &i_pos) < 0)
-			continue;
-		de->name[0] = DELETED_FLAG;
-		de->attr = ATTR_NONE;
-		mark_buffer_dirty(bh);
-		if (sb->s_flags & MS_SYNCHRONOUS)
-			sync_dirty_buffer(bh);
-	}
-	brelse(bh);
-}
-
 static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
@@ -865,14 +832,15 @@ static int vfat_rmdir(struct inode *dir,
 	if (err)
 		goto out;
 
+	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */
+	if (err)
+		goto out;
+	dir->i_nlink--;
+
 	inode->i_nlink = 0;
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 	mark_inode_dirty(inode);
-	/* releases bh and syncs it if necessary */
-	vfat_remove_entry(dir, &sinfo);
-
-	dir->i_nlink--;
 out:
 	unlock_kernel();
 
@@ -891,12 +859,13 @@ static int vfat_unlink(struct inode *dir
 	if (err)
 		goto out;
 
+	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */
+	if (err)
+		goto out;
 	inode->i_nlink = 0;
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 	mark_inode_dirty(inode);
-	/* releases bh and syncs it if necessary */
-	vfat_remove_entry(dir, &sinfo);
 out:
 	unlock_kernel();
 
@@ -939,8 +908,7 @@ mkdir_failed:
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 	mark_inode_dirty(inode);
-	/* releases bh ands syncs if necessary */
-	vfat_remove_entry(dir, &sinfo);
+	fat_remove_entries(dir, &sinfo);	/* and releases bh */
 	iput(inode);
 	dir->i_nlink--;
 	goto out;
@@ -956,49 +924,56 @@ static int vfat_rename(struct inode *old
 	int err, is_dir;
 	struct fat_slot_info old_sinfo, sinfo;
 
-	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
+	old_sinfo.bh = dotdot_bh = NULL;
 	old_inode = old_dentry->d_inode;
 	new_inode = new_dentry->d_inode;
 	lock_kernel();
 	err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
 	if (err)
-		goto rename_done;
+		goto out;
 
 	is_dir = S_ISDIR(old_inode->i_mode);
 	if (is_dir) {
 		if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
 			     &dotdot_de, &dotdot_i_pos) < 0) {
 			err = -EIO;
-			goto rename_done;
+			goto out;
 		}
 	}
 
 	if (new_dentry->d_inode) {
 		err = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
-		if (err || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
+		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");
-			goto rename_done;
+			goto out;
 		}
 
 		if (is_dir) {
 			err = fat_dir_empty(new_inode);
 			if (err)
-				goto rename_done;
+				goto out;
 		}
 		fat_detach(new_inode);
 	} else {
 		err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
 				     &sinfo);
 		if (err)
-			goto rename_done;
+			goto out;
+		brelse(sinfo.bh);
 	}
-
 	new_dir->i_version++;
 
 	/* releases old_bh */
-	vfat_remove_entry(old_dir, &old_sinfo);
+	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);
@@ -1019,7 +994,6 @@ static int vfat_rename(struct inode *old
 		if (new_dir->i_sb->s_flags & MS_SYNCHRONOUS)
 			sync_dirty_buffer(dotdot_bh);
 
-		old_dir->i_nlink--;
 		if (new_inode) {
 			new_inode->i_nlink--;
 		} else {
@@ -1027,10 +1001,9 @@ static int vfat_rename(struct inode *old
 			mark_inode_dirty(new_dir);
 		}
 	}
-rename_done:
+out:
 	brelse(dotdot_bh);
 	brelse(old_sinfo.bh);
-	brelse(sinfo.bh);
 	unlock_kernel();
 
 	return err;
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup3 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync06-fat_dir-cleanup3	2005-03-06 02:36:28.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:36:29.000000000 +0900
@@ -333,6 +333,7 @@ extern int fat_subdirs(struct inode *dir
 extern int fat_scan(struct inode *dir, const unsigned char *name,
 		    struct buffer_head **res_bh,
 		    struct msdos_dir_entry **res_de, loff_t *i_pos);
+extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
 
 /* fat/fatent.c */
 struct fat_entry {
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 11/29] FAT: fat_build_inode() cleanup
  2005-03-05 18:49                 ` [PATCH 10/29] FAT: Add fat_remove_entries() OGAWA Hirofumi
@ 2005-03-05 18:49                   ` OGAWA Hirofumi
  2005-03-05 18:50                     ` [PATCH 12/29] FAT: Use "struct fat_slot_info" for fat_scan() OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:49 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


Just use ERR_PTR() instead of getting the error code by additional
argument.

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

 fs/fat/inode.c           |   62 ++++++++++++++++++++++-------------------------
 fs/msdos/namei.c         |   17 +++++++-----
 fs/vfat/namei.c          |   19 ++++++++------
 include/linux/msdos_fs.h |    2 -
 4 files changed, 52 insertions(+), 48 deletions(-)

diff -puN fs/fat/inode.c~sync06-fat_dir-cleanup4 fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~sync06-fat_dir-cleanup4	2005-03-06 02:36:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c	2005-03-06 02:36:32.000000000 +0900
@@ -304,23 +304,25 @@ static int fat_fill_inode(struct inode *
 }
 
 struct inode *fat_build_inode(struct super_block *sb,
-			struct msdos_dir_entry *de, loff_t i_pos, int *res)
+			struct msdos_dir_entry *de, loff_t i_pos)
 {
 	struct inode *inode;
-	*res = 0;
+	int err;
+
 	inode = fat_iget(sb, i_pos);
 	if (inode)
 		goto out;
 	inode = new_inode(sb);
-	*res = -ENOMEM;
-	if (!inode)
+	if (!inode) {
+		inode = ERR_PTR(-ENOMEM);
 		goto out;
+	}
 	inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
 	inode->i_version = 1;
-	*res = fat_fill_inode(inode, de);
-	if (*res < 0) {
+	err = fat_fill_inode(inode, de);
+	if (err) {
 		iput(inode);
-		inode = NULL;
+		inode = ERR_PTR(err);
 		goto out;
 	}
 	fat_attach(inode, i_pos);
@@ -643,39 +645,35 @@ fat_encode_fh(struct dentry *de, __u32 *
 
 static struct dentry *fat_get_parent(struct dentry *child)
 {
-	struct buffer_head *bh=NULL;
-	struct msdos_dir_entry *de = NULL;
-	struct dentry *parent = NULL;
-	int res;
-	loff_t i_pos = 0;
+	struct buffer_head *bh;
+	struct msdos_dir_entry *de;
+	loff_t i_pos;
+	struct dentry *parent;
 	struct inode *inode;
+	int err;
 
 	lock_kernel();
-	res = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &i_pos);
 
-	if (res < 0)
+	err = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &i_pos);
+	if (err) {
+		parent = ERR_PTR(err);
 		goto out;
-	inode = fat_build_inode(child->d_sb, de, i_pos, &res);
-	if (res)
+	}
+	inode = fat_build_inode(child->d_sb, de, i_pos);
+	brelse(bh);
+	if (IS_ERR(inode)) {
+		parent = ERR_PTR(PTR_ERR(inode));
 		goto out;
-	if (!inode)
-		res = -EACCES;
-	else {
-		parent = d_alloc_anon(inode);
-		if (!parent) {
-			iput(inode);
-			res = -ENOMEM;
-		}
 	}
-
- out:
-	if(bh)
-		brelse(bh);
+	parent = d_alloc_anon(inode);
+	if (!parent) {
+		iput(inode);
+		parent = ERR_PTR(-ENOMEM);
+	}
+out:
 	unlock_kernel();
-	if (res)
-		return ERR_PTR(res);
-	else
-		return parent;
+
+	return parent;
 }
 
 static struct export_operations fat_export_ops = {
diff -puN fs/msdos/namei.c~sync06-fat_dir-cleanup4 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync06-fat_dir-cleanup4	2005-03-06 02:36:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c	2005-03-06 02:36:32.000000000 +0900
@@ -236,9 +236,11 @@ static struct dentry *msdos_lookup(struc
 		goto add;
 	if (res < 0)
 		goto out;
-	inode = fat_build_inode(sb, de, i_pos, &res);
-	if (res)
+	inode = fat_build_inode(sb, de, i_pos);
+	if (IS_ERR(inode)) {
+		res = PTR_ERR(inode);
 		goto out;
+	}
 add:
 	res = 0;
 	dentry = d_splice_alias(inode, dentry);
@@ -314,11 +316,11 @@ static int msdos_create(struct inode *di
 		unlock_kernel();
 		return res;
 	}
-	inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
+	inode = fat_build_inode(dir->i_sb, de, i_pos);
 	brelse(bh);
-	if (!inode) {
+	if (IS_ERR(inode)) {
 		unlock_kernel();
-		return res;
+		return PTR_ERR(inode);
 	}
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
 	mark_inode_dirty(inode);
@@ -392,9 +394,10 @@ static int msdos_mkdir(struct inode *dir
 	res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid);
 	if (res)
 		goto out_unlock;
-	inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
-	if (!inode) {
+	inode = fat_build_inode(dir->i_sb, de, i_pos);
+	if (IS_ERR(inode)) {
 		brelse(bh);
+		res = PTR_ERR(inode);
 		goto out_unlock;
 	}
 	res = 0;
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup4 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync06-fat_dir-cleanup4	2005-03-06 02:36:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:36:32.000000000 +0900
@@ -757,11 +757,11 @@ static struct dentry *vfat_lookup(struct
 		table++;
 		goto error;
 	}
-	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos, &err);
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 	brelse(sinfo.bh);
-	if (err) {
+	if (IS_ERR(inode)) {
 		unlock_kernel();
-		return ERR_PTR(err);
+		return ERR_PTR(PTR_ERR(inode));
 	}
 	alias = d_find_alias(inode);
 	if (alias) {
@@ -798,10 +798,12 @@ static int vfat_create(struct inode *dir
 	res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo);
 	if (res < 0)
 		goto out;
-	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos, &res);
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 	brelse(sinfo.bh);
-	if (!inode)
+	if (IS_ERR(inode)) {
+		res = PTR_ERR(inode);
 		goto out;
+	}
 	res = 0;
 	inode->i_version++;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
@@ -883,9 +885,11 @@ static int vfat_mkdir(struct inode *dir,
 	res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo);
 	if (res < 0)
 		goto out;
-	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos, &res);
-	if (!inode)
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+	if (IS_ERR(inode)) {
+		res = PTR_ERR(inode);
 		goto out_brelse;
+	}
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
 	mark_inode_dirty(inode);
 	inode->i_version++;
@@ -967,7 +971,6 @@ static int vfat_rename(struct inode *old
 	}
 	new_dir->i_version++;
 
-	/* releases old_bh */
 	err = fat_remove_entries(old_dir, &old_sinfo);	/* and releases bh */
 	old_sinfo.bh = NULL;
 	if (err)
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup4 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync06-fat_dir-cleanup4	2005-03-06 02:36:32.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:36:32.000000000 +0900
@@ -394,7 +394,7 @@ extern void fat_attach(struct inode *ino
 extern void fat_detach(struct inode *inode);
 extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos);
 extern struct inode *fat_build_inode(struct super_block *sb,
-			struct msdos_dir_entry *de, loff_t i_pos, int *res);
+			struct msdos_dir_entry *de, loff_t i_pos);
 extern int fat_sync_inode(struct inode *inode);
 extern int fat_fill_super(struct super_block *sb, void *data, int silent,
 			struct inode_operations *fs_dir_inode_ops, int isvfat);
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 12/29] FAT: Use "struct fat_slot_info" for fat_scan()
  2005-03-05 18:49                   ` [PATCH 11/29] FAT: fat_build_inode() cleanup OGAWA Hirofumi
@ 2005-03-05 18:50                     ` OGAWA Hirofumi
  2005-03-05 18:50                       ` [PATCH 13/29] FAT: Use "struct fat_slot_info" for msdos_find() OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:50 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


Use "struct fat_slot_info" for fat_scan().  But ".." entry can not provide
valid informations for inode, so add the fat_get_dotdot_entry() as
special case.

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

 fs/fat/dir.c             |   41 +++++++++++++++++-----
 fs/fat/inode.c           |    2 -
 fs/msdos/namei.c         |   84 ++++++++++++++++++++++++++---------------------
 fs/vfat/namei.c          |   16 +++-----
 include/linux/msdos_fs.h |    5 +-
 5 files changed, 88 insertions(+), 60 deletions(-)

diff -puN fs/fat/dir.c~sync06-fat_dir-cleanup5 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync06-fat_dir-cleanup5	2005-03-06 02:36:35.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:36:35.000000000 +0900
@@ -510,9 +510,9 @@ ParseLong:
 	j = last_u;
 
 	lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry);
-	if (!memcmp(de->name,MSDOS_DOT,11))
+	if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME))
 		inum = inode->i_ino;
-	else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
+	else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
 		inum = parent_ino(filp->f_dentry);
 	} else {
 		struct inode *tmp = fat_iget(sb, i_pos);
@@ -695,6 +695,26 @@ static int fat_get_short_entry(struct in
 	return -ENOENT;
 }
 
+/*
+ * The ".." entry can not provide the "struct fat_slot_info" informations
+ * for inode. So, this function provide the some informations only.
+ */
+int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
+			 struct msdos_dir_entry **de, loff_t *i_pos)
+{
+	loff_t offset;
+
+	offset = 0;
+	*bh = NULL;
+	while (fat_get_short_entry(dir, &offset, bh, de, i_pos) >= 0) {
+		if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME))
+			return 0;
+	}
+	return -ENOENT;
+}
+
+EXPORT_SYMBOL(fat_get_dotdot_entry);
+
 /* See if directory is empty */
 int fat_dir_empty(struct inode *dir)
 {
@@ -744,16 +764,17 @@ int fat_subdirs(struct inode *dir)
  * Returns an error code or zero.
  */
 int fat_scan(struct inode *dir, const unsigned char *name,
-	     struct buffer_head **bh, struct msdos_dir_entry **de,
-	     loff_t *i_pos)
+	     struct fat_slot_info *sinfo)
 {
-	loff_t cpos;
-
-	*bh = NULL;
-	cpos = 0;
-	while (fat_get_short_entry(dir, &cpos, bh, de, i_pos) >= 0) {
-		if (!strncmp((*de)->name, name, MSDOS_NAME))
+	sinfo->slot_off = 0;
+	sinfo->bh = NULL;
+	while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh,
+				   &sinfo->de, &sinfo->i_pos) >= 0) {
+		if (!strncmp(sinfo->de->name, name, MSDOS_NAME)) {
+			sinfo->slot_off -= sizeof(*sinfo->de);
+			sinfo->nr_slots = 1;
 			return 0;
+		}
 	}
 	return -ENOENT;
 }
diff -puN fs/fat/inode.c~sync06-fat_dir-cleanup5 fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~sync06-fat_dir-cleanup5	2005-03-06 02:36:35.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c	2005-03-06 02:36:35.000000000 +0900
@@ -654,7 +654,7 @@ static struct dentry *fat_get_parent(str
 
 	lock_kernel();
 
-	err = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &i_pos);
+	err = fat_get_dotdot_entry(child->d_inode, &bh, &de, &i_pos);
 	if (err) {
 		parent = ERR_PTR(err);
 		goto out;
diff -puN fs/msdos/namei.c~sync06-fat_dir-cleanup5 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync06-fat_dir-cleanup5	2005-03-06 02:36:35.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c	2005-03-06 02:36:35.000000000 +0900
@@ -140,26 +140,33 @@ static int msdos_find(struct inode *dir,
 		      struct buffer_head **bh, struct msdos_dir_entry **de,
 		      loff_t *i_pos)
 {
+	struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
+	struct fat_slot_info sinfo;
 	unsigned char msdos_name[MSDOS_NAME];
-	char dotsOK;
-	int res;
+	int err;
 
-	dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
-	res = msdos_format_name(name, len, msdos_name,
-				&MSDOS_SB(dir->i_sb)->options);
-	if (res < 0)
+	err = msdos_format_name(name, len, msdos_name, &sbi->options);
+	if (err)
 		return -ENOENT;
-	res = fat_scan(dir, msdos_name, bh, de, i_pos);
-	if (!res && dotsOK) {
+
+	err = fat_scan(dir, msdos_name, &sinfo);
+	if (!err && sbi->options.dotsOK) {
 		if (name[0] == '.') {
-			if (!((*de)->attr & ATTR_HIDDEN))
-				res = -ENOENT;
+			if (!(sinfo.de->attr & ATTR_HIDDEN))
+				err = -ENOENT;
 		} else {
-			if ((*de)->attr & ATTR_HIDDEN)
-				res = -ENOENT;
+			if (sinfo.de->attr & ATTR_HIDDEN)
+				err = -ENOENT;
 		}
+		if (err)
+			brelse(sinfo.bh);
 	}
-	return res;
+	if (!err) {
+		*i_pos = sinfo.i_pos;
+		*de = sinfo.de;
+		*bh = sinfo.bh;
+	}
+	return err;
 }
 
 /*
@@ -289,6 +296,7 @@ static int msdos_create(struct inode *di
 			struct nameidata *nd)
 {
 	struct super_block *sb = dir->i_sb;
+	struct fat_slot_info sinfo;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 	struct inode *inode;
@@ -305,18 +313,18 @@ static int msdos_create(struct inode *di
 	}
 	is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
 	/* Have to do it due to foo vs. .foo conflicts */
-	if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) {
-		brelse(bh);
+	if (!fat_scan(dir, msdos_name, &sinfo)) {
+		brelse(sinfo.bh);
 		unlock_kernel();
 		return -EINVAL;
 	}
-	inode = NULL;
+
 	res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid);
 	if (res) {
 		unlock_kernel();
 		return res;
 	}
-	inode = fat_build_inode(dir->i_sb, de, i_pos);
+	inode = fat_build_inode(sb, de, i_pos);
 	brelse(bh);
 	if (IS_ERR(inode)) {
 		unlock_kernel();
@@ -372,6 +380,7 @@ rmdir_done:
 static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
 	struct super_block *sb = dir->i_sb;
+	struct fat_slot_info sinfo;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 	struct inode *inode;
@@ -388,8 +397,11 @@ static int msdos_mkdir(struct inode *dir
 	}
 	is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
 	/* foo vs .foo situation */
-	if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0)
-		goto out_exist;
+	if (!fat_scan(dir, msdos_name, &sinfo)) {
+		brelse(sinfo.bh);
+		res = -EINVAL;
+		goto out_unlock;
+	}
 
 	res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid);
 	if (res)
@@ -400,7 +412,6 @@ static int msdos_mkdir(struct inode *dir
 		res = PTR_ERR(inode);
 		goto out_unlock;
 	}
-	res = 0;
 
 	dir->i_nlink++;
 	inode->i_nlink = 2;	/* no need to mark them dirty */
@@ -408,7 +419,6 @@ static int msdos_mkdir(struct inode *dir
 	res = fat_new_dir(inode, dir, 0);
 	if (res)
 		goto mkdir_error;
-
 	brelse(bh);
 	d_instantiate(dentry, inode);
 	res = 0;
@@ -429,11 +439,6 @@ mkdir_error:
 	fat_detach(inode);
 	iput(inode);
 	goto out_unlock;
-
-out_exist:
-	brelse(bh);
-	res = -EINVAL;
-	goto out_unlock;
 }
 
 /***** Unlink a file */
@@ -474,6 +479,7 @@ static int do_msdos_rename(struct inode 
 			   struct msdos_dir_entry *old_de, loff_t old_i_pos,
 			   int is_hid)
 {
+	struct fat_slot_info sinfo;
 	struct buffer_head *new_bh = NULL, *dotdot_bh = NULL;
 	struct msdos_dir_entry *new_de, *dotdot_de;
 	struct inode *old_inode, *new_inode;
@@ -485,17 +491,22 @@ static int do_msdos_rename(struct inode 
 	new_inode = new_dentry->d_inode;
 	is_dir = S_ISDIR(old_inode->i_mode);
 
-	if (fat_scan(new_dir, new_name, &new_bh, &new_de, &new_i_pos) >= 0 &&
-	    !new_inode)
-		goto degenerate_case;
+	error = fat_scan(new_dir, new_name, &sinfo);
+	if (!error) {
+		new_i_pos = sinfo.i_pos;
+		new_bh = sinfo.bh;
+		new_de = sinfo.de;
+		if (!new_inode)
+			goto degenerate_case;
+	}
 	if (is_dir) {
 		if (new_inode) {
 			error = fat_dir_empty(new_inode);
 			if (error)
 				goto out;
 		}
-		if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
-			     &dotdot_de, &dotdot_i_pos) < 0) {
+		if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
+					 &dotdot_i_pos) < 0) {
 			error = -EIO;
 			goto out;
 		}
@@ -554,6 +565,7 @@ degenerate_case:
 	error = -EINVAL;
 	if (new_de != old_de)
 		goto out;
+	brelse(new_bh);
 	if (is_hid)
 		MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
 	else
@@ -569,9 +581,7 @@ degenerate_case:
 static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
 			struct inode *new_dir, struct dentry *new_dentry)
 {
-	struct buffer_head *old_bh;
-	struct msdos_dir_entry *old_de;
-	loff_t old_i_pos;
+	struct fat_slot_info sinfo;
 	int error, is_hid, old_hid; /* if new file and old file are hidden */
 	unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
 
@@ -592,14 +602,14 @@ static int msdos_rename(struct inode *ol
 	old_hid =
 	     (old_dentry->d_name.name[0] == '.') && (old_msdos_name[0] != '.');
 
-	error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_i_pos);
+	error = fat_scan(old_dir, old_msdos_name, &sinfo);
 	if (error < 0)
 		goto rename_done;
 
 	error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
 				new_dir, new_msdos_name, new_dentry,
-				old_bh, old_de, old_i_pos, is_hid);
-	brelse(old_bh);
+				sinfo.bh, sinfo.de, sinfo.i_pos, is_hid);
+	brelse(sinfo.bh);
 
 rename_done:
 	unlock_kernel();
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup5 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync06-fat_dir-cleanup5	2005-03-06 02:36:35.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:36:35.000000000 +0900
@@ -208,15 +208,11 @@ static int vfat_valid_longname(const uns
 
 static int vfat_find_form(struct inode *dir, unsigned char *name)
 {
-	struct msdos_dir_entry *de;
-	struct buffer_head *bh = NULL;
-	loff_t i_pos;
-	int res;
-
-	res = fat_scan(dir, name, &bh, &de, &i_pos);
-	brelse(bh);
-	if (res < 0)
+	struct fat_slot_info sinfo;
+	int err = fat_scan(dir, name, &sinfo);
+	if (err)
 		return -ENOENT;
+	brelse(sinfo.bh);
 	return 0;
 }
 
@@ -938,8 +934,8 @@ static int vfat_rename(struct inode *old
 
 	is_dir = S_ISDIR(old_inode->i_mode);
 	if (is_dir) {
-		if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
-			     &dotdot_de, &dotdot_i_pos) < 0) {
+		if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
+					 &dotdot_i_pos) < 0) {
 			err = -EIO;
 			goto out;
 		}
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup5 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync06-fat_dir-cleanup5	2005-03-06 02:36:35.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:36:35.000000000 +0900
@@ -331,8 +331,9 @@ extern int fat_new_dir(struct inode *dir
 extern int fat_dir_empty(struct inode *dir);
 extern int fat_subdirs(struct inode *dir);
 extern int fat_scan(struct inode *dir, const unsigned char *name,
-		    struct buffer_head **res_bh,
-		    struct msdos_dir_entry **res_de, loff_t *i_pos);
+		    struct fat_slot_info *sinfo);
+extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
+				struct msdos_dir_entry **de, loff_t *i_pos);
 extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
 
 /* fat/fatent.c */
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 13/29] FAT: Use "struct fat_slot_info" for msdos_find()
  2005-03-05 18:50                     ` [PATCH 12/29] FAT: Use "struct fat_slot_info" for fat_scan() OGAWA Hirofumi
@ 2005-03-05 18:50                       ` OGAWA Hirofumi
  2005-03-05 18:51                         ` [PATCH 14/29] FAT: vfat_build_slots() cleanup OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:50 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


The msdos_find() provide the "struct fat_slot_info". Then some cleanups.

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

 fs/msdos/namei.c |   88 ++++++++++++++++++++++---------------------------------
 1 files changed, 36 insertions(+), 52 deletions(-)

diff -puN fs/msdos/namei.c~sync06-fat_dir-cleanup6 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync06-fat_dir-cleanup6	2005-03-06 02:36:39.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c	2005-03-06 02:36:39.000000000 +0900
@@ -137,11 +137,9 @@ static int msdos_format_name(const unsig
 
 /***** Locates a directory entry.  Uses unformatted name. */
 static int msdos_find(struct inode *dir, const unsigned char *name, int len,
-		      struct buffer_head **bh, struct msdos_dir_entry **de,
-		      loff_t *i_pos)
+		      struct fat_slot_info *sinfo)
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
-	struct fat_slot_info sinfo;
 	unsigned char msdos_name[MSDOS_NAME];
 	int err;
 
@@ -149,22 +147,17 @@ static int msdos_find(struct inode *dir,
 	if (err)
 		return -ENOENT;
 
-	err = fat_scan(dir, msdos_name, &sinfo);
+	err = fat_scan(dir, msdos_name, sinfo);
 	if (!err && sbi->options.dotsOK) {
 		if (name[0] == '.') {
-			if (!(sinfo.de->attr & ATTR_HIDDEN))
+			if (!(sinfo->de->attr & ATTR_HIDDEN))
 				err = -ENOENT;
 		} else {
-			if (sinfo.de->attr & ATTR_HIDDEN)
+			if (sinfo->de->attr & ATTR_HIDDEN)
 				err = -ENOENT;
 		}
 		if (err)
-			brelse(sinfo.bh);
-	}
-	if (!err) {
-		*i_pos = sinfo.i_pos;
-		*de = sinfo.de;
-		*bh = sinfo.bh;
+			brelse(sinfo->bh);
 	}
 	return err;
 }
@@ -228,22 +221,20 @@ static struct dentry *msdos_lookup(struc
 				   struct nameidata *nd)
 {
 	struct super_block *sb = dir->i_sb;
+	struct fat_slot_info sinfo;
 	struct inode *inode = NULL;
-	struct msdos_dir_entry *de;
-	struct buffer_head *bh = NULL;
-	loff_t i_pos;
 	int res;
 
 	dentry->d_op = &msdos_dentry_operations;
 
 	lock_kernel();
-	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh,
-			 &de, &i_pos);
+	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
 	if (res == -ENOENT)
 		goto add;
 	if (res < 0)
 		goto out;
-	inode = fat_build_inode(sb, de, i_pos);
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+	brelse(sinfo.bh);
 	if (IS_ERR(inode)) {
 		res = PTR_ERR(inode);
 		goto out;
@@ -254,7 +245,6 @@ add:
 	if (dentry)
 		dentry->d_op = &msdos_dentry_operations;
 out:
-	brelse(bh);
 	unlock_kernel();
 	if (!res)
 		return dentry;
@@ -341,39 +331,35 @@ static int msdos_create(struct inode *di
 static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	loff_t i_pos;
-	int res;
-	struct buffer_head *bh;
-	struct msdos_dir_entry *de;
+	struct fat_slot_info sinfo;
+	int err;
 
-	bh = NULL;
 	lock_kernel();
-	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
-			 &bh, &de, &i_pos);
-	if (res < 0)
-		goto rmdir_done;
 	/*
 	 * Check whether the directory is not in use, then check
 	 * whether it is empty.
 	 */
-	res = fat_dir_empty(inode);
-	if (res)
-		goto rmdir_done;
+	err = fat_dir_empty(inode);
+	if (err)
+		goto out;
+	err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
+	if (err)
+		goto out;
 
-	de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(bh);
+	sinfo.de->name[0] = DELETED_FLAG;
+	mark_buffer_dirty(sinfo.bh);
+	brelse(sinfo.bh);
 	fat_detach(inode);
 	inode->i_nlink = 0;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
-	dir->i_nlink--;
 	mark_inode_dirty(inode);
-	mark_inode_dirty(dir);
-	res = 0;
 
-rmdir_done:
-	brelse(bh);
+	dir->i_nlink--;
+	mark_inode_dirty(dir);
+out:
 	unlock_kernel();
-	return res;
+
+	return err;
 }
 
 /***** Make a directory */
@@ -420,6 +406,7 @@ static int msdos_mkdir(struct inode *dir
 	if (res)
 		goto mkdir_error;
 	brelse(bh);
+
 	d_instantiate(dentry, inode);
 	res = 0;
 
@@ -445,30 +432,27 @@ mkdir_error:
 static int msdos_unlink(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	loff_t i_pos;
-	int res;
-	struct buffer_head *bh;
-	struct msdos_dir_entry *de;
+	struct fat_slot_info sinfo;
+	int err;
 
-	bh = NULL;
 	lock_kernel();
-	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
-			 &bh, &de, &i_pos);
-	if (res < 0)
+	err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
+	if (err)
 		goto unlink_done;
 
-	de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(bh);
+	sinfo.de->name[0] = DELETED_FLAG;
+	mark_buffer_dirty(sinfo.bh);
+	brelse(sinfo.bh);
 	fat_detach(inode);
-	brelse(bh);
 	inode->i_nlink = 0;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
 	mark_inode_dirty(inode);
+
 	mark_inode_dirty(dir);
-	res = 0;
 unlink_done:
 	unlock_kernel();
-	return res;
+
+	return err;
 }
 
 static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 14/29] FAT: vfat_build_slots() cleanup
  2005-03-05 18:50                       ` [PATCH 13/29] FAT: Use "struct fat_slot_info" for msdos_find() OGAWA Hirofumi
@ 2005-03-05 18:51                         ` OGAWA Hirofumi
  2005-03-05 18:52                           ` [PATCH 15/29] FAT: Use a same timestamp on some operations path OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:51 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


With this, the vfat_build_slots() builds the completely data including
the timestamp and cluster. (But this is not using "cluster", it's not
complete yet)

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

 fs/vfat/namei.c |  110 ++++++++++++++++++++++++++------------------------------
 1 files changed, 52 insertions(+), 58 deletions(-)

diff -puN fs/vfat/namei.c~sync07-fat_dir fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync07-fat_dir	2005-03-06 02:36:41.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:36:41.000000000 +0900
@@ -575,8 +575,9 @@ xlate_to_uni(const unsigned char *name, 
 }
 
 static int vfat_build_slots(struct inode *dir, const unsigned char *name,
-			    int len, struct msdos_dir_slot *ds,
-			    int *slots, int is_dir)
+			    int len, int is_dir, int cluster,
+			    struct timespec *ts,
+			    struct msdos_dir_slot *slots, int *nr_slots)
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
 	struct fat_mount_options *opts = &sbi->options;
@@ -586,83 +587,85 @@ static int vfat_build_slots(struct inode
 	unsigned char cksum, lcase;
 	unsigned char msdos_name[MSDOS_NAME];
 	wchar_t *uname;
-	int res, slot, ulen, usize, i;
+	__le16 time, date;
+	int err, ulen, usize, i;
 	loff_t offset;
 
-	*slots = 0;
-	res = vfat_valid_longname(name, len);
-	if (res)
-		return res;
+	*nr_slots = 0;
+	err = vfat_valid_longname(name, len);
+	if (err)
+		return err;
 
 	page = __get_free_page(GFP_KERNEL);
 	if (!page)
 		return -ENOMEM;
 
 	uname = (wchar_t *)page;
-	res = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,
+	err = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,
 			   opts->unicode_xlate, opts->utf8, sbi->nls_io);
-	if (res < 0)
+	if (err)
 		goto out_free;
 
-	res = vfat_is_used_badchars(uname, ulen);
-	if (res < 0)
+	err = vfat_is_used_badchars(uname, ulen);
+	if (err)
 		goto out_free;
 
-	res = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen,
+	err = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen,
 				    msdos_name, &lcase);
-	if (res < 0)
+	if (err < 0)
 		goto out_free;
-	else if (res == 1) {
-		de = (struct msdos_dir_entry *)ds;
-		res = 0;
+	else if (err == 1) {
+		de = (struct msdos_dir_entry *)slots;
+		err = 0;
 		goto shortname;
 	}
 
 	/* build the entry of long file name */
-	*slots = usize / 13;
 	for (cksum = i = 0; i < 11; i++)
 		cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i];
 
-	for (ps = ds, slot = *slots; slot > 0; slot--, ps++) {
-		ps->id = slot;
+	*nr_slots = usize / 13;
+	for (ps = slots, i = *nr_slots; i > 0; i--, ps++) {
+		ps->id = i;
 		ps->attr = ATTR_EXT;
 		ps->reserved = 0;
 		ps->alias_checksum = cksum;
 		ps->start = 0;
-		offset = (slot - 1) * 13;
+		offset = (i - 1) * 13;
 		fatwchar_to16(ps->name0_4, uname + offset, 5);
 		fatwchar_to16(ps->name5_10, uname + offset + 5, 6);
 		fatwchar_to16(ps->name11_12, uname + offset + 11, 2);
 	}
-	ds[0].id |= 0x40;
+	slots[0].id |= 0x40;
 	de = (struct msdos_dir_entry *)ps;
 
 shortname:
 	/* build the entry of 8.3 alias name */
-	(*slots)++;
+	(*nr_slots)++;
 	memcpy(de->name, msdos_name, MSDOS_NAME);
 	de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
 	de->lcase = lcase;
-	de->adate = de->cdate = de->date = 0;
-	de->ctime = de->time = 0;
+	fat_date_unix2dos(ts->tv_sec, &time, &date);
+	de->time = de->ctime = time;
+	de->date = de->cdate = de->adate = date;
 	de->ctime_cs = 0;
-	de->start = 0;
-	de->starthi = 0;
+	de->start = cpu_to_le16(cluster);
+	de->starthi = cpu_to_le16(cluster >> 16);
 	de->size = 0;
-
 out_free:
 	free_page(page);
-	return res;
+	return err;
 }
 
-static int vfat_add_entry(struct inode *dir, struct qstr *qname,
-			  int is_dir, struct fat_slot_info *sinfo)
+static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,
+			  struct fat_slot_info *sinfo)
 {
 	struct super_block *sb = dir->i_sb;
-	struct msdos_dir_slot *dir_slots;
-	loff_t offset;
-	int res, slots, slot;
+	struct msdos_dir_slot *slots;
+	struct timespec ts;
 	unsigned int len;
+	int err, i, nr_slots;
+	loff_t offset;
 	struct msdos_dir_entry *de, *dummy_de;
 	struct buffer_head *bh, *dummy_bh;
 	loff_t dummy_i_pos;
@@ -671,59 +674,50 @@ static int vfat_add_entry(struct inode *
 	if (len == 0)
 		return -ENOENT;
 
-	dir_slots = kmalloc(sizeof(*dir_slots) * MSDOS_SLOTS, GFP_KERNEL);
-	if (dir_slots == NULL)
+	slots = kmalloc(sizeof(*slots) * MSDOS_SLOTS, GFP_KERNEL);
+	if (slots == NULL)
 		return -ENOMEM;
 
-	res = vfat_build_slots(dir, qname->name, len,
-			       dir_slots, &slots, is_dir);
-	if (res < 0)
+	ts = CURRENT_TIME_SEC;
+	err = vfat_build_slots(dir, qname->name, len, is_dir, 0, &ts,
+			       slots, &nr_slots);
+	if (err)
 		goto cleanup;
 
 	/* build the empty directory entry of number of slots */
 	offset =
-	    fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_i_pos);
+	    fat_add_entries(dir, nr_slots, &dummy_bh, &dummy_de, &dummy_i_pos);
 	if (offset < 0) {
-		res = offset;
+		err = offset;
 		goto cleanup;
 	}
 	brelse(dummy_bh);
 
 	/* Now create the new entry */
 	bh = NULL;
-	for (slot = 0; slot < slots; slot++) {
+	for (i = 0; i < nr_slots; i++) {
 		if (fat_get_entry(dir, &offset, &bh, &de, &sinfo->i_pos) < 0) {
-			res = -EIO;
+			err = -EIO;
 			goto cleanup;
 		}
-		memcpy(de, dir_slots + slot, sizeof(struct msdos_dir_slot));
+		memcpy(de, slots + i, sizeof(struct msdos_dir_slot));
 		mark_buffer_dirty(bh);
 		if (sb->s_flags & MS_SYNCHRONOUS)
 			sync_dirty_buffer(bh);
 	}
 
-	res = 0;
 	/* update timestamp */
-	dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
+	dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
 	mark_inode_dirty(dir);
 
-	fat_date_unix2dos(dir->i_mtime.tv_sec, &de->time, &de->date);
-	dir->i_mtime.tv_nsec = 0;
-	de->ctime = de->time;
-	de->adate = de->cdate = de->date;
-	mark_buffer_dirty(bh);
-	if (sb->s_flags & MS_SYNCHRONOUS)
-		sync_dirty_buffer(bh);
-
 	/* slots can't be less than 1 */
-	sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * slots;
-	sinfo->nr_slots = slots;
+	sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * nr_slots;
+	sinfo->nr_slots = nr_slots;
 	sinfo->de = de;
 	sinfo->bh = bh;
-
 cleanup:
-	kfree(dir_slots);
-	return res;
+	kfree(slots);
+	return err;
 }
 
 static int vfat_find(struct inode *dir, struct qstr *qname,
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 15/29] FAT: Use a same timestamp on some operations path
  2005-03-05 18:51                         ` [PATCH 14/29] FAT: vfat_build_slots() cleanup OGAWA Hirofumi
@ 2005-03-05 18:52                           ` OGAWA Hirofumi
  2005-03-05 18:52                             ` [PATCH 16/29] FAT: msdos_rename() cleanup OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:52 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


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

 fs/vfat/namei.c |   63 +++++++++++++++++++++++++++++++-------------------------
 1 files changed, 35 insertions(+), 28 deletions(-)

diff -puN fs/vfat/namei.c~sync07-fat_dir2 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync07-fat_dir2	2005-03-06 02:36:44.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:36:44.000000000 +0900
@@ -658,11 +658,11 @@ out_free:
 }
 
 static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,
+			  struct timespec *ts,
 			  struct fat_slot_info *sinfo)
 {
 	struct super_block *sb = dir->i_sb;
 	struct msdos_dir_slot *slots;
-	struct timespec ts;
 	unsigned int len;
 	int err, i, nr_slots;
 	loff_t offset;
@@ -678,8 +678,7 @@ static int vfat_add_entry(struct inode *
 	if (slots == NULL)
 		return -ENOMEM;
 
-	ts = CURRENT_TIME_SEC;
-	err = vfat_build_slots(dir, qname->name, len, is_dir, 0, &ts,
+	err = vfat_build_slots(dir, qname->name, len, is_dir, 0, ts,
 			       slots, &nr_slots);
 	if (err)
 		goto cleanup;
@@ -707,7 +706,7 @@ static int vfat_add_entry(struct inode *
 	}
 
 	/* update timestamp */
-	dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
+	dir->i_ctime = dir->i_mtime = dir->i_atime = *ts;
 	mark_inode_dirty(dir);
 
 	/* slots can't be less than 1 */
@@ -780,33 +779,33 @@ static int vfat_create(struct inode *dir
 		       struct nameidata *nd)
 {
 	struct super_block *sb = dir->i_sb;
-	struct inode *inode = NULL;
+	struct inode *inode;
 	struct fat_slot_info sinfo;
-	int res;
+	struct timespec ts;
+	int err;
 
 	lock_kernel();
-	res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo);
-	if (res < 0)
+
+	ts = CURRENT_TIME_SEC;
+	err = vfat_add_entry(dir, &dentry->d_name, 0, &ts, &sinfo);
+	if (err)
 		goto out;
 	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 	brelse(sinfo.bh);
 	if (IS_ERR(inode)) {
-		res = PTR_ERR(inode);
+		err = PTR_ERR(inode);
 		goto out;
 	}
-	res = 0;
 	inode->i_version++;
-	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
-	mark_inode_dirty(inode);
-	if (IS_SYNC(inode))
-		fat_sync_inode(inode);
+	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
+	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
 	dir->i_version++;
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry, inode);
 out:
 	unlock_kernel();
-	return res;
+	return err;
 }
 
 static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
@@ -869,37 +868,42 @@ static int vfat_mkdir(struct inode *dir,
 	struct super_block *sb = dir->i_sb;
 	struct inode *inode = NULL;
 	struct fat_slot_info sinfo;
-	int res;
+	struct timespec ts;
+	int err;
 
 	lock_kernel();
-	res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo);
-	if (res < 0)
+
+	ts = CURRENT_TIME_SEC;
+	err = vfat_add_entry(dir, &dentry->d_name, 1, &ts, &sinfo);
+	if (err)
 		goto out;
 	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 	if (IS_ERR(inode)) {
-		res = PTR_ERR(inode);
+		err = PTR_ERR(inode);
 		goto out_brelse;
 	}
-	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
-	mark_inode_dirty(inode);
 	inode->i_version++;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
+	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
+
 	dir->i_version++;
 	dir->i_nlink++;
 	inode->i_nlink = 2;	/* no need to mark them dirty */
-	res = fat_new_dir(inode, dir, 1);
-	if (res < 0)
+	err = fat_new_dir(inode, dir, 1);
+	if (err)
 		goto mkdir_failed;
+
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry, inode);
 out_brelse:
 	brelse(sinfo.bh);
 out:
 	unlock_kernel();
-	return res;
+	return err;
 
 mkdir_failed:
 	inode->i_nlink = 0;
-	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
+	inode->i_mtime = inode->i_atime = ts;
 	fat_detach(inode);
 	mark_inode_dirty(inode);
 	fat_remove_entries(dir, &sinfo);	/* and releases bh */
@@ -917,6 +921,7 @@ static int vfat_rename(struct inode *old
 	struct inode *old_inode, *new_inode;
 	int err, is_dir;
 	struct fat_slot_info old_sinfo, sinfo;
+	struct timespec ts;
 
 	old_sinfo.bh = dotdot_bh = NULL;
 	old_inode = old_dentry->d_inode;
@@ -935,6 +940,7 @@ static int vfat_rename(struct inode *old
 		}
 	}
 
+	ts = CURRENT_TIME_SEC;
 	if (new_dentry->d_inode) {
 		err = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
 		if (err)
@@ -953,7 +959,7 @@ static int vfat_rename(struct inode *old
 		}
 		fat_detach(new_inode);
 	} else {
-		err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
+		err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, &ts,
 				     &sinfo);
 		if (err)
 			goto out;
@@ -972,11 +978,12 @@ static int vfat_rename(struct inode *old
 	mark_inode_dirty(old_inode);
 
 	old_dir->i_version++;
-	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+	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 = CURRENT_TIME_SEC;
+		new_inode->i_ctime = ts;
 	}
 
 	if (is_dir) {
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 16/29] FAT: msdos_rename() cleanup
  2005-03-05 18:52                           ` [PATCH 15/29] FAT: Use a same timestamp on some operations path OGAWA Hirofumi
@ 2005-03-05 18:52                             ` OGAWA Hirofumi
  2005-03-05 18:53                               ` [PATCH 17/29] FAT: msdos_add_entry() cleanup OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:52 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


Cleans up the msdos_rename(). (use the logic similar to vfat_rename().)

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

 fs/msdos/namei.c |  175 +++++++++++++++++++++++++++----------------------------
 1 files changed, 89 insertions(+), 86 deletions(-)

diff -puN fs/msdos/namei.c~sync07-fat_dir3 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync07-fat_dir3	2005-03-06 02:36:47.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c	2005-03-06 02:36:47.000000000 +0900
@@ -458,146 +458,149 @@ unlink_done:
 static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
 			   struct dentry *old_dentry,
 			   struct inode *new_dir, unsigned char *new_name,
-			   struct dentry *new_dentry,
-			   struct buffer_head *old_bh,
-			   struct msdos_dir_entry *old_de, loff_t old_i_pos,
-			   int is_hid)
-{
-	struct fat_slot_info sinfo;
-	struct buffer_head *new_bh = NULL, *dotdot_bh = NULL;
-	struct msdos_dir_entry *new_de, *dotdot_de;
+			   struct dentry *new_dentry, int is_hid)
+{
+	struct buffer_head *dotdot_bh;
+	struct msdos_dir_entry *dotdot_de;
+	loff_t dotdot_i_pos;
 	struct inode *old_inode, *new_inode;
-	loff_t new_i_pos, dotdot_i_pos;
-	int error;
-	int is_dir;
+	struct fat_slot_info old_sinfo, sinfo;
+	int err, is_dir;
 
+	old_sinfo.bh = dotdot_bh = NULL;
 	old_inode = old_dentry->d_inode;
 	new_inode = new_dentry->d_inode;
-	is_dir = S_ISDIR(old_inode->i_mode);
 
-	error = fat_scan(new_dir, new_name, &sinfo);
-	if (!error) {
-		new_i_pos = sinfo.i_pos;
-		new_bh = sinfo.bh;
-		new_de = sinfo.de;
-		if (!new_inode)
-			goto degenerate_case;
+	err = fat_scan(old_dir, old_name, &old_sinfo);
+	if (err) {
+		err = -EIO;
+		goto out;
 	}
+
+	is_dir = S_ISDIR(old_inode->i_mode);
 	if (is_dir) {
-		if (new_inode) {
-			error = fat_dir_empty(new_inode);
-			if (error)
-				goto out;
-		}
 		if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
 					 &dotdot_i_pos) < 0) {
-			error = -EIO;
+			err = -EIO;
 			goto out;
 		}
 	}
-	if (!new_bh) {
-		error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de,
-					&new_i_pos, is_dir, is_hid);
-		if (error)
+
+	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) {
+				err = -EINVAL;
+				goto out;
+			}
+			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 = CURRENT_TIME_SEC;
+			mark_inode_dirty(old_dir);
 			goto out;
+		}
 	}
-	new_dir->i_version++;
-
-	/* There we go */
+	if (new_inode) {
+		if (err)
+			goto out;
+		if (MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
+			/* WTF??? Cry and fail. */
+			printk(KERN_WARNING "msdos_rename: fs corrupted\n");
+			goto out;
+		}
 
-	if (new_inode)
+		if (is_dir) {
+			err = fat_dir_empty(new_inode);
+			if (err)
+				goto out;
+		}
 		fat_detach(new_inode);
-	old_de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(old_bh);
+	} else {
+		err = msdos_add_entry(new_dir, new_name, &sinfo.bh, &sinfo.de,
+				      &sinfo.i_pos, is_dir, is_hid);
+		if (err)
+			goto out;
+		brelse(sinfo.bh);
+	}
+	new_dir->i_version++;
+
+	old_sinfo.de->name[0] = DELETED_FLAG;
+	mark_buffer_dirty(old_sinfo.bh);
+	brelse(old_sinfo.bh);
+	old_sinfo.bh = NULL;
+	if (is_dir)
+		old_dir->i_nlink--;
 	fat_detach(old_inode);
-	fat_attach(old_inode, new_i_pos);
+	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 = CURRENT_TIME_SEC;
 	mark_inode_dirty(old_dir);
+
 	if (new_inode) {
 		new_inode->i_nlink--;
 		new_inode->i_ctime = CURRENT_TIME_SEC;
 		mark_inode_dirty(new_inode);
 	}
-	if (dotdot_bh) {
-		dotdot_de->start = cpu_to_le16(MSDOS_I(new_dir)->i_logstart);
-		dotdot_de->starthi =
-			cpu_to_le16((MSDOS_I(new_dir)->i_logstart) >> 16);
+	if (is_dir) {
+		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);
-		old_dir->i_nlink--;
-		mark_inode_dirty(old_dir);
+
 		if (new_inode) {
 			new_inode->i_nlink--;
-			mark_inode_dirty(new_inode);
 		} else {
 			new_dir->i_nlink++;
 			mark_inode_dirty(new_dir);
 		}
 	}
-	error = 0;
 out:
-	brelse(new_bh);
 	brelse(dotdot_bh);
-	return error;
-
-degenerate_case:
-	error = -EINVAL;
-	if (new_de != old_de)
-		goto out;
-	brelse(new_bh);
-	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 = CURRENT_TIME_SEC;
-	mark_inode_dirty(old_dir);
-	return 0;
+	brelse(old_sinfo.bh);
+	return err;
 }
 
 /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
 static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
 			struct inode *new_dir, struct dentry *new_dentry)
 {
-	struct fat_slot_info sinfo;
-	int error, is_hid, old_hid; /* if new file and old file are hidden */
 	unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
+	int err, is_hid;
 
 	lock_kernel();
-	error = msdos_format_name(old_dentry->d_name.name,
-				  old_dentry->d_name.len, old_msdos_name,
-				  &MSDOS_SB(old_dir->i_sb)->options);
-	if (error < 0)
-		goto rename_done;
-	error = msdos_format_name(new_dentry->d_name.name,
-				  new_dentry->d_name.len, new_msdos_name,
-				  &MSDOS_SB(new_dir->i_sb)->options);
-	if (error < 0)
-		goto rename_done;
+
+	err = msdos_format_name(old_dentry->d_name.name,
+				old_dentry->d_name.len, old_msdos_name,
+				&MSDOS_SB(old_dir->i_sb)->options);
+	if (err)
+		goto out;
+	err = msdos_format_name(new_dentry->d_name.name,
+				new_dentry->d_name.len, new_msdos_name,
+				&MSDOS_SB(new_dir->i_sb)->options);
+	if (err)
+		goto out;
 
 	is_hid =
 	     (new_dentry->d_name.name[0] == '.') && (new_msdos_name[0] != '.');
-	old_hid =
-	     (old_dentry->d_name.name[0] == '.') && (old_msdos_name[0] != '.');
 
-	error = fat_scan(old_dir, old_msdos_name, &sinfo);
-	if (error < 0)
-		goto rename_done;
-
-	error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
-				new_dir, new_msdos_name, new_dentry,
-				sinfo.bh, sinfo.de, sinfo.i_pos, is_hid);
-	brelse(sinfo.bh);
-
-rename_done:
+	err = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
+			      new_dir, new_msdos_name, new_dentry, is_hid);
+out:
 	unlock_kernel();
-	return error;
+	return err;
 }
 
 static struct inode_operations msdos_dir_inode_operations = {
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 17/29] FAT: msdos_add_entry() cleanup
  2005-03-05 18:52                             ` [PATCH 16/29] FAT: msdos_rename() cleanup OGAWA Hirofumi
@ 2005-03-05 18:53                               ` OGAWA Hirofumi
  2005-03-05 18:53                                 ` [PATCH 18/29] FAT: Allocate the cluster before adding the directory entry OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:53 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


The msdos_add_entry() use similar interface to vfat_add_entry().
And use a same timestamp on some operations path.

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

 fs/msdos/namei.c |  162 ++++++++++++++++++++++++++++---------------------------
 1 files changed, 84 insertions(+), 78 deletions(-)

diff -puN fs/msdos/namei.c~sync07-fat_dir4 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync07-fat_dir4	2005-03-06 02:36:50.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c	2005-03-06 02:36:50.000000000 +0900
@@ -253,31 +253,38 @@ out:
 
 /***** Creates a directory entry (name is already formatted). */
 static int msdos_add_entry(struct inode *dir, const unsigned char *name,
-			   struct buffer_head **bh,
-			   struct msdos_dir_entry **de,
-			   loff_t *i_pos, int is_dir, int is_hid)
+			   int is_dir, int is_hid, struct timespec *ts,
+			   struct fat_slot_info *sinfo)
 {
-	int res;
+	struct msdos_dir_entry de;
+	__le16 time, date;
+	int offset;
 
-	res = fat_add_entries(dir, 1, bh, de, i_pos);
-	if (res < 0)
-		return res;
+	memcpy(de.name, name, MSDOS_NAME);
+	de.attr = is_dir ? ATTR_DIR : ATTR_ARCH;
+	if (is_hid)
+		de.attr |= ATTR_HIDDEN;
+	de.lcase = 0;
+	fat_date_unix2dos(ts->tv_sec, &time, &date);
+	de.time = de.ctime = time;
+	de.date = de.cdate = de.adate = date;
+	de.ctime_cs = 0;
+	de.start = 0;
+	de.starthi = 0;
+	de.size = 0;
+
+	offset = fat_add_entries(dir, 1, &sinfo->bh, &sinfo->de, &sinfo->i_pos);
+	if (offset < 0)
+		return offset;
+	sinfo->slot_off = offset;
+	sinfo->nr_slots = 1;
 
-	/*
-	 * XXX all times should be set by caller upon successful completion.
-	 */
-	dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+	memcpy(sinfo->de, &de, sizeof(de));
+	mark_buffer_dirty(sinfo->bh);
+
+	dir->i_ctime = dir->i_mtime = *ts;
 	mark_inode_dirty(dir);
 
-	memcpy((*de)->name, name, MSDOS_NAME);
-	(*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
-	if (is_hid)
-		(*de)->attr |= ATTR_HIDDEN;
-	(*de)->start = 0;
-	(*de)->starthi = 0;
-	fat_date_unix2dos(dir->i_mtime.tv_sec, &(*de)->time, &(*de)->date);
-	(*de)->size = 0;
-	mark_buffer_dirty(*bh);
 	return 0;
 }
 
@@ -286,45 +293,43 @@ static int msdos_create(struct inode *di
 			struct nameidata *nd)
 {
 	struct super_block *sb = dir->i_sb;
-	struct fat_slot_info sinfo;
-	struct buffer_head *bh;
-	struct msdos_dir_entry *de;
 	struct inode *inode;
-	loff_t i_pos;
-	int res, is_hid;
+	struct fat_slot_info sinfo;
+	struct timespec ts;
 	unsigned char msdos_name[MSDOS_NAME];
+	int err, is_hid;
 
 	lock_kernel();
-	res = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
+
+	err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
 				msdos_name, &MSDOS_SB(sb)->options);
-	if (res < 0) {
-		unlock_kernel();
-		return res;
-	}
+	if (err)
+		goto out;
 	is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
 	/* Have to do it due to foo vs. .foo conflicts */
 	if (!fat_scan(dir, msdos_name, &sinfo)) {
 		brelse(sinfo.bh);
-		unlock_kernel();
-		return -EINVAL;
+		err = -EINVAL;
+		goto out;
 	}
 
-	res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid);
-	if (res) {
-		unlock_kernel();
-		return res;
-	}
-	inode = fat_build_inode(sb, de, i_pos);
-	brelse(bh);
+	ts = CURRENT_TIME_SEC;
+	err = msdos_add_entry(dir, msdos_name, 0, is_hid, &ts, &sinfo);
+	if (err)
+		goto out;
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+	brelse(sinfo.bh);
 	if (IS_ERR(inode)) {
-		unlock_kernel();
-		return PTR_ERR(inode);
+		err = PTR_ERR(inode);
+		goto out;
 	}
-	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
-	mark_inode_dirty(inode);
+	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
+	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
+
 	d_instantiate(dentry, inode);
+out:
 	unlock_kernel();
-	return 0;
+	return err;
 }
 
 /***** Remove a directory */
@@ -367,65 +372,63 @@ static int msdos_mkdir(struct inode *dir
 {
 	struct super_block *sb = dir->i_sb;
 	struct fat_slot_info sinfo;
-	struct buffer_head *bh;
-	struct msdos_dir_entry *de;
 	struct inode *inode;
-	int res, is_hid;
 	unsigned char msdos_name[MSDOS_NAME];
-	loff_t i_pos;
+	struct timespec ts;
+	int err, is_hid;
 
 	lock_kernel();
-	res = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
+
+	err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
 				msdos_name, &MSDOS_SB(sb)->options);
-	if (res < 0) {
-		unlock_kernel();
-		return res;
-	}
+	if (err)
+		goto out;
 	is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
 	/* foo vs .foo situation */
 	if (!fat_scan(dir, msdos_name, &sinfo)) {
 		brelse(sinfo.bh);
-		res = -EINVAL;
-		goto out_unlock;
+		err = -EINVAL;
+		goto out;
 	}
 
-	res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid);
-	if (res)
-		goto out_unlock;
-	inode = fat_build_inode(dir->i_sb, de, i_pos);
+	ts = CURRENT_TIME_SEC;
+	err = msdos_add_entry(dir, msdos_name, 1, is_hid, &ts, &sinfo);
+	if (err)
+		goto out;
+	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 	if (IS_ERR(inode)) {
-		brelse(bh);
-		res = PTR_ERR(inode);
-		goto out_unlock;
+		brelse(sinfo.bh);
+		err = PTR_ERR(inode);
+		goto out;
 	}
+	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
+	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
 	dir->i_nlink++;
 	inode->i_nlink = 2;	/* no need to mark them dirty */
 
-	res = fat_new_dir(inode, dir, 0);
-	if (res)
+	err = fat_new_dir(inode, dir, 0);
+	if (err)
 		goto mkdir_error;
-	brelse(bh);
+	brelse(sinfo.bh);
 
 	d_instantiate(dentry, inode);
-	res = 0;
-
-out_unlock:
+out:
 	unlock_kernel();
-	return res;
+	return err;
 
 mkdir_error:
 	inode->i_nlink = 0;
-	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+	inode->i_ctime = dir->i_ctime = dir->i_mtime = ts;
 	dir->i_nlink--;
 	mark_inode_dirty(inode);
 	mark_inode_dirty(dir);
-	de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(bh);
-	brelse(bh);
+	sinfo.de->name[0] = DELETED_FLAG;
+	mark_buffer_dirty(sinfo.bh);
+	brelse(sinfo.bh);
 	fat_detach(inode);
 	iput(inode);
-	goto out_unlock;
+	goto out;
 }
 
 /***** Unlink a file */
@@ -465,6 +468,7 @@ static int do_msdos_rename(struct inode 
 	loff_t dotdot_i_pos;
 	struct inode *old_inode, *new_inode;
 	struct fat_slot_info old_sinfo, sinfo;
+	struct timespec ts;
 	int err, is_dir;
 
 	old_sinfo.bh = dotdot_bh = NULL;
@@ -507,6 +511,8 @@ static int do_msdos_rename(struct inode 
 			goto out;
 		}
 	}
+
+	ts = CURRENT_TIME_SEC;
 	if (new_inode) {
 		if (err)
 			goto out;
@@ -523,8 +529,8 @@ static int do_msdos_rename(struct inode 
 		}
 		fat_detach(new_inode);
 	} else {
-		err = msdos_add_entry(new_dir, new_name, &sinfo.bh, &sinfo.de,
-				      &sinfo.i_pos, is_dir, is_hid);
+		err = msdos_add_entry(new_dir, new_name, is_dir, is_hid,
+				      &ts, &sinfo);
 		if (err)
 			goto out;
 		brelse(sinfo.bh);
@@ -546,12 +552,12 @@ static int do_msdos_rename(struct inode 
 	mark_inode_dirty(old_inode);
 
 	old_dir->i_version++;
-	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+	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 = CURRENT_TIME_SEC;
+		new_inode->i_ctime = ts;
 		mark_inode_dirty(new_inode);
 	}
 	if (is_dir) {
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 18/29] FAT: Allocate the cluster before adding the directory entry
  2005-03-05 18:53                               ` [PATCH 17/29] FAT: msdos_add_entry() cleanup OGAWA Hirofumi
@ 2005-03-05 18:53                                 ` OGAWA Hirofumi
  2005-03-05 18:54                                   ` [PATCH 19/29] FAT: Rewrite fat_add_entries() OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:53 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


With this change, ->mkdir() uses the correct updating order.

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

 fs/fat/dir.c             |  155 +++++++++++++++++++++++++++++++++--------------
 fs/fat/fatent.c          |    3 
 fs/msdos/namei.c         |   54 +++++++---------
 fs/vfat/namei.c          |   59 ++++++++---------
 include/linux/msdos_fs.h |    2 
 5 files changed, 169 insertions(+), 104 deletions(-)

diff -puN fs/fat/dir.c~sync07-fat_dir5 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync07-fat_dir5	2005-03-06 02:36:53.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:36:53.000000000 +0900
@@ -869,6 +869,118 @@ int fat_remove_entries(struct inode *dir
 
 EXPORT_SYMBOL(fat_remove_entries);
 
+static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used,
+			      struct buffer_head **bhs, int nr_bhs)
+{
+	struct super_block *sb = dir->i_sb;
+	sector_t last_blknr = blknr + MSDOS_SB(sb)->sec_per_clus;
+	int err, i, n;
+
+	/* Zeroing the unused blocks on this cluster */
+	blknr += nr_used;
+	n = nr_used;
+	while (blknr < last_blknr) {
+		bhs[n] = sb_getblk(sb, blknr);
+		if (!bhs[n]) {
+			err = -ENOMEM;
+			goto error;
+		}
+		memset(bhs[n]->b_data, 0, sb->s_blocksize);
+		set_buffer_uptodate(bhs[n]);
+		mark_buffer_dirty(bhs[n]);
+
+		n++;
+		blknr++;
+		if (n == nr_bhs) {
+			if (IS_DIRSYNC(dir)) {
+				err = fat_sync_bhs(bhs, n);
+				if (err)
+					goto error;
+			}
+			for (i = 0; i < n; i++)
+				brelse(bhs[i]);
+			n = 0;
+		}
+	}
+	if (IS_DIRSYNC(dir)) {
+		err = fat_sync_bhs(bhs, n);
+		if (err)
+			goto error;
+	}
+	for (i = 0; i < n; i++)
+		brelse(bhs[i]);
+
+	return 0;
+
+error:
+	for (i = 0; i < n; i++)
+		bforget(bhs[i]);
+	return err;
+}
+
+int fat_alloc_new_dir(struct inode *dir, struct timespec *ts)
+{
+	struct super_block *sb = dir->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+	struct msdos_dir_entry *de;
+	sector_t blknr;
+	__le16 date, time;
+	int err, cluster;
+
+	err = fat_alloc_clusters(dir, &cluster, 1);
+	if (err)
+		goto error;
+
+	blknr = fat_clus_to_blknr(sbi, cluster);
+	bhs[0] = sb_getblk(sb, blknr);
+	if (!bhs[0]) {
+		err = -ENOMEM;
+		goto error_free;
+	}
+
+	fat_date_unix2dos(ts->tv_sec, &time, &date);
+
+	de = (struct msdos_dir_entry *)bhs[0]->b_data;
+	/* filling the new directory slots ("." and ".." entries) */
+	memcpy(de[0].name, MSDOS_DOT, MSDOS_NAME);
+	memcpy(de[1].name, MSDOS_DOTDOT, MSDOS_NAME);
+	de->attr = de[1].attr = ATTR_DIR;
+	de[0].lcase = de[1].lcase = 0;
+	de[0].time = de[1].time = time;
+	de[0].date = de[1].date = date;
+	de[0].ctime_cs = de[1].ctime_cs = 0;
+	if (sbi->options.isvfat) {
+		/* extra timestamps */
+		de[0].ctime = de[1].ctime = time;
+		de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date;
+	} else {
+		de[0].ctime = de[1].ctime = 0;
+		de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0;
+	}
+	de[0].start = cpu_to_le16(cluster);
+	de[0].starthi = cpu_to_le16(cluster >> 16);
+	de[1].start = cpu_to_le16(MSDOS_I(dir)->i_logstart);
+	de[1].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart >> 16);
+	de[0].size = de[1].size = 0;
+	memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de));
+	set_buffer_uptodate(bhs[0]);
+	mark_buffer_dirty(bhs[0]);
+
+	err = fat_zeroed_cluster(dir, blknr, 1, bhs, MAX_BUF_PER_PAGE);
+	if (err)
+		goto error_free;
+
+	return cluster;
+
+error_free:
+	fat_free_clusters(dir, cluster);
+error:
+	return err;
+}
+
+EXPORT_SYMBOL(fat_alloc_new_dir);
+
 static struct buffer_head *fat_extend_dir(struct inode *inode)
 {
 	struct super_block *sb = inode->i_sb;
@@ -960,46 +1072,3 @@ int fat_add_entries(struct inode *dir,in
 }
 
 EXPORT_SYMBOL(fat_add_entries);
-
-int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
-{
-	struct super_block *sb = dir->i_sb;
-	struct buffer_head *bh;
-	struct msdos_dir_entry *de;
-	__le16 date, time;
-
-	bh = fat_extend_dir(dir);
-	if (IS_ERR(bh))
-		return PTR_ERR(bh);
-
-	/* zeroed out, so... */
-	fat_date_unix2dos(dir->i_mtime.tv_sec, &time, &date);
-	de = (struct msdos_dir_entry *)bh->b_data;
-	memcpy(de[0].name, MSDOS_DOT, MSDOS_NAME);
-	memcpy(de[1].name, MSDOS_DOTDOT, MSDOS_NAME);
-	de[0].attr = de[1].attr = ATTR_DIR;
-	de[0].time = de[1].time = time;
-	de[0].date = de[1].date = date;
-	if (is_vfat) {
-		/* extra timestamps */
-		de[0].ctime = de[1].ctime = time;
-		de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date;
-	}
-	de[0].start = cpu_to_le16(MSDOS_I(dir)->i_logstart);
-	de[0].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart >> 16);
-	de[1].start = cpu_to_le16(MSDOS_I(parent)->i_logstart);
-	de[1].starthi = cpu_to_le16(MSDOS_I(parent)->i_logstart >> 16);
-	mark_buffer_dirty(bh);
-	if (sb->s_flags & MS_SYNCHRONOUS)
-		sync_dirty_buffer(bh);
-	brelse(bh);
-
-	dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
-	mark_inode_dirty(dir);
-	if (IS_SYNC(dir))
-		fat_sync_inode(dir);
-
-	return 0;
-}
-
-EXPORT_SYMBOL(fat_new_dir);
diff -puN fs/fat/fatent.c~sync07-fat_dir5 fs/fat/fatent.c
--- linux-2.6.11/fs/fat/fatent.c~sync07-fat_dir5	2005-03-06 02:36:53.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/fatent.c	2005-03-06 02:36:53.000000000 +0900
@@ -3,6 +3,7 @@
  * Released under GPL v2.
  */
 
+#include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/msdos_fs.h>
 
@@ -577,6 +578,8 @@ error:
 	return err;
 }
 
+EXPORT_SYMBOL(fat_free_clusters);
+
 int fat_count_free_clusters(struct super_block *sb)
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
diff -puN fs/msdos/namei.c~sync07-fat_dir5 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync07-fat_dir5	2005-03-06 02:36:53.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c	2005-03-06 02:36:53.000000000 +0900
@@ -253,8 +253,8 @@ out:
 
 /***** Creates a directory entry (name is already formatted). */
 static int msdos_add_entry(struct inode *dir, const unsigned char *name,
-			   int is_dir, int is_hid, struct timespec *ts,
-			   struct fat_slot_info *sinfo)
+			   int is_dir, int is_hid, int cluster,
+			   struct timespec *ts, struct fat_slot_info *sinfo)
 {
 	struct msdos_dir_entry de;
 	__le16 time, date;
@@ -269,8 +269,8 @@ static int msdos_add_entry(struct inode 
 	de.time = de.ctime = time;
 	de.date = de.cdate = de.adate = date;
 	de.ctime_cs = 0;
-	de.start = 0;
-	de.starthi = 0;
+	de.start = cpu_to_le16(cluster);
+	de.starthi = cpu_to_le16(cluster >> 16);
 	de.size = 0;
 
 	offset = fat_add_entries(dir, 1, &sinfo->bh, &sinfo->de, &sinfo->i_pos);
@@ -314,7 +314,7 @@ static int msdos_create(struct inode *di
 	}
 
 	ts = CURRENT_TIME_SEC;
-	err = msdos_add_entry(dir, msdos_name, 0, is_hid, &ts, &sinfo);
+	err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo);
 	if (err)
 		goto out;
 	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
@@ -375,7 +375,7 @@ static int msdos_mkdir(struct inode *dir
 	struct inode *inode;
 	unsigned char msdos_name[MSDOS_NAME];
 	struct timespec ts;
-	int err, is_hid;
+	int err, is_hid, cluster;
 
 	lock_kernel();
 
@@ -392,43 +392,37 @@ static int msdos_mkdir(struct inode *dir
 	}
 
 	ts = CURRENT_TIME_SEC;
-	err = msdos_add_entry(dir, msdos_name, 1, is_hid, &ts, &sinfo);
-	if (err)
+	cluster = fat_alloc_new_dir(dir, &ts);
+	if (cluster < 0) {
+		err = cluster;
 		goto out;
+	}
+	err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
+	if (err)
+		goto out_free;
+	dir->i_nlink++;
+
 	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+	brelse(sinfo.bh);
 	if (IS_ERR(inode)) {
-		brelse(sinfo.bh);
 		err = PTR_ERR(inode);
+		/* the directory was completed, just return a error */
 		goto out;
 	}
+	inode->i_nlink = 2;	/* no need to mark them dirty */
 	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
 	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
-	dir->i_nlink++;
-	inode->i_nlink = 2;	/* no need to mark them dirty */
+	d_instantiate(dentry, inode);
 
-	err = fat_new_dir(inode, dir, 0);
-	if (err)
-		goto mkdir_error;
-	brelse(sinfo.bh);
+	unlock_kernel();
+	return 0;
 
-	d_instantiate(dentry, inode);
+out_free:
+	fat_free_clusters(dir, cluster);
 out:
 	unlock_kernel();
 	return err;
-
-mkdir_error:
-	inode->i_nlink = 0;
-	inode->i_ctime = dir->i_ctime = dir->i_mtime = ts;
-	dir->i_nlink--;
-	mark_inode_dirty(inode);
-	mark_inode_dirty(dir);
-	sinfo.de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(sinfo.bh);
-	brelse(sinfo.bh);
-	fat_detach(inode);
-	iput(inode);
-	goto out;
 }
 
 /***** Unlink a file */
@@ -529,7 +523,7 @@ static int do_msdos_rename(struct inode 
 		}
 		fat_detach(new_inode);
 	} else {
-		err = msdos_add_entry(new_dir, new_name, is_dir, is_hid,
+		err = msdos_add_entry(new_dir, new_name, is_dir, is_hid, 0,
 				      &ts, &sinfo);
 		if (err)
 			goto out;
diff -puN fs/vfat/namei.c~sync07-fat_dir5 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync07-fat_dir5	2005-03-06 02:36:53.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:36:53.000000000 +0900
@@ -658,7 +658,7 @@ out_free:
 }
 
 static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,
-			  struct timespec *ts,
+			  int cluster, struct timespec *ts,
 			  struct fat_slot_info *sinfo)
 {
 	struct super_block *sb = dir->i_sb;
@@ -678,7 +678,7 @@ static int vfat_add_entry(struct inode *
 	if (slots == NULL)
 		return -ENOMEM;
 
-	err = vfat_build_slots(dir, qname->name, len, is_dir, 0, ts,
+	err = vfat_build_slots(dir, qname->name, len, is_dir, cluster, ts,
 			       slots, &nr_slots);
 	if (err)
 		goto cleanup;
@@ -787,9 +787,11 @@ static int vfat_create(struct inode *dir
 	lock_kernel();
 
 	ts = CURRENT_TIME_SEC;
-	err = vfat_add_entry(dir, &dentry->d_name, 0, &ts, &sinfo);
+	err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo);
 	if (err)
 		goto out;
+	dir->i_version++;
+
 	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 	brelse(sinfo.bh);
 	if (IS_ERR(inode)) {
@@ -800,7 +802,6 @@ static int vfat_create(struct inode *dir
 	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
 	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
-	dir->i_version++;
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry, inode);
 out:
@@ -866,50 +867,48 @@ out:
 static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
 	struct super_block *sb = dir->i_sb;
-	struct inode *inode = NULL;
+	struct inode *inode;
 	struct fat_slot_info sinfo;
 	struct timespec ts;
-	int err;
+	int err, cluster;
 
 	lock_kernel();
 
 	ts = CURRENT_TIME_SEC;
-	err = vfat_add_entry(dir, &dentry->d_name, 1, &ts, &sinfo);
-	if (err)
+	cluster = fat_alloc_new_dir(dir, &ts);
+	if (cluster < 0) {
+		err = cluster;
 		goto out;
+	}
+	err = vfat_add_entry(dir, &dentry->d_name, 1, cluster, &ts, &sinfo);
+	if (err)
+		goto out_free;
+	dir->i_version++;
+	dir->i_nlink++;
+
 	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+	brelse(sinfo.bh);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
-		goto out_brelse;
+		/* the directory was completed, just return a error */
+		goto out;
 	}
 	inode->i_version++;
+	inode->i_nlink = 2;	/* no need to mark them dirty */
 	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
 	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
-	dir->i_version++;
-	dir->i_nlink++;
-	inode->i_nlink = 2;	/* no need to mark them dirty */
-	err = fat_new_dir(inode, dir, 1);
-	if (err)
-		goto mkdir_failed;
-
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry, inode);
-out_brelse:
-	brelse(sinfo.bh);
+
+	unlock_kernel();
+	return 0;
+
+out_free:
+	fat_free_clusters(dir, cluster);
 out:
 	unlock_kernel();
 	return err;
-
-mkdir_failed:
-	inode->i_nlink = 0;
-	inode->i_mtime = inode->i_atime = ts;
-	fat_detach(inode);
-	mark_inode_dirty(inode);
-	fat_remove_entries(dir, &sinfo);	/* and releases bh */
-	iput(inode);
-	dir->i_nlink--;
-	goto out;
 }
 
 static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -959,8 +958,8 @@ static int vfat_rename(struct inode *old
 		}
 		fat_detach(new_inode);
 	} else {
-		err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, &ts,
-				     &sinfo);
+		err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, 0,
+				     &ts, &sinfo);
 		if (err)
 			goto out;
 		brelse(sinfo.bh);
diff -puN include/linux/msdos_fs.h~sync07-fat_dir5 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync07-fat_dir5	2005-03-06 02:36:53.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:36:53.000000000 +0900
@@ -327,13 +327,13 @@ extern int fat_search_long(struct inode 
 extern int fat_add_entries(struct inode *dir, int slots,
 			   struct buffer_head **bh,
 			   struct msdos_dir_entry **de, loff_t *i_pos);
-extern int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat);
 extern int fat_dir_empty(struct inode *dir);
 extern int fat_subdirs(struct inode *dir);
 extern int fat_scan(struct inode *dir, const unsigned char *name,
 		    struct fat_slot_info *sinfo);
 extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
 				struct msdos_dir_entry **de, loff_t *i_pos);
+extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts);
 extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
 
 /* fat/fatent.c */
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 19/29] FAT: Rewrite fat_add_entries()
  2005-03-05 18:53                                 ` [PATCH 18/29] FAT: Allocate the cluster before adding the directory entry OGAWA Hirofumi
@ 2005-03-05 18:54                                   ` OGAWA Hirofumi
  2005-03-05 18:55                                     ` [PATCH 20/29] FAT: Use fat_remove_entries() for msdos OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:54 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


In order not to write out the same block repeatedly, rewrite the
fat_add_entries().

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

 fs/fat/dir.c             |  261 ++++++++++++++++++++++++++++++++++-------------
 fs/msdos/namei.c         |   13 --
 fs/vfat/namei.c          |   35 ------
 include/linux/msdos_fs.h |    5 
 4 files changed, 198 insertions(+), 116 deletions(-)

diff -puN fs/fat/dir.c~sync07-fat_dir6 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync07-fat_dir6	2005-03-06 02:36:56.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:36:56.000000000 +0900
@@ -981,94 +981,211 @@ error:
 
 EXPORT_SYMBOL(fat_alloc_new_dir);
 
-static struct buffer_head *fat_extend_dir(struct inode *inode)
+static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots,
+			       int *nr_cluster, struct msdos_dir_entry **de,
+			       struct buffer_head **bh, loff_t *i_pos)
 {
-	struct super_block *sb = inode->i_sb;
-	struct buffer_head *bh, *res = NULL;
-	int err, cluster, sec_per_clus = MSDOS_SB(sb)->sec_per_clus;
-	sector_t sector, last_sector;
-
-	if (MSDOS_SB(sb)->fat_bits != 32) {
-		if (inode->i_ino == MSDOS_ROOT_INO)
-			return ERR_PTR(-ENOSPC);
-	}
+	struct super_block *sb = dir->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+	sector_t blknr, start_blknr, last_blknr;
+	unsigned long size, copy;
+	int err, i, n, offset, cluster[2];
+
+	/*
+	 * The minimum cluster size is 512bytes, and maximum entry
+	 * size is 32*slots (672bytes).  So, iff the cluster size is
+	 * 512bytes, we may need two clusters.
+	 */
+	size = nr_slots * sizeof(struct msdos_dir_entry);
+	*nr_cluster = (size + (sbi->cluster_size - 1)) >> sbi->cluster_bits;
+	BUG_ON(*nr_cluster > 2);
 
-	err = fat_alloc_clusters(inode, &cluster, 1);
+	err = fat_alloc_clusters(dir, cluster, *nr_cluster);
 	if (err)
-		return ERR_PTR(err);
-	err = fat_chain_add(inode, cluster, 1);
-	if (err) {
-		fat_free_clusters(inode, cluster);
-		return ERR_PTR(err);
-	}
+		goto error;
 
-	sector = fat_clus_to_blknr(MSDOS_SB(sb), cluster);
-	last_sector = sector + sec_per_clus;
-	for ( ; sector < last_sector; sector++) {
-		if ((bh = sb_getblk(sb, sector))) {
-			memset(bh->b_data, 0, sb->s_blocksize);
-			set_buffer_uptodate(bh);
-			mark_buffer_dirty(bh);
-			if (sb->s_flags & MS_SYNCHRONOUS)
-				sync_dirty_buffer(bh);
-			if (!res)
-				res = bh;
-			else
-				brelse(bh);
+	/*
+	 * First stage: Fill the directory entry.  NOTE: This cluster
+	 * is not referenced from any inode yet, so updates order is
+	 * not important.
+	 */
+	i = n = copy = 0;
+	do {
+		start_blknr = blknr = fat_clus_to_blknr(sbi, cluster[i]);
+		last_blknr = start_blknr + sbi->sec_per_clus;
+		while (blknr < last_blknr) {
+			bhs[n] = sb_getblk(sb, blknr);
+			if (!bhs[n]) {
+				err = -ENOMEM;
+				goto error_nomem;
+			}
+
+			/* fill the directory entry */
+			copy = min(size, sb->s_blocksize);
+			memcpy(bhs[n]->b_data, slots, copy);
+			slots += copy;
+			size -= copy;
+			set_buffer_uptodate(bhs[n]);
+			mark_buffer_dirty(bhs[n]);
+			if (!size)
+				break;
+			n++;
+			blknr++;
 		}
-	}
-	if (res == NULL)
-		res = ERR_PTR(-EIO);
-	if (inode->i_size & (sb->s_blocksize - 1)) {
-		fat_fs_panic(sb, "Odd directory size");
-		inode->i_size = (inode->i_size + sb->s_blocksize)
-			& ~((loff_t)sb->s_blocksize - 1);
-	}
-	inode->i_size += MSDOS_SB(sb)->cluster_size;
-	MSDOS_I(inode)->mmu_private += MSDOS_SB(sb)->cluster_size;
+	} while (++i < *nr_cluster);
 
-	return res;
-}
+	memset(bhs[n]->b_data + copy, 0, sb->s_blocksize - copy);
+	offset = copy - sizeof(struct msdos_dir_entry);
+	get_bh(bhs[n]);
+	*bh = bhs[n];
+	*de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
+	*i_pos = ((loff_t)blknr << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
 
-/* This assumes that size of cluster is above the 32*slots */
+	/* Second stage: clear the rest of cluster, and write outs */
+	err = fat_zeroed_cluster(dir, start_blknr, ++n, bhs, MAX_BUF_PER_PAGE);
+	if (err)
+		goto error_free;
 
-int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
-		  struct msdos_dir_entry **de, loff_t *i_pos)
-{
-	struct super_block *sb = dir->i_sb;
-	loff_t offset, curr;
-	int row;
-	struct buffer_head *new_bh;
+	return cluster[0];
 
-	offset = curr = 0;
+error_free:
+	brelse(*bh);
 	*bh = NULL;
-	row = 0;
-	while (fat_get_entry(dir, &curr, bh, de, i_pos) > -1) {
+	n = 0;
+error_nomem:
+	for (i = 0; i < n; i++)
+		bforget(bhs[i]);
+	fat_free_clusters(dir, cluster[0]);
+error:
+	return err;
+}
+
+int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
+		    struct fat_slot_info *sinfo)
+{
+	struct super_block *sb = dir->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct buffer_head *bh, *prev, *bhs[3]; /* 32*slots (672bytes) */
+	struct msdos_dir_entry *de;
+	int err, free_slots, i, nr_bhs;
+	loff_t pos, i_pos;
+
+	sinfo->nr_slots = nr_slots;
+
+	/* First stage: search free direcotry entries */
+	free_slots = nr_bhs = 0;
+	bh = prev = NULL;
+	pos = 0;
+	err = -ENOSPC;
+	while (fat_get_entry(dir, &pos, &bh, &de, &i_pos) > -1) {
 		/* check the maximum size of directory */
-		if (curr >= FAT_MAX_DIR_SIZE) {
-			brelse(*bh);
-			return -ENOSPC;
-		}
+		if (pos >= FAT_MAX_DIR_SIZE)
+			goto error;
 
-		if (IS_FREE((*de)->name)) {
-			if (++row == slots)
-				return offset;
+		if (IS_FREE(de->name)) {
+			if (prev != bh) {
+				get_bh(bh);
+				bhs[nr_bhs] = prev = bh;
+				nr_bhs++;
+			}
+			free_slots++;
+			if (free_slots == nr_slots)
+				goto found;
 		} else {
-			row = 0;
-			offset = curr;
+			for (i = 0; i < nr_bhs; i++)
+				brelse(bhs[i]);
+			prev = NULL;
+			free_slots = nr_bhs = 0;
 		}
 	}
-	if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32))
-		return -ENOSPC;
-	new_bh = fat_extend_dir(dir);
-	if (IS_ERR(new_bh))
-		return PTR_ERR(new_bh);
-	brelse(new_bh);
-	do {
-		fat_get_entry(dir, &curr, bh, de, i_pos);
-	} while (++row < slots);
+	if ((dir->i_ino == MSDOS_ROOT_INO) && (sbi->fat_bits != 32))
+		goto error;
+
+found:
+	err = 0;
+	pos -= free_slots * sizeof(*de);
+	nr_slots -= free_slots;
+	if (free_slots) {
+		/*
+		 * Second stage: filling the free entries with new entries.
+		 * NOTE: If this slots has shortname, first, we write
+		 * the long name slots, then write the short name.
+		 */
+		int size = free_slots * sizeof(*de);
+		int offset = pos & (sb->s_blocksize - 1);
+		int long_bhs = nr_bhs - (nr_slots == 0);
+
+		/* Fill the long name slots. */
+		for (i = 0; i < long_bhs; i++) {
+			int copy = min_t(int, sb->s_blocksize - offset, size);
+			memcpy(bhs[i]->b_data + offset, slots, copy);
+			mark_buffer_dirty(bhs[i]);
+			offset = 0;
+			slots += copy;
+			size -= copy;
+		}
+		if (long_bhs && IS_DIRSYNC(dir))
+			err = fat_sync_bhs(bhs, long_bhs);
+		if (!err && i < nr_bhs) {
+			/* Fill the short name slot. */
+			int copy = min_t(int, sb->s_blocksize - offset, size);
+			memcpy(bhs[i]->b_data + offset, slots, copy);
+			mark_buffer_dirty(bhs[i]);
+			if (IS_DIRSYNC(dir))
+				err = sync_dirty_buffer(bhs[i]);
+		}
+		for (i = 0; i < nr_bhs; i++)
+			brelse(bhs[i]);
+		if (err)
+			goto error_remove;
+	}
+
+	if (nr_slots) {
+		int cluster, nr_cluster;
 
-	return offset;
+		/*
+		 * Third stage: allocate the cluster for new entries.
+		 * And initialize the cluster with new entries, then
+		 * add the cluster to dir.
+		 */
+		cluster = fat_add_new_entries(dir, slots, nr_slots, &nr_cluster,
+					      &de, &bh, &i_pos);
+		if (cluster < 0) {
+			err = cluster;
+			goto error_remove;
+		}
+		err = fat_chain_add(dir, cluster, nr_cluster);
+		if (err) {
+			fat_free_clusters(dir, cluster);
+			goto error_remove;
+		}
+		if (dir->i_size & (sbi->cluster_size - 1)) {
+			fat_fs_panic(sb, "Odd directory size");
+			dir->i_size = (dir->i_size + sbi->cluster_size - 1)
+				& ~((loff_t)sbi->cluster_size - 1);
+		}
+		dir->i_size += nr_cluster << sbi->cluster_bits;
+		MSDOS_I(dir)->mmu_private += nr_cluster << sbi->cluster_bits;
+	}
+	sinfo->slot_off = pos;
+	sinfo->i_pos = i_pos;
+	sinfo->de = de;
+	sinfo->bh = bh;
+
+	return 0;
+
+error:
+	brelse(bh);
+	for (i = 0; i < nr_bhs; i++)
+		brelse(bhs[i]);
+	return err;
+
+error_remove:
+	brelse(bh);
+	if (free_slots)
+		__fat_remove_entries(dir, pos, free_slots);
+	return err;
 }
 
 EXPORT_SYMBOL(fat_add_entries);
diff -puN fs/msdos/namei.c~sync07-fat_dir6 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync07-fat_dir6	2005-03-06 02:36:56.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c	2005-03-06 02:36:56.000000000 +0900
@@ -258,7 +258,7 @@ static int msdos_add_entry(struct inode 
 {
 	struct msdos_dir_entry de;
 	__le16 time, date;
-	int offset;
+	int err;
 
 	memcpy(de.name, name, MSDOS_NAME);
 	de.attr = is_dir ? ATTR_DIR : ATTR_ARCH;
@@ -273,14 +273,9 @@ static int msdos_add_entry(struct inode 
 	de.starthi = cpu_to_le16(cluster >> 16);
 	de.size = 0;
 
-	offset = fat_add_entries(dir, 1, &sinfo->bh, &sinfo->de, &sinfo->i_pos);
-	if (offset < 0)
-		return offset;
-	sinfo->slot_off = offset;
-	sinfo->nr_slots = 1;
-
-	memcpy(sinfo->de, &de, sizeof(de));
-	mark_buffer_dirty(sinfo->bh);
+	err = fat_add_entries(dir, &de, 1, sinfo);
+	if (err)
+		return err;
 
 	dir->i_ctime = dir->i_mtime = *ts;
 	mark_inode_dirty(dir);
diff -puN fs/vfat/namei.c~sync07-fat_dir6 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync07-fat_dir6	2005-03-06 02:36:56.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:36:56.000000000 +0900
@@ -661,14 +661,9 @@ static int vfat_add_entry(struct inode *
 			  int cluster, struct timespec *ts,
 			  struct fat_slot_info *sinfo)
 {
-	struct super_block *sb = dir->i_sb;
 	struct msdos_dir_slot *slots;
 	unsigned int len;
-	int err, i, nr_slots;
-	loff_t offset;
-	struct msdos_dir_entry *de, *dummy_de;
-	struct buffer_head *bh, *dummy_bh;
-	loff_t dummy_i_pos;
+	int err, nr_slots;
 
 	len = vfat_striptail_len(qname);
 	if (len == 0)
@@ -683,37 +678,13 @@ static int vfat_add_entry(struct inode *
 	if (err)
 		goto cleanup;
 
-	/* build the empty directory entry of number of slots */
-	offset =
-	    fat_add_entries(dir, nr_slots, &dummy_bh, &dummy_de, &dummy_i_pos);
-	if (offset < 0) {
-		err = offset;
+	err = fat_add_entries(dir, slots, nr_slots, sinfo);
+	if (err)
 		goto cleanup;
-	}
-	brelse(dummy_bh);
-
-	/* Now create the new entry */
-	bh = NULL;
-	for (i = 0; i < nr_slots; i++) {
-		if (fat_get_entry(dir, &offset, &bh, &de, &sinfo->i_pos) < 0) {
-			err = -EIO;
-			goto cleanup;
-		}
-		memcpy(de, slots + i, sizeof(struct msdos_dir_slot));
-		mark_buffer_dirty(bh);
-		if (sb->s_flags & MS_SYNCHRONOUS)
-			sync_dirty_buffer(bh);
-	}
 
 	/* update timestamp */
 	dir->i_ctime = dir->i_mtime = dir->i_atime = *ts;
 	mark_inode_dirty(dir);
-
-	/* slots can't be less than 1 */
-	sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * nr_slots;
-	sinfo->nr_slots = nr_slots;
-	sinfo->de = de;
-	sinfo->bh = bh;
 cleanup:
 	kfree(slots);
 	return err;
diff -puN include/linux/msdos_fs.h~sync07-fat_dir6 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync07-fat_dir6	2005-03-06 02:36:56.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:36:56.000000000 +0900
@@ -324,9 +324,6 @@ extern int fat_bmap(struct inode *inode,
 extern struct file_operations fat_dir_operations;
 extern int fat_search_long(struct inode *inode, const unsigned char *name,
 			   int name_len, struct fat_slot_info *sinfo);
-extern int fat_add_entries(struct inode *dir, int slots,
-			   struct buffer_head **bh,
-			   struct msdos_dir_entry **de, loff_t *i_pos);
 extern int fat_dir_empty(struct inode *dir);
 extern int fat_subdirs(struct inode *dir);
 extern int fat_scan(struct inode *dir, const unsigned char *name,
@@ -334,6 +331,8 @@ extern int fat_scan(struct inode *dir, c
 extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
 				struct msdos_dir_entry **de, loff_t *i_pos);
 extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts);
+extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
+			   struct fat_slot_info *sinfo);
 extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
 
 /* fat/fatent.c */
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 20/29] FAT: Use fat_remove_entries() for msdos
  2005-03-05 18:54                                   ` [PATCH 19/29] FAT: Rewrite fat_add_entries() OGAWA Hirofumi
@ 2005-03-05 18:55                                     ` OGAWA Hirofumi
  2005-03-05 18:55                                       ` [PATCH 21/29] FAT: make the fat_get_entry()/fat__get_entry() the static OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:55 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


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

 fs/msdos/namei.c |   37 +++++++++++++++++--------------------
 1 files changed, 17 insertions(+), 20 deletions(-)

diff -puN fs/msdos/namei.c~sync07-fat_dir7 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync07-fat_dir7	2005-03-06 02:37:00.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c	2005-03-06 02:37:00.000000000 +0900
@@ -346,16 +346,15 @@ static int msdos_rmdir(struct inode *dir
 	if (err)
 		goto out;
 
-	sinfo.de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(sinfo.bh);
-	brelse(sinfo.bh);
-	fat_detach(inode);
+	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */
+	if (err)
+		goto out;
+	dir->i_nlink--;
+
 	inode->i_nlink = 0;
-	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+	inode->i_ctime = CURRENT_TIME_SEC;
+	fat_detach(inode);
 	mark_inode_dirty(inode);
-
-	dir->i_nlink--;
-	mark_inode_dirty(dir);
 out:
 	unlock_kernel();
 
@@ -430,18 +429,16 @@ static int msdos_unlink(struct inode *di
 	lock_kernel();
 	err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
 	if (err)
-		goto unlink_done;
+		goto out;
 
-	sinfo.de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(sinfo.bh);
-	brelse(sinfo.bh);
-	fat_detach(inode);
+	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */
+	if (err)
+		goto out;
 	inode->i_nlink = 0;
-	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+	inode->i_ctime = CURRENT_TIME_SEC;
+	fat_detach(inode);
 	mark_inode_dirty(inode);
-
-	mark_inode_dirty(dir);
-unlink_done:
+out:
 	unlock_kernel();
 
 	return err;
@@ -526,10 +523,10 @@ static int do_msdos_rename(struct inode 
 	}
 	new_dir->i_version++;
 
-	old_sinfo.de->name[0] = DELETED_FLAG;
-	mark_buffer_dirty(old_sinfo.bh);
-	brelse(old_sinfo.bh);
+	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);
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 21/29] FAT: make the fat_get_entry()/fat__get_entry() the static
  2005-03-05 18:55                                     ` [PATCH 20/29] FAT: Use fat_remove_entries() for msdos OGAWA Hirofumi
@ 2005-03-05 18:55                                       ` OGAWA Hirofumi
  2005-03-05 18:56                                         ` [PATCH 22/29] FAT: "i_pos" cleanup OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:55 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


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

 fs/fat/dir.c             |   63 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/fat/misc.c            |   50 -------------------------------------
 include/linux/msdos_fs.h |   17 ------------
 3 files changed, 63 insertions(+), 67 deletions(-)

diff -puN fs/fat/dir.c~sync08-fat_tweak1 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync08-fat_tweak1	2005-03-06 02:37:02.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:37:03.000000000 +0900
@@ -22,6 +22,69 @@
 #include <linux/buffer_head.h>
 #include <asm/uaccess.h>
 
+/* Returns the inode number of the directory entry at offset pos. If bh is
+   non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
+   returned in bh.
+   AV. Most often we do it item-by-item. Makes sense to optimize.
+   AV. OK, there we go: if both bh and de are non-NULL we assume that we just
+   AV. want the next entry (took one explicit de=NULL in vfat/namei.c).
+   AV. It's done in fat_get_entry() (inlined), here the slow case lives.
+   AV. Additionally, when we return -1 (i.e. reached the end of directory)
+   AV. we make bh NULL.
+ */
+static int fat__get_entry(struct inode *dir, loff_t *pos,
+			  struct buffer_head **bh,
+			  struct msdos_dir_entry **de, loff_t *i_pos)
+{
+	struct super_block *sb = dir->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	sector_t phys, iblock;
+	loff_t offset;
+	int err;
+
+next:
+	offset = *pos;
+	if (*bh)
+		brelse(*bh);
+
+	*bh = NULL;
+	iblock = *pos >> sb->s_blocksize_bits;
+	err = fat_bmap(dir, iblock, &phys);
+	if (err || !phys)
+		return -1;	/* beyond EOF or error */
+
+	*bh = sb_bread(sb, phys);
+	if (*bh == NULL) {
+		printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
+		       (unsigned long long)phys);
+		/* skip this block */
+		*pos = (iblock + 1) << sb->s_blocksize_bits;
+		goto next;
+	}
+
+	offset &= sb->s_blocksize - 1;
+	*pos += sizeof(struct msdos_dir_entry);
+	*de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
+	*i_pos = ((loff_t)phys << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
+
+	return 0;
+}
+
+static inline int fat_get_entry(struct inode *dir, loff_t *pos,
+				struct buffer_head **bh,
+				struct msdos_dir_entry **de, loff_t *i_pos)
+{
+	/* Fast stuff first */
+	if (*bh && *de &&
+	    (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) {
+		*pos += sizeof(struct msdos_dir_entry);
+		(*de)++;
+		(*i_pos)++;
+		return 0;
+	}
+	return fat__get_entry(dir, pos, bh, de, i_pos);
+}
+
 /*
  * Convert Unicode 16 to UTF8, translated Unicode, or ASCII.
  * If uni_xlate is enabled and we can't get a 1:1 conversion, use a
diff -puN fs/fat/misc.c~sync08-fat_tweak1 fs/fat/misc.c
--- linux-2.6.11/fs/fat/misc.c~sync08-fat_tweak1	2005-03-06 02:37:02.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/misc.c	2005-03-06 02:37:03.000000000 +0900
@@ -194,56 +194,6 @@ void fat_date_unix2dos(int unix_date, __
 
 EXPORT_SYMBOL(fat_date_unix2dos);
 
-/* Returns the inode number of the directory entry at offset pos. If bh is
-   non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
-   returned in bh.
-   AV. Most often we do it item-by-item. Makes sense to optimize.
-   AV. OK, there we go: if both bh and de are non-NULL we assume that we just
-   AV. want the next entry (took one explicit de=NULL in vfat/namei.c).
-   AV. It's done in fat_get_entry() (inlined), here the slow case lives.
-   AV. Additionally, when we return -1 (i.e. reached the end of directory)
-   AV. we make bh NULL.
- */
-
-int fat__get_entry(struct inode *dir, loff_t *pos, struct buffer_head **bh,
-		   struct msdos_dir_entry **de, loff_t *i_pos)
-{
-	struct super_block *sb = dir->i_sb;
-	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	sector_t phys, iblock;
-	loff_t offset;
-	int err;
-
-next:
-	offset = *pos;
-	if (*bh)
-		brelse(*bh);
-
-	*bh = NULL;
-	iblock = *pos >> sb->s_blocksize_bits;
-	err = fat_bmap(dir, iblock, &phys);
-	if (err || !phys)
-		return -1;	/* beyond EOF or error */
-
-	*bh = sb_bread(sb, phys);
-	if (*bh == NULL) {
-		printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
-		       (unsigned long long)phys);
-		/* skip this block */
-		*pos = (iblock + 1) << sb->s_blocksize_bits;
-		goto next;
-	}
-
-	offset &= sb->s_blocksize - 1;
-	*pos += sizeof(struct msdos_dir_entry);
-	*de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
-	*i_pos = ((loff_t)phys << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
-
-	return 0;
-}
-
-EXPORT_SYMBOL(fat__get_entry);
-
 int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
 {
 	int i, e, err = 0;
diff -puN include/linux/msdos_fs.h~sync08-fat_tweak1 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync08-fat_tweak1	2005-03-06 02:37:02.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h	2005-03-06 02:37:03.000000000 +0900
@@ -405,23 +405,6 @@ extern void fat_clusters_flush(struct su
 extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
 extern int date_dos2unix(unsigned short time, unsigned short date);
 extern void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date);
-extern int fat__get_entry(struct inode *dir, loff_t *pos,
-			  struct buffer_head **bh,
-			  struct msdos_dir_entry **de, loff_t *i_pos);
-static __inline__ int fat_get_entry(struct inode *dir, loff_t *pos,
-				    struct buffer_head **bh,
-				    struct msdos_dir_entry **de, loff_t *i_pos)
-{
-	/* Fast stuff first */
-	if (*bh && *de &&
-	    (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) {
-		*pos += sizeof(struct msdos_dir_entry);
-		(*de)++;
-		(*i_pos)++;
-		return 0;
-	}
-	return fat__get_entry(dir, pos, bh, de, i_pos);
-}
 extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
 
 #endif /* __KERNEL__ */
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 22/29] FAT: "i_pos" cleanup
  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                                         ` OGAWA Hirofumi
  2005-03-05 18:56                                           ` [PATCH 23/29] FAT: Remove the multiple MSDOS_SB() call OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:56 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


The "i_pos" can calculate later, so this makes the "i_pos" when it's needed.

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

 fs/fat/dir.c |   70 ++++++++++++++++++++++++++++++++---------------------------
 1 files changed, 39 insertions(+), 31 deletions(-)

diff -puN fs/fat/dir.c~sync08-fat_tweak2 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync08-fat_tweak2	2005-03-06 02:37:15.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:37:15.000000000 +0900
@@ -22,6 +22,14 @@
 #include <linux/buffer_head.h>
 #include <asm/uaccess.h>
 
+static inline loff_t fat_make_i_pos(struct super_block *sb,
+				    struct buffer_head *bh,
+				    struct msdos_dir_entry *de)
+{
+	return ((loff_t)bh->b_blocknr << MSDOS_SB(sb)->dir_per_block_bits)
+		| (de - (struct msdos_dir_entry *)bh->b_data);
+}
+
 /* Returns the inode number of the directory entry at offset pos. If bh is
    non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
    returned in bh.
@@ -33,17 +41,14 @@
    AV. we make bh NULL.
  */
 static int fat__get_entry(struct inode *dir, loff_t *pos,
-			  struct buffer_head **bh,
-			  struct msdos_dir_entry **de, loff_t *i_pos)
+			  struct buffer_head **bh, struct msdos_dir_entry **de)
 {
 	struct super_block *sb = dir->i_sb;
-	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	sector_t phys, iblock;
-	loff_t offset;
+	int offset;
 	int err;
 
 next:
-	offset = *pos;
 	if (*bh)
 		brelse(*bh);
 
@@ -62,27 +67,25 @@ next:
 		goto next;
 	}
 
-	offset &= sb->s_blocksize - 1;
+	offset = *pos & (sb->s_blocksize - 1);
 	*pos += sizeof(struct msdos_dir_entry);
 	*de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
-	*i_pos = ((loff_t)phys << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
 
 	return 0;
 }
 
 static inline int fat_get_entry(struct inode *dir, loff_t *pos,
 				struct buffer_head **bh,
-				struct msdos_dir_entry **de, loff_t *i_pos)
+				struct msdos_dir_entry **de)
 {
 	/* Fast stuff first */
 	if (*bh && *de &&
 	    (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) {
 		*pos += sizeof(struct msdos_dir_entry);
 		(*de)++;
-		(*i_pos)++;
 		return 0;
 	}
-	return fat__get_entry(dir, pos, bh, de, i_pos);
+	return fat__get_entry(dir, pos, bh, de);
 }
 
 /*
@@ -214,12 +217,12 @@ int fat_search_long(struct inode *inode,
 	int utf8 = MSDOS_SB(sb)->options.utf8;
 	int anycase = (MSDOS_SB(sb)->options.name_check != 's');
 	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
+	loff_t cpos = 0;
 	int chl, i, j, last_u, err;
-	loff_t i_pos, cpos = 0;
 
 	err = -ENOENT;
 	while(1) {
-		if (fat_get_entry(inode, &cpos, &bh, &de, &i_pos) == -1)
+		if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
 			goto EODir;
 parse_record:
 		nr_slots = 0;
@@ -270,7 +273,7 @@ parse_long:
 				if (ds->id & 0x40) {
 					unicode[offset + 13] = 0;
 				}
-				if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos)<0)
+				if (fat_get_entry(inode, &cpos, &bh, &de) < 0)
 					goto EODir;
 				if (slot == 0)
 					break;
@@ -354,11 +357,11 @@ parse_long:
 
 Found:
 	nr_slots++;	/* include the de */
-	sinfo->i_pos = i_pos;
 	sinfo->slot_off = cpos - nr_slots * sizeof(*de);
 	sinfo->nr_slots = nr_slots;
 	sinfo->de = de;
 	sinfo->bh = bh;
+	sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
 	err = 0;
 EODir:
 	if (unicode)
@@ -401,7 +404,7 @@ static int fat_readdirx(struct inode *in
 	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
 	unsigned long inum;
 	int chi, chl, i, i2, j, last, last_u, dotoffset = 0;
-	loff_t i_pos, cpos;
+	loff_t cpos;
 	int ret = 0;
 
 	lock_kernel();
@@ -429,7 +432,7 @@ static int fat_readdirx(struct inode *in
 	bh = NULL;
 GetNew:
 	long_slots = 0;
-	if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
+	if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
 		goto EODir;
 	/* Check for long filename entry */
 	if (isvfat) {
@@ -486,7 +489,7 @@ ParseLong:
 			if (ds->id & 0x40) {
 				unicode[offset + 13] = 0;
 			}
-			if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
+			if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
 				goto EODir;
 			if (slot == 0)
 				break;
@@ -578,6 +581,7 @@ ParseLong:
 	else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
 		inum = parent_ino(filp->f_dentry);
 	} else {
+		loff_t i_pos = fat_make_i_pos(sb, bh, de);
 		struct inode *tmp = fat_iget(sb, i_pos);
 		if (tmp) {
 			inum = tmp->i_ino;
@@ -748,9 +752,9 @@ struct file_operations fat_dir_operation
 
 static int fat_get_short_entry(struct inode *dir, loff_t *pos,
 			       struct buffer_head **bh,
-			       struct msdos_dir_entry **de, loff_t *i_pos)
+			       struct msdos_dir_entry **de)
 {
-	while (fat_get_entry(dir, pos, bh, de, i_pos) >= 0) {
+	while (fat_get_entry(dir, pos, bh, de) >= 0) {
 		/* free entry or long name entry or volume label */
 		if (!IS_FREE((*de)->name) && !((*de)->attr & ATTR_VOLUME))
 			return 0;
@@ -769,9 +773,11 @@ int fat_get_dotdot_entry(struct inode *d
 
 	offset = 0;
 	*bh = NULL;
-	while (fat_get_short_entry(dir, &offset, bh, de, i_pos) >= 0) {
-		if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME))
+	while (fat_get_short_entry(dir, &offset, bh, de) >= 0) {
+		if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME)) {
+			*i_pos = fat_make_i_pos(dir->i_sb, *bh, *de);
 			return 0;
+		}
 	}
 	return -ENOENT;
 }
@@ -783,12 +789,12 @@ int fat_dir_empty(struct inode *dir)
 {
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
-	loff_t cpos, i_pos;
+	loff_t cpos;
 	int result = 0;
 
 	bh = NULL;
 	cpos = 0;
-	while (fat_get_short_entry(dir, &cpos, &bh, &de, &i_pos) >= 0) {
+	while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) {
 		if (strncmp(de->name, MSDOS_DOT   , MSDOS_NAME) &&
 		    strncmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
 			result = -ENOTEMPTY;
@@ -809,12 +815,12 @@ int fat_subdirs(struct inode *dir)
 {
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
-	loff_t cpos, i_pos;
+	loff_t cpos;
 	int count = 0;
 
 	bh = NULL;
 	cpos = 0;
-	while (fat_get_short_entry(dir, &cpos, &bh, &de, &i_pos) >= 0) {
+	while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) {
 		if (de->attr & ATTR_DIR)
 			count++;
 	}
@@ -829,13 +835,16 @@ int fat_subdirs(struct inode *dir)
 int fat_scan(struct inode *dir, const unsigned char *name,
 	     struct fat_slot_info *sinfo)
 {
+	struct super_block *sb = dir->i_sb;
+
 	sinfo->slot_off = 0;
 	sinfo->bh = NULL;
 	while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh,
-				   &sinfo->de, &sinfo->i_pos) >= 0) {
+				   &sinfo->de) >= 0) {
 		if (!strncmp(sinfo->de->name, name, MSDOS_NAME)) {
 			sinfo->slot_off -= sizeof(*sinfo->de);
 			sinfo->nr_slots = 1;
+			sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
 			return 0;
 		}
 	}
@@ -849,12 +858,11 @@ static int __fat_remove_entries(struct i
 	struct super_block *sb = dir->i_sb;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de, *endp;
-	loff_t i_pos;
 	int err = 0, orig_slots;
 
 	while (nr_slots) {
 		bh = NULL;
-		if (fat_get_entry(dir, &pos, &bh, &de, &i_pos) < 0) {
+		if (fat_get_entry(dir, &pos, &bh, &de) < 0) {
 			err = -EIO;
 			break;
 		}
@@ -1103,7 +1111,7 @@ static int fat_add_new_entries(struct in
 	get_bh(bhs[n]);
 	*bh = bhs[n];
 	*de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
-	*i_pos = ((loff_t)blknr << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
+	*i_pos = fat_make_i_pos(sb, *bh, *de);
 
 	/* Second stage: clear the rest of cluster, and write outs */
 	err = fat_zeroed_cluster(dir, start_blknr, ++n, bhs, MAX_BUF_PER_PAGE);
@@ -1141,7 +1149,7 @@ int fat_add_entries(struct inode *dir, v
 	bh = prev = NULL;
 	pos = 0;
 	err = -ENOSPC;
-	while (fat_get_entry(dir, &pos, &bh, &de, &i_pos) > -1) {
+	while (fat_get_entry(dir, &pos, &bh, &de) > -1) {
 		/* check the maximum size of directory */
 		if (pos >= FAT_MAX_DIR_SIZE)
 			goto error;
@@ -1232,9 +1240,9 @@ found:
 		MSDOS_I(dir)->mmu_private += nr_cluster << sbi->cluster_bits;
 	}
 	sinfo->slot_off = pos;
-	sinfo->i_pos = i_pos;
 	sinfo->de = de;
 	sinfo->bh = bh;
+	sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
 
 	return 0;
 
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 23/29] FAT: Remove the multiple MSDOS_SB() call
  2005-03-05 18:56                                         ` [PATCH 22/29] FAT: "i_pos" cleanup OGAWA Hirofumi
@ 2005-03-05 18:56                                           ` OGAWA Hirofumi
  2005-03-05 18:57                                             ` [PATCH 24/29] FAT: Remove unneed mark_inode_dirty() OGAWA Hirofumi
                                                               ` (2 more replies)
  0 siblings, 3 replies; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:56 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


Since MSDOS_SB() is inline function, it increases text size at each calls.
I don't know whether there is __attribute__ for avoiding this.

This removes the multiple call.

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

 fs/fat/dir.c    |   30 ++++++++++++++++--------------
 fs/vfat/namei.c |    8 ++++----
 2 files changed, 20 insertions(+), 18 deletions(-)

diff -puN fs/fat/dir.c~sync08-fat_tweak3 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync08-fat_tweak3	2005-03-06 02:37:18.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c	2005-03-06 02:37:18.000000000 +0900
@@ -205,18 +205,19 @@ int fat_search_long(struct inode *inode,
 		    int name_len, struct fat_slot_info *sinfo)
 {
 	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	struct buffer_head *bh = NULL;
 	struct msdos_dir_entry *de;
-	struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
-	struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
+	struct nls_table *nls_io = sbi->nls_io;
+	struct nls_table *nls_disk = sbi->nls_disk;
 	wchar_t bufuname[14];
 	unsigned char xlate_len, nr_slots;
 	wchar_t *unicode = NULL;
 	unsigned char work[8], bufname[260];	/* 256 + 4 */
-	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
-	int utf8 = MSDOS_SB(sb)->options.utf8;
-	int anycase = (MSDOS_SB(sb)->options.name_check != 's');
-	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
+	int uni_xlate = sbi->options.unicode_xlate;
+	int utf8 = sbi->options.utf8;
+	int anycase = (sbi->options.name_check != 's');
+	unsigned short opt_shortname = sbi->options.shortname;
 	loff_t cpos = 0;
 	int chl, i, j, last_u, err;
 
@@ -386,10 +387,11 @@ static int fat_readdirx(struct inode *in
 			filldir_t filldir, int short_only, int both)
 {
 	struct super_block *sb = inode->i_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
-	struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
-	struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
+	struct nls_table *nls_io = sbi->nls_io;
+	struct nls_table *nls_disk = sbi->nls_disk;
 	unsigned char long_slots;
 	const char *fill_name;
 	int fill_len;
@@ -397,11 +399,11 @@ static int fat_readdirx(struct inode *in
 	wchar_t *unicode = NULL;
 	unsigned char c, work[8], bufname[56], *ptname = bufname;
 	unsigned long lpos, dummy, *furrfu = &lpos;
-	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
-	int isvfat = MSDOS_SB(sb)->options.isvfat;
-	int utf8 = MSDOS_SB(sb)->options.utf8;
-	int nocase = MSDOS_SB(sb)->options.nocase;
-	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
+	int uni_xlate = sbi->options.unicode_xlate;
+	int isvfat = sbi->options.isvfat;
+	int utf8 = sbi->options.utf8;
+	int nocase = sbi->options.nocase;
+	unsigned short opt_shortname = sbi->options.shortname;
 	unsigned long inum;
 	int chi, chl, i, i2, j, last, last_u, dotoffset = 0;
 	loff_t cpos;
@@ -513,7 +515,7 @@ ParseLong:
 			long_slots = 0;
 	}
 
-	if (MSDOS_SB(sb)->options.dotsOK) {
+	if (sbi->options.dotsOK) {
 		ptname = bufname;
 		dotoffset = 0;
 		if (de->attr & ATTR_HIDDEN) {
diff -puN fs/vfat/namei.c~sync08-fat_tweak3 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync08-fat_tweak3	2005-03-06 02:37:18.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:37:18.000000000 +0900
@@ -301,6 +301,7 @@ static int vfat_create_shortname(struct 
 				 wchar_t *uname, int ulen,
 				 unsigned char *name_res, unsigned char *lcase)
 {
+	struct fat_mount_options *opts = &MSDOS_SB(dir->i_sb)->options;
 	wchar_t *ip, *ext_start, *end, *name_start;
 	unsigned char base[9], ext[4], buf[8], *p;
 	unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
@@ -308,7 +309,6 @@ static int vfat_create_shortname(struct 
 	int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen;
 	int is_shortname;
 	struct shortname_info base_info, ext_info;
-	unsigned short opt_shortname = MSDOS_SB(dir->i_sb)->options.shortname;
 
 	is_shortname = 1;
 	INIT_SHORTNAME_INFO(&base_info);
@@ -421,9 +421,9 @@ static int vfat_create_shortname(struct 
 		if (vfat_find_form(dir, name_res) == 0)
 			return -EEXIST;
 
-		if (opt_shortname & VFAT_SFN_CREATE_WIN95) {
+		if (opts->shortname & VFAT_SFN_CREATE_WIN95) {
 			return (base_info.upper && ext_info.upper);
-		} else if (opt_shortname & VFAT_SFN_CREATE_WINNT) {
+		} else if (opts->shortname & VFAT_SFN_CREATE_WINNT) {
 			if ((base_info.upper || base_info.lower) &&
 			    (ext_info.upper || ext_info.lower)) {
 				if (!base_info.upper && base_info.lower)
@@ -438,7 +438,7 @@ static int vfat_create_shortname(struct 
 		}
 	}
 
-	if (MSDOS_SB(dir->i_sb)->options.numtail == 0)
+	if (opts->numtail == 0)
 		if (vfat_find_form(dir, name_res) < 0)
 			return 0;
 
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 24/29] FAT: Remove unneed mark_inode_dirty()
  2005-03-05 18:56                                           ` [PATCH 23/29] FAT: Remove the multiple MSDOS_SB() call OGAWA Hirofumi
@ 2005-03-05 18:57                                             ` OGAWA Hirofumi
  2005-03-05 18:57                                               ` [PATCH 25/29] FAT: Fix fat_truncate() 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
  2 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:57 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


Some mark_inode_dirty() is unneeded. Those are already detached (it's
not written) or change a ->i_nlink count only (fatfs don't have).

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

 fs/msdos/namei.c |   11 +++--------
 fs/vfat/namei.c  |   10 +++-------
 2 files changed, 6 insertions(+), 15 deletions(-)

diff -puN fs/msdos/namei.c~sync08-fat_tweak4 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync08-fat_tweak4	2005-03-06 02:37:21.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c	2005-03-06 02:37:21.000000000 +0900
@@ -354,7 +354,6 @@ static int msdos_rmdir(struct inode *dir
 	inode->i_nlink = 0;
 	inode->i_ctime = CURRENT_TIME_SEC;
 	fat_detach(inode);
-	mark_inode_dirty(inode);
 out:
 	unlock_kernel();
 
@@ -403,7 +402,7 @@ static int msdos_mkdir(struct inode *dir
 		/* the directory was completed, just return a error */
 		goto out;
 	}
-	inode->i_nlink = 2;	/* no need to mark them dirty */
+	inode->i_nlink = 2;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
 	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
@@ -437,7 +436,6 @@ static int msdos_unlink(struct inode *di
 	inode->i_nlink = 0;
 	inode->i_ctime = CURRENT_TIME_SEC;
 	fat_detach(inode);
-	mark_inode_dirty(inode);
 out:
 	unlock_kernel();
 
@@ -544,7 +542,6 @@ static int do_msdos_rename(struct inode 
 	if (new_inode) {
 		new_inode->i_nlink--;
 		new_inode->i_ctime = ts;
-		mark_inode_dirty(new_inode);
 	}
 	if (is_dir) {
 		int start = MSDOS_I(new_dir)->i_logstart;
@@ -552,12 +549,10 @@ static int do_msdos_rename(struct inode 
 		dotdot_de->starthi = cpu_to_le16(start >> 16);
 		mark_buffer_dirty(dotdot_bh);
 
-		if (new_inode) {
+		if (new_inode)
 			new_inode->i_nlink--;
-		} else {
+		else
 			new_dir->i_nlink++;
-			mark_inode_dirty(new_dir);
-		}
 	}
 out:
 	brelse(dotdot_bh);
diff -puN fs/vfat/namei.c~sync08-fat_tweak4 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync08-fat_tweak4	2005-03-06 02:37:21.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:37:21.000000000 +0900
@@ -803,7 +803,6 @@ static int vfat_rmdir(struct inode *dir,
 	inode->i_nlink = 0;
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
-	mark_inode_dirty(inode);
 out:
 	unlock_kernel();
 
@@ -828,7 +827,6 @@ static int vfat_unlink(struct inode *dir
 	inode->i_nlink = 0;
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
-	mark_inode_dirty(inode);
 out:
 	unlock_kernel();
 
@@ -865,7 +863,7 @@ static int vfat_mkdir(struct inode *dir,
 		goto out;
 	}
 	inode->i_version++;
-	inode->i_nlink = 2;	/* no need to mark them dirty */
+	inode->i_nlink = 2;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
 	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
@@ -964,12 +962,10 @@ static int vfat_rename(struct inode *old
 		if (new_dir->i_sb->s_flags & MS_SYNCHRONOUS)
 			sync_dirty_buffer(dotdot_bh);
 
-		if (new_inode) {
+		if (new_inode)
 			new_inode->i_nlink--;
-		} else {
+		else
 			new_dir->i_nlink++;
-			mark_inode_dirty(new_dir);
-		}
 	}
 out:
 	brelse(dotdot_bh);
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 25/29] FAT: Fix fat_truncate()
  2005-03-05 18:57                                             ` [PATCH 24/29] FAT: Remove unneed mark_inode_dirty() OGAWA Hirofumi
@ 2005-03-05 18:57                                               ` OGAWA Hirofumi
  2005-03-05 18:58                                                 ` [PATCH 26/29] FAT: Fix fat_write_inode() OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:57 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


Instead of
	mark_inode_dirty(inode);
	if (IS_SYNC(inode))
		fat_sync_inode(inode);

use this
	if (IS_SYNC(inode))
		fat_sync_inode(inode);
	else
		mark_inode_dirty(inode);

And if occurs a error, restore the ->i_start and ->i_logstart.

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

 fs/fat/file.c |   40 +++++++++++++++++++++++-----------------
 1 files changed, 23 insertions(+), 17 deletions(-)

diff -puN fs/fat/file.c~sync08-fat_tweak5 fs/fat/file.c
--- linux-2.6.11/fs/fat/file.c~sync08-fat_tweak5	2005-03-06 02:37:23.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/file.c	2005-03-06 02:37:24.000000000 +0900
@@ -212,7 +212,7 @@ EXPORT_SYMBOL(fat_notify_change);
 static int fat_free(struct inode *inode, int skip)
 {
 	struct super_block *sb = inode->i_sb;
-	int ret, wait;
+	int err, wait, free_start, i_start, i_logstart;
 
 	if (MSDOS_I(inode)->i_start == 0)
 		return 0;
@@ -223,7 +223,7 @@ static int fat_free(struct inode *inode,
 	wait = IS_DIRSYNC(inode);
 	if (skip) {
 		struct fat_entry fatent;
-		int fclus, dclus;
+		int ret, fclus, dclus;
 
 		ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus);
 		if (ret < 0)
@@ -242,8 +242,7 @@ static int fat_free(struct inode *inode,
 				     __FUNCTION__, MSDOS_I(inode)->i_pos);
 			ret = -EIO;
 		} else if (ret > 0) {
-			int err = fat_ent_write(inode, &fatent, FAT_ENT_EOF,
-						wait);
+			err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait);
 			if (err)
 				ret = err;
 		}
@@ -251,24 +250,36 @@ static int fat_free(struct inode *inode,
 		if (ret < 0)
 			return ret;
 
+		free_start = ret;
+		i_start = i_logstart = 0;
 		fat_cache_inval_inode(inode);
 	} else {
 		fat_cache_inval_inode(inode);
 
-		ret = MSDOS_I(inode)->i_start;
+		i_start = free_start = MSDOS_I(inode)->i_start;
+		i_logstart = MSDOS_I(inode)->i_logstart;
 		MSDOS_I(inode)->i_start = 0;
 		MSDOS_I(inode)->i_logstart = 0;
-		if (wait) {
-			int err = fat_sync_inode(inode);
-			if (err)
-				return err;
-		} else
-			mark_inode_dirty(inode);
 	}
+	MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+	if (wait) {
+		err = fat_sync_inode(inode);
+		if (err)
+			goto error;
+	} else
+		mark_inode_dirty(inode);
 	inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);
 
 	/* Freeing the remained cluster chain */
-	return fat_free_clusters(inode, ret);
+	return fat_free_clusters(inode, free_start);
+
+error:
+	if (i_start) {
+		MSDOS_I(inode)->i_start = i_start;
+		MSDOS_I(inode)->i_logstart = i_logstart;
+	}
+	return err;
 }
 
 void fat_truncate(struct inode *inode)
@@ -288,12 +299,7 @@ void fat_truncate(struct inode *inode)
 
 	lock_kernel();
 	fat_free(inode, nr_clusters);
-	MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 	unlock_kernel();
-	inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
-	mark_inode_dirty(inode);
-	if (IS_SYNC(inode))
-		fat_sync_inode(inode);
 }
 
 struct inode_operations fat_file_inode_operations = {
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 26/29] FAT: Fix fat_write_inode()
  2005-03-05 18:57                                               ` [PATCH 25/29] FAT: Fix fat_truncate() OGAWA Hirofumi
@ 2005-03-05 18:58                                                 ` OGAWA Hirofumi
  2005-03-05 18:58                                                   ` [PATCH 27/29] FAT: Use synchronous update for {vfat,msdos}_add_entry() OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:58 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


Fix a missing error check for sync_buffer_dirty().

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

 fs/fat/inode.c |   18 ++++++++++--------
 1 files changed, 10 insertions(+), 8 deletions(-)

diff -puN fs/fat/inode.c~sync08-fat_tweak6 fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~sync08-fat_tweak6	2005-03-06 02:37:26.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c	2005-03-06 02:37:26.000000000 +0900
@@ -463,18 +463,20 @@ static int fat_write_inode(struct inode 
 	struct buffer_head *bh;
 	struct msdos_dir_entry *raw_entry;
 	loff_t i_pos;
+	int err = 0;
 
 retry:
 	i_pos = MSDOS_I(inode)->i_pos;
-	if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) {
+	if (inode->i_ino == MSDOS_ROOT_INO || !i_pos)
 		return 0;
-	}
+
 	lock_kernel();
-	if (!(bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits))) {
+	bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits);
+	if (!bh) {
 		printk(KERN_ERR "FAT: unable to read inode block "
 		       "for updating (i_pos %lld)\n", i_pos);
-		unlock_kernel();
-		return -EIO;
+		err = -EIO;
+		goto out;
 	}
 	spin_lock(&sbi->inode_hash_lock);
 	if (i_pos != MSDOS_I(inode)->i_pos) {
@@ -502,11 +504,11 @@ retry:
 	spin_unlock(&sbi->inode_hash_lock);
 	mark_buffer_dirty(bh);
 	if (wait)
-		sync_dirty_buffer(bh);
+		err = sync_dirty_buffer(bh);
 	brelse(bh);
+out:
 	unlock_kernel();
-
-	return 0;
+	return err;
 }
 
 int fat_sync_inode(struct inode *inode)
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 27/29] FAT: Use synchronous update for {vfat,msdos}_add_entry()
  2005-03-05 18:58                                                 ` [PATCH 26/29] FAT: Fix fat_write_inode() OGAWA Hirofumi
@ 2005-03-05 18:58                                                   ` OGAWA Hirofumi
  2005-03-05 18:59                                                     ` [PATCH 28/29] FAT: Update ->rename() path OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:58 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


Use the synchronous updates, in order to guarantee that the writing to
a disk is completeing when a system call returns.

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

 fs/msdos/namei.c |    5 ++++-
 fs/vfat/namei.c  |    5 ++++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff -puN fs/msdos/namei.c~sync08-fat_tweak7 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync08-fat_tweak7	2005-03-06 02:37:29.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c	2005-03-06 02:37:29.000000000 +0900
@@ -278,7 +278,10 @@ static int msdos_add_entry(struct inode 
 		return err;
 
 	dir->i_ctime = dir->i_mtime = *ts;
-	mark_inode_dirty(dir);
+	if (IS_DIRSYNC(dir))
+		(void)fat_sync_inode(dir);
+	else
+		mark_inode_dirty(dir);
 
 	return 0;
 }
diff -puN fs/vfat/namei.c~sync08-fat_tweak7 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync08-fat_tweak7	2005-03-06 02:37:29.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c	2005-03-06 02:37:29.000000000 +0900
@@ -684,7 +684,10 @@ static int vfat_add_entry(struct inode *
 
 	/* update timestamp */
 	dir->i_ctime = dir->i_mtime = dir->i_atime = *ts;
-	mark_inode_dirty(dir);
+	if (IS_DIRSYNC(dir))
+		(void)fat_sync_inode(dir);
+	else
+		mark_inode_dirty(dir);
 cleanup:
 	kfree(slots);
 	return err;
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 28/29] FAT: Update ->rename() path
  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
  2005-03-05 19:00                                                       ` [PATCH 29/29] FAT: Fix typo OGAWA Hirofumi
  0 siblings, 1 reply; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 18:59 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


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 = {
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 29/29] FAT: Fix typo
  2005-03-05 18:59                                                     ` [PATCH 28/29] FAT: Update ->rename() path OGAWA Hirofumi
@ 2005-03-05 19:00                                                       ` OGAWA Hirofumi
  0 siblings, 0 replies; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-05 19:00 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


Add a `:'.

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

 fs/fat/misc.c |    2 +-
 1 files changed, 1 insertion(+), 1 deletion(-)

diff -puN fs/fat/misc.c~sync08-fat_tweak9 fs/fat/misc.c
--- linux-2.6.11/fs/fat/misc.c~sync08-fat_tweak9	2005-03-06 02:38:03.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/misc.c	2005-03-06 02:38:04.000000000 +0900
@@ -48,7 +48,7 @@ void fat_clusters_flush(struct super_blo
 
 	bh = sb_bread(sb, sbi->fsinfo_sector);
 	if (bh == NULL) {
-		printk(KERN_ERR "FAT bread failed in fat_clusters_flush\n");
+		printk(KERN_ERR "FAT: bread failed in fat_clusters_flush\n");
 		return;
 	}
 
_

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH] FAT: Support synchronous updates
  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-06  0:07   ` OGAWA Hirofumi
  1 sibling, 0 replies; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-06  0:07 UTC (permalink / raw)
  To: linux-kernel

[It seems that my first e-mail was lost, so this is re-post. If you
received duplicated email, sorry.]

Hi,

These patches adds the `-o sync' and `-o dirsync' supports to fatfs.
If user specified that option, the fatfs does traditional ordered
updates by using synchronous writes.  If compared to before, these
patches will show a improvement of robustness I think.

`-o sync'    - writes all buffers out before returning from syscall.
`-o dirsync' - writes the directory's metadata, and unreferencing
               operations of data block.

    remaining to be done
         fat_generic_ioctl(), fat_notify_change(),
	 ATTR_ARCH of fat_xxx_write[v],
	 and probably, filling hole in cont_prepare_write(),

NOTE: Since fatfs doesn't have link-count, unfortunately ->rename() is
not safe order at all.  It may make the shared blocks, but user
shouldn't lose the data by ->rename().

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

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/29] FAT: Updated FAT attributes patch
  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-06 15:53     ` Michael Geng
  2005-03-06 17:02       ` OGAWA Hirofumi
  2005-03-06 22:45       ` Christoph Hellwig
  1 sibling, 2 replies; 40+ messages in thread
From: Michael Geng @ 2005-03-06 15:53 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: linux-kernel, hpa, Andrew Morton

On Sun, Mar 06, 2005 at 03:42:28AM +0900, OGAWA Hirofumi wrote:
> +/* <linux/videotext.h> has used 0x72 ('r') in collision, so skip a few */

These ioctls in videotext.h have been removed with 2.6.11. They were not used anywhere in the 
kernel.

Michael

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/29] FAT: Updated FAT attributes patch
  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
  1 sibling, 0 replies; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-06 17:02 UTC (permalink / raw)
  To: Michael Geng; +Cc: linux-kernel, hpa, Andrew Morton

linux@MichaelGeng.de (Michael Geng) writes:

> On Sun, Mar 06, 2005 at 03:42:28AM +0900, OGAWA Hirofumi wrote:
>> +/* <linux/videotext.h> has used 0x72 ('r') in collision, so skip a few */
>
> These ioctls in videotext.h have been removed with 2.6.11. They were not used anywhere in the 
> kernel.

Thanks.  I think we still had better skip them, because the app such
as strace can handle it easily.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 4/29] let fat handle MS_SYNCHRONOUS flag
  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
  0 siblings, 1 reply; 40+ messages in thread
From: Christoph Hellwig @ 2005-03-06 22:38 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: linux-kernel, Andrew Morton

>  		mark_buffer_dirty(bh);
> +		if (sb->s_flags & MS_SYNCHRONOUS)
> +			sync_dirty_buffer(bh);

These three lines are duplicated a lot. I think you want a helper ala:

static inline void fat_buffer_modified(struct super_block *sb,
		struct buffer_head *bh)
{
	mark_buffer_dirty(bh);
	if (sb->s_flags & MS_SYNCHRONOUS)
		sync_dirty_buffer(bh);
}


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 23/29] FAT: Remove the multiple MSDOS_SB() call
  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-06 22:44                                             ` Christoph Hellwig
  2005-03-07 22:01                                             ` Adrian Bunk
  2 siblings, 0 replies; 40+ messages in thread
From: Christoph Hellwig @ 2005-03-06 22:44 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: Andrew Morton, linux-kernel

On Sun, Mar 06, 2005 at 03:56:51AM +0900, OGAWA Hirofumi wrote:
> 
> Since MSDOS_SB() is inline function, it increases text size at each calls.
> I don't know whether there is __attribute__ for avoiding this.

If you mark it pure the compile should be smart enough to optimize way
multiple invocations - heck for an inline it should be smart enough without
annotaitons..

Anyway, your new version looks much more readable.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/29] FAT: Updated FAT attributes patch
  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
  1 sibling, 0 replies; 40+ messages in thread
From: Christoph Hellwig @ 2005-03-06 22:45 UTC (permalink / raw)
  To: Michael Geng; +Cc: OGAWA Hirofumi, linux-kernel, hpa, Andrew Morton

On Sun, Mar 06, 2005 at 04:53:29PM +0100, Michael Geng wrote:
> On Sun, Mar 06, 2005 at 03:42:28AM +0900, OGAWA Hirofumi wrote:
> > +/* <linux/videotext.h> has used 0x72 ('r') in collision, so skip a few */
> 
> These ioctls in videotext.h have been removed with 2.6.11. They were not used anywhere in the 
> kernel.

I'd rather avoid the collision anyway.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] FAT: Support synchronous update
       [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-07  1:10 ` Andrew Morton
  2005-03-07 15:02   ` OGAWA Hirofumi
  1 sibling, 1 reply; 40+ messages in thread
From: Andrew Morton @ 2005-03-07  1:10 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: linux-kernel

OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> wrote:
>
> Hi,
> 
> These patches adds the `-o sync' and `-o dirsync' supports to fatfs.
> If user specified that option, the fatfs does traditional ordered
> updates by using synchronous writes.  If compared to before, these
> patches will show a improvement of robustness I think.
> 
> `-o sync'    - writes all buffers out before returning from syscall.
> `-o dirsync' - writes the directory's metadata, and unreferencing
>                operations of data block.
> 
>     remaining to be done
>          fat_generic_ioctl(), fat_notify_change(),
> 	 ATTR_ARCH of fat_xxx_write[v],
> 	 and probably, filling hole in cont_prepare_write(),
> 
> NOTE: Since fatfs doesn't have link-count, unfortunately ->rename() is
> not safe order at all.  It may make the shared blocks, but user
> shouldn't lose the data by ->rename().
> 
> Please apply.
> 
> 
> If you test this, please use attached dosfstools. This is fixing
> several bugs of dosfstools.  And "2/29" patch from hpa adds new ioctl,
> the attached archive is also including the commands for testing it.
> -- 
> OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
> 
> 

OK.  This email was way too big for linux-kernel, so nobody saw it.

I put the modified fatfsprogs at
http://www.zip.com.au/~akpm/linux/patches/stuff/fatfsprogs.tar.bz2 and
updated the changlog to mention that.

Is there an official place where people should go to download the modified
fatfsprogs?


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 4/29] let fat handle MS_SYNCHRONOUS flag
  2005-03-06 22:38         ` Christoph Hellwig
@ 2005-03-07 14:56           ` OGAWA Hirofumi
  0 siblings, 0 replies; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-07 14:56 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-kernel, Andrew Morton

Christoph Hellwig <hch@infradead.org> writes:

>>  		mark_buffer_dirty(bh);
>> +		if (sb->s_flags & MS_SYNCHRONOUS)
>> +			sync_dirty_buffer(bh);
>
> These three lines are duplicated a lot. I think you want a helper ala:
>
> static inline void fat_buffer_modified(struct super_block *sb,
> 		struct buffer_head *bh)
> {
> 	mark_buffer_dirty(bh);
> 	if (sb->s_flags & MS_SYNCHRONOUS)
> 		sync_dirty_buffer(bh);
> }

Yes, I may want the following helper. However I'll put it as is for now.

static inline void fat_buffer_modified(struct super_block *sb,
		struct buffer_head *bh, int wait)
{
	int err = 0;
	mark_buffer_dirty(bh);
	if (wait)
		err = sync_dirty_buffer(bh);
	return err;
}
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] FAT: Support synchronous update
  2005-03-07  1:10 ` [PATCH] FAT: Support synchronous update Andrew Morton
@ 2005-03-07 15:02   ` OGAWA Hirofumi
  0 siblings, 0 replies; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-07 15:02 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel

Andrew Morton <akpm@osdl.org> writes:

> OK.  This email was way too big for linux-kernel, so nobody saw it.
>
> I put the modified fatfsprogs at
> http://www.zip.com.au/~akpm/linux/patches/stuff/fatfsprogs.tar.bz2 and
> updated the changlog to mention that.
>
> Is there an official place where people should go to download the modified
> fatfsprogs?

Oh, Thanks. Umm.. ok, I'll put fatfsprogs.tar.bz2 to the following for now.

http://user.parknet.co.jp/hirofumi/tmp/fatfsprogs.tar.bz2
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 23/29] FAT: Remove the multiple MSDOS_SB() call
  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-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
  2 siblings, 1 reply; 40+ messages in thread
From: Adrian Bunk @ 2005-03-07 22:01 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: Andrew Morton, linux-kernel

On Sun, Mar 06, 2005 at 03:56:51AM +0900, OGAWA Hirofumi wrote:
> 
> Since MSDOS_SB() is inline function, it increases text size at each calls.
> I don't know whether there is __attribute__ for avoiding this.
> 
> This removes the multiple call.
>...

"inline" in the kernel is (for recent gcc's) mapped to 
__attribute__((always_inline)), and therefore the
"static inline struct msdos_sb_info *MSDOS_SB" does exactly the opposite 
of what you want.

You'd have to move this into a .c file to remove the "inline".

But considering that the whole function is

static inline struct msdos_sb_info *MSDOS_SB(struct super_block *sb)
{
        return sb->s_fs_info;
}

I'm quite surprised that there's any problem with it.

cu
Adrian

-- 

       "Is there not promise of rain?" Ling Tan asked suddenly out
        of the darkness. There had been need of rain for many days.
       "Only a promise," Lao Er said.
                                       Pearl S. Buck - Dragon Seed


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 23/29] FAT: Remove the multiple MSDOS_SB() call
  2005-03-07 22:01                                             ` Adrian Bunk
@ 2005-03-08 13:48                                               ` OGAWA Hirofumi
  0 siblings, 0 replies; 40+ messages in thread
From: OGAWA Hirofumi @ 2005-03-08 13:48 UTC (permalink / raw)
  To: Adrian Bunk; +Cc: Andrew Morton, linux-kernel

Adrian Bunk <bunk@stusta.de> writes:

> On Sun, Mar 06, 2005 at 03:56:51AM +0900, OGAWA Hirofumi wrote:
>> 
>> Since MSDOS_SB() is inline function, it increases text size at each calls.
>> I don't know whether there is __attribute__ for avoiding this.
>> 
>> This removes the multiple call.
>>...

[...]

> static inline struct msdos_sb_info *MSDOS_SB(struct super_block *sb)
> {
>         return sb->s_fs_info;
> }
>
> I'm quite surprised that there's any problem with it.

Whoops, actually the cause was not inline. Sorry.

    #define MSDOS_SB(x)	((struct msdos_sb_info *)(x)->s_fs_info)

was same result. This just needed my patch.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2005-03-08 13:49 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [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                                                     ` [PATCH 28/29] FAT: Update ->rename() path OGAWA Hirofumi
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).