Skip to contentSkip to conversation

fat: fix writev(), add aio support

PATCH In review OGAWA Hirofumi 5 participants 40 messages Mar 5, 2005 – Mar 8, 2005 1 message not in the archive VFAT/FAT/msdos filesystem

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

OGAWA Hirofumi

author maintainer
#1 lore raw

PATCH 1/29 fat: fix writev(), add aio support

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 <[email protected]>

---

 fs/fat/file.c |   31 ++++++++++++++++++++++++-------
 1 files changed, 24 insertions(+), 7 deletions(-)
fs/fat/file.c renamed from fs/fat/file.c~fat_support-aio +24 -7
diff -puN fs/fat/file.c~fat_support-aio fs/fat/file.c
@@ -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,
 };
 

_

author maintainer
#2 lore raw

PATCH 2/29 FAT: Updated FAT attributes patch

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.

---

 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(-)
fs/fat/dir.c renamed from fs/fat/dir.c~fat_attribute-ioctl +1 -1
diff -puN fs/fat/dir.c~fat_attribute-ioctl fs/fat/dir.c
@@ -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;
fs/fat/file.c renamed from fs/fat/file.c~fat_attribute-ioctl +99 -0

111 lines not on this page · raw message

fs/fat/inode.c renamed from fs/fat/inode.c~fat_attribute-ioctl +18 -20
diff -puN fs/fat/inode.c~fat_attribute-ioctl fs/fat/inode.c
@@ -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;
fs/vfat/namei.c renamed from fs/vfat/namei.c~fat_attribute-ioctl +1 -1
diff -puN fs/vfat/namei.c~fat_attribute-ioctl fs/vfat/namei.c
@@ -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;
include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~fat_attribute-ioctl +16 -6
diff -puN include/linux/msdos_fs.h~fat_attribute-ioctl include/linux/msdos_fs.h
@@ -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);

_

author maintainer
#3 lore raw

PATCH 3/29 FAT: fat_readdirx() with dotOK=yes fix

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

This fixes it.

---

 fs/fat/dir.c |   10 +++++++---
 1 files changed, 7 insertions(+), 3 deletions(-)
fs/fat/dir.c renamed from fs/fat/dir.c~fat_readdirx-fix +7 -3
diff -puN fs/fat/dir.c~fat_readdirx-fix fs/fat/dir.c
@@ -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));

_

author maintainer
#4 lore raw

PATCH 4/29 let fat handle MS_SYNCHRONOUS flag

Adds MS_SYNCHRONOUS flag support.

---

 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(-)
fs/fat/cache.c renamed from fs/fat/cache.c~sync03-fat_sync00 +8 -0
diff -puN fs/fat/cache.c~sync03-fat_sync00 fs/fat/cache.c
@@ -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);
 		}
 	}
fs/fat/dir.c renamed from fs/fat/dir.c~sync03-fat_sync00 +17 -9
diff -puN fs/fat/dir.c~sync03-fat_sync00 fs/fat/dir.c
@@ -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;
 }
fs/fat/file.c renamed from fs/fat/file.c~sync03-fat_sync00 +5 -0
diff -puN fs/fat/file.c~sync03-fat_sync00 fs/fat/file.c
@@ -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 = {
fs/fat/inode.c renamed from fs/fat/inode.c~sync03-fat_sync00 +10 -0
diff -puN fs/fat/inode.c~sync03-fat_sync00 fs/fat/inode.c
@@ -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,
fs/fat/misc.c renamed from fs/fat/misc.c~sync03-fat_sync00 +2 -0
diff -puN fs/fat/misc.c~sync03-fat_sync00 fs/fat/misc.c
@@ -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);
 }
fs/vfat/namei.c renamed from fs/vfat/namei.c~sync03-fat_sync00 +24 -7
diff -puN fs/vfat/namei.c~sync03-fat_sync00 fs/vfat/namei.c
@@ -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--;
include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~sync03-fat_sync00 +1 -0
diff -puN include/linux/msdos_fs.h~sync03-fat_sync00 include/linux/msdos_fs.h
@@ -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);
 

_

#5 lore raw

Re: [PATCH 4/29] let fat handle MS_SYNCHRONOUS flag

fs/fat/cache.c static int __fat_access(struct super_blo · line 277

Quoted 3 lines
fs/fat/cache.c renamed from fs/fat/cache.c~sync03-fat_sync00 +2 -0
 		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);
}
author maintainer
#6 lore raw

Re: [PATCH 4/29] let fat handle MS_SYNCHRONOUS flag

Quoted 6 lines · Christoph Hellwig

fs/fat/cache.c static int __fat_access(struct super_blo · line 277

Quoted 3 lines
fs/fat/cache.c renamed from fs/fat/cache.c~sync03-fat_sync00 +2 -0
 		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:

Quoted 7 lines

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;
}
Signature · 1 line
OGAWA Hirofumi <[email protected]>
author maintainer
#7 lore raw

PATCH 5/29 FAT: Rewrite the FAT (File Allocation Table) access stuff

In reply to OGAWA Hirofumi

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.)

---

 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(-)
fs/fat/Makefile renamed from fs/fat/Makefile~sync05-fat_dep-fatent +1 -1
diff -puN fs/fat/Makefile~sync05-fat_dep-fatent fs/fat/Makefile
@@ -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
fs/fat/cache.c renamed from fs/fat/cache.c~sync05-fat_dep-fatent +13 -132

185 lines not on this page · raw message

fs/fat/dir.c renamed from fs/fat/dir.c~sync05-fat_dep-fatent +10 -5
diff -puN fs/fat/dir.c~sync05-fat_dep-fatent fs/fat/dir.c
@@ -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))) {
fs/fat/fatent.c new file +590 -0

590 lines not on this page · raw message

fs/fat/file.c renamed from fs/fat/file.c~sync05-fat_dep-fatent +35 -34

97 lines not on this page · raw message

fs/fat/inode.c renamed from fs/fat/inode.c~sync05-fat_dep-fatent +29 -31

96 lines not on this page · raw message

fs/fat/misc.c renamed from fs/fat/misc.c~sync05-fat_dep-fatent +56 -66

167 lines not on this page · raw message

include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~sync05-fat_dep-fatent +47 -10

102 lines not on this page · raw message

_

author maintainer
#8 lore raw

PATCH 6/29 FAT: add debugging code to fatent.c

---

 fs/fat/fatent.c          |   20 ++++++++++++++++++++
 include/linux/msdos_fs.h |    6 ++++++
 2 files changed, 26 insertions(+)
fs/fat/fatent.c renamed from fs/fat/fatent.c~sync05-fat_dep-fatent-debug +20 -0
diff -puN fs/fat/fatent.c~sync05-fat_dep-fatent-debug fs/fat/fatent.c
@@ -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)
 {
include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~sync05-fat_dep-fatent-debug +6 -0
diff -puN include/linux/msdos_fs.h~sync05-fat_dep-fatent-debug include/linux/msdos_fs.h
@@ -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);

_

author maintainer
#9 lore raw

PATCH 7/29 FAT: Use "unsigned int" for ->free_clusters and ->prev_free

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.

---

 fs/fat/fatent.c          |    3 +--
 fs/fat/inode.c           |    6 +++++-
 include/linux/msdos_fs.h |    4 ++--
 3 files changed, 8 insertions(+), 5 deletions(-)
fs/fat/fatent.c renamed from fs/fat/fatent.c~sync05-fat_free-unsigned +1 -2
diff -puN fs/fat/fatent.c~sync05-fat_free-unsigned fs/fat/fatent.c
@@ -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);
fs/fat/inode.c renamed from fs/fat/inode.c~sync05-fat_free-unsigned +5 -1
diff -puN fs/fat/inode.c~sync05-fat_free-unsigned fs/fat/inode.c
@@ -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);
 
include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~sync05-fat_free-unsigned +2 -2
diff -puN include/linux/msdos_fs.h~sync05-fat_free-unsigned include/linux/msdos_fs.h
@@ -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 */

_

author maintainer
#10 lore raw

PATCH 8/29 FAT: "struct vfat_slot_info" cleanup

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

---

 fs/vfat/namei.c          |  126 ++++++++++++++++++++---------------------------
 include/linux/msdos_fs.h |    8 +-
 2 files changed, 61 insertions(+), 73 deletions(-)
fs/vfat/namei.c renamed from fs/vfat/namei.c~sync06-fat_dir-cleanup +56 -70
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup fs/vfat/namei.c
@@ -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;
 }
include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~sync06-fat_dir-cleanup +5 -3
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup include/linux/msdos_fs.h
@@ -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__

_

author maintainer
#11 lore raw

PATCH 9/29 FAT: Use "struct fat_slot_info" for fat_search_long()

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.

---

 fs/fat/dir.c             |   26 +++++++------
 fs/vfat/namei.c          |   89 ++++++++++++++++++++---------------------------
 include/linux/msdos_fs.h |    3 -
 3 files changed, 54 insertions(+), 64 deletions(-)
fs/fat/dir.c renamed from fs/fat/dir.c~sync06-fat_dir-cleanup2 +15 -11
diff -puN fs/fat/dir.c~sync06-fat_dir-cleanup2 fs/fat/dir.c
@@ -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);
fs/vfat/namei.c renamed from fs/vfat/namei.c~sync06-fat_dir-cleanup2 +38 -51

193 lines not on this page · raw message

include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~sync06-fat_dir-cleanup2 +1 -2
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup2 include/linux/msdos_fs.h
@@ -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);

_

author maintainer
#12 lore raw

PATCH 10/29 FAT: Add fat_remove_entries()

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().

---

 fs/fat/dir.c             |  103 +++++++++++++++++++++++++++++++++++++++++++----
 fs/vfat/namei.c          |   81 ++++++++++++------------------------
 include/linux/msdos_fs.h |    1 
 3 files changed, 124 insertions(+), 61 deletions(-)
fs/fat/dir.c renamed from fs/fat/dir.c~sync06-fat_dir-cleanup3 +96 -7
diff -puN fs/fat/dir.c~sync06-fat_dir-cleanup3 fs/fat/dir.c
@@ -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;
fs/vfat/namei.c renamed from fs/vfat/namei.c~sync06-fat_dir-cleanup3 +27 -54

173 lines not on this page · raw message

include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~sync06-fat_dir-cleanup3 +1 -0
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup3 include/linux/msdos_fs.h
@@ -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 {

_

author maintainer
#13 lore raw

PATCH 11/29 FAT: fat_build_inode() cleanup

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

---

 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(-)
fs/fat/inode.c renamed from fs/fat/inode.c~sync06-fat_dir-cleanup4 +30 -32
diff -puN fs/fat/inode.c~sync06-fat_dir-cleanup4 fs/fat/inode.c
@@ -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 = {
fs/msdos/namei.c renamed from fs/msdos/namei.c~sync06-fat_dir-cleanup4 +10 -7
diff -puN fs/msdos/namei.c~sync06-fat_dir-cleanup4 fs/msdos/namei.c
@@ -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;
fs/vfat/namei.c renamed from fs/vfat/namei.c~sync06-fat_dir-cleanup4 +11 -8
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup4 fs/vfat/namei.c
@@ -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)
include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~sync06-fat_dir-cleanup4 +1 -1
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup4 include/linux/msdos_fs.h
@@ -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);

_

author maintainer
#14 lore raw

PATCH 12/29 FAT: Use "struct fat_slot_info" for fat_scan()

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.

---

 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(-)
fs/fat/dir.c renamed from fs/fat/dir.c~sync06-fat_dir-cleanup5 +31 -10
diff -puN fs/fat/dir.c~sync06-fat_dir-cleanup5 fs/fat/dir.c
@@ -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;
 }
fs/fat/inode.c renamed from fs/fat/inode.c~sync06-fat_dir-cleanup5 +1 -1
diff -puN fs/fat/inode.c~sync06-fat_dir-cleanup5 fs/fat/inode.c
@@ -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;
fs/msdos/namei.c renamed from fs/msdos/namei.c~sync06-fat_dir-cleanup5 +47 -37

188 lines not on this page · raw message

fs/vfat/namei.c renamed from fs/vfat/namei.c~sync06-fat_dir-cleanup5 +6 -10
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup5 fs/vfat/namei.c
@@ -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;
 		}
include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~sync06-fat_dir-cleanup5 +3 -2
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup5 include/linux/msdos_fs.h
@@ -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 */

_

author maintainer
#15 lore raw

PATCH 13/29 FAT: Use "struct fat_slot_info" for msdos_find()

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

---

 fs/msdos/namei.c |   88 ++++++++++++++++++++++---------------------------------
 1 files changed, 36 insertions(+), 52 deletions(-)
fs/msdos/namei.c renamed from fs/msdos/namei.c~sync06-fat_dir-cleanup6 +36 -52
diff -puN fs/msdos/namei.c~sync06-fat_dir-cleanup6 fs/msdos/namei.c
@@ -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,

_

author maintainer
#16 lore raw

PATCH 14/29 FAT: vfat_build_slots() cleanup

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)

---

 fs/vfat/namei.c |  110 ++++++++++++++++++++++++++------------------------------
 1 files changed, 52 insertions(+), 58 deletions(-)
fs/vfat/namei.c renamed from fs/vfat/namei.c~sync07-fat_dir +52 -58
diff -puN fs/vfat/namei.c~sync07-fat_dir fs/vfat/namei.c
@@ -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,

_

author maintainer
#17 lore raw

PATCH 15/29 FAT: Use a same timestamp on some operations path

---

 fs/vfat/namei.c |   63 +++++++++++++++++++++++++++++++-------------------------
 1 files changed, 35 insertions(+), 28 deletions(-)
fs/vfat/namei.c renamed from fs/vfat/namei.c~sync07-fat_dir2 +35 -28
diff -puN fs/vfat/namei.c~sync07-fat_dir2 fs/vfat/namei.c
@@ -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) {

_

author maintainer
#18 lore raw

PATCH 16/29 FAT: msdos_rename() cleanup

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

---

 fs/msdos/namei.c |  175 +++++++++++++++++++++++++++----------------------------
 1 files changed, 89 insertions(+), 86 deletions(-)
fs/msdos/namei.c renamed from fs/msdos/namei.c~sync07-fat_dir3 +89 -86
diff -puN fs/msdos/namei.c~sync07-fat_dir3 fs/msdos/namei.c
@@ -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 = {

_

author maintainer
#19 lore raw

PATCH 17/29 FAT: msdos_add_entry() cleanup

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

---

 fs/msdos/namei.c |  162 ++++++++++++++++++++++++++++---------------------------
 1 files changed, 84 insertions(+), 78 deletions(-)
fs/msdos/namei.c renamed from fs/msdos/namei.c~sync07-fat_dir4 +84 -78
diff -puN fs/msdos/namei.c~sync07-fat_dir4 fs/msdos/namei.c
@@ -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) {

_

author maintainer
#20 lore raw

PATCH 18/29 FAT: Allocate the cluster before adding the directory entry

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

---

 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(-)
fs/fat/dir.c renamed from fs/fat/dir.c~sync07-fat_dir5 +112 -43
diff -puN fs/fat/dir.c~sync07-fat_dir5 fs/fat/dir.c
@@ -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);
fs/fat/fatent.c renamed from fs/fat/fatent.c~sync07-fat_dir5 +3 -0
diff -puN fs/fat/fatent.c~sync07-fat_dir5 fs/fat/fatent.c
@@ -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);
fs/msdos/namei.c renamed from fs/msdos/namei.c~sync07-fat_dir5 +24 -30

104 lines not on this page · raw message

fs/vfat/namei.c renamed from fs/vfat/namei.c~sync07-fat_dir5 +29 -30

117 lines not on this page · raw message

include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~sync07-fat_dir5 +1 -1
diff -puN include/linux/msdos_fs.h~sync07-fat_dir5 include/linux/msdos_fs.h
@@ -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 */

_

author maintainer
#21 lore raw

PATCH 19/29 FAT: Rewrite fat_add_entries()

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

---

 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(-)
fs/fat/dir.c renamed from fs/fat/dir.c~sync07-fat_dir6 +189 -72
diff -puN fs/fat/dir.c~sync07-fat_dir6 fs/fat/dir.c
@@ -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);
fs/msdos/namei.c renamed from fs/msdos/namei.c~sync07-fat_dir6 +4 -9
diff -puN fs/msdos/namei.c~sync07-fat_dir6 fs/msdos/namei.c
@@ -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);
fs/vfat/namei.c renamed from fs/vfat/namei.c~sync07-fat_dir6 +3 -32
diff -puN fs/vfat/namei.c~sync07-fat_dir6 fs/vfat/namei.c
@@ -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;
include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~sync07-fat_dir6 +2 -3
diff -puN include/linux/msdos_fs.h~sync07-fat_dir6 include/linux/msdos_fs.h
@@ -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 */

_

author maintainer
#22 lore raw

PATCH 20/29 FAT: Use fat_remove_entries() for msdos

---

 fs/msdos/namei.c |   37 +++++++++++++++++--------------------
 1 files changed, 17 insertions(+), 20 deletions(-)
fs/msdos/namei.c renamed from fs/msdos/namei.c~sync07-fat_dir7 +17 -20
diff -puN fs/msdos/namei.c~sync07-fat_dir7 fs/msdos/namei.c
@@ -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);

_

author maintainer
#23 lore raw

PATCH 21/29 FAT: make the fat_get_entry()/fat__get_entry() the static

---

 fs/fat/dir.c             |   63 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/fat/misc.c            |   50 -------------------------------------
 include/linux/msdos_fs.h |   17 ------------
 3 files changed, 63 insertions(+), 67 deletions(-)
fs/fat/dir.c renamed from fs/fat/dir.c~sync08-fat_tweak1 +63 -0
diff -puN fs/fat/dir.c~sync08-fat_tweak1 fs/fat/dir.c
@@ -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
fs/fat/misc.c renamed from fs/fat/misc.c~sync08-fat_tweak1 +0 -50

56 lines not on this page · raw message

include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~sync08-fat_tweak1 +0 -17
diff -puN include/linux/msdos_fs.h~sync08-fat_tweak1 include/linux/msdos_fs.h
@@ -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__ */

_

author maintainer
#24 lore raw

PATCH 22/29 FAT: "i_pos" cleanup

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

---

 fs/fat/dir.c |   70 ++++++++++++++++++++++++++++++++---------------------------
 1 files changed, 39 insertions(+), 31 deletions(-)
fs/fat/dir.c renamed from fs/fat/dir.c~sync08-fat_tweak2 +39 -31
diff -puN fs/fat/dir.c~sync08-fat_tweak2 fs/fat/dir.c
@@ -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;
 

_

author maintainer
#25 lore raw

PATCH 23/29 FAT: Remove the multiple MSDOS_SB() call

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.

---

 fs/fat/dir.c    |   30 ++++++++++++++++--------------
 fs/vfat/namei.c |    8 ++++----
 2 files changed, 20 insertions(+), 18 deletions(-)
fs/fat/dir.c renamed from fs/fat/dir.c~sync08-fat_tweak3 +16 -14
diff -puN fs/fat/dir.c~sync08-fat_tweak3 fs/fat/dir.c
@@ -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) {
fs/vfat/namei.c renamed from fs/vfat/namei.c~sync08-fat_tweak3 +4 -4
diff -puN fs/vfat/namei.c~sync08-fat_tweak3 fs/vfat/namei.c
@@ -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;
 

_

author maintainer
#26 lore raw

PATCH 24/29 FAT: Remove unneed mark_inode_dirty()

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).

---

 fs/msdos/namei.c |   11 +++--------
 fs/vfat/namei.c  |   10 +++-------
 2 files changed, 6 insertions(+), 15 deletions(-)
fs/msdos/namei.c renamed from fs/msdos/namei.c~sync08-fat_tweak4 +3 -8
diff -puN fs/msdos/namei.c~sync08-fat_tweak4 fs/msdos/namei.c
@@ -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);
fs/vfat/namei.c renamed from fs/vfat/namei.c~sync08-fat_tweak4 +3 -7
diff -puN fs/vfat/namei.c~sync08-fat_tweak4 fs/vfat/namei.c
@@ -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);

_

author maintainer
#27 lore raw

PATCH 25/29 FAT: Fix fat_truncate()

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.

---

 fs/fat/file.c |   40 +++++++++++++++++++++++-----------------
 1 files changed, 23 insertions(+), 17 deletions(-)
fs/fat/file.c renamed from fs/fat/file.c~sync08-fat_tweak5 +23 -17
diff -puN fs/fat/file.c~sync08-fat_tweak5 fs/fat/file.c
@@ -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 = {

_

author maintainer
#28 lore raw

PATCH 26/29 FAT: Fix fat_write_inode()

Fix a missing error check for sync_buffer_dirty().

---

 fs/fat/inode.c |   18 ++++++++++--------
 1 files changed, 10 insertions(+), 8 deletions(-)
fs/fat/inode.c renamed from fs/fat/inode.c~sync08-fat_tweak6 +10 -8
diff -puN fs/fat/inode.c~sync08-fat_tweak6 fs/fat/inode.c
@@ -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)

_

author maintainer
#29 lore raw

PATCH 27/29 FAT: Use synchronous update for {vfat,msdos}_add_entry()

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

---

 fs/msdos/namei.c |    5 ++++-
 fs/vfat/namei.c  |    5 ++++-
 2 files changed, 8 insertions(+), 2 deletions(-)
fs/msdos/namei.c renamed from fs/msdos/namei.c~sync08-fat_tweak7 +4 -1
diff -puN fs/msdos/namei.c~sync08-fat_tweak7 fs/msdos/namei.c
@@ -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;
 }
fs/vfat/namei.c renamed from fs/vfat/namei.c~sync08-fat_tweak7 +4 -1
diff -puN fs/vfat/namei.c~sync08-fat_tweak7 fs/vfat/namei.c
@@ -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;

_

author maintainer
#30 lore raw

PATCH 28/29 FAT: Update ->rename() path

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.

---

 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(-)
fs/fat/cache.c renamed from fs/fat/cache.c~sync08-fat_tweak8 +1 -3
diff -puN fs/fat/cache.c~sync08-fat_tweak8 fs/fat/cache.c
@@ -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;
fs/fat/dir.c renamed from fs/fat/dir.c~sync08-fat_tweak8 +8 -1
diff -puN fs/fat/dir.c~sync08-fat_tweak8 fs/fat/dir.c
@@ -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;
fs/fat/misc.c renamed from fs/fat/misc.c~sync08-fat_tweak8 +2 -0
diff -puN fs/fat/misc.c~sync08-fat_tweak8 fs/fat/misc.c
@@ -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)
fs/msdos/namei.c renamed from fs/msdos/namei.c~sync08-fat_tweak8 +86 -26

169 lines not on this page · raw message

fs/vfat/namei.c renamed from fs/vfat/namei.c~sync08-fat_tweak8 +73 -28

150 lines not on this page · raw message

_

author maintainer
#31 lore raw

PATCH 29/29 FAT: Fix typo

Add a `:'.

---

 fs/fat/misc.c |    2 +-
 1 files changed, 1 insertion(+), 1 deletion(-)
fs/fat/misc.c renamed from fs/fat/misc.c~sync08-fat_tweak9 +1 -1
diff -puN fs/fat/misc.c~sync08-fat_tweak9 fs/fat/misc.c
@@ -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;
 	}
 

_

#32 lore raw

Re: [PATCH 23/29] FAT: Remove the multiple MSDOS_SB() call

In reply to OGAWA Hirofumi
Quoted 3 lines · OGAWA Hirofumi

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.

#33 lore raw

Re: [PATCH 23/29] FAT: Remove the multiple MSDOS_SB() call

In reply to OGAWA Hirofumi
Quoted 6 lines · OGAWA Hirofumi

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

Signature · 4 lines
       "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
author maintainer
#34 lore raw

Re: [PATCH 23/29] FAT: Remove the multiple MSDOS_SB() call

Quoted 7 lines · Adrian Bunk
Quoted 6 lines · OGAWA Hirofumi

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.
...

[...]

Quoted 6 lines

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.

Signature · 1 line
OGAWA Hirofumi <[email protected]>
#35 lore raw

Re: [PATCH 2/29] FAT: Updated FAT attributes patch

In reply to OGAWA Hirofumi
Quoted 1 line · OGAWA Hirofumi

+/* <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

author maintainer
#36 lore raw

Re: [PATCH 2/29] FAT: Updated FAT attributes patch

Quoted 5 lines · [email protected] (Michael Geng) writes:
Quoted 1 line · OGAWA Hirofumi

+/* <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.

Signature · 1 line
OGAWA Hirofumi <[email protected]>
#37 lore raw

Re: [PATCH 2/29] FAT: Updated FAT attributes patch

In reply to Michael Geng
Quoted 5 lines · Michael Geng
Quoted 1 line · OGAWA Hirofumi

+/* <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.

author maintainer
#38 lore raw

PATCH 1/1 FAT: Support synchronous updates

In reply to OGAWA Hirofumi

[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.

Signature · 1 line
OGAWA Hirofumi <[email protected]>
#39 lore raw

Re: [PATCH] FAT: Support synchronous update

In reply to a message not in the archive
Quoted 21 lines · OGAWA Hirofumi

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().

Quoted 10 lines

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.

Signature · 1 line
OGAWA Hirofumi <[email protected]>

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?

author maintainer
#40 lore raw

Re: [PATCH] FAT: Support synchronous update

Quoted 8 lines · Andrew Morton

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

Signature · 1 line
OGAWA Hirofumi <[email protected]>