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]>
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/file.c | 31 ++++++++++++++++++++++++-------
1 files changed, 24 insertions(+), 7 deletions(-)
diff -puN fs/fat/file.c~fat_support-aio fs/fat/file.c
--- linux-2.6.11/fs/fat/file.c~fat_support-aio 2005-03-06 02:17:05.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/file.c 2005-03-06 02:35:38.000000000 +0900
@@ -12,13 +12,28 @@
#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
-static ssize_t fat_file_write(struct file *filp, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t fat_file_aio_write(struct kiocb *iocb, const char __user *buf,
+ size_t count, loff_t pos)
+{
+ struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
+ int retval;
+
+ retval = generic_file_aio_write(iocb, buf, count, pos);
+ if (retval > 0) {
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+ MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+ mark_inode_dirty(inode);
+ }
+ return retval;
+}
+
+static ssize_t fat_file_writev(struct file *filp, const struct iovec *iov,
+ unsigned long nr_segs, loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
int retval;
- retval = generic_file_write(filp, buf, count, ppos);
+ retval = generic_file_writev(filp, iov, nr_segs, ppos);
if (retval > 0) {
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
@@ -29,12 +44,14 @@ static ssize_t fat_file_write(struct fil
struct file_operations fat_file_operations = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
- .write = fat_file_write,
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .readv = generic_file_readv,
+ .writev = fat_file_writev,
+ .aio_read = generic_file_aio_read,
+ .aio_write = fat_file_aio_write,
.mmap = generic_file_mmap,
.fsync = file_fsync,
- .readv = generic_file_readv,
- .writev = generic_file_writev,
.sendfile = generic_file_sendfile,
};
_
This updates the FAT attributes as well as (hopefully) corrects the
handling of VFAT ctime. The FAT attributes are implemented as a 32-bit
ioctl, per the previous discussions.
Signed-Off-By: H. Peter Anvin <[email protected]>
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/dir.c | 2
fs/fat/file.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++
fs/fat/inode.c | 38 ++++++++----------
fs/vfat/namei.c | 2
include/linux/msdos_fs.h | 22 +++++++---
5 files changed, 135 insertions(+), 28 deletions(-)
diff -puN fs/fat/dir.c~fat_attribute-ioctl fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~fat_attribute-ioctl 2005-03-06 02:36:02.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:36:02.000000000 +0900
@@ -639,7 +639,7 @@ static int fat_dir_ioctl(struct inode *
both = 1;
break;
default:
- return -EINVAL;
+ return fat_generic_ioctl(inode, filp, cmd, arg);
}
d1 = (struct dirent __user *)arg;
diff -puN fs/fat/file.c~fat_attribute-ioctl fs/fat/file.c
--- linux-2.6.11/fs/fat/file.c~fat_attribute-ioctl 2005-03-06 02:36:02.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/file.c 2005-03-06 02:36:02.000000000 +0900
@@ -42,6 +42,104 @@ static ssize_t fat_file_writev(struct fi
return retval;
}
+int fat_generic_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+ u32 __user *user_attr = (u32 __user *)arg;
+
+ switch (cmd) {
+ case FAT_IOCTL_GET_ATTRIBUTES:
+ {
+ u32 attr;
+
+ if (inode->i_ino == MSDOS_ROOT_INO)
+ attr = ATTR_DIR;
+ else
+ attr = fat_attr(inode);
+
+ return put_user(attr, user_attr);
+ }
+ case FAT_IOCTL_SET_ATTRIBUTES:
+ {
+ u32 attr, oldattr;
+ int err, is_dir = S_ISDIR(inode->i_mode);
+ struct iattr ia;
+
+ err = get_user(attr, user_attr);
+ if (err)
+ return err;
+
+ down(&inode->i_sem);
+
+ if (IS_RDONLY(inode)) {
+ err = -EROFS;
+ goto up;
+ }
+
+ /*
+ * ATTR_VOLUME and ATTR_DIR cannot be changed; this also
+ * prevents the user from turning us into a VFAT
+ * longname entry. Also, we obviously can't set
+ * any of the NTFS attributes in the high 24 bits.
+ */
+ attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR);
+ /* Merge in ATTR_VOLUME and ATTR_DIR */
+ attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) |
+ (is_dir ? ATTR_DIR : 0);
+ oldattr = fat_attr(inode);
+
+ /* Equivalent to a chmod() */
+ ia.ia_valid = ATTR_MODE | ATTR_CTIME;
+ if (is_dir) {
+ ia.ia_mode = MSDOS_MKMODE(attr,
+ S_IRWXUGO & ~sbi->options.fs_dmask)
+ | S_IFDIR;
+ } else {
+ ia.ia_mode = MSDOS_MKMODE(attr,
+ (S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO))
+ & ~sbi->options.fs_fmask)
+ | S_IFREG;
+ }
+
+ /* The root directory has no attributes */
+ if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) {
+ err = -EINVAL;
+ goto up;
+ }
+
+ if (sbi->options.sys_immutable) {
+ if ((attr | oldattr) & ATTR_SYS) {
+ if (!capable(CAP_LINUX_IMMUTABLE)) {
+ err = -EPERM;
+ goto up;
+ }
+ }
+ }
+
+ /* This MUST be done before doing anything irreversible... */
+ err = notify_change(filp->f_dentry, &ia);
+ if (err)
+ goto up;
+
+ if (sbi->options.sys_immutable) {
+ if (attr & ATTR_SYS)
+ inode->i_flags |= S_IMMUTABLE;
+ else
+ inode->i_flags &= S_IMMUTABLE;
+ }
+
+ MSDOS_I(inode)->i_attrs = attr & ATTR_UNUSED;
+ mark_inode_dirty(inode);
+ up:
+ up(&inode->i_sem);
+ return err;
+ }
+ default:
+ return -ENOTTY; /* Inappropriate ioctl for device */
+ }
+}
+
struct file_operations fat_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
@@ -51,6 +149,7 @@ struct file_operations fat_file_operatio
.aio_read = generic_file_aio_read,
.aio_write = fat_file_aio_write,
.mmap = generic_file_mmap,
+ .ioctl = fat_generic_ioctl,
.fsync = file_fsync,
.sendfile = generic_file_sendfile,
};
diff -puN fs/fat/inode.c~fat_attribute-ioctl fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~fat_attribute-ioctl 2005-03-06 02:36:02.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c 2005-03-06 02:36:02.000000000 +0900
@@ -220,8 +220,7 @@ static int fat_calc_dir_size(struct inod
/* doesn't deal with root inode */
static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
{
- struct super_block *sb = inode->i_sb;
- struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
int error;
MSDOS_I(inode)->i_pos = 0;
@@ -266,9 +265,10 @@ static int fat_fill_inode(struct inode *
inode->i_mapping->a_ops = &fat_aops;
MSDOS_I(inode)->mmu_private = inode->i_size;
}
- if(de->attr & ATTR_SYS)
+ if (de->attr & ATTR_SYS) {
if (sbi->options.sys_immutable)
inode->i_flags |= S_IMMUTABLE;
+ }
MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
/* this is as close to the truth as we can get ... */
inode->i_blksize = sbi->cluster_size;
@@ -277,12 +277,15 @@ static int fat_fill_inode(struct inode *
inode->i_mtime.tv_sec = inode->i_atime.tv_sec =
date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date));
inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = 0;
- inode->i_ctime.tv_sec =
- MSDOS_SB(sb)->options.isvfat
- ? date_dos2unix(le16_to_cpu(de->ctime), le16_to_cpu(de->cdate))
- : inode->i_mtime.tv_sec;
- inode->i_ctime.tv_nsec = de->ctime_ms * 1000000;
- MSDOS_I(inode)->i_ctime_ms = de->ctime_ms;
+ if (sbi->options.isvfat) {
+ int secs = de->ctime_cs / 100;
+ int csecs = de->ctime_cs % 100;
+ inode->i_ctime.tv_sec =
+ date_dos2unix(le16_to_cpu(de->ctime),
+ le16_to_cpu(de->cdate)) + secs;
+ inode->i_ctime.tv_nsec = csecs * 10000000;
+ } else
+ inode->i_ctime = inode->i_mtime;
return 0;
}
@@ -483,22 +486,18 @@ retry:
raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
[i_pos & (sbi->dir_per_block - 1)];
- if (S_ISDIR(inode->i_mode)) {
- raw_entry->attr = ATTR_DIR;
+ if (S_ISDIR(inode->i_mode))
raw_entry->size = 0;
- }
- else {
- raw_entry->attr = ATTR_NONE;
+ else
raw_entry->size = cpu_to_le32(inode->i_size);
- }
- raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) |
- MSDOS_I(inode)->i_attrs;
+ raw_entry->attr = fat_attr(inode);
raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart);
raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16);
fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, &raw_entry->date);
if (sbi->options.isvfat) {
fat_date_unix2dos(inode->i_ctime.tv_sec,&raw_entry->ctime,&raw_entry->cdate);
- raw_entry->ctime_ms = MSDOS_I(inode)->i_ctime_ms; /* use i_ctime.tv_nsec? */
+ raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 +
+ inode->i_ctime.tv_nsec / 10000000;
}
spin_unlock(&sbi->inode_hash_lock);
mark_buffer_dirty(bh);
@@ -1026,10 +1025,9 @@ static int fat_read_root(struct inode *i
MSDOS_I(inode)->i_logstart = 0;
MSDOS_I(inode)->mmu_private = inode->i_size;
- MSDOS_I(inode)->i_attrs = 0;
+ MSDOS_I(inode)->i_attrs = ATTR_NONE;
inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0;
inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0;
- MSDOS_I(inode)->i_ctime_ms = 0;
inode->i_nlink = fat_subdirs(inode)+2;
return 0;
diff -puN fs/vfat/namei.c~fat_attribute-ioctl fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~fat_attribute-ioctl 2005-03-06 02:36:02.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:36:02.000000000 +0900
@@ -649,7 +649,7 @@ shortname:
de->lcase = lcase;
de->adate = de->cdate = de->date = 0;
de->ctime = de->time = 0;
- de->ctime_ms = 0;
+ de->ctime_cs = 0;
de->start = 0;
de->starthi = 0;
de->size = 0;
diff -puN include/linux/msdos_fs.h~fat_attribute-ioctl include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~fat_attribute-ioctl 2005-03-06 02:36:02.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:02.000000000 +0900
@@ -50,8 +50,6 @@
#define MSDOS_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)
/* Convert attribute bits and a mask to the UNIX mode. */
#define MSDOS_MKMODE(a, m) (m & (a & ATTR_RO ? S_IRUGO|S_IXUGO : S_IRWXUGO))
-/* Convert the UNIX mode to MS-DOS attribute bits. */
-#define MSDOS_MKATTR(m) ((m & S_IWUGO) ? ATTR_NONE : ATTR_RO)
#define MSDOS_NAME 11 /* maximum name length */
#define MSDOS_LONGNAME 256 /* maximum name length */
@@ -100,8 +98,11 @@
/*
* ioctl commands
*/
-#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
-#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
+#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
+#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
+/* <linux/videotext.h> has used 0x72 ('r') in collision, so skip a few */
+#define FAT_IOCTL_GET_ATTRIBUTES _IOR('r', 0x10, __u32)
+#define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, __u32)
/*
* vfat shortname flags
@@ -152,7 +153,7 @@ struct msdos_dir_entry {
__u8 name[8],ext[3]; /* name and extension */
__u8 attr; /* attribute bits */
__u8 lcase; /* Case for base and extension */
- __u8 ctime_ms; /* Creation time, milliseconds */
+ __u8 ctime_cs; /* Creation time, centiseconds (0-199) */
__le16 ctime; /* Creation time */
__le16 cdate; /* Creation date */
__le16 adate; /* Last access date */
@@ -257,7 +258,6 @@ struct msdos_inode_info {
int i_start; /* first cluster or 0 */
int i_logstart; /* logical first cluster */
int i_attrs; /* unused attribute bits */
- int i_ctime_ms; /* unused change time in milliseconds */
loff_t i_pos; /* on-disk position of directory entry or 0 */
struct hlist_node i_fat_hash; /* hash by i_location */
struct inode vfs_inode;
@@ -273,6 +273,14 @@ static inline struct msdos_inode_info *M
return container_of(inode, struct msdos_inode_info, vfs_inode);
}
+/* Return the FAT attribute byte for this inode */
+static inline u8 fat_attr(struct inode *inode)
+{
+ return ((inode->i_mode & S_IWUGO) ? ATTR_NONE : ATTR_RO) |
+ (S_ISDIR(inode->i_mode) ? ATTR_DIR : ATTR_NONE) |
+ MSDOS_I(inode)->i_attrs;
+}
+
static inline sector_t fat_clus_to_blknr(struct msdos_sb_info *sbi, int clus)
{
return ((sector_t)clus - FAT_START_ENT) * sbi->sec_per_clus
@@ -328,6 +336,8 @@ extern int fat_scan(struct inode *dir, c
struct msdos_dir_entry **res_de, loff_t *i_pos);
/* fat/file.c */
+extern int fat_generic_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
extern struct file_operations fat_file_operations;
extern struct inode_operations fat_file_inode_operations;
extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
_
In the case of dotsOK, re-initialization of "ptname" pointer is needed,
otherwise, "ptname" is pointing the previous start position.
This fixes it.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/dir.c | 10 +++++++---
1 files changed, 7 insertions(+), 3 deletions(-)
diff -puN fs/fat/dir.c~fat_readdirx-fix fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~fat_readdirx-fix 2005-03-06 02:36:05.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:36:05.000000000 +0900
@@ -442,9 +442,13 @@ ParseLong:
long_slots = 0;
}
- if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
- *ptname++ = '.';
- dotoffset = 1;
+ if (MSDOS_SB(sb)->options.dotsOK) {
+ ptname = bufname;
+ dotoffset = 0;
+ if (de->attr & ATTR_HIDDEN) {
+ *ptname++ = '.';
+ dotoffset = 1;
+ }
}
memcpy(work, de->name, sizeof(de->name));
_
This changes ->free_clusters and ->prev_free from "int" to "unsigned int".
These value should be never negative value (but it's using 0xffffffff(-1)
as undefined state).
With this changes, fatfs would handle the corruption of free_clusters
more proper.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/fatent.c | 3 +--
fs/fat/inode.c | 6 +++++-
include/linux/msdos_fs.h | 4 ++--
3 files changed, 8 insertions(+), 5 deletions(-)
diff -puN fs/fat/fatent.c~sync05-fat_free-unsigned fs/fat/fatent.c
--- linux-2.6.11/fs/fat/fatent.c~sync05-fat_free-unsigned 2005-03-06 02:36:19.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/fatent.c 2005-03-06 02:36:19.000000000 +0900
@@ -453,8 +453,7 @@ int fat_alloc_clusters(struct inode *ino
fatent_init(&fatent);
fatent_set_entry(&fatent, sbi->prev_free + 1);
while (count < sbi->max_cluster) {
- fatent.entry %= sbi->max_cluster;
- if (fatent.entry < FAT_START_ENT)
+ if (fatent.entry >= sbi->max_cluster)
fatent.entry = FAT_START_ENT;
fatent_set_entry(&fatent, fatent.entry);
err = fat_ent_read_block(sb, &fatent);
diff -puN fs/fat/inode.c~sync05-fat_free-unsigned fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~sync05-fat_free-unsigned 2005-03-06 02:36:19.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c 2005-03-06 02:36:19.000000000 +0900
@@ -1163,7 +1163,7 @@ int fat_fill_super(struct super_block *s
sbi->fat_length = le16_to_cpu(b->fat_length);
sbi->root_cluster = 0;
sbi->free_clusters = -1; /* Don't know yet */
- sbi->prev_free = -1;
+ sbi->prev_free = FAT_START_ENT;
if (!sbi->fat_length && b->fat32_length) {
struct fat_boot_fsinfo *fsinfo;
@@ -1247,6 +1247,10 @@ int fat_fill_super(struct super_block *s
/* check the free_clusters, it's not necessarily correct */
if (sbi->free_clusters != -1 && sbi->free_clusters > total_clusters)
sbi->free_clusters = -1;
+ /* check the prev_free, it's not necessarily correct */
+ sbi->prev_free %= sbi->max_cluster;
+ if (sbi->prev_free < FAT_START_ENT)
+ sbi->prev_free = FAT_START_ENT;
brelse(bh);
diff -puN include/linux/msdos_fs.h~sync05-fat_free-unsigned include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync05-fat_free-unsigned 2005-03-06 02:36:19.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:19.000000000 +0900
@@ -225,8 +225,8 @@ struct msdos_sb_info {
unsigned long root_cluster; /* first cluster of the root directory */
unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */
struct semaphore fat_lock;
- int prev_free; /* previously allocated cluster number */
- int free_clusters; /* -1 if undefined */
+ unsigned int prev_free; /* previously allocated cluster number */
+ unsigned int free_clusters; /* -1 if undefined */
struct fat_mount_options options;
struct nls_table *nls_disk; /* Codepage used on disk */
struct nls_table *nls_io; /* Charset used for input and display */
_
Add "struct fat_slot_info" for updating data of the directory entries.
1) Rename "struct vfat_slot_info" to "struct fat_slot_info"
2) Add "de" and "bh" to fat_slot_info instead of using argument.
3) Replace the "vfat_slot_info + de + bh" by new fat_slot_info
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/vfat/namei.c | 126 ++++++++++++++++++++---------------------------
include/linux/msdos_fs.h | 8 +-
2 files changed, 61 insertions(+), 73 deletions(-)
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync06-fat_dir-cleanup 2005-03-06 02:36:22.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:36:22.000000000 +0900
@@ -660,16 +660,15 @@ out_free:
}
static int vfat_add_entry(struct inode *dir, struct qstr *qname,
- int is_dir, struct vfat_slot_info *sinfo_out,
- struct buffer_head **bh, struct msdos_dir_entry **de)
+ int is_dir, struct fat_slot_info *sinfo)
{
struct super_block *sb = dir->i_sb;
struct msdos_dir_slot *dir_slots;
loff_t offset;
int res, slots, slot;
unsigned int len;
- struct msdos_dir_entry *dummy_de;
- struct buffer_head *dummy_bh;
+ struct msdos_dir_entry *de, *dummy_de;
+ struct buffer_head *bh, *dummy_bh;
loff_t dummy_i_pos;
len = vfat_striptail_len(qname);
@@ -695,16 +694,16 @@ static int vfat_add_entry(struct inode *
brelse(dummy_bh);
/* Now create the new entry */
- *bh = NULL;
+ bh = NULL;
for (slot = 0; slot < slots; slot++) {
- if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->i_pos) < 0) {
+ if (fat_get_entry(dir, &offset, &bh, &de, &sinfo->i_pos) < 0) {
res = -EIO;
goto cleanup;
}
- memcpy(*de, dir_slots + slot, sizeof(struct msdos_dir_slot));
- mark_buffer_dirty(*bh);
+ memcpy(de, dir_slots + slot, sizeof(struct msdos_dir_slot));
+ mark_buffer_dirty(bh);
if (sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(*bh);
+ sync_dirty_buffer(bh);
}
res = 0;
@@ -712,18 +711,19 @@ static int vfat_add_entry(struct inode *
dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
mark_inode_dirty(dir);
- fat_date_unix2dos(dir->i_mtime.tv_sec, &(*de)->time, &(*de)->date);
+ fat_date_unix2dos(dir->i_mtime.tv_sec, &de->time, &de->date);
dir->i_mtime.tv_nsec = 0;
- (*de)->ctime = (*de)->time;
- (*de)->adate = (*de)->cdate = (*de)->date;
- mark_buffer_dirty(*bh);
+ de->ctime = de->time;
+ de->adate = de->cdate = de->date;
+ mark_buffer_dirty(bh);
if (sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(*bh);
+ sync_dirty_buffer(bh);
/* slots can't be less than 1 */
- sinfo_out->long_slots = slots - 1;
- sinfo_out->longname_offset =
- offset - sizeof(struct msdos_dir_slot) * slots;
+ sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * slots;
+ sinfo->nr_slots = slots - 1;
+ sinfo->de = de;
+ sinfo->bh = bh;
cleanup:
kfree(dir_slots);
@@ -731,8 +731,7 @@ cleanup:
}
static int vfat_find(struct inode *dir, struct qstr *qname,
- struct vfat_slot_info *sinfo, struct buffer_head **last_bh,
- struct msdos_dir_entry **last_de)
+ struct fat_slot_info *sinfo)
{
struct super_block *sb = dir->i_sb;
loff_t offset;
@@ -745,10 +744,10 @@ static int vfat_find(struct inode *dir,
res = fat_search_long(dir, qname->name, len,
(MSDOS_SB(sb)->options.name_check != 's'),
- &offset, &sinfo->longname_offset);
+ &offset, &sinfo->slot_off);
if (res > 0) {
- sinfo->long_slots = res - 1;
- if (fat_get_entry(dir, &offset, last_bh, last_de, &sinfo->i_pos) >= 0)
+ sinfo->nr_slots = res - 1;
+ if (fat_get_entry(dir, &offset, &sinfo->bh, &sinfo->de, &sinfo->i_pos) >= 0)
return 0;
res = -EIO;
}
@@ -759,11 +758,9 @@ static struct dentry *vfat_lookup(struct
struct nameidata *nd)
{
int res;
- struct vfat_slot_info sinfo;
+ struct fat_slot_info sinfo;
struct inode *inode;
struct dentry *alias;
- struct buffer_head *bh = NULL;
- struct msdos_dir_entry *de;
int table;
lock_kernel();
@@ -771,13 +768,13 @@ static struct dentry *vfat_lookup(struct
dentry->d_op = &vfat_dentry_ops[table];
inode = NULL;
- res = vfat_find(dir, &dentry->d_name, &sinfo, &bh, &de);
+ res = vfat_find(dir, &dentry->d_name, &sinfo);
if (res < 0) {
table++;
goto error;
}
- inode = fat_build_inode(dir->i_sb, de, sinfo.i_pos, &res);
- brelse(bh);
+ inode = fat_build_inode(dir->i_sb, sinfo.de, sinfo.i_pos, &res);
+ brelse(sinfo.bh);
if (res) {
unlock_kernel();
return ERR_PTR(res);
@@ -810,17 +807,15 @@ static int vfat_create(struct inode *dir
{
struct super_block *sb = dir->i_sb;
struct inode *inode = NULL;
- struct buffer_head *bh = NULL;
- struct msdos_dir_entry *de;
- struct vfat_slot_info sinfo;
+ struct fat_slot_info sinfo;
int res;
lock_kernel();
- res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo, &bh, &de);
+ res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo);
if (res < 0)
goto out;
- inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
- brelse(bh);
+ inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos, &res);
+ brelse(sinfo.bh);
if (!inode)
goto out;
res = 0;
@@ -838,11 +833,11 @@ out:
return res;
}
-static void vfat_remove_entry(struct inode *dir, struct vfat_slot_info *sinfo,
- struct buffer_head *bh,
- struct msdos_dir_entry *de)
+static void vfat_remove_entry(struct inode *dir, struct fat_slot_info *sinfo)
{
struct super_block *sb = dir->i_sb;
+ struct msdos_dir_entry *de = sinfo->de;
+ struct buffer_head *bh = sinfo->bh;
loff_t offset, i_pos;
int i;
@@ -857,9 +852,9 @@ static void vfat_remove_entry(struct ino
sync_dirty_buffer(bh);
/* remove the longname */
- offset = sinfo->longname_offset;
+ offset = sinfo->slot_off;
de = NULL;
- for (i = sinfo->long_slots; i > 0; --i) {
+ for (i = sinfo->nr_slots; i > 0; --i) {
if (fat_get_entry(dir, &offset, &bh, &de, &i_pos) < 0)
continue;
de->name[0] = DELETED_FLAG;
@@ -874,9 +869,7 @@ static void vfat_remove_entry(struct ino
static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
- struct vfat_slot_info sinfo;
- struct buffer_head *bh = NULL;
- struct msdos_dir_entry *de;
+ struct fat_slot_info sinfo;
int res;
lock_kernel();
@@ -884,7 +877,7 @@ static int vfat_rmdir(struct inode *dir,
if (res)
goto out;
- res = vfat_find(dir, &dentry->d_name, &sinfo, &bh, &de);
+ res = vfat_find(dir, &dentry->d_name, &sinfo);
if (res < 0)
goto out;
@@ -894,7 +887,7 @@ static int vfat_rmdir(struct inode *dir,
fat_detach(inode);
mark_inode_dirty(inode);
/* releases bh and syncs it if necessary */
- vfat_remove_entry(dir, &sinfo, bh, de);
+ vfat_remove_entry(dir, &sinfo);
dir->i_nlink--;
out:
unlock_kernel();
@@ -904,13 +897,11 @@ out:
static int vfat_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
- struct vfat_slot_info sinfo;
- struct buffer_head *bh = NULL;
- struct msdos_dir_entry *de;
+ struct fat_slot_info sinfo;
int res;
lock_kernel();
- res = vfat_find(dir, &dentry->d_name, &sinfo, &bh, &de);
+ res = vfat_find(dir, &dentry->d_name, &sinfo);
if (res < 0)
goto out;
inode->i_nlink = 0;
@@ -918,7 +909,7 @@ static int vfat_unlink(struct inode *dir
fat_detach(inode);
mark_inode_dirty(inode);
/* releases bh and syncs it if necessary */
- vfat_remove_entry(dir, &sinfo, bh, de);
+ vfat_remove_entry(dir, &sinfo);
out:
unlock_kernel();
@@ -929,16 +920,14 @@ static int vfat_mkdir(struct inode *dir,
{
struct super_block *sb = dir->i_sb;
struct inode *inode = NULL;
- struct vfat_slot_info sinfo;
- struct buffer_head *bh = NULL;
- struct msdos_dir_entry *de;
+ struct fat_slot_info sinfo;
int res;
lock_kernel();
- res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo, &bh, &de);
+ res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo);
if (res < 0)
goto out;
- inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
+ inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos, &res);
if (!inode)
goto out_brelse;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
@@ -953,7 +942,7 @@ static int vfat_mkdir(struct inode *dir,
dentry->d_time = dentry->d_parent->d_inode->i_version;
d_instantiate(dentry, inode);
out_brelse:
- brelse(bh);
+ brelse(sinfo.bh);
out:
unlock_kernel();
return res;
@@ -964,7 +953,7 @@ mkdir_failed:
fat_detach(inode);
mark_inode_dirty(inode);
/* releases bh ands syncs if necessary */
- vfat_remove_entry(dir, &sinfo, bh, de);
+ vfat_remove_entry(dir, &sinfo);
iput(inode);
dir->i_nlink--;
goto out;
@@ -973,24 +962,22 @@ mkdir_failed:
static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
- struct buffer_head *old_bh, *new_bh, *dotdot_bh;
- struct msdos_dir_entry *old_de, *new_de, *dotdot_de;
+ struct buffer_head *dotdot_bh;
+ struct msdos_dir_entry *dotdot_de;
loff_t dotdot_i_pos;
struct inode *old_inode, *new_inode;
int res, is_dir;
- struct vfat_slot_info old_sinfo, sinfo;
+ struct fat_slot_info old_sinfo, sinfo;
- old_bh = new_bh = dotdot_bh = NULL;
+ old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode;
lock_kernel();
- res = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo, &old_bh,
- &old_de);
+ res = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
if (res < 0)
goto rename_done;
is_dir = S_ISDIR(old_inode->i_mode);
-
if (is_dir) {
if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
&dotdot_de, &dotdot_i_pos) < 0) {
@@ -1000,8 +987,7 @@ static int vfat_rename(struct inode *old
}
if (new_dentry->d_inode) {
- res = vfat_find(new_dir, &new_dentry->d_name, &sinfo, &new_bh,
- &new_de);
+ res = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
if (res < 0 || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
/* WTF??? Cry and fail. */
printk(KERN_WARNING "vfat_rename: fs corrupted\n");
@@ -1016,7 +1002,7 @@ static int vfat_rename(struct inode *old
fat_detach(new_inode);
} else {
res = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
- &sinfo, &new_bh, &new_de);
+ &sinfo);
if (res < 0)
goto rename_done;
}
@@ -1024,8 +1010,8 @@ static int vfat_rename(struct inode *old
new_dir->i_version++;
/* releases old_bh */
- vfat_remove_entry(old_dir, &old_sinfo, old_bh, old_de);
- old_bh = NULL;
+ vfat_remove_entry(old_dir, &old_sinfo);
+ old_sinfo.bh = NULL;
fat_detach(old_inode);
fat_attach(old_inode, sinfo.i_pos);
mark_inode_dirty(old_inode);
@@ -1057,8 +1043,8 @@ static int vfat_rename(struct inode *old
rename_done:
brelse(dotdot_bh);
- brelse(old_bh);
- brelse(new_bh);
+ brelse(old_sinfo.bh);
+ brelse(sinfo.bh);
unlock_kernel();
return res;
}
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync06-fat_dir-cleanup 2005-03-06 02:36:22.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:22.000000000 +0900
@@ -170,10 +170,12 @@ struct msdos_dir_slot {
__u8 name11_12[4]; /* last 2 characters in name */
};
-struct vfat_slot_info {
- int long_slots; /* number of long slots in filename */
- loff_t longname_offset; /* dir offset for longname start */
+struct fat_slot_info {
loff_t i_pos; /* on-disk position of directory entry */
+ loff_t slot_off; /* offset for slot or de start */
+ int nr_slots; /* number of slots + 1(de) in filename */
+ struct msdos_dir_entry *de;
+ struct buffer_head *bh;
};
#ifdef __KERNEL__
_
In order not to write the same block repeatedly, rewrite the FAT entry
access stuff.
And this separates the "allocate the cluster" and "link to cluster
chain" operations for expanding the file/dir safely.
(fat_alloc_clusters() allocates the cluster, and fat_chain_add() links
allocated cluster to the chain which inode has.)
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/Makefile | 2
fs/fat/cache.c | 145 +----------
fs/fat/dir.c | 15 -
fs/fat/fatent.c | 590 +++++++++++++++++++++++++++++++++++++++++++++++
fs/fat/file.c | 69 ++---
fs/fat/inode.c | 60 ++--
fs/fat/misc.c | 122 ++++-----
include/linux/msdos_fs.h | 57 +++-
8 files changed, 781 insertions(+), 279 deletions(-)
diff -puN fs/fat/Makefile~sync05-fat_dep-fatent fs/fat/Makefile
--- linux-2.6.11/fs/fat/Makefile~sync05-fat_dep-fatent 2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/Makefile 2005-03-06 02:36:12.000000000 +0900
@@ -4,4 +4,4 @@
obj-$(CONFIG_FAT_FS) += fat.o
-fat-objs := cache.o dir.o file.o inode.o misc.o
+fat-objs := cache.o dir.o fatent.o file.o inode.o misc.o
diff -puN fs/fat/cache.c~sync05-fat_dep-fatent fs/fat/cache.c
--- linux-2.6.11/fs/fat/cache.c~sync05-fat_dep-fatent 2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/cache.c 2005-03-06 02:36:12.000000000 +0900
@@ -203,132 +203,6 @@ void fat_cache_inval_inode(struct inode
spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
}
-static int __fat_access(struct super_block *sb, int nr, int new_value)
-{
- struct msdos_sb_info *sbi = MSDOS_SB(sb);
- struct buffer_head *bh, *bh2, *c_bh, *c_bh2;
- unsigned char *p_first, *p_last;
- int copy, first, last, next, b;
-
- if (sbi->fat_bits == 32) {
- first = last = nr*4;
- } else if (sbi->fat_bits == 16) {
- first = last = nr*2;
- } else {
- first = nr*3/2;
- last = first+1;
- }
- b = sbi->fat_start + (first >> sb->s_blocksize_bits);
- if (!(bh = sb_bread(sb, b))) {
- printk(KERN_ERR "FAT: bread(block %d) in"
- " fat_access failed\n", b);
- return -EIO;
- }
- if ((first >> sb->s_blocksize_bits) == (last >> sb->s_blocksize_bits)) {
- bh2 = bh;
- } else {
- if (!(bh2 = sb_bread(sb, b + 1))) {
- brelse(bh);
- printk(KERN_ERR "FAT: bread(block %d) in"
- " fat_access failed\n", b + 1);
- return -EIO;
- }
- }
- if (sbi->fat_bits == 32) {
- p_first = p_last = NULL; /* GCC needs that stuff */
- next = le32_to_cpu(((__le32 *) bh->b_data)[(first &
- (sb->s_blocksize - 1)) >> 2]);
- /* Fscking Microsoft marketing department. Their "32" is 28. */
- next &= 0x0fffffff;
- } else if (sbi->fat_bits == 16) {
- p_first = p_last = NULL; /* GCC needs that stuff */
- next = le16_to_cpu(((__le16 *) bh->b_data)[(first &
- (sb->s_blocksize - 1)) >> 1]);
- } else {
- p_first = &((__u8 *)bh->b_data)[first & (sb->s_blocksize - 1)];
- p_last = &((__u8 *)bh2->b_data)[(first + 1) & (sb->s_blocksize - 1)];
- if (nr & 1)
- next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff;
- else
- next = (*p_first+(*p_last << 8)) & 0xfff;
- }
- if (new_value != -1) {
- if (sbi->fat_bits == 32) {
- ((__le32 *)bh->b_data)[(first & (sb->s_blocksize - 1)) >> 2]
- = cpu_to_le32(new_value);
- } else if (sbi->fat_bits == 16) {
- ((__le16 *)bh->b_data)[(first & (sb->s_blocksize - 1)) >> 1]
- = cpu_to_le16(new_value);
- } else {
- if (nr & 1) {
- *p_first = (*p_first & 0xf) | (new_value << 4);
- *p_last = new_value >> 4;
- }
- else {
- *p_first = new_value & 0xff;
- *p_last = (*p_last & 0xf0) | (new_value >> 8);
- }
- mark_buffer_dirty(bh2);
- if (sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(bh2);
- }
- mark_buffer_dirty(bh);
- if (sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(bh);
- for (copy = 1; copy < sbi->fats; copy++) {
- b = sbi->fat_start + (first >> sb->s_blocksize_bits)
- + sbi->fat_length * copy;
- if (!(c_bh = sb_bread(sb, b)))
- break;
- if (bh != bh2) {
- if (!(c_bh2 = sb_bread(sb, b+1))) {
- brelse(c_bh);
- break;
- }
- memcpy(c_bh2->b_data, bh2->b_data, sb->s_blocksize);
- mark_buffer_dirty(c_bh2);
- if (sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(c_bh2);
- brelse(c_bh2);
- }
- memcpy(c_bh->b_data, bh->b_data, sb->s_blocksize);
- mark_buffer_dirty(c_bh);
- if (sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(c_bh);
- brelse(c_bh);
- }
- }
- brelse(bh);
- if (bh != bh2)
- brelse(bh2);
- return next;
-}
-
-/*
- * Returns the this'th FAT entry, -1 if it is an end-of-file entry. If
- * new_value is != -1, that FAT entry is replaced by it.
- */
-int fat_access(struct super_block *sb, int nr, int new_value)
-{
- int next;
-
- next = -EIO;
- if (nr < FAT_START_ENT || MSDOS_SB(sb)->max_cluster <= nr) {
- fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", nr);
- goto out;
- }
- if (new_value == FAT_ENT_EOF)
- new_value = EOF_FAT(sb);
-
- next = __fat_access(sb, nr, new_value);
- if (next < 0)
- goto out;
- if (next >= BAD_FAT(sb))
- next = FAT_ENT_EOF;
-out:
- return next;
-}
-
static inline int cache_contiguous(struct fat_cache_id *cid, int dclus)
{
cid->nr_contig++;
@@ -347,6 +221,7 @@ int fat_get_cluster(struct inode *inode,
{
struct super_block *sb = inode->i_sb;
const int limit = sb->s_maxbytes >> MSDOS_SB(sb)->cluster_bits;
+ struct fat_entry fatent;
struct fat_cache_id cid;
int nr;
@@ -365,34 +240,40 @@ int fat_get_cluster(struct inode *inode,
cache_init(&cid, -1, -1);
}
+ fatent_init(&fatent);
while (*fclus < cluster) {
/* prevent the infinite loop of cluster chain */
if (*fclus > limit) {
fat_fs_panic(sb, "%s: detected the cluster chain loop"
" (i_pos %lld)", __FUNCTION__,
MSDOS_I(inode)->i_pos);
- return -EIO;
+ nr = -EIO;
+ goto out;
}
- nr = fat_access(sb, *dclus, -1);
+ nr = fat_ent_read(inode, &fatent, *dclus);
if (nr < 0)
- return nr;
+ goto out;
else if (nr == FAT_ENT_FREE) {
fat_fs_panic(sb, "%s: invalid cluster chain"
" (i_pos %lld)", __FUNCTION__,
MSDOS_I(inode)->i_pos);
- return -EIO;
+ nr = -EIO;
+ goto out;
} else if (nr == FAT_ENT_EOF) {
fat_cache_add(inode, &cid);
- return FAT_ENT_EOF;
+ goto out;
}
(*fclus)++;
*dclus = nr;
if (!cache_contiguous(&cid, *dclus))
cache_init(&cid, *fclus, *dclus);
}
+ nr = 0;
fat_cache_add(inode, &cid);
- return 0;
+out:
+ fatent_brelse(&fatent);
+ return nr;
}
static int fat_bmap_cluster(struct inode *inode, int cluster)
diff -puN fs/fat/dir.c~sync05-fat_dep-fatent fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync05-fat_dep-fatent 2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:36:12.000000000 +0900
@@ -759,7 +759,7 @@ static struct buffer_head *fat_extend_di
{
struct super_block *sb = inode->i_sb;
struct buffer_head *bh, *res = NULL;
- int nr, sec_per_clus = MSDOS_SB(sb)->sec_per_clus;
+ int err, cluster, sec_per_clus = MSDOS_SB(sb)->sec_per_clus;
sector_t sector, last_sector;
if (MSDOS_SB(sb)->fat_bits != 32) {
@@ -767,11 +767,16 @@ static struct buffer_head *fat_extend_di
return ERR_PTR(-ENOSPC);
}
- nr = fat_add_cluster(inode);
- if (nr < 0)
- return ERR_PTR(nr);
+ err = fat_alloc_clusters(inode, &cluster, 1);
+ if (err)
+ return ERR_PTR(err);
+ err = fat_chain_add(inode, cluster, 1);
+ if (err) {
+ fat_free_clusters(inode, cluster);
+ return ERR_PTR(err);
+ }
- sector = fat_clus_to_blknr(MSDOS_SB(sb), nr);
+ sector = fat_clus_to_blknr(MSDOS_SB(sb), cluster);
last_sector = sector + sec_per_clus;
for ( ; sector < last_sector; sector++) {
if ((bh = sb_getblk(sb, sector))) {
diff -puN /dev/null fs/fat/fatent.c
--- /dev/null 2004-09-13 22:36:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/fatent.c 2005-03-06 02:36:12.000000000 +0900
@@ -0,0 +1,590 @@
+/*
+ * Copyright (C) 2004, OGAWA Hirofumi
+ * Released under GPL v2.
+ */
+
+#include <linux/fs.h>
+#include <linux/msdos_fs.h>
+
+struct fatent_operations {
+ void (*ent_blocknr)(struct super_block *, int, int *, sector_t *);
+ void (*ent_set_ptr)(struct fat_entry *, int);
+ int (*ent_bread)(struct super_block *, struct fat_entry *,
+ int, sector_t);
+ int (*ent_get)(struct fat_entry *);
+ void (*ent_put)(struct fat_entry *, int);
+ int (*ent_next)(struct fat_entry *);
+};
+
+static void fat12_ent_blocknr(struct super_block *sb, int entry,
+ int *offset, sector_t *blocknr)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ int bytes = entry + (entry >> 1);
+ *offset = bytes & (sb->s_blocksize - 1);
+ *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
+}
+
+static void fat_ent_blocknr(struct super_block *sb, int entry,
+ int *offset, sector_t *blocknr)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ int bytes = (entry << sbi->fatent_shift);
+ *offset = bytes & (sb->s_blocksize - 1);
+ *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
+}
+
+static void fat12_ent_set_ptr(struct fat_entry *fatent, int offset)
+{
+ struct buffer_head **bhs = fatent->bhs;
+ if (fatent->nr_bhs == 1) {
+ fatent->u.ent12_p[0] = bhs[0]->b_data + offset;
+ fatent->u.ent12_p[1] = bhs[0]->b_data + (offset + 1);
+ } else {
+ fatent->u.ent12_p[0] = bhs[0]->b_data + offset;
+ fatent->u.ent12_p[1] = bhs[1]->b_data;
+ }
+}
+
+static void fat16_ent_set_ptr(struct fat_entry *fatent, int offset)
+{
+ fatent->u.ent16_p = (__le16 *)(fatent->bhs[0]->b_data + offset);
+}
+
+static void fat32_ent_set_ptr(struct fat_entry *fatent, int offset)
+{
+ fatent->u.ent32_p = (__le32 *)(fatent->bhs[0]->b_data + offset);
+}
+
+static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent,
+ int offset, sector_t blocknr)
+{
+ struct buffer_head **bhs = fatent->bhs;
+
+ bhs[0] = sb_bread(sb, blocknr);
+ if (!bhs[0])
+ goto err;
+
+ if ((offset + 1) < sb->s_blocksize)
+ fatent->nr_bhs = 1;
+ else {
+ /* This entry is block boundary, it needs the next block */
+ blocknr++;
+ bhs[1] = sb_bread(sb, blocknr);
+ if (!bhs[1])
+ goto err_brelse;
+ fatent->nr_bhs = 2;
+ }
+ fat12_ent_set_ptr(fatent, offset);
+ return 0;
+
+err_brelse:
+ brelse(bhs[0]);
+err:
+ printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n",
+ (unsigned long long)blocknr);
+ return -EIO;
+}
+
+static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent,
+ int offset, sector_t blocknr)
+{
+ struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+
+ fatent->bhs[0] = sb_bread(sb, blocknr);
+ if (!fatent->bhs[0]) {
+ printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n",
+ (unsigned long long)blocknr);
+ return -EIO;
+ }
+ fatent->nr_bhs = 1;
+ ops->ent_set_ptr(fatent, offset);
+ return 0;
+}
+
+static int fat12_ent_get(struct fat_entry *fatent)
+{
+ u8 **ent12_p = fatent->u.ent12_p;
+ int next;
+
+ if (fatent->entry & 1)
+ next = (*ent12_p[0] >> 4) | (*ent12_p[1] << 4);
+ else
+ next = (*ent12_p[1] << 8) | *ent12_p[0];
+ next &= 0x0fff;
+ if (next >= BAD_FAT12)
+ next = FAT_ENT_EOF;
+ return next;
+}
+
+static int fat16_ent_get(struct fat_entry *fatent)
+{
+ int next = le16_to_cpu(*fatent->u.ent16_p);
+ if (next >= BAD_FAT16)
+ next = FAT_ENT_EOF;
+ return next;
+}
+
+static int fat32_ent_get(struct fat_entry *fatent)
+{
+ int next = le32_to_cpu(*fatent->u.ent32_p) & 0x0fffffff;
+ if (next >= BAD_FAT32)
+ next = FAT_ENT_EOF;
+ return next;
+}
+
+static void fat12_ent_put(struct fat_entry *fatent, int new)
+{
+ u8 **ent12_p = fatent->u.ent12_p;
+
+ if (new == FAT_ENT_EOF)
+ new = EOF_FAT12;
+
+ if (fatent->entry & 1) {
+ *ent12_p[0] = (new << 4) | (*ent12_p[0] & 0x0f);
+ *ent12_p[1] = new >> 4;
+ } else {
+ *ent12_p[0] = new & 0xff;
+ *ent12_p[1] = (*ent12_p[1] & 0xf0) | (new >> 8);
+ }
+
+ mark_buffer_dirty(fatent->bhs[0]);
+ if (fatent->nr_bhs == 2)
+ mark_buffer_dirty(fatent->bhs[1]);
+}
+
+static void fat16_ent_put(struct fat_entry *fatent, int new)
+{
+ if (new == FAT_ENT_EOF)
+ new = EOF_FAT16;
+
+ *fatent->u.ent16_p = cpu_to_le16(new);
+ mark_buffer_dirty(fatent->bhs[0]);
+}
+
+static void fat32_ent_put(struct fat_entry *fatent, int new)
+{
+ if (new == FAT_ENT_EOF)
+ new = EOF_FAT32;
+
+ new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff;
+ *fatent->u.ent32_p = cpu_to_le32(new);
+ mark_buffer_dirty(fatent->bhs[0]);
+}
+
+static int fat12_ent_next(struct fat_entry *fatent)
+{
+ u8 **ent12_p = fatent->u.ent12_p;
+ struct buffer_head **bhs = fatent->bhs;
+ u8 *nextp = ent12_p[1] + 1 + (fatent->entry & 1);
+
+ fatent->entry++;
+ if (fatent->nr_bhs == 1) {
+ if (nextp < (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))) {
+ ent12_p[0] = nextp - 1;
+ ent12_p[1] = nextp;
+ return 1;
+ }
+ } else {
+ ent12_p[0] = nextp - 1;
+ ent12_p[1] = nextp;
+ brelse(bhs[0]);
+ bhs[0] = bhs[1];
+ fatent->nr_bhs = 1;
+ return 1;
+ }
+ return 0;
+}
+
+static int fat16_ent_next(struct fat_entry *fatent)
+{
+ const struct buffer_head *bh = fatent->bhs[0];
+ fatent->entry++;
+ if (fatent->u.ent16_p < (__le16 *)(bh->b_data + (bh->b_size - 2))) {
+ fatent->u.ent16_p++;
+ return 1;
+ }
+ return 0;
+}
+
+static int fat32_ent_next(struct fat_entry *fatent)
+{
+ const struct buffer_head *bh = fatent->bhs[0];
+ fatent->entry++;
+ if (fatent->u.ent32_p < (__le32 *)(bh->b_data + (bh->b_size - 4))) {
+ fatent->u.ent32_p++;
+ return 1;
+ }
+ return 0;
+}
+
+static struct fatent_operations fat12_ops = {
+ .ent_blocknr = fat12_ent_blocknr,
+ .ent_set_ptr = fat12_ent_set_ptr,
+ .ent_bread = fat12_ent_bread,
+ .ent_get = fat12_ent_get,
+ .ent_put = fat12_ent_put,
+ .ent_next = fat12_ent_next,
+};
+
+static struct fatent_operations fat16_ops = {
+ .ent_blocknr = fat_ent_blocknr,
+ .ent_set_ptr = fat16_ent_set_ptr,
+ .ent_bread = fat_ent_bread,
+ .ent_get = fat16_ent_get,
+ .ent_put = fat16_ent_put,
+ .ent_next = fat16_ent_next,
+};
+
+static struct fatent_operations fat32_ops = {
+ .ent_blocknr = fat_ent_blocknr,
+ .ent_set_ptr = fat32_ent_set_ptr,
+ .ent_bread = fat_ent_bread,
+ .ent_get = fat32_ent_get,
+ .ent_put = fat32_ent_put,
+ .ent_next = fat32_ent_next,
+};
+
+static inline void lock_fat(struct msdos_sb_info *sbi)
+{
+ down(&sbi->fat_lock);
+}
+
+static inline void unlock_fat(struct msdos_sb_info *sbi)
+{
+ up(&sbi->fat_lock);
+}
+
+void fat_ent_access_init(struct super_block *sb)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+
+ init_MUTEX(&sbi->fat_lock);
+
+ switch (sbi->fat_bits) {
+ case 32:
+ sbi->fatent_shift = 2;
+ sbi->fatent_ops = &fat32_ops;
+ break;
+ case 16:
+ sbi->fatent_shift = 1;
+ sbi->fatent_ops = &fat16_ops;
+ break;
+ case 12:
+ sbi->fatent_shift = -1;
+ sbi->fatent_ops = &fat12_ops;
+ break;
+ }
+}
+
+static inline int fat_ent_update_ptr(struct super_block *sb,
+ struct fat_entry *fatent,
+ int offset, sector_t blocknr)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ struct fatent_operations *ops = sbi->fatent_ops;
+ struct buffer_head **bhs = fatent->bhs;
+
+ /* Is this fatent's blocks including this entry? */
+ if (!fatent->nr_bhs || bhs[0]->b_blocknr != blocknr)
+ return 0;
+ /* Does this entry need the next block? */
+ if (sbi->fat_bits == 12 && (offset + 1) >= sb->s_blocksize) {
+ if (fatent->nr_bhs != 2 || bhs[1]->b_blocknr != (blocknr + 1))
+ return 0;
+ }
+ ops->ent_set_ptr(fatent, offset);
+ return 1;
+}
+
+int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry)
+{
+ struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+ struct fatent_operations *ops = sbi->fatent_ops;
+ int err, offset;
+ sector_t blocknr;
+
+ if (entry < FAT_START_ENT || sbi->max_cluster <= entry) {
+ fatent_brelse(fatent);
+ fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", entry);
+ return -EIO;
+ }
+
+ fatent_set_entry(fatent, entry);
+ ops->ent_blocknr(sb, entry, &offset, &blocknr);
+
+ if (!fat_ent_update_ptr(sb, fatent, offset, blocknr)) {
+ fatent_brelse(fatent);
+ err = ops->ent_bread(sb, fatent, offset, blocknr);
+ if (err)
+ return err;
+ }
+ return ops->ent_get(fatent);
+}
+
+static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs,
+ int nr_bhs)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ struct buffer_head *c_bh;
+ int err, n, copy;
+
+ err = 0;
+ for (copy = 1; copy < sbi->fats; copy++) {
+ sector_t backup_fat = sbi->fat_length * copy;
+
+ for (n = 0; n < nr_bhs; n++) {
+ c_bh = sb_getblk(sb, backup_fat + bhs[n]->b_blocknr);
+ if (!c_bh) {
+ err = -ENOMEM;
+ goto error;
+ }
+ memcpy(c_bh->b_data, bhs[n]->b_data, sb->s_blocksize);
+ set_buffer_uptodate(c_bh);
+ mark_buffer_dirty(c_bh);
+ if (sb->s_flags & MS_SYNCHRONOUS)
+ err = sync_dirty_buffer(c_bh);
+ brelse(c_bh);
+ if (err)
+ goto error;
+ }
+ }
+error:
+ return err;
+}
+
+int fat_ent_write(struct inode *inode, struct fat_entry *fatent,
+ int new, int wait)
+{
+ struct super_block *sb = inode->i_sb;
+ struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+ int err;
+
+ ops->ent_put(fatent, new);
+ if (wait) {
+ err = fat_sync_bhs(fatent->bhs, fatent->nr_bhs);
+ if (err)
+ return err;
+ }
+ return fat_mirror_bhs(sb, fatent->bhs, fatent->nr_bhs);
+}
+
+static inline int fat_ent_next(struct msdos_sb_info *sbi,
+ struct fat_entry *fatent)
+{
+ if (sbi->fatent_ops->ent_next(fatent)) {
+ if (fatent->entry < sbi->max_cluster)
+ return 1;
+ }
+ return 0;
+}
+
+static inline int fat_ent_read_block(struct super_block *sb,
+ struct fat_entry *fatent)
+{
+ struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+ sector_t blocknr;
+ int offset;
+
+ fatent_brelse(fatent);
+ ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr);
+ return ops->ent_bread(sb, fatent, offset, blocknr);
+}
+
+static void fat_collect_bhs(struct buffer_head **bhs, int *nr_bhs,
+ struct fat_entry *fatent)
+{
+ int n, i;
+
+ for (n = 0; n < fatent->nr_bhs; n++) {
+ for (i = 0; i < *nr_bhs; i++) {
+ if (fatent->bhs[n] == bhs[i])
+ break;
+ }
+ if (i == *nr_bhs) {
+ get_bh(fatent->bhs[n]);
+ bhs[i] = fatent->bhs[n];
+ (*nr_bhs)++;
+ }
+ }
+}
+
+int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
+{
+ struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ struct fatent_operations *ops = sbi->fatent_ops;
+ struct fat_entry fatent, prev_ent;
+ struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+ int i, count, err, nr_bhs, idx_clus;
+
+ BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2)); /* fixed limit */
+
+ lock_fat(sbi);
+ if (sbi->free_clusters != -1 && sbi->free_clusters < nr_cluster) {
+ unlock_fat(sbi);
+ return -ENOSPC;
+ }
+
+ err = nr_bhs = idx_clus = 0;
+ count = FAT_START_ENT;
+ fatent_init(&prev_ent);
+ fatent_init(&fatent);
+ fatent_set_entry(&fatent, sbi->prev_free + 1);
+ while (count < sbi->max_cluster) {
+ fatent.entry %= sbi->max_cluster;
+ if (fatent.entry < FAT_START_ENT)
+ fatent.entry = FAT_START_ENT;
+ fatent_set_entry(&fatent, fatent.entry);
+ err = fat_ent_read_block(sb, &fatent);
+ if (err)
+ goto out;
+
+ /* Find the free entries in a block */
+ do {
+ if (ops->ent_get(&fatent) == FAT_ENT_FREE) {
+ int entry = fatent.entry;
+
+ /* make the cluster chain */
+ ops->ent_put(&fatent, FAT_ENT_EOF);
+ if (prev_ent.nr_bhs)
+ ops->ent_put(&prev_ent, entry);
+
+ fat_collect_bhs(bhs, &nr_bhs, &fatent);
+
+ sbi->prev_free = entry;
+ if (sbi->free_clusters != -1)
+ sbi->free_clusters--;
+
+ cluster[idx_clus] = entry;
+ idx_clus++;
+ if (idx_clus == nr_cluster)
+ goto out;
+
+ /*
+ * fat_collect_bhs() gets ref-count of bhs,
+ * so we can still use the prev_ent.
+ */
+ prev_ent = fatent;
+ }
+ count++;
+ if (count == sbi->max_cluster)
+ break;
+ } while (fat_ent_next(sbi, &fatent));
+ }
+
+ /* Couldn't allocate the free entries */
+ sbi->free_clusters = 0;
+ err = -ENOSPC;
+
+out:
+ unlock_fat(sbi);
+ fatent_brelse(&fatent);
+ if (!err) {
+ if (inode_needs_sync(inode))
+ err = fat_sync_bhs(bhs, nr_bhs);
+ if (!err)
+ err = fat_mirror_bhs(sb, bhs, nr_bhs);
+ }
+ for (i = 0; i < nr_bhs; i++)
+ brelse(bhs[i]);
+ fat_clusters_flush(sb);
+
+ if (err && idx_clus)
+ fat_free_clusters(inode, cluster[0]);
+
+ return err;
+}
+
+int fat_free_clusters(struct inode *inode, int cluster)
+{
+ struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ struct fatent_operations *ops = sbi->fatent_ops;
+ struct fat_entry fatent;
+ struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+ int i, err, nr_bhs;
+
+ nr_bhs = 0;
+ fatent_init(&fatent);
+ lock_fat(sbi);
+ do {
+ cluster = fat_ent_read(inode, &fatent, cluster);
+ if (cluster < 0) {
+ err = cluster;
+ goto error;
+ } else if (cluster == FAT_ENT_FREE) {
+ fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF",
+ __FUNCTION__);
+ err = -EIO;
+ goto error;
+ }
+
+ ops->ent_put(&fatent, FAT_ENT_FREE);
+ if (sbi->free_clusters != -1)
+ sbi->free_clusters++;
+
+ if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) {
+ if (sb->s_flags & MS_SYNCHRONOUS) {
+ err = fat_sync_bhs(bhs, nr_bhs);
+ if (err)
+ goto error;
+ }
+ err = fat_mirror_bhs(sb, bhs, nr_bhs);
+ if (err)
+ goto error;
+ for (i = 0; i < nr_bhs; i++)
+ brelse(bhs[i]);
+ nr_bhs = 0;
+ }
+ fat_collect_bhs(bhs, &nr_bhs, &fatent);
+ } while (cluster != FAT_ENT_EOF);
+
+ if (sb->s_flags & MS_SYNCHRONOUS) {
+ err = fat_sync_bhs(bhs, nr_bhs);
+ if (err)
+ goto error;
+ }
+ err = fat_mirror_bhs(sb, bhs, nr_bhs);
+error:
+ fatent_brelse(&fatent);
+ for (i = 0; i < nr_bhs; i++)
+ brelse(bhs[i]);
+ unlock_fat(sbi);
+
+ fat_clusters_flush(sb);
+
+ return err;
+}
+
+int fat_count_free_clusters(struct super_block *sb)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ struct fatent_operations *ops = sbi->fatent_ops;
+ struct fat_entry fatent;
+ int err = 0, free;
+
+ lock_fat(sbi);
+ if (sbi->free_clusters != -1)
+ goto out;
+
+ free = 0;
+ fatent_init(&fatent);
+ fatent_set_entry(&fatent, FAT_START_ENT);
+ while (fatent.entry < sbi->max_cluster) {
+ err = fat_ent_read_block(sb, &fatent);
+ if (err)
+ goto out;
+
+ do {
+ if (ops->ent_get(&fatent) == FAT_ENT_FREE)
+ free++;
+ } while (fat_ent_next(sbi, &fatent));
+ }
+ sbi->free_clusters = free;
+ fatent_brelse(&fatent);
+out:
+ unlock_fat(sbi);
+ return err;
+}
diff -puN fs/fat/file.c~sync05-fat_dep-fatent fs/fat/file.c
--- linux-2.6.11/fs/fat/file.c~sync05-fat_dep-fatent 2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/file.c 2005-03-06 02:36:12.000000000 +0900
@@ -212,62 +212,63 @@ EXPORT_SYMBOL(fat_notify_change);
static int fat_free(struct inode *inode, int skip)
{
struct super_block *sb = inode->i_sb;
- int nr, ret, fclus, dclus;
+ int ret, wait;
if (MSDOS_I(inode)->i_start == 0)
return 0;
+ /*
+ * Write a new EOF, and get the remaining cluster chain for freeing.
+ */
+ wait = IS_DIRSYNC(inode);
if (skip) {
+ struct fat_entry fatent;
+ int fclus, dclus;
+
ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus);
if (ret < 0)
return ret;
else if (ret == FAT_ENT_EOF)
return 0;
- nr = fat_access(sb, dclus, -1);
- if (nr == FAT_ENT_EOF)
+ fatent_init(&fatent);
+ ret = fat_ent_read(inode, &fatent, dclus);
+ if (ret == FAT_ENT_EOF) {
+ fatent_brelse(&fatent);
return 0;
- else if (nr > 0) {
- /*
- * write a new EOF, and get the remaining cluster
- * chain for freeing.
- */
- nr = fat_access(sb, dclus, FAT_ENT_EOF);
+ } else if (ret == FAT_ENT_FREE) {
+ fat_fs_panic(sb,
+ "%s: invalid cluster chain (i_pos %lld)",
+ __FUNCTION__, MSDOS_I(inode)->i_pos);
+ ret = -EIO;
+ } else if (ret > 0) {
+ int err = fat_ent_write(inode, &fatent, FAT_ENT_EOF,
+ wait);
+ if (err)
+ ret = err;
}
- if (nr < 0)
- return nr;
+ fatent_brelse(&fatent);
+ if (ret < 0)
+ return ret;
fat_cache_inval_inode(inode);
} else {
fat_cache_inval_inode(inode);
- nr = MSDOS_I(inode)->i_start;
+ ret = MSDOS_I(inode)->i_start;
MSDOS_I(inode)->i_start = 0;
MSDOS_I(inode)->i_logstart = 0;
- mark_inode_dirty(inode);
+ if (wait) {
+ int err = fat_sync_inode(inode);
+ if (err)
+ return err;
+ } else
+ mark_inode_dirty(inode);
}
+ inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);
- lock_fat(sb);
- do {
- nr = fat_access(sb, nr, FAT_ENT_FREE);
- if (nr < 0)
- goto error;
- else if (nr == FAT_ENT_FREE) {
- fat_fs_panic(sb, "%s: deleting beyond EOF (i_pos %lld)",
- __FUNCTION__, MSDOS_I(inode)->i_pos);
- nr = -EIO;
- goto error;
- }
- if (MSDOS_SB(sb)->free_clusters != -1)
- MSDOS_SB(sb)->free_clusters++;
- inode->i_blocks -= MSDOS_SB(sb)->cluster_size >> 9;
- } while (nr != FAT_ENT_EOF);
- fat_clusters_flush(sb);
- nr = 0;
-error:
- unlock_fat(sb);
-
- return nr;
+ /* Freeing the remained cluster chain */
+ return fat_free_clusters(inode, ret);
}
void fat_truncate(struct inode *inode)
diff -puN fs/fat/inode.c~sync05-fat_dep-fatent fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~sync05-fat_dep-fatent 2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c 2005-03-06 02:36:12.000000000 +0900
@@ -33,6 +33,21 @@ static int fat_default_codepage = CONFIG
static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET;
+static int fat_add_cluster(struct inode *inode)
+{
+ int err, cluster;
+
+ err = fat_alloc_clusters(inode, &cluster, 1);
+ if (err)
+ return err;
+ /* FIXME: this cluster should be added after data of this
+ * cluster is writed */
+ err = fat_chain_add(inode, cluster, 1);
+ if (err)
+ fat_free_clusters(inode, cluster);
+ return err;
+}
+
static int fat_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
@@ -55,11 +70,9 @@ static int fat_get_block(struct inode *i
return -EIO;
}
if (!((unsigned long)iblock & (MSDOS_SB(sb)->sec_per_clus - 1))) {
- int error;
-
- error = fat_add_cluster(inode);
- if (error < 0)
- return error;
+ err = fat_add_cluster(inode);
+ if (err)
+ return err;
}
MSDOS_I(inode)->mmu_private += sb->s_blocksize;
err = fat_bmap(inode, iblock, &phys);
@@ -423,34 +436,19 @@ static int fat_remount(struct super_bloc
static int fat_statfs(struct super_block *sb, struct kstatfs *buf)
{
struct msdos_sb_info *sbi = MSDOS_SB(sb);
- int free, nr, ret;
- if (sbi->free_clusters != -1)
- free = sbi->free_clusters;
- else {
- lock_fat(sb);
- if (sbi->free_clusters != -1)
- free = sbi->free_clusters;
- else {
- free = 0;
- for (nr = FAT_START_ENT; nr < sbi->max_cluster; nr++) {
- ret = fat_access(sb, nr, -1);
- if (ret < 0) {
- unlock_fat(sb);
- return ret;
- } else if (ret == FAT_ENT_FREE)
- free++;
- }
- sbi->free_clusters = free;
- }
- unlock_fat(sb);
+ /* If the count of free cluster is still unknown, counts it here. */
+ if (sbi->free_clusters == -1) {
+ int err = fat_count_free_clusters(sb);
+ if (err)
+ return err;
}
buf->f_type = sb->s_magic;
buf->f_bsize = sbi->cluster_size;
buf->f_blocks = sbi->max_cluster - FAT_START_ENT;
- buf->f_bfree = free;
- buf->f_bavail = free;
+ buf->f_bfree = sbi->free_clusters;
+ buf->f_bavail = sbi->free_clusters;
buf->f_namelen = sbi->options.isvfat ? 260 : 12;
return 0;
@@ -1076,10 +1074,6 @@ int fat_fill_super(struct super_block *s
if (error)
goto out_fail;
- /* set up enough so that it can read an inode */
- fat_hash_init(sb);
- init_MUTEX(&sbi->fat_lock);
-
error = -EIO;
sb_min_blocksize(sb, 512);
bh = sb_bread(sb, 0);
@@ -1256,6 +1250,10 @@ int fat_fill_super(struct super_block *s
brelse(bh);
+ /* set up enough so that it can read an inode */
+ fat_hash_init(sb);
+ fat_ent_access_init(sb);
+
/*
* The low byte of FAT's first entry must have same value with
* media-field. But in real world, too many devices is
diff -puN fs/fat/misc.c~sync05-fat_dep-fatent fs/fat/misc.c
--- linux-2.6.11/fs/fat/misc.c~sync05-fat_dep-fatent 2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/misc.c 2005-03-06 02:36:12.000000000 +0900
@@ -33,16 +33,6 @@ void fat_fs_panic(struct super_block *s,
}
}
-void lock_fat(struct super_block *sb)
-{
- down(&(MSDOS_SB(sb)->fat_lock));
-}
-
-void unlock_fat(struct super_block *sb)
-{
- up(&(MSDOS_SB(sb)->fat_lock));
-}
-
/* Flushes the number of free clusters on FAT32 */
/* XXX: Need to write one per FSINFO block. Currently only writes 1 */
void fat_clusters_flush(struct super_block *sb)
@@ -82,26 +72,22 @@ void fat_clusters_flush(struct super_blo
}
/*
- * fat_add_cluster tries to allocate a new cluster and adds it to the
- * file represented by inode.
+ * fat_chain_add() adds a new cluster to the chain of clusters represented
+ * by inode.
*/
-int fat_add_cluster(struct inode *inode)
+int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
{
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
- int ret, count, limit, new_dclus, new_fclus, last;
- int cluster_bits = sbi->cluster_bits;
+ int ret, new_fclus, last;
/*
* We must locate the last cluster of the file to add this new
* one (new_dclus) to the end of the link list (the FAT).
- *
- * In order to confirm that the cluster chain is valid, we
- * find out EOF first.
*/
last = new_fclus = 0;
if (MSDOS_I(inode)->i_start) {
- int ret, fclus, dclus;
+ int fclus, dclus;
ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus);
if (ret < 0)
@@ -110,66 +96,42 @@ int fat_add_cluster(struct inode *inode)
last = dclus;
}
- /* find free FAT entry */
- lock_fat(sb);
-
- if (sbi->free_clusters == 0) {
- unlock_fat(sb);
- return -ENOSPC;
- }
-
- limit = sbi->max_cluster;
- new_dclus = sbi->prev_free + 1;
- for (count = FAT_START_ENT; count < limit; count++, new_dclus++) {
- new_dclus = new_dclus % limit;
- if (new_dclus < FAT_START_ENT)
- new_dclus = FAT_START_ENT;
-
- ret = fat_access(sb, new_dclus, -1);
- if (ret < 0) {
- unlock_fat(sb);
- return ret;
- } else if (ret == FAT_ENT_FREE)
- break;
- }
- if (count >= limit) {
- sbi->free_clusters = 0;
- unlock_fat(sb);
- return -ENOSPC;
- }
-
- ret = fat_access(sb, new_dclus, FAT_ENT_EOF);
- if (ret < 0) {
- unlock_fat(sb);
- return ret;
- }
-
- sbi->prev_free = new_dclus;
- if (sbi->free_clusters != -1)
- sbi->free_clusters--;
- fat_clusters_flush(sb);
-
- unlock_fat(sb);
-
/* add new one to the last of the cluster chain */
if (last) {
- ret = fat_access(sb, last, new_dclus);
+ struct fat_entry fatent;
+
+ fatent_init(&fatent);
+ ret = fat_ent_read(inode, &fatent, last);
+ if (ret >= 0) {
+ int wait = inode_needs_sync(inode);
+ ret = fat_ent_write(inode, &fatent, new_dclus, wait);
+ fatent_brelse(&fatent);
+ }
if (ret < 0)
return ret;
// fat_cache_add(inode, new_fclus, new_dclus);
} else {
MSDOS_I(inode)->i_start = new_dclus;
MSDOS_I(inode)->i_logstart = new_dclus;
- mark_inode_dirty(inode);
+ /*
+ * Since generic_osync_inode() synchronize later if
+ * this is not directory, we don't here.
+ */
+ if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) {
+ ret = fat_sync_inode(inode);
+ if (ret)
+ return ret;
+ } else
+ mark_inode_dirty(inode);
}
- if (new_fclus != (inode->i_blocks >> (cluster_bits - 9))) {
+ if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) {
fat_fs_panic(sb, "clusters badly computed (%d != %lu)",
- new_fclus, inode->i_blocks >> (cluster_bits - 9));
+ new_fclus, inode->i_blocks >> (sbi->cluster_bits - 9));
fat_cache_inval_inode(inode);
}
- inode->i_blocks += sbi->cluster_size >> 9;
+ inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9);
- return new_dclus;
+ return 0;
}
extern struct timezone sys_tz;
@@ -281,3 +243,31 @@ next:
}
EXPORT_SYMBOL(fat__get_entry);
+
+int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
+{
+ int i, e, err = 0;
+
+ for (i = 0; i < nr_bhs; i++) {
+ lock_buffer(bhs[i]);
+ if (test_clear_buffer_dirty(bhs[i])) {
+ get_bh(bhs[i]);
+ bhs[i]->b_end_io = end_buffer_write_sync;
+ e = submit_bh(WRITE, bhs[i]);
+ if (!err && e)
+ err = e;
+ } else
+ unlock_buffer(bhs[i]);
+ }
+ for (i = 0; i < nr_bhs; i++) {
+ wait_on_buffer(bhs[i]);
+ if (buffer_eopnotsupp(bhs[i])) {
+ clear_buffer_eopnotsupp(bhs[i]);
+ err = -EOPNOTSUPP;
+ } else if (!err && !buffer_uptodate(bhs[i]))
+ err = -EIO;
+ }
+ return err;
+}
+
+EXPORT_SYMBOL(fat_sync_bhs);
diff -puN include/linux/msdos_fs.h~sync05-fat_dep-fatent include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync05-fat_dep-fatent 2005-03-06 02:36:12.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:12.000000000 +0900
@@ -76,15 +76,11 @@
#define BAD_FAT12 0xFF7
#define BAD_FAT16 0xFFF7
#define BAD_FAT32 0x0FFFFFF7
-#define BAD_FAT(s) (MSDOS_SB(s)->fat_bits == 32 ? BAD_FAT32 : \
- MSDOS_SB(s)->fat_bits == 16 ? BAD_FAT16 : BAD_FAT12)
/* standard EOF */
#define EOF_FAT12 0xFFF
#define EOF_FAT16 0xFFFF
#define EOF_FAT32 0x0FFFFFFF
-#define EOF_FAT(s) (MSDOS_SB(s)->fat_bits == 32 ? EOF_FAT32 : \
- MSDOS_SB(s)->fat_bits == 16 ? EOF_FAT16 : EOF_FAT12)
#define FAT_ENT_FREE (0)
#define FAT_ENT_BAD (BAD_FAT32)
@@ -238,6 +234,9 @@ struct msdos_sb_info {
int dir_per_block; /* dir entries per block */
int dir_per_block_bits; /* log2(dir_per_block) */
+ int fatent_shift;
+ struct fatent_operations *fatent_ops;
+
spinlock_t inode_hash_lock;
struct hlist_head inode_hashtable[FAT_HASH_SIZE];
};
@@ -315,7 +314,6 @@ static inline void fatwchar_to16(__u8 *d
/* fat/cache.c */
extern void fat_cache_inval_inode(struct inode *inode);
-extern int fat_access(struct super_block *sb, int nr, int new_value);
extern int fat_get_cluster(struct inode *inode, int cluster,
int *fclus, int *dclus);
extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys);
@@ -335,6 +333,46 @@ extern int fat_scan(struct inode *dir, c
struct buffer_head **res_bh,
struct msdos_dir_entry **res_de, loff_t *i_pos);
+/* fat/fatent.c */
+struct fat_entry {
+ int entry;
+ union {
+ u8 *ent12_p[2];
+ __le16 *ent16_p;
+ __le32 *ent32_p;
+ } u;
+ int nr_bhs;
+ struct buffer_head *bhs[2];
+};
+
+static inline void fatent_init(struct fat_entry *fatent)
+{
+ fatent->nr_bhs = 0;
+}
+
+static inline void fatent_set_entry(struct fat_entry *fatent, int entry)
+{
+ fatent->entry = entry;
+}
+
+static inline void fatent_brelse(struct fat_entry *fatent)
+{
+ int i;
+ for (i = 0; i < fatent->nr_bhs; i++)
+ brelse(fatent->bhs[i]);
+ fatent->nr_bhs = 0;
+}
+
+extern void fat_ent_access_init(struct super_block *sb);
+extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent,
+ int entry);
+extern int fat_ent_write(struct inode *inode, struct fat_entry *fatent,
+ int new, int wait);
+extern int fat_alloc_clusters(struct inode *inode, int *cluster,
+ int nr_cluster);
+extern int fat_free_clusters(struct inode *inode, int cluster);
+extern int fat_count_free_clusters(struct super_block *sb);
+
/* fat/file.c */
extern int fat_generic_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
@@ -350,15 +388,13 @@ extern struct inode *fat_iget(struct sup
extern struct inode *fat_build_inode(struct super_block *sb,
struct msdos_dir_entry *de, loff_t i_pos, int *res);
extern int fat_sync_inode(struct inode *inode);
-int fat_fill_super(struct super_block *sb, void *data, int silent,
- struct inode_operations *fs_dir_inode_ops, int isvfat);
+extern int fat_fill_super(struct super_block *sb, void *data, int silent,
+ struct inode_operations *fs_dir_inode_ops, int isvfat);
/* fat/misc.c */
extern void fat_fs_panic(struct super_block *s, const char *fmt, ...);
-extern void lock_fat(struct super_block *sb);
-extern void unlock_fat(struct super_block *sb);
extern void fat_clusters_flush(struct super_block *sb);
-extern int fat_add_cluster(struct inode *inode);
+extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
extern int date_dos2unix(unsigned short time, unsigned short date);
extern void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date);
extern int fat__get_entry(struct inode *dir, loff_t *pos,
@@ -378,6 +414,7 @@ static __inline__ int fat_get_entry(stru
}
return fat__get_entry(dir, pos, bh, de, i_pos);
}
+extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
#endif /* __KERNEL__ */
_
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/fatent.c | 20 ++++++++++++++++++++
include/linux/msdos_fs.h | 6 ++++++
2 files changed, 26 insertions(+)
diff -puN fs/fat/fatent.c~sync05-fat_dep-fatent-debug fs/fat/fatent.c
--- linux-2.6.11/fs/fat/fatent.c~sync05-fat_dep-fatent-debug 2005-03-06 02:36:16.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/fatent.c 2005-03-06 02:36:16.000000000 +0900
@@ -21,6 +21,7 @@ static void fat12_ent_blocknr(struct sup
{
struct msdos_sb_info *sbi = MSDOS_SB(sb);
int bytes = entry + (entry >> 1);
+ WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry);
*offset = bytes & (sb->s_blocksize - 1);
*blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
}
@@ -30,6 +31,7 @@ static void fat_ent_blocknr(struct super
{
struct msdos_sb_info *sbi = MSDOS_SB(sb);
int bytes = (entry << sbi->fatent_shift);
+ WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry);
*offset = bytes & (sb->s_blocksize - 1);
*blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
}
@@ -38,9 +40,11 @@ static void fat12_ent_set_ptr(struct fat
{
struct buffer_head **bhs = fatent->bhs;
if (fatent->nr_bhs == 1) {
+ WARN_ON(offset >= (bhs[0]->b_size - 1));
fatent->u.ent12_p[0] = bhs[0]->b_data + offset;
fatent->u.ent12_p[1] = bhs[0]->b_data + (offset + 1);
} else {
+ WARN_ON(offset != (bhs[0]->b_size - 1));
fatent->u.ent12_p[0] = bhs[0]->b_data + offset;
fatent->u.ent12_p[1] = bhs[1]->b_data;
}
@@ -48,11 +52,13 @@ static void fat12_ent_set_ptr(struct fat
static void fat16_ent_set_ptr(struct fat_entry *fatent, int offset)
{
+ WARN_ON(offset & (2 - 1));
fatent->u.ent16_p = (__le16 *)(fatent->bhs[0]->b_data + offset);
}
static void fat32_ent_set_ptr(struct fat_entry *fatent, int offset)
{
+ WARN_ON(offset & (4 - 1));
fatent->u.ent32_p = (__le32 *)(fatent->bhs[0]->b_data + offset);
}
@@ -61,6 +67,7 @@ static int fat12_ent_bread(struct super_
{
struct buffer_head **bhs = fatent->bhs;
+ WARN_ON(blocknr < MSDOS_SB(sb)->fat_start);
bhs[0] = sb_bread(sb, blocknr);
if (!bhs[0])
goto err;
@@ -91,6 +98,7 @@ static int fat_ent_bread(struct super_bl
{
struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+ WARN_ON(blocknr < MSDOS_SB(sb)->fat_start);
fatent->bhs[0] = sb_bread(sb, blocknr);
if (!fatent->bhs[0]) {
printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n",
@@ -120,6 +128,7 @@ static int fat12_ent_get(struct fat_entr
static int fat16_ent_get(struct fat_entry *fatent)
{
int next = le16_to_cpu(*fatent->u.ent16_p);
+ WARN_ON((unsigned long)fatent->u.ent16_p & (2 - 1));
if (next >= BAD_FAT16)
next = FAT_ENT_EOF;
return next;
@@ -128,6 +137,7 @@ static int fat16_ent_get(struct fat_entr
static int fat32_ent_get(struct fat_entry *fatent)
{
int next = le32_to_cpu(*fatent->u.ent32_p) & 0x0fffffff;
+ WARN_ON((unsigned long)fatent->u.ent32_p & (4 - 1));
if (next >= BAD_FAT32)
next = FAT_ENT_EOF;
return next;
@@ -167,6 +177,7 @@ static void fat32_ent_put(struct fat_ent
if (new == FAT_ENT_EOF)
new = EOF_FAT32;
+ WARN_ON(new & 0xf0000000);
new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff;
*fatent->u.ent32_p = cpu_to_le32(new);
mark_buffer_dirty(fatent->bhs[0]);
@@ -180,12 +191,16 @@ static int fat12_ent_next(struct fat_ent
fatent->entry++;
if (fatent->nr_bhs == 1) {
+ WARN_ON(ent12_p[0] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 2)));
+ WARN_ON(ent12_p[1] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1)));
if (nextp < (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))) {
ent12_p[0] = nextp - 1;
ent12_p[1] = nextp;
return 1;
}
} else {
+ WARN_ON(ent12_p[0] != (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1)));
+ WARN_ON(ent12_p[1] != (u8 *)bhs[1]->b_data);
ent12_p[0] = nextp - 1;
ent12_p[1] = nextp;
brelse(bhs[0]);
@@ -193,6 +208,8 @@ static int fat12_ent_next(struct fat_ent
fatent->nr_bhs = 1;
return 1;
}
+ ent12_p[0] = NULL;
+ ent12_p[1] = NULL;
return 0;
}
@@ -204,6 +221,7 @@ static int fat16_ent_next(struct fat_ent
fatent->u.ent16_p++;
return 1;
}
+ fatent->u.ent16_p = NULL;
return 0;
}
@@ -215,6 +233,7 @@ static int fat32_ent_next(struct fat_ent
fatent->u.ent32_p++;
return 1;
}
+ fatent->u.ent32_p = NULL;
return 0;
}
@@ -323,6 +342,7 @@ int fat_ent_read(struct inode *inode, st
return ops->ent_get(fatent);
}
+/* FIXME: We can write the blocks as more big chunk. */
static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs,
int nr_bhs)
{
diff -puN include/linux/msdos_fs.h~sync05-fat_dep-fatent-debug include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync05-fat_dep-fatent-debug 2005-03-06 02:36:16.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:16.000000000 +0900
@@ -348,19 +348,25 @@ struct fat_entry {
static inline void fatent_init(struct fat_entry *fatent)
{
fatent->nr_bhs = 0;
+ fatent->entry = 0;
+ fatent->u.ent32_p = NULL;
+ fatent->bhs[0] = fatent->bhs[1] = NULL;
}
static inline void fatent_set_entry(struct fat_entry *fatent, int entry)
{
fatent->entry = entry;
+ fatent->u.ent32_p = NULL;
}
static inline void fatent_brelse(struct fat_entry *fatent)
{
int i;
+ fatent->u.ent32_p = NULL;
for (i = 0; i < fatent->nr_bhs; i++)
brelse(fatent->bhs[i]);
fatent->nr_bhs = 0;
+ fatent->bhs[0] = fatent->bhs[1] = NULL;
}
extern void fat_ent_access_init(struct super_block *sb);
_
Adds MS_SYNCHRONOUS flag support.
Signed-off-by: Colin Leroy <[email protected]>
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/cache.c | 8 ++++++++
fs/fat/dir.c | 26 +++++++++++++++++---------
fs/fat/file.c | 5 +++++
fs/fat/inode.c | 10 ++++++++++
fs/fat/misc.c | 2 ++
fs/vfat/namei.c | 31 ++++++++++++++++++++++++-------
include/linux/msdos_fs.h | 1 +
7 files changed, 67 insertions(+), 16 deletions(-)
diff -puN fs/fat/cache.c~sync03-fat_sync00 fs/fat/cache.c
--- linux-2.6.11/fs/fat/cache.c~sync03-fat_sync00 2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/cache.c 2005-03-06 02:36:08.000000000 +0900
@@ -269,8 +269,12 @@ static int __fat_access(struct super_blo
*p_last = (*p_last & 0xf0) | (new_value >> 8);
}
mark_buffer_dirty(bh2);
+ if (sb->s_flags & MS_SYNCHRONOUS)
+ sync_dirty_buffer(bh2);
}
mark_buffer_dirty(bh);
+ if (sb->s_flags & MS_SYNCHRONOUS)
+ sync_dirty_buffer(bh);
for (copy = 1; copy < sbi->fats; copy++) {
b = sbi->fat_start + (first >> sb->s_blocksize_bits)
+ sbi->fat_length * copy;
@@ -283,10 +287,14 @@ static int __fat_access(struct super_blo
}
memcpy(c_bh2->b_data, bh2->b_data, sb->s_blocksize);
mark_buffer_dirty(c_bh2);
+ if (sb->s_flags & MS_SYNCHRONOUS)
+ sync_dirty_buffer(c_bh2);
brelse(c_bh2);
}
memcpy(c_bh->b_data, bh->b_data, sb->s_blocksize);
mark_buffer_dirty(c_bh);
+ if (sb->s_flags & MS_SYNCHRONOUS)
+ sync_dirty_buffer(c_bh);
brelse(c_bh);
}
}
diff -puN fs/fat/dir.c~sync03-fat_sync00 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync03-fat_sync00 2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:36:08.000000000 +0900
@@ -778,6 +778,8 @@ static struct buffer_head *fat_extend_di
memset(bh->b_data, 0, sb->s_blocksize);
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
+ if (sb->s_flags & MS_SYNCHRONOUS)
+ sync_dirty_buffer(bh);
if (!res)
res = bh;
else
@@ -842,6 +844,7 @@ EXPORT_SYMBOL(fat_add_entries);
int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
{
+ struct super_block *sb = dir->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *de;
__le16 date, time;
@@ -851,26 +854,31 @@ int fat_new_dir(struct inode *dir, struc
return PTR_ERR(bh);
/* zeroed out, so... */
- fat_date_unix2dos(dir->i_mtime.tv_sec,&time,&date);
- de = (struct msdos_dir_entry*)&bh->b_data[0];
- memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
- memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
+ fat_date_unix2dos(dir->i_mtime.tv_sec, &time, &date);
+ de = (struct msdos_dir_entry *)bh->b_data;
+ memcpy(de[0].name, MSDOS_DOT, MSDOS_NAME);
+ memcpy(de[1].name, MSDOS_DOTDOT, MSDOS_NAME);
de[0].attr = de[1].attr = ATTR_DIR;
de[0].time = de[1].time = time;
de[0].date = de[1].date = date;
- if (is_vfat) { /* extra timestamps */
+ if (is_vfat) {
+ /* extra timestamps */
de[0].ctime = de[1].ctime = time;
- de[0].adate = de[0].cdate =
- de[1].adate = de[1].cdate = date;
+ de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date;
}
de[0].start = cpu_to_le16(MSDOS_I(dir)->i_logstart);
- de[0].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart>>16);
+ de[0].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart >> 16);
de[1].start = cpu_to_le16(MSDOS_I(parent)->i_logstart);
- de[1].starthi = cpu_to_le16(MSDOS_I(parent)->i_logstart>>16);
+ de[1].starthi = cpu_to_le16(MSDOS_I(parent)->i_logstart >> 16);
mark_buffer_dirty(bh);
+ if (sb->s_flags & MS_SYNCHRONOUS)
+ sync_dirty_buffer(bh);
brelse(bh);
+
dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(dir);
+ if (IS_SYNC(dir))
+ fat_sync_inode(dir);
return 0;
}
diff -puN fs/fat/file.c~sync03-fat_sync00 fs/fat/file.c
--- linux-2.6.11/fs/fat/file.c~sync03-fat_sync00 2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/file.c 2005-03-06 02:36:08.000000000 +0900
@@ -23,6 +23,9 @@ static ssize_t fat_file_aio_write(struct
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
mark_inode_dirty(inode);
+// check the locking rules
+// if (IS_SYNC(inode))
+// fat_sync_inode(inode);
}
return retval;
}
@@ -288,6 +291,8 @@ void fat_truncate(struct inode *inode)
unlock_kernel();
inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
+ if (IS_SYNC(inode))
+ fat_sync_inode(inode);
}
struct inode_operations fat_file_inode_operations = {
diff -puN fs/fat/inode.c~sync03-fat_sync00 fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~sync03-fat_sync00 2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c 2005-03-06 02:36:08.000000000 +0900
@@ -501,11 +501,21 @@ retry:
}
spin_unlock(&sbi->inode_hash_lock);
mark_buffer_dirty(bh);
+ if (wait)
+ sync_dirty_buffer(bh);
brelse(bh);
unlock_kernel();
+
return 0;
}
+int fat_sync_inode(struct inode *inode)
+{
+ return fat_write_inode(inode, 1);
+}
+
+EXPORT_SYMBOL(fat_sync_inode);
+
static int fat_show_options(struct seq_file *m, struct vfsmount *mnt);
static struct super_operations fat_sops = {
.alloc_inode = fat_alloc_inode,
diff -puN fs/fat/misc.c~sync03-fat_sync00 fs/fat/misc.c
--- linux-2.6.11/fs/fat/misc.c~sync03-fat_sync00 2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/misc.c 2005-03-06 02:36:08.000000000 +0900
@@ -75,6 +75,8 @@ void fat_clusters_flush(struct super_blo
if (sbi->prev_free != -1)
fsinfo->next_cluster = cpu_to_le32(sbi->prev_free);
mark_buffer_dirty(bh);
+ if (sb->s_flags & MS_SYNCHRONOUS)
+ sync_dirty_buffer(bh);
}
brelse(bh);
}
diff -puN fs/vfat/namei.c~sync03-fat_sync00 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync03-fat_sync00 2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:36:08.000000000 +0900
@@ -663,6 +663,7 @@ static int vfat_add_entry(struct inode *
int is_dir, struct vfat_slot_info *sinfo_out,
struct buffer_head **bh, struct msdos_dir_entry **de)
{
+ struct super_block *sb = dir->i_sb;
struct msdos_dir_slot *dir_slots;
loff_t offset;
int res, slots, slot;
@@ -702,6 +703,8 @@ static int vfat_add_entry(struct inode *
}
memcpy(*de, dir_slots + slot, sizeof(struct msdos_dir_slot));
mark_buffer_dirty(*bh);
+ if (sb->s_flags & MS_SYNCHRONOUS)
+ sync_dirty_buffer(*bh);
}
res = 0;
@@ -713,8 +716,9 @@ static int vfat_add_entry(struct inode *
dir->i_mtime.tv_nsec = 0;
(*de)->ctime = (*de)->time;
(*de)->adate = (*de)->cdate = (*de)->date;
-
mark_buffer_dirty(*bh);
+ if (sb->s_flags & MS_SYNCHRONOUS)
+ sync_dirty_buffer(*bh);
/* slots can't be less than 1 */
sinfo_out->long_slots = slots - 1;
@@ -820,9 +824,12 @@ static int vfat_create(struct inode *dir
if (!inode)
goto out;
res = 0;
+ inode->i_version++;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
- inode->i_version++;
+ if (IS_SYNC(inode))
+ fat_sync_inode(inode);
+
dir->i_version++;
dentry->d_time = dentry->d_parent->d_inode->i_version;
d_instantiate(dentry, inode);
@@ -835,15 +842,20 @@ static void vfat_remove_entry(struct ino
struct buffer_head *bh,
struct msdos_dir_entry *de)
{
+ struct super_block *sb = dir->i_sb;
loff_t offset, i_pos;
int i;
- /* remove the shortname */
dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
dir->i_version++;
mark_inode_dirty(dir);
+
+ /* remove the shortname */
de->name[0] = DELETED_FLAG;
mark_buffer_dirty(bh);
+ if (sb->s_flags & MS_SYNCHRONOUS)
+ sync_dirty_buffer(bh);
+
/* remove the longname */
offset = sinfo->longname_offset;
de = NULL;
@@ -853,6 +865,8 @@ static void vfat_remove_entry(struct ino
de->name[0] = DELETED_FLAG;
de->attr = ATTR_NONE;
mark_buffer_dirty(bh);
+ if (sb->s_flags & MS_SYNCHRONOUS)
+ sync_dirty_buffer(bh);
}
brelse(bh);
}
@@ -879,7 +893,7 @@ static int vfat_rmdir(struct inode *dir,
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
- /* releases bh */
+ /* releases bh and syncs it if necessary */
vfat_remove_entry(dir, &sinfo, bh, de);
dir->i_nlink--;
out:
@@ -903,7 +917,7 @@ static int vfat_unlink(struct inode *dir
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
- /* releases bh */
+ /* releases bh and syncs it if necessary */
vfat_remove_entry(dir, &sinfo, bh, de);
out:
unlock_kernel();
@@ -949,7 +963,7 @@ mkdir_failed:
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
- /* releases bh */
+ /* releases bh ands syncs if necessary */
vfat_remove_entry(dir, &sinfo, bh, de);
iput(inode);
dir->i_nlink--;
@@ -1027,8 +1041,11 @@ static int vfat_rename(struct inode *old
if (is_dir) {
int start = MSDOS_I(new_dir)->i_logstart;
dotdot_de->start = cpu_to_le16(start);
- dotdot_de->starthi = cpu_to_le16(start>>16);
+ dotdot_de->starthi = cpu_to_le16(start >> 16);
mark_buffer_dirty(dotdot_bh);
+ if (new_dir->i_sb->s_flags & MS_SYNCHRONOUS)
+ sync_dirty_buffer(dotdot_bh);
+
old_dir->i_nlink--;
if (new_inode) {
new_inode->i_nlink--;
diff -puN include/linux/msdos_fs.h~sync03-fat_sync00 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync03-fat_sync00 2005-03-06 02:36:08.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:08.000000000 +0900
@@ -349,6 +349,7 @@ extern void fat_detach(struct inode *ino
extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos);
extern struct inode *fat_build_inode(struct super_block *sb,
struct msdos_dir_entry *de, loff_t i_pos, int *res);
+extern int fat_sync_inode(struct inode *inode);
int fat_fill_super(struct super_block *sb, void *data, int silent,
struct inode_operations *fs_dir_inode_ops, int isvfat);
_
Since MSDOS_SB() is inline function, it increases text size at each calls.
I don't know whether there is __attribute__ for avoiding this.
This removes the multiple call.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/dir.c | 30 ++++++++++++++++--------------
fs/vfat/namei.c | 8 ++++----
2 files changed, 20 insertions(+), 18 deletions(-)
diff -puN fs/fat/dir.c~sync08-fat_tweak3 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync08-fat_tweak3 2005-03-06 02:37:18.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:37:18.000000000 +0900
@@ -205,18 +205,19 @@ int fat_search_long(struct inode *inode,
int name_len, struct fat_slot_info *sinfo)
{
struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
struct buffer_head *bh = NULL;
struct msdos_dir_entry *de;
- struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
- struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
+ struct nls_table *nls_io = sbi->nls_io;
+ struct nls_table *nls_disk = sbi->nls_disk;
wchar_t bufuname[14];
unsigned char xlate_len, nr_slots;
wchar_t *unicode = NULL;
unsigned char work[8], bufname[260]; /* 256 + 4 */
- int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
- int utf8 = MSDOS_SB(sb)->options.utf8;
- int anycase = (MSDOS_SB(sb)->options.name_check != 's');
- unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
+ int uni_xlate = sbi->options.unicode_xlate;
+ int utf8 = sbi->options.utf8;
+ int anycase = (sbi->options.name_check != 's');
+ unsigned short opt_shortname = sbi->options.shortname;
loff_t cpos = 0;
int chl, i, j, last_u, err;
@@ -386,10 +387,11 @@ static int fat_readdirx(struct inode *in
filldir_t filldir, int short_only, int both)
{
struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
struct buffer_head *bh;
struct msdos_dir_entry *de;
- struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
- struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
+ struct nls_table *nls_io = sbi->nls_io;
+ struct nls_table *nls_disk = sbi->nls_disk;
unsigned char long_slots;
const char *fill_name;
int fill_len;
@@ -397,11 +399,11 @@ static int fat_readdirx(struct inode *in
wchar_t *unicode = NULL;
unsigned char c, work[8], bufname[56], *ptname = bufname;
unsigned long lpos, dummy, *furrfu = &lpos;
- int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
- int isvfat = MSDOS_SB(sb)->options.isvfat;
- int utf8 = MSDOS_SB(sb)->options.utf8;
- int nocase = MSDOS_SB(sb)->options.nocase;
- unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
+ int uni_xlate = sbi->options.unicode_xlate;
+ int isvfat = sbi->options.isvfat;
+ int utf8 = sbi->options.utf8;
+ int nocase = sbi->options.nocase;
+ unsigned short opt_shortname = sbi->options.shortname;
unsigned long inum;
int chi, chl, i, i2, j, last, last_u, dotoffset = 0;
loff_t cpos;
@@ -513,7 +515,7 @@ ParseLong:
long_slots = 0;
}
- if (MSDOS_SB(sb)->options.dotsOK) {
+ if (sbi->options.dotsOK) {
ptname = bufname;
dotoffset = 0;
if (de->attr & ATTR_HIDDEN) {
diff -puN fs/vfat/namei.c~sync08-fat_tweak3 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync08-fat_tweak3 2005-03-06 02:37:18.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:37:18.000000000 +0900
@@ -301,6 +301,7 @@ static int vfat_create_shortname(struct
wchar_t *uname, int ulen,
unsigned char *name_res, unsigned char *lcase)
{
+ struct fat_mount_options *opts = &MSDOS_SB(dir->i_sb)->options;
wchar_t *ip, *ext_start, *end, *name_start;
unsigned char base[9], ext[4], buf[8], *p;
unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
@@ -308,7 +309,6 @@ static int vfat_create_shortname(struct
int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen;
int is_shortname;
struct shortname_info base_info, ext_info;
- unsigned short opt_shortname = MSDOS_SB(dir->i_sb)->options.shortname;
is_shortname = 1;
INIT_SHORTNAME_INFO(&base_info);
@@ -421,9 +421,9 @@ static int vfat_create_shortname(struct
if (vfat_find_form(dir, name_res) == 0)
return -EEXIST;
- if (opt_shortname & VFAT_SFN_CREATE_WIN95) {
+ if (opts->shortname & VFAT_SFN_CREATE_WIN95) {
return (base_info.upper && ext_info.upper);
- } else if (opt_shortname & VFAT_SFN_CREATE_WINNT) {
+ } else if (opts->shortname & VFAT_SFN_CREATE_WINNT) {
if ((base_info.upper || base_info.lower) &&
(ext_info.upper || ext_info.lower)) {
if (!base_info.upper && base_info.lower)
@@ -438,7 +438,7 @@ static int vfat_create_shortname(struct
}
}
- if (MSDOS_SB(dir->i_sb)->options.numtail == 0)
+ if (opts->numtail == 0)
if (vfat_find_form(dir, name_res) < 0)
return 0;
_
Some mark_inode_dirty() is unneeded. Those are already detached (it's
not written) or change a ->i_nlink count only (fatfs don't have).
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/msdos/namei.c | 11 +++--------
fs/vfat/namei.c | 10 +++-------
2 files changed, 6 insertions(+), 15 deletions(-)
diff -puN fs/msdos/namei.c~sync08-fat_tweak4 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync08-fat_tweak4 2005-03-06 02:37:21.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c 2005-03-06 02:37:21.000000000 +0900
@@ -354,7 +354,6 @@ static int msdos_rmdir(struct inode *dir
inode->i_nlink = 0;
inode->i_ctime = CURRENT_TIME_SEC;
fat_detach(inode);
- mark_inode_dirty(inode);
out:
unlock_kernel();
@@ -403,7 +402,7 @@ static int msdos_mkdir(struct inode *dir
/* the directory was completed, just return a error */
goto out;
}
- inode->i_nlink = 2; /* no need to mark them dirty */
+ inode->i_nlink = 2;
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
@@ -437,7 +436,6 @@ static int msdos_unlink(struct inode *di
inode->i_nlink = 0;
inode->i_ctime = CURRENT_TIME_SEC;
fat_detach(inode);
- mark_inode_dirty(inode);
out:
unlock_kernel();
@@ -544,7 +542,6 @@ static int do_msdos_rename(struct inode
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_ctime = ts;
- mark_inode_dirty(new_inode);
}
if (is_dir) {
int start = MSDOS_I(new_dir)->i_logstart;
@@ -552,12 +549,10 @@ static int do_msdos_rename(struct inode
dotdot_de->starthi = cpu_to_le16(start >> 16);
mark_buffer_dirty(dotdot_bh);
- if (new_inode) {
+ if (new_inode)
new_inode->i_nlink--;
- } else {
+ else
new_dir->i_nlink++;
- mark_inode_dirty(new_dir);
- }
}
out:
brelse(dotdot_bh);
diff -puN fs/vfat/namei.c~sync08-fat_tweak4 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync08-fat_tweak4 2005-03-06 02:37:21.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:37:21.000000000 +0900
@@ -803,7 +803,6 @@ static int vfat_rmdir(struct inode *dir,
inode->i_nlink = 0;
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
- mark_inode_dirty(inode);
out:
unlock_kernel();
@@ -828,7 +827,6 @@ static int vfat_unlink(struct inode *dir
inode->i_nlink = 0;
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
- mark_inode_dirty(inode);
out:
unlock_kernel();
@@ -865,7 +863,7 @@ static int vfat_mkdir(struct inode *dir,
goto out;
}
inode->i_version++;
- inode->i_nlink = 2; /* no need to mark them dirty */
+ inode->i_nlink = 2;
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
@@ -964,12 +962,10 @@ static int vfat_rename(struct inode *old
if (new_dir->i_sb->s_flags & MS_SYNCHRONOUS)
sync_dirty_buffer(dotdot_bh);
- if (new_inode) {
+ if (new_inode)
new_inode->i_nlink--;
- } else {
+ else
new_dir->i_nlink++;
- mark_inode_dirty(new_dir);
- }
}
out:
brelse(dotdot_bh);
_
This changes the fat_slot_info->nr_slot, now it's total counts which
include a shortname entry. And this adds a fat_remove_entries()
which use the ->nr_slots.
In order not to write out the same block repeatedly,
fat_remove_entries() was rewritten from vfat_remove_entries().
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/dir.c | 103 +++++++++++++++++++++++++++++++++++++++++++----
fs/vfat/namei.c | 81 ++++++++++++------------------------
include/linux/msdos_fs.h | 1
3 files changed, 124 insertions(+), 61 deletions(-)
diff -puN fs/fat/dir.c~sync06-fat_dir-cleanup3 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync06-fat_dir-cleanup3 2005-03-06 02:36:28.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:36:29.000000000 +0900
@@ -144,7 +144,7 @@ int fat_search_long(struct inode *inode,
struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
wchar_t bufuname[14];
- unsigned char xlate_len, long_slots;
+ unsigned char xlate_len, nr_slots;
wchar_t *unicode = NULL;
unsigned char work[8], bufname[260]; /* 256 + 4 */
int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
@@ -159,7 +159,7 @@ int fat_search_long(struct inode *inode,
if (fat_get_entry(inode, &cpos, &bh, &de, &i_pos) == -1)
goto EODir;
parse_record:
- long_slots = 0;
+ nr_slots = 0;
if (de->name[0] == DELETED_FLAG)
continue;
if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
@@ -191,7 +191,7 @@ parse_long:
slots = id & ~0x40;
if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
continue;
- long_slots = slots;
+ nr_slots = slots;
alias_checksum = ds->alias_checksum;
slot = slots;
@@ -228,7 +228,7 @@ parse_long:
for (sum = 0, i = 0; i < 11; i++)
sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
if (sum != alias_checksum)
- long_slots = 0;
+ nr_slots = 0;
}
memcpy(work, de->name, sizeof(de->name));
@@ -276,7 +276,7 @@ parse_long:
xlate_len)))
goto Found;
- if (long_slots) {
+ if (nr_slots) {
xlate_len = utf8
?utf8_wcstombs(bufname, unicode, sizeof(bufname))
:uni16_to_x8(bufname, unicode, uni_xlate, nls_io);
@@ -290,9 +290,10 @@ parse_long:
}
Found:
+ nr_slots++; /* include the de */
sinfo->i_pos = i_pos;
- sinfo->slot_off = cpos - (long_slots + 1) * sizeof(*de);
- sinfo->nr_slots = long_slots;
+ sinfo->slot_off = cpos - nr_slots * sizeof(*de);
+ sinfo->nr_slots = nr_slots;
sinfo->de = de;
sinfo->bh = bh;
err = 0;
@@ -759,6 +760,94 @@ int fat_scan(struct inode *dir, const un
EXPORT_SYMBOL(fat_scan);
+static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots)
+{
+ struct super_block *sb = dir->i_sb;
+ struct buffer_head *bh;
+ struct msdos_dir_entry *de, *endp;
+ loff_t i_pos;
+ int err = 0, orig_slots;
+
+ while (nr_slots) {
+ bh = NULL;
+ if (fat_get_entry(dir, &pos, &bh, &de, &i_pos) < 0) {
+ err = -EIO;
+ break;
+ }
+
+ orig_slots = nr_slots;
+ endp = (struct msdos_dir_entry *)(bh->b_data + sb->s_blocksize);
+ while (nr_slots && de < endp) {
+ de->name[0] = DELETED_FLAG;
+ de++;
+ nr_slots--;
+ }
+ mark_buffer_dirty(bh);
+ if (IS_DIRSYNC(dir))
+ err = sync_dirty_buffer(bh);
+ brelse(bh);
+ if (err)
+ break;
+
+ /* pos is *next* de's position, so this does `- sizeof(de)' */
+ pos += ((orig_slots - nr_slots) * sizeof(*de)) - sizeof(*de);
+ }
+
+ return err;
+}
+
+int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo)
+{
+ struct msdos_dir_entry *de;
+ struct buffer_head *bh;
+ int err = 0, nr_slots;
+
+ /*
+ * First stage: Remove the shortname. By this, the directory
+ * entry is removed.
+ */
+ nr_slots = sinfo->nr_slots;
+ de = sinfo->de;
+ sinfo->de = NULL;
+ bh = sinfo->bh;
+ sinfo->bh = NULL;
+ while (nr_slots && de >= (struct msdos_dir_entry *)bh->b_data) {
+ de->name[0] = DELETED_FLAG;
+ de--;
+ nr_slots--;
+ }
+ mark_buffer_dirty(bh);
+ if (IS_DIRSYNC(dir))
+ err = sync_dirty_buffer(bh);
+ brelse(bh);
+ if (err)
+ return err;
+ dir->i_version++;
+
+ if (nr_slots) {
+ /*
+ * Second stage: remove the remaining longname slots.
+ * (This directory entry is already removed, and so return
+ * the success)
+ */
+ err = __fat_remove_entries(dir, sinfo->slot_off, nr_slots);
+ if (err) {
+ printk(KERN_WARNING
+ "FAT: Couldn't remove the long name slots\n");
+ }
+ }
+
+ dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
+ if (IS_DIRSYNC(dir))
+ (void)fat_sync_inode(dir);
+ else
+ mark_inode_dirty(dir);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(fat_remove_entries);
+
static struct buffer_head *fat_extend_dir(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup3 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync06-fat_dir-cleanup3 2005-03-06 02:36:28.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:36:29.000000000 +0900
@@ -721,7 +721,7 @@ static int vfat_add_entry(struct inode *
/* slots can't be less than 1 */
sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * slots;
- sinfo->nr_slots = slots - 1;
+ sinfo->nr_slots = slots;
sinfo->de = de;
sinfo->bh = bh;
@@ -817,39 +817,6 @@ out:
return res;
}
-static void vfat_remove_entry(struct inode *dir, struct fat_slot_info *sinfo)
-{
- struct super_block *sb = dir->i_sb;
- struct msdos_dir_entry *de = sinfo->de;
- struct buffer_head *bh = sinfo->bh;
- loff_t offset, i_pos;
- int i;
-
- dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
- dir->i_version++;
- mark_inode_dirty(dir);
-
- /* remove the shortname */
- de->name[0] = DELETED_FLAG;
- mark_buffer_dirty(bh);
- if (sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(bh);
-
- /* remove the longname */
- offset = sinfo->slot_off;
- de = NULL;
- for (i = sinfo->nr_slots; i > 0; --i) {
- if (fat_get_entry(dir, &offset, &bh, &de, &i_pos) < 0)
- continue;
- de->name[0] = DELETED_FLAG;
- de->attr = ATTR_NONE;
- mark_buffer_dirty(bh);
- if (sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(bh);
- }
- brelse(bh);
-}
-
static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
@@ -865,14 +832,15 @@ static int vfat_rmdir(struct inode *dir,
if (err)
goto out;
+ err = fat_remove_entries(dir, &sinfo); /* and releases bh */
+ if (err)
+ goto out;
+ dir->i_nlink--;
+
inode->i_nlink = 0;
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
- /* releases bh and syncs it if necessary */
- vfat_remove_entry(dir, &sinfo);
-
- dir->i_nlink--;
out:
unlock_kernel();
@@ -891,12 +859,13 @@ static int vfat_unlink(struct inode *dir
if (err)
goto out;
+ err = fat_remove_entries(dir, &sinfo); /* and releases bh */
+ if (err)
+ goto out;
inode->i_nlink = 0;
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
- /* releases bh and syncs it if necessary */
- vfat_remove_entry(dir, &sinfo);
out:
unlock_kernel();
@@ -939,8 +908,7 @@ mkdir_failed:
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
- /* releases bh ands syncs if necessary */
- vfat_remove_entry(dir, &sinfo);
+ fat_remove_entries(dir, &sinfo); /* and releases bh */
iput(inode);
dir->i_nlink--;
goto out;
@@ -956,49 +924,56 @@ static int vfat_rename(struct inode *old
int err, is_dir;
struct fat_slot_info old_sinfo, sinfo;
- old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
+ old_sinfo.bh = dotdot_bh = NULL;
old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode;
lock_kernel();
err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
if (err)
- goto rename_done;
+ goto out;
is_dir = S_ISDIR(old_inode->i_mode);
if (is_dir) {
if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
&dotdot_de, &dotdot_i_pos) < 0) {
err = -EIO;
- goto rename_done;
+ goto out;
}
}
if (new_dentry->d_inode) {
err = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
- if (err || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
+ if (err)
+ goto out;
+ brelse(sinfo.bh);
+ if (MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
/* WTF??? Cry and fail. */
printk(KERN_WARNING "vfat_rename: fs corrupted\n");
- goto rename_done;
+ goto out;
}
if (is_dir) {
err = fat_dir_empty(new_inode);
if (err)
- goto rename_done;
+ goto out;
}
fat_detach(new_inode);
} else {
err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
&sinfo);
if (err)
- goto rename_done;
+ goto out;
+ brelse(sinfo.bh);
}
-
new_dir->i_version++;
/* releases old_bh */
- vfat_remove_entry(old_dir, &old_sinfo);
+ err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
old_sinfo.bh = NULL;
+ if (err)
+ goto out;
+ if (is_dir)
+ old_dir->i_nlink--;
fat_detach(old_inode);
fat_attach(old_inode, sinfo.i_pos);
mark_inode_dirty(old_inode);
@@ -1019,7 +994,6 @@ static int vfat_rename(struct inode *old
if (new_dir->i_sb->s_flags & MS_SYNCHRONOUS)
sync_dirty_buffer(dotdot_bh);
- old_dir->i_nlink--;
if (new_inode) {
new_inode->i_nlink--;
} else {
@@ -1027,10 +1001,9 @@ static int vfat_rename(struct inode *old
mark_inode_dirty(new_dir);
}
}
-rename_done:
+out:
brelse(dotdot_bh);
brelse(old_sinfo.bh);
- brelse(sinfo.bh);
unlock_kernel();
return err;
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup3 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync06-fat_dir-cleanup3 2005-03-06 02:36:28.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:29.000000000 +0900
@@ -333,6 +333,7 @@ extern int fat_subdirs(struct inode *dir
extern int fat_scan(struct inode *dir, const unsigned char *name,
struct buffer_head **res_bh,
struct msdos_dir_entry **res_de, loff_t *i_pos);
+extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
/* fat/fatent.c */
struct fat_entry {
_
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/dir.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++
fs/fat/misc.c | 50 -------------------------------------
include/linux/msdos_fs.h | 17 ------------
3 files changed, 63 insertions(+), 67 deletions(-)
diff -puN fs/fat/dir.c~sync08-fat_tweak1 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync08-fat_tweak1 2005-03-06 02:37:02.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:37:03.000000000 +0900
@@ -22,6 +22,69 @@
#include <linux/buffer_head.h>
#include <asm/uaccess.h>
+/* Returns the inode number of the directory entry at offset pos. If bh is
+ non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
+ returned in bh.
+ AV. Most often we do it item-by-item. Makes sense to optimize.
+ AV. OK, there we go: if both bh and de are non-NULL we assume that we just
+ AV. want the next entry (took one explicit de=NULL in vfat/namei.c).
+ AV. It's done in fat_get_entry() (inlined), here the slow case lives.
+ AV. Additionally, when we return -1 (i.e. reached the end of directory)
+ AV. we make bh NULL.
+ */
+static int fat__get_entry(struct inode *dir, loff_t *pos,
+ struct buffer_head **bh,
+ struct msdos_dir_entry **de, loff_t *i_pos)
+{
+ struct super_block *sb = dir->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ sector_t phys, iblock;
+ loff_t offset;
+ int err;
+
+next:
+ offset = *pos;
+ if (*bh)
+ brelse(*bh);
+
+ *bh = NULL;
+ iblock = *pos >> sb->s_blocksize_bits;
+ err = fat_bmap(dir, iblock, &phys);
+ if (err || !phys)
+ return -1; /* beyond EOF or error */
+
+ *bh = sb_bread(sb, phys);
+ if (*bh == NULL) {
+ printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
+ (unsigned long long)phys);
+ /* skip this block */
+ *pos = (iblock + 1) << sb->s_blocksize_bits;
+ goto next;
+ }
+
+ offset &= sb->s_blocksize - 1;
+ *pos += sizeof(struct msdos_dir_entry);
+ *de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
+ *i_pos = ((loff_t)phys << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
+
+ return 0;
+}
+
+static inline int fat_get_entry(struct inode *dir, loff_t *pos,
+ struct buffer_head **bh,
+ struct msdos_dir_entry **de, loff_t *i_pos)
+{
+ /* Fast stuff first */
+ if (*bh && *de &&
+ (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) {
+ *pos += sizeof(struct msdos_dir_entry);
+ (*de)++;
+ (*i_pos)++;
+ return 0;
+ }
+ return fat__get_entry(dir, pos, bh, de, i_pos);
+}
+
/*
* Convert Unicode 16 to UTF8, translated Unicode, or ASCII.
* If uni_xlate is enabled and we can't get a 1:1 conversion, use a
diff -puN fs/fat/misc.c~sync08-fat_tweak1 fs/fat/misc.c
--- linux-2.6.11/fs/fat/misc.c~sync08-fat_tweak1 2005-03-06 02:37:02.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/misc.c 2005-03-06 02:37:03.000000000 +0900
@@ -194,56 +194,6 @@ void fat_date_unix2dos(int unix_date, __
EXPORT_SYMBOL(fat_date_unix2dos);
-/* Returns the inode number of the directory entry at offset pos. If bh is
- non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
- returned in bh.
- AV. Most often we do it item-by-item. Makes sense to optimize.
- AV. OK, there we go: if both bh and de are non-NULL we assume that we just
- AV. want the next entry (took one explicit de=NULL in vfat/namei.c).
- AV. It's done in fat_get_entry() (inlined), here the slow case lives.
- AV. Additionally, when we return -1 (i.e. reached the end of directory)
- AV. we make bh NULL.
- */
-
-int fat__get_entry(struct inode *dir, loff_t *pos, struct buffer_head **bh,
- struct msdos_dir_entry **de, loff_t *i_pos)
-{
- struct super_block *sb = dir->i_sb;
- struct msdos_sb_info *sbi = MSDOS_SB(sb);
- sector_t phys, iblock;
- loff_t offset;
- int err;
-
-next:
- offset = *pos;
- if (*bh)
- brelse(*bh);
-
- *bh = NULL;
- iblock = *pos >> sb->s_blocksize_bits;
- err = fat_bmap(dir, iblock, &phys);
- if (err || !phys)
- return -1; /* beyond EOF or error */
-
- *bh = sb_bread(sb, phys);
- if (*bh == NULL) {
- printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
- (unsigned long long)phys);
- /* skip this block */
- *pos = (iblock + 1) << sb->s_blocksize_bits;
- goto next;
- }
-
- offset &= sb->s_blocksize - 1;
- *pos += sizeof(struct msdos_dir_entry);
- *de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
- *i_pos = ((loff_t)phys << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
-
- return 0;
-}
-
-EXPORT_SYMBOL(fat__get_entry);
-
int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
{
int i, e, err = 0;
diff -puN include/linux/msdos_fs.h~sync08-fat_tweak1 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync08-fat_tweak1 2005-03-06 02:37:02.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:37:03.000000000 +0900
@@ -405,23 +405,6 @@ extern void fat_clusters_flush(struct su
extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
extern int date_dos2unix(unsigned short time, unsigned short date);
extern void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date);
-extern int fat__get_entry(struct inode *dir, loff_t *pos,
- struct buffer_head **bh,
- struct msdos_dir_entry **de, loff_t *i_pos);
-static __inline__ int fat_get_entry(struct inode *dir, loff_t *pos,
- struct buffer_head **bh,
- struct msdos_dir_entry **de, loff_t *i_pos)
-{
- /* Fast stuff first */
- if (*bh && *de &&
- (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) {
- *pos += sizeof(struct msdos_dir_entry);
- (*de)++;
- (*i_pos)++;
- return 0;
- }
- return fat__get_entry(dir, pos, bh, de, i_pos);
-}
extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
#endif /* __KERNEL__ */
_
The fat_search_long() provide the "struct fat_slot_info" by this
change. So, vfat_find() became to be enough simple, and it just
returns 0 or error.
And the error check of vfat_find() is also simplify.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/dir.c | 26 +++++++------
fs/vfat/namei.c | 89 ++++++++++++++++++++---------------------------
include/linux/msdos_fs.h | 3 -
3 files changed, 54 insertions(+), 64 deletions(-)
diff -puN fs/fat/dir.c~sync06-fat_dir-cleanup2 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync06-fat_dir-cleanup2 2005-03-06 02:36:25.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:36:25.000000000 +0900
@@ -136,7 +136,7 @@ fat_shortname2uni(struct nls_table *nls,
* value is the total amount of slots, including the shortname entry.
*/
int fat_search_long(struct inode *inode, const unsigned char *name,
- int name_len, int anycase, loff_t *spos, loff_t *lpos)
+ int name_len, struct fat_slot_info *sinfo)
{
struct super_block *sb = inode->i_sb;
struct buffer_head *bh = NULL;
@@ -149,12 +149,14 @@ int fat_search_long(struct inode *inode,
unsigned char work[8], bufname[260]; /* 256 + 4 */
int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
int utf8 = MSDOS_SB(sb)->options.utf8;
+ int anycase = (MSDOS_SB(sb)->options.name_check != 's');
unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
- int chl, i, j, last_u, res = 0;
+ int chl, i, j, last_u, err;
loff_t i_pos, cpos = 0;
+ err = -ENOENT;
while(1) {
- if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
+ if (fat_get_entry(inode, &cpos, &bh, &de, &i_pos) == -1)
goto EODir;
parse_record:
long_slots = 0;
@@ -288,15 +290,17 @@ parse_long:
}
Found:
- res = long_slots + 1;
- *spos = cpos - sizeof(struct msdos_dir_entry);
- *lpos = cpos - res*sizeof(struct msdos_dir_entry);
+ sinfo->i_pos = i_pos;
+ sinfo->slot_off = cpos - (long_slots + 1) * sizeof(*de);
+ sinfo->nr_slots = long_slots;
+ sinfo->de = de;
+ sinfo->bh = bh;
+ err = 0;
EODir:
- brelse(bh);
- if (unicode) {
- free_page((unsigned long) unicode);
- }
- return res;
+ if (unicode)
+ free_page((unsigned long)unicode);
+
+ return err;
}
EXPORT_SYMBOL(fat_search_long);
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup2 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync06-fat_dir-cleanup2 2005-03-06 02:36:25.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:36:25.000000000 +0900
@@ -733,51 +733,35 @@ cleanup:
static int vfat_find(struct inode *dir, struct qstr *qname,
struct fat_slot_info *sinfo)
{
- struct super_block *sb = dir->i_sb;
- loff_t offset;
- unsigned int len;
- int res;
-
- len = vfat_striptail_len(qname);
+ unsigned int len = vfat_striptail_len(qname);
if (len == 0)
return -ENOENT;
-
- res = fat_search_long(dir, qname->name, len,
- (MSDOS_SB(sb)->options.name_check != 's'),
- &offset, &sinfo->slot_off);
- if (res > 0) {
- sinfo->nr_slots = res - 1;
- if (fat_get_entry(dir, &offset, &sinfo->bh, &sinfo->de, &sinfo->i_pos) >= 0)
- return 0;
- res = -EIO;
- }
- return res ? res : -ENOENT;
+ return fat_search_long(dir, qname->name, len, sinfo);
}
static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
- int res;
+ struct super_block *sb = dir->i_sb;
struct fat_slot_info sinfo;
- struct inode *inode;
+ struct inode *inode = NULL;
struct dentry *alias;
- int table;
+ int err, table;
lock_kernel();
- table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0;
+ table = (MSDOS_SB(sb)->options.name_check == 's') ? 2 : 0;
dentry->d_op = &vfat_dentry_ops[table];
- inode = NULL;
- res = vfat_find(dir, &dentry->d_name, &sinfo);
- if (res < 0) {
+ err = vfat_find(dir, &dentry->d_name, &sinfo);
+ if (err) {
table++;
goto error;
}
- inode = fat_build_inode(dir->i_sb, sinfo.de, sinfo.i_pos, &res);
+ inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos, &err);
brelse(sinfo.bh);
- if (res) {
+ if (err) {
unlock_kernel();
- return ERR_PTR(res);
+ return ERR_PTR(err);
}
alias = d_find_alias(inode);
if (alias) {
@@ -870,40 +854,43 @@ static int vfat_rmdir(struct inode *dir,
{
struct inode *inode = dentry->d_inode;
struct fat_slot_info sinfo;
- int res;
+ int err;
lock_kernel();
- res = fat_dir_empty(inode);
- if (res)
- goto out;
- res = vfat_find(dir, &dentry->d_name, &sinfo);
- if (res < 0)
+ err = fat_dir_empty(inode);
+ if (err)
+ goto out;
+ err = vfat_find(dir, &dentry->d_name, &sinfo);
+ if (err)
goto out;
- res = 0;
inode->i_nlink = 0;
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
/* releases bh and syncs it if necessary */
vfat_remove_entry(dir, &sinfo);
+
dir->i_nlink--;
out:
unlock_kernel();
- return res;
+
+ return err;
}
static int vfat_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
struct fat_slot_info sinfo;
- int res;
+ int err;
lock_kernel();
- res = vfat_find(dir, &dentry->d_name, &sinfo);
- if (res < 0)
+
+ err = vfat_find(dir, &dentry->d_name, &sinfo);
+ if (err)
goto out;
+
inode->i_nlink = 0;
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
@@ -913,7 +900,7 @@ static int vfat_unlink(struct inode *dir
out:
unlock_kernel();
- return res;
+ return err;
}
static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
@@ -966,44 +953,44 @@ static int vfat_rename(struct inode *old
struct msdos_dir_entry *dotdot_de;
loff_t dotdot_i_pos;
struct inode *old_inode, *new_inode;
- int res, is_dir;
+ int err, is_dir;
struct fat_slot_info old_sinfo, sinfo;
old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode;
lock_kernel();
- res = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
- if (res < 0)
+ err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
+ if (err)
goto rename_done;
is_dir = S_ISDIR(old_inode->i_mode);
if (is_dir) {
if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
&dotdot_de, &dotdot_i_pos) < 0) {
- res = -EIO;
+ err = -EIO;
goto rename_done;
}
}
if (new_dentry->d_inode) {
- res = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
- if (res < 0 || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
+ err = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
+ if (err || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
/* WTF??? Cry and fail. */
printk(KERN_WARNING "vfat_rename: fs corrupted\n");
goto rename_done;
}
if (is_dir) {
- res = fat_dir_empty(new_inode);
- if (res)
+ err = fat_dir_empty(new_inode);
+ if (err)
goto rename_done;
}
fat_detach(new_inode);
} else {
- res = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
+ err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
&sinfo);
- if (res < 0)
+ if (err)
goto rename_done;
}
@@ -1040,13 +1027,13 @@ static int vfat_rename(struct inode *old
mark_inode_dirty(new_dir);
}
}
-
rename_done:
brelse(dotdot_bh);
brelse(old_sinfo.bh);
brelse(sinfo.bh);
unlock_kernel();
- return res;
+
+ return err;
}
static struct inode_operations vfat_dir_inode_operations = {
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup2 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync06-fat_dir-cleanup2 2005-03-06 02:36:25.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:25.000000000 +0900
@@ -323,8 +323,7 @@ extern int fat_bmap(struct inode *inode,
/* fat/dir.c */
extern struct file_operations fat_dir_operations;
extern int fat_search_long(struct inode *inode, const unsigned char *name,
- int name_len, int anycase,
- loff_t *spos, loff_t *lpos);
+ int name_len, struct fat_slot_info *sinfo);
extern int fat_add_entries(struct inode *dir, int slots,
struct buffer_head **bh,
struct msdos_dir_entry **de, loff_t *i_pos);
_
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/vfat/namei.c | 63 +++++++++++++++++++++++++++++++-------------------------
1 files changed, 35 insertions(+), 28 deletions(-)
diff -puN fs/vfat/namei.c~sync07-fat_dir2 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync07-fat_dir2 2005-03-06 02:36:44.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:36:44.000000000 +0900
@@ -658,11 +658,11 @@ out_free:
}
static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,
+ struct timespec *ts,
struct fat_slot_info *sinfo)
{
struct super_block *sb = dir->i_sb;
struct msdos_dir_slot *slots;
- struct timespec ts;
unsigned int len;
int err, i, nr_slots;
loff_t offset;
@@ -678,8 +678,7 @@ static int vfat_add_entry(struct inode *
if (slots == NULL)
return -ENOMEM;
- ts = CURRENT_TIME_SEC;
- err = vfat_build_slots(dir, qname->name, len, is_dir, 0, &ts,
+ err = vfat_build_slots(dir, qname->name, len, is_dir, 0, ts,
slots, &nr_slots);
if (err)
goto cleanup;
@@ -707,7 +706,7 @@ static int vfat_add_entry(struct inode *
}
/* update timestamp */
- dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
+ dir->i_ctime = dir->i_mtime = dir->i_atime = *ts;
mark_inode_dirty(dir);
/* slots can't be less than 1 */
@@ -780,33 +779,33 @@ static int vfat_create(struct inode *dir
struct nameidata *nd)
{
struct super_block *sb = dir->i_sb;
- struct inode *inode = NULL;
+ struct inode *inode;
struct fat_slot_info sinfo;
- int res;
+ struct timespec ts;
+ int err;
lock_kernel();
- res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo);
- if (res < 0)
+
+ ts = CURRENT_TIME_SEC;
+ err = vfat_add_entry(dir, &dentry->d_name, 0, &ts, &sinfo);
+ if (err)
goto out;
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh);
if (IS_ERR(inode)) {
- res = PTR_ERR(inode);
+ err = PTR_ERR(inode);
goto out;
}
- res = 0;
inode->i_version++;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
- mark_inode_dirty(inode);
- if (IS_SYNC(inode))
- fat_sync_inode(inode);
+ inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
+ /* timestamp is already written, so mark_inode_dirty() is unneeded. */
dir->i_version++;
dentry->d_time = dentry->d_parent->d_inode->i_version;
d_instantiate(dentry, inode);
out:
unlock_kernel();
- return res;
+ return err;
}
static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
@@ -869,37 +868,42 @@ static int vfat_mkdir(struct inode *dir,
struct super_block *sb = dir->i_sb;
struct inode *inode = NULL;
struct fat_slot_info sinfo;
- int res;
+ struct timespec ts;
+ int err;
lock_kernel();
- res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo);
- if (res < 0)
+
+ ts = CURRENT_TIME_SEC;
+ err = vfat_add_entry(dir, &dentry->d_name, 1, &ts, &sinfo);
+ if (err)
goto out;
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
if (IS_ERR(inode)) {
- res = PTR_ERR(inode);
+ err = PTR_ERR(inode);
goto out_brelse;
}
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
- mark_inode_dirty(inode);
inode->i_version++;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
+ /* timestamp is already written, so mark_inode_dirty() is unneeded. */
+
dir->i_version++;
dir->i_nlink++;
inode->i_nlink = 2; /* no need to mark them dirty */
- res = fat_new_dir(inode, dir, 1);
- if (res < 0)
+ err = fat_new_dir(inode, dir, 1);
+ if (err)
goto mkdir_failed;
+
dentry->d_time = dentry->d_parent->d_inode->i_version;
d_instantiate(dentry, inode);
out_brelse:
brelse(sinfo.bh);
out:
unlock_kernel();
- return res;
+ return err;
mkdir_failed:
inode->i_nlink = 0;
- inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = ts;
fat_detach(inode);
mark_inode_dirty(inode);
fat_remove_entries(dir, &sinfo); /* and releases bh */
@@ -917,6 +921,7 @@ static int vfat_rename(struct inode *old
struct inode *old_inode, *new_inode;
int err, is_dir;
struct fat_slot_info old_sinfo, sinfo;
+ struct timespec ts;
old_sinfo.bh = dotdot_bh = NULL;
old_inode = old_dentry->d_inode;
@@ -935,6 +940,7 @@ static int vfat_rename(struct inode *old
}
}
+ ts = CURRENT_TIME_SEC;
if (new_dentry->d_inode) {
err = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
if (err)
@@ -953,7 +959,7 @@ static int vfat_rename(struct inode *old
}
fat_detach(new_inode);
} else {
- err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
+ err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, &ts,
&sinfo);
if (err)
goto out;
@@ -972,11 +978,12 @@ static int vfat_rename(struct inode *old
mark_inode_dirty(old_inode);
old_dir->i_version++;
- old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+ old_dir->i_ctime = old_dir->i_mtime = ts;
mark_inode_dirty(old_dir);
+
if (new_inode) {
new_inode->i_nlink--;
- new_inode->i_ctime = CURRENT_TIME_SEC;
+ new_inode->i_ctime = ts;
}
if (is_dir) {
_
Just use ERR_PTR() instead of getting the error code by additional
argument.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/inode.c | 62 ++++++++++++++++++++++-------------------------
fs/msdos/namei.c | 17 +++++++-----
fs/vfat/namei.c | 19 ++++++++------
include/linux/msdos_fs.h | 2 -
4 files changed, 52 insertions(+), 48 deletions(-)
diff -puN fs/fat/inode.c~sync06-fat_dir-cleanup4 fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~sync06-fat_dir-cleanup4 2005-03-06 02:36:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c 2005-03-06 02:36:32.000000000 +0900
@@ -304,23 +304,25 @@ static int fat_fill_inode(struct inode *
}
struct inode *fat_build_inode(struct super_block *sb,
- struct msdos_dir_entry *de, loff_t i_pos, int *res)
+ struct msdos_dir_entry *de, loff_t i_pos)
{
struct inode *inode;
- *res = 0;
+ int err;
+
inode = fat_iget(sb, i_pos);
if (inode)
goto out;
inode = new_inode(sb);
- *res = -ENOMEM;
- if (!inode)
+ if (!inode) {
+ inode = ERR_PTR(-ENOMEM);
goto out;
+ }
inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
inode->i_version = 1;
- *res = fat_fill_inode(inode, de);
- if (*res < 0) {
+ err = fat_fill_inode(inode, de);
+ if (err) {
iput(inode);
- inode = NULL;
+ inode = ERR_PTR(err);
goto out;
}
fat_attach(inode, i_pos);
@@ -643,39 +645,35 @@ fat_encode_fh(struct dentry *de, __u32 *
static struct dentry *fat_get_parent(struct dentry *child)
{
- struct buffer_head *bh=NULL;
- struct msdos_dir_entry *de = NULL;
- struct dentry *parent = NULL;
- int res;
- loff_t i_pos = 0;
+ struct buffer_head *bh;
+ struct msdos_dir_entry *de;
+ loff_t i_pos;
+ struct dentry *parent;
struct inode *inode;
+ int err;
lock_kernel();
- res = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &i_pos);
- if (res < 0)
+ err = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &i_pos);
+ if (err) {
+ parent = ERR_PTR(err);
goto out;
- inode = fat_build_inode(child->d_sb, de, i_pos, &res);
- if (res)
+ }
+ inode = fat_build_inode(child->d_sb, de, i_pos);
+ brelse(bh);
+ if (IS_ERR(inode)) {
+ parent = ERR_PTR(PTR_ERR(inode));
goto out;
- if (!inode)
- res = -EACCES;
- else {
- parent = d_alloc_anon(inode);
- if (!parent) {
- iput(inode);
- res = -ENOMEM;
- }
}
-
- out:
- if(bh)
- brelse(bh);
+ parent = d_alloc_anon(inode);
+ if (!parent) {
+ iput(inode);
+ parent = ERR_PTR(-ENOMEM);
+ }
+out:
unlock_kernel();
- if (res)
- return ERR_PTR(res);
- else
- return parent;
+
+ return parent;
}
static struct export_operations fat_export_ops = {
diff -puN fs/msdos/namei.c~sync06-fat_dir-cleanup4 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync06-fat_dir-cleanup4 2005-03-06 02:36:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c 2005-03-06 02:36:32.000000000 +0900
@@ -236,9 +236,11 @@ static struct dentry *msdos_lookup(struc
goto add;
if (res < 0)
goto out;
- inode = fat_build_inode(sb, de, i_pos, &res);
- if (res)
+ inode = fat_build_inode(sb, de, i_pos);
+ if (IS_ERR(inode)) {
+ res = PTR_ERR(inode);
goto out;
+ }
add:
res = 0;
dentry = d_splice_alias(inode, dentry);
@@ -314,11 +316,11 @@ static int msdos_create(struct inode *di
unlock_kernel();
return res;
}
- inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
+ inode = fat_build_inode(dir->i_sb, de, i_pos);
brelse(bh);
- if (!inode) {
+ if (IS_ERR(inode)) {
unlock_kernel();
- return res;
+ return PTR_ERR(inode);
}
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
@@ -392,9 +394,10 @@ static int msdos_mkdir(struct inode *dir
res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid);
if (res)
goto out_unlock;
- inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
- if (!inode) {
+ inode = fat_build_inode(dir->i_sb, de, i_pos);
+ if (IS_ERR(inode)) {
brelse(bh);
+ res = PTR_ERR(inode);
goto out_unlock;
}
res = 0;
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup4 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync06-fat_dir-cleanup4 2005-03-06 02:36:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:36:32.000000000 +0900
@@ -757,11 +757,11 @@ static struct dentry *vfat_lookup(struct
table++;
goto error;
}
- inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos, &err);
+ inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh);
- if (err) {
+ if (IS_ERR(inode)) {
unlock_kernel();
- return ERR_PTR(err);
+ return ERR_PTR(PTR_ERR(inode));
}
alias = d_find_alias(inode);
if (alias) {
@@ -798,10 +798,12 @@ static int vfat_create(struct inode *dir
res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo);
if (res < 0)
goto out;
- inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos, &res);
+ inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh);
- if (!inode)
+ if (IS_ERR(inode)) {
+ res = PTR_ERR(inode);
goto out;
+ }
res = 0;
inode->i_version++;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
@@ -883,9 +885,11 @@ static int vfat_mkdir(struct inode *dir,
res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo);
if (res < 0)
goto out;
- inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos, &res);
- if (!inode)
+ inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+ if (IS_ERR(inode)) {
+ res = PTR_ERR(inode);
goto out_brelse;
+ }
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
inode->i_version++;
@@ -967,7 +971,6 @@ static int vfat_rename(struct inode *old
}
new_dir->i_version++;
- /* releases old_bh */
err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
old_sinfo.bh = NULL;
if (err)
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup4 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync06-fat_dir-cleanup4 2005-03-06 02:36:32.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:32.000000000 +0900
@@ -394,7 +394,7 @@ extern void fat_attach(struct inode *ino
extern void fat_detach(struct inode *inode);
extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos);
extern struct inode *fat_build_inode(struct super_block *sb,
- struct msdos_dir_entry *de, loff_t i_pos, int *res);
+ struct msdos_dir_entry *de, loff_t i_pos);
extern int fat_sync_inode(struct inode *inode);
extern int fat_fill_super(struct super_block *sb, void *data, int silent,
struct inode_operations *fs_dir_inode_ops, int isvfat);
_
The msdos_find() provide the "struct fat_slot_info". Then some cleanups.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/msdos/namei.c | 88 ++++++++++++++++++++++---------------------------------
1 files changed, 36 insertions(+), 52 deletions(-)
diff -puN fs/msdos/namei.c~sync06-fat_dir-cleanup6 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync06-fat_dir-cleanup6 2005-03-06 02:36:39.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c 2005-03-06 02:36:39.000000000 +0900
@@ -137,11 +137,9 @@ static int msdos_format_name(const unsig
/***** Locates a directory entry. Uses unformatted name. */
static int msdos_find(struct inode *dir, const unsigned char *name, int len,
- struct buffer_head **bh, struct msdos_dir_entry **de,
- loff_t *i_pos)
+ struct fat_slot_info *sinfo)
{
struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
- struct fat_slot_info sinfo;
unsigned char msdos_name[MSDOS_NAME];
int err;
@@ -149,22 +147,17 @@ static int msdos_find(struct inode *dir,
if (err)
return -ENOENT;
- err = fat_scan(dir, msdos_name, &sinfo);
+ err = fat_scan(dir, msdos_name, sinfo);
if (!err && sbi->options.dotsOK) {
if (name[0] == '.') {
- if (!(sinfo.de->attr & ATTR_HIDDEN))
+ if (!(sinfo->de->attr & ATTR_HIDDEN))
err = -ENOENT;
} else {
- if (sinfo.de->attr & ATTR_HIDDEN)
+ if (sinfo->de->attr & ATTR_HIDDEN)
err = -ENOENT;
}
if (err)
- brelse(sinfo.bh);
- }
- if (!err) {
- *i_pos = sinfo.i_pos;
- *de = sinfo.de;
- *bh = sinfo.bh;
+ brelse(sinfo->bh);
}
return err;
}
@@ -228,22 +221,20 @@ static struct dentry *msdos_lookup(struc
struct nameidata *nd)
{
struct super_block *sb = dir->i_sb;
+ struct fat_slot_info sinfo;
struct inode *inode = NULL;
- struct msdos_dir_entry *de;
- struct buffer_head *bh = NULL;
- loff_t i_pos;
int res;
dentry->d_op = &msdos_dentry_operations;
lock_kernel();
- res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh,
- &de, &i_pos);
+ res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
if (res == -ENOENT)
goto add;
if (res < 0)
goto out;
- inode = fat_build_inode(sb, de, i_pos);
+ inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+ brelse(sinfo.bh);
if (IS_ERR(inode)) {
res = PTR_ERR(inode);
goto out;
@@ -254,7 +245,6 @@ add:
if (dentry)
dentry->d_op = &msdos_dentry_operations;
out:
- brelse(bh);
unlock_kernel();
if (!res)
return dentry;
@@ -341,39 +331,35 @@ static int msdos_create(struct inode *di
static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
- loff_t i_pos;
- int res;
- struct buffer_head *bh;
- struct msdos_dir_entry *de;
+ struct fat_slot_info sinfo;
+ int err;
- bh = NULL;
lock_kernel();
- res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
- &bh, &de, &i_pos);
- if (res < 0)
- goto rmdir_done;
/*
* Check whether the directory is not in use, then check
* whether it is empty.
*/
- res = fat_dir_empty(inode);
- if (res)
- goto rmdir_done;
+ err = fat_dir_empty(inode);
+ if (err)
+ goto out;
+ err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
+ if (err)
+ goto out;
- de->name[0] = DELETED_FLAG;
- mark_buffer_dirty(bh);
+ sinfo.de->name[0] = DELETED_FLAG;
+ mark_buffer_dirty(sinfo.bh);
+ brelse(sinfo.bh);
fat_detach(inode);
inode->i_nlink = 0;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
- dir->i_nlink--;
mark_inode_dirty(inode);
- mark_inode_dirty(dir);
- res = 0;
-rmdir_done:
- brelse(bh);
+ dir->i_nlink--;
+ mark_inode_dirty(dir);
+out:
unlock_kernel();
- return res;
+
+ return err;
}
/***** Make a directory */
@@ -420,6 +406,7 @@ static int msdos_mkdir(struct inode *dir
if (res)
goto mkdir_error;
brelse(bh);
+
d_instantiate(dentry, inode);
res = 0;
@@ -445,30 +432,27 @@ mkdir_error:
static int msdos_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
- loff_t i_pos;
- int res;
- struct buffer_head *bh;
- struct msdos_dir_entry *de;
+ struct fat_slot_info sinfo;
+ int err;
- bh = NULL;
lock_kernel();
- res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
- &bh, &de, &i_pos);
- if (res < 0)
+ err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
+ if (err)
goto unlink_done;
- de->name[0] = DELETED_FLAG;
- mark_buffer_dirty(bh);
+ sinfo.de->name[0] = DELETED_FLAG;
+ mark_buffer_dirty(sinfo.bh);
+ brelse(sinfo.bh);
fat_detach(inode);
- brelse(bh);
inode->i_nlink = 0;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
+
mark_inode_dirty(dir);
- res = 0;
unlink_done:
unlock_kernel();
- return res;
+
+ return err;
}
static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
_
With this, the vfat_build_slots() builds the completely data including
the timestamp and cluster. (But this is not using "cluster", it's not
complete yet)
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/vfat/namei.c | 110 ++++++++++++++++++++++++++------------------------------
1 files changed, 52 insertions(+), 58 deletions(-)
diff -puN fs/vfat/namei.c~sync07-fat_dir fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync07-fat_dir 2005-03-06 02:36:41.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:36:41.000000000 +0900
@@ -575,8 +575,9 @@ xlate_to_uni(const unsigned char *name,
}
static int vfat_build_slots(struct inode *dir, const unsigned char *name,
- int len, struct msdos_dir_slot *ds,
- int *slots, int is_dir)
+ int len, int is_dir, int cluster,
+ struct timespec *ts,
+ struct msdos_dir_slot *slots, int *nr_slots)
{
struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
struct fat_mount_options *opts = &sbi->options;
@@ -586,83 +587,85 @@ static int vfat_build_slots(struct inode
unsigned char cksum, lcase;
unsigned char msdos_name[MSDOS_NAME];
wchar_t *uname;
- int res, slot, ulen, usize, i;
+ __le16 time, date;
+ int err, ulen, usize, i;
loff_t offset;
- *slots = 0;
- res = vfat_valid_longname(name, len);
- if (res)
- return res;
+ *nr_slots = 0;
+ err = vfat_valid_longname(name, len);
+ if (err)
+ return err;
page = __get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
uname = (wchar_t *)page;
- res = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,
+ err = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,
opts->unicode_xlate, opts->utf8, sbi->nls_io);
- if (res < 0)
+ if (err)
goto out_free;
- res = vfat_is_used_badchars(uname, ulen);
- if (res < 0)
+ err = vfat_is_used_badchars(uname, ulen);
+ if (err)
goto out_free;
- res = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen,
+ err = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen,
msdos_name, &lcase);
- if (res < 0)
+ if (err < 0)
goto out_free;
- else if (res == 1) {
- de = (struct msdos_dir_entry *)ds;
- res = 0;
+ else if (err == 1) {
+ de = (struct msdos_dir_entry *)slots;
+ err = 0;
goto shortname;
}
/* build the entry of long file name */
- *slots = usize / 13;
for (cksum = i = 0; i < 11; i++)
cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i];
- for (ps = ds, slot = *slots; slot > 0; slot--, ps++) {
- ps->id = slot;
+ *nr_slots = usize / 13;
+ for (ps = slots, i = *nr_slots; i > 0; i--, ps++) {
+ ps->id = i;
ps->attr = ATTR_EXT;
ps->reserved = 0;
ps->alias_checksum = cksum;
ps->start = 0;
- offset = (slot - 1) * 13;
+ offset = (i - 1) * 13;
fatwchar_to16(ps->name0_4, uname + offset, 5);
fatwchar_to16(ps->name5_10, uname + offset + 5, 6);
fatwchar_to16(ps->name11_12, uname + offset + 11, 2);
}
- ds[0].id |= 0x40;
+ slots[0].id |= 0x40;
de = (struct msdos_dir_entry *)ps;
shortname:
/* build the entry of 8.3 alias name */
- (*slots)++;
+ (*nr_slots)++;
memcpy(de->name, msdos_name, MSDOS_NAME);
de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
de->lcase = lcase;
- de->adate = de->cdate = de->date = 0;
- de->ctime = de->time = 0;
+ fat_date_unix2dos(ts->tv_sec, &time, &date);
+ de->time = de->ctime = time;
+ de->date = de->cdate = de->adate = date;
de->ctime_cs = 0;
- de->start = 0;
- de->starthi = 0;
+ de->start = cpu_to_le16(cluster);
+ de->starthi = cpu_to_le16(cluster >> 16);
de->size = 0;
-
out_free:
free_page(page);
- return res;
+ return err;
}
-static int vfat_add_entry(struct inode *dir, struct qstr *qname,
- int is_dir, struct fat_slot_info *sinfo)
+static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,
+ struct fat_slot_info *sinfo)
{
struct super_block *sb = dir->i_sb;
- struct msdos_dir_slot *dir_slots;
- loff_t offset;
- int res, slots, slot;
+ struct msdos_dir_slot *slots;
+ struct timespec ts;
unsigned int len;
+ int err, i, nr_slots;
+ loff_t offset;
struct msdos_dir_entry *de, *dummy_de;
struct buffer_head *bh, *dummy_bh;
loff_t dummy_i_pos;
@@ -671,59 +674,50 @@ static int vfat_add_entry(struct inode *
if (len == 0)
return -ENOENT;
- dir_slots = kmalloc(sizeof(*dir_slots) * MSDOS_SLOTS, GFP_KERNEL);
- if (dir_slots == NULL)
+ slots = kmalloc(sizeof(*slots) * MSDOS_SLOTS, GFP_KERNEL);
+ if (slots == NULL)
return -ENOMEM;
- res = vfat_build_slots(dir, qname->name, len,
- dir_slots, &slots, is_dir);
- if (res < 0)
+ ts = CURRENT_TIME_SEC;
+ err = vfat_build_slots(dir, qname->name, len, is_dir, 0, &ts,
+ slots, &nr_slots);
+ if (err)
goto cleanup;
/* build the empty directory entry of number of slots */
offset =
- fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_i_pos);
+ fat_add_entries(dir, nr_slots, &dummy_bh, &dummy_de, &dummy_i_pos);
if (offset < 0) {
- res = offset;
+ err = offset;
goto cleanup;
}
brelse(dummy_bh);
/* Now create the new entry */
bh = NULL;
- for (slot = 0; slot < slots; slot++) {
+ for (i = 0; i < nr_slots; i++) {
if (fat_get_entry(dir, &offset, &bh, &de, &sinfo->i_pos) < 0) {
- res = -EIO;
+ err = -EIO;
goto cleanup;
}
- memcpy(de, dir_slots + slot, sizeof(struct msdos_dir_slot));
+ memcpy(de, slots + i, sizeof(struct msdos_dir_slot));
mark_buffer_dirty(bh);
if (sb->s_flags & MS_SYNCHRONOUS)
sync_dirty_buffer(bh);
}
- res = 0;
/* update timestamp */
- dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
+ dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
mark_inode_dirty(dir);
- fat_date_unix2dos(dir->i_mtime.tv_sec, &de->time, &de->date);
- dir->i_mtime.tv_nsec = 0;
- de->ctime = de->time;
- de->adate = de->cdate = de->date;
- mark_buffer_dirty(bh);
- if (sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(bh);
-
/* slots can't be less than 1 */
- sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * slots;
- sinfo->nr_slots = slots;
+ sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * nr_slots;
+ sinfo->nr_slots = nr_slots;
sinfo->de = de;
sinfo->bh = bh;
-
cleanup:
- kfree(dir_slots);
- return res;
+ kfree(slots);
+ return err;
}
static int vfat_find(struct inode *dir, struct qstr *qname,
_
Use the synchronous updates, in order to guarantee that the writing to
a disk is completeing when a system call returns.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/msdos/namei.c | 5 ++++-
fs/vfat/namei.c | 5 ++++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff -puN fs/msdos/namei.c~sync08-fat_tweak7 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync08-fat_tweak7 2005-03-06 02:37:29.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c 2005-03-06 02:37:29.000000000 +0900
@@ -278,7 +278,10 @@ static int msdos_add_entry(struct inode
return err;
dir->i_ctime = dir->i_mtime = *ts;
- mark_inode_dirty(dir);
+ if (IS_DIRSYNC(dir))
+ (void)fat_sync_inode(dir);
+ else
+ mark_inode_dirty(dir);
return 0;
}
diff -puN fs/vfat/namei.c~sync08-fat_tweak7 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync08-fat_tweak7 2005-03-06 02:37:29.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:37:29.000000000 +0900
@@ -684,7 +684,10 @@ static int vfat_add_entry(struct inode *
/* update timestamp */
dir->i_ctime = dir->i_mtime = dir->i_atime = *ts;
- mark_inode_dirty(dir);
+ if (IS_DIRSYNC(dir))
+ (void)fat_sync_inode(dir);
+ else
+ mark_inode_dirty(dir);
cleanup:
kfree(slots);
return err;
_
The "i_pos" can calculate later, so this makes the "i_pos" when it's needed.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/dir.c | 70 ++++++++++++++++++++++++++++++++---------------------------
1 files changed, 39 insertions(+), 31 deletions(-)
diff -puN fs/fat/dir.c~sync08-fat_tweak2 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync08-fat_tweak2 2005-03-06 02:37:15.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:37:15.000000000 +0900
@@ -22,6 +22,14 @@
#include <linux/buffer_head.h>
#include <asm/uaccess.h>
+static inline loff_t fat_make_i_pos(struct super_block *sb,
+ struct buffer_head *bh,
+ struct msdos_dir_entry *de)
+{
+ return ((loff_t)bh->b_blocknr << MSDOS_SB(sb)->dir_per_block_bits)
+ | (de - (struct msdos_dir_entry *)bh->b_data);
+}
+
/* Returns the inode number of the directory entry at offset pos. If bh is
non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
returned in bh.
@@ -33,17 +41,14 @@
AV. we make bh NULL.
*/
static int fat__get_entry(struct inode *dir, loff_t *pos,
- struct buffer_head **bh,
- struct msdos_dir_entry **de, loff_t *i_pos)
+ struct buffer_head **bh, struct msdos_dir_entry **de)
{
struct super_block *sb = dir->i_sb;
- struct msdos_sb_info *sbi = MSDOS_SB(sb);
sector_t phys, iblock;
- loff_t offset;
+ int offset;
int err;
next:
- offset = *pos;
if (*bh)
brelse(*bh);
@@ -62,27 +67,25 @@ next:
goto next;
}
- offset &= sb->s_blocksize - 1;
+ offset = *pos & (sb->s_blocksize - 1);
*pos += sizeof(struct msdos_dir_entry);
*de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
- *i_pos = ((loff_t)phys << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
return 0;
}
static inline int fat_get_entry(struct inode *dir, loff_t *pos,
struct buffer_head **bh,
- struct msdos_dir_entry **de, loff_t *i_pos)
+ struct msdos_dir_entry **de)
{
/* Fast stuff first */
if (*bh && *de &&
(*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) {
*pos += sizeof(struct msdos_dir_entry);
(*de)++;
- (*i_pos)++;
return 0;
}
- return fat__get_entry(dir, pos, bh, de, i_pos);
+ return fat__get_entry(dir, pos, bh, de);
}
/*
@@ -214,12 +217,12 @@ int fat_search_long(struct inode *inode,
int utf8 = MSDOS_SB(sb)->options.utf8;
int anycase = (MSDOS_SB(sb)->options.name_check != 's');
unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
+ loff_t cpos = 0;
int chl, i, j, last_u, err;
- loff_t i_pos, cpos = 0;
err = -ENOENT;
while(1) {
- if (fat_get_entry(inode, &cpos, &bh, &de, &i_pos) == -1)
+ if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
goto EODir;
parse_record:
nr_slots = 0;
@@ -270,7 +273,7 @@ parse_long:
if (ds->id & 0x40) {
unicode[offset + 13] = 0;
}
- if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos)<0)
+ if (fat_get_entry(inode, &cpos, &bh, &de) < 0)
goto EODir;
if (slot == 0)
break;
@@ -354,11 +357,11 @@ parse_long:
Found:
nr_slots++; /* include the de */
- sinfo->i_pos = i_pos;
sinfo->slot_off = cpos - nr_slots * sizeof(*de);
sinfo->nr_slots = nr_slots;
sinfo->de = de;
sinfo->bh = bh;
+ sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
err = 0;
EODir:
if (unicode)
@@ -401,7 +404,7 @@ static int fat_readdirx(struct inode *in
unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
unsigned long inum;
int chi, chl, i, i2, j, last, last_u, dotoffset = 0;
- loff_t i_pos, cpos;
+ loff_t cpos;
int ret = 0;
lock_kernel();
@@ -429,7 +432,7 @@ static int fat_readdirx(struct inode *in
bh = NULL;
GetNew:
long_slots = 0;
- if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
+ if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
goto EODir;
/* Check for long filename entry */
if (isvfat) {
@@ -486,7 +489,7 @@ ParseLong:
if (ds->id & 0x40) {
unicode[offset + 13] = 0;
}
- if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
+ if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
goto EODir;
if (slot == 0)
break;
@@ -578,6 +581,7 @@ ParseLong:
else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
inum = parent_ino(filp->f_dentry);
} else {
+ loff_t i_pos = fat_make_i_pos(sb, bh, de);
struct inode *tmp = fat_iget(sb, i_pos);
if (tmp) {
inum = tmp->i_ino;
@@ -748,9 +752,9 @@ struct file_operations fat_dir_operation
static int fat_get_short_entry(struct inode *dir, loff_t *pos,
struct buffer_head **bh,
- struct msdos_dir_entry **de, loff_t *i_pos)
+ struct msdos_dir_entry **de)
{
- while (fat_get_entry(dir, pos, bh, de, i_pos) >= 0) {
+ while (fat_get_entry(dir, pos, bh, de) >= 0) {
/* free entry or long name entry or volume label */
if (!IS_FREE((*de)->name) && !((*de)->attr & ATTR_VOLUME))
return 0;
@@ -769,9 +773,11 @@ int fat_get_dotdot_entry(struct inode *d
offset = 0;
*bh = NULL;
- while (fat_get_short_entry(dir, &offset, bh, de, i_pos) >= 0) {
- if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME))
+ while (fat_get_short_entry(dir, &offset, bh, de) >= 0) {
+ if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME)) {
+ *i_pos = fat_make_i_pos(dir->i_sb, *bh, *de);
return 0;
+ }
}
return -ENOENT;
}
@@ -783,12 +789,12 @@ int fat_dir_empty(struct inode *dir)
{
struct buffer_head *bh;
struct msdos_dir_entry *de;
- loff_t cpos, i_pos;
+ loff_t cpos;
int result = 0;
bh = NULL;
cpos = 0;
- while (fat_get_short_entry(dir, &cpos, &bh, &de, &i_pos) >= 0) {
+ while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) {
if (strncmp(de->name, MSDOS_DOT , MSDOS_NAME) &&
strncmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
result = -ENOTEMPTY;
@@ -809,12 +815,12 @@ int fat_subdirs(struct inode *dir)
{
struct buffer_head *bh;
struct msdos_dir_entry *de;
- loff_t cpos, i_pos;
+ loff_t cpos;
int count = 0;
bh = NULL;
cpos = 0;
- while (fat_get_short_entry(dir, &cpos, &bh, &de, &i_pos) >= 0) {
+ while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) {
if (de->attr & ATTR_DIR)
count++;
}
@@ -829,13 +835,16 @@ int fat_subdirs(struct inode *dir)
int fat_scan(struct inode *dir, const unsigned char *name,
struct fat_slot_info *sinfo)
{
+ struct super_block *sb = dir->i_sb;
+
sinfo->slot_off = 0;
sinfo->bh = NULL;
while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh,
- &sinfo->de, &sinfo->i_pos) >= 0) {
+ &sinfo->de) >= 0) {
if (!strncmp(sinfo->de->name, name, MSDOS_NAME)) {
sinfo->slot_off -= sizeof(*sinfo->de);
sinfo->nr_slots = 1;
+ sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
return 0;
}
}
@@ -849,12 +858,11 @@ static int __fat_remove_entries(struct i
struct super_block *sb = dir->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *de, *endp;
- loff_t i_pos;
int err = 0, orig_slots;
while (nr_slots) {
bh = NULL;
- if (fat_get_entry(dir, &pos, &bh, &de, &i_pos) < 0) {
+ if (fat_get_entry(dir, &pos, &bh, &de) < 0) {
err = -EIO;
break;
}
@@ -1103,7 +1111,7 @@ static int fat_add_new_entries(struct in
get_bh(bhs[n]);
*bh = bhs[n];
*de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
- *i_pos = ((loff_t)blknr << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
+ *i_pos = fat_make_i_pos(sb, *bh, *de);
/* Second stage: clear the rest of cluster, and write outs */
err = fat_zeroed_cluster(dir, start_blknr, ++n, bhs, MAX_BUF_PER_PAGE);
@@ -1141,7 +1149,7 @@ int fat_add_entries(struct inode *dir, v
bh = prev = NULL;
pos = 0;
err = -ENOSPC;
- while (fat_get_entry(dir, &pos, &bh, &de, &i_pos) > -1) {
+ while (fat_get_entry(dir, &pos, &bh, &de) > -1) {
/* check the maximum size of directory */
if (pos >= FAT_MAX_DIR_SIZE)
goto error;
@@ -1232,9 +1240,9 @@ found:
MSDOS_I(dir)->mmu_private += nr_cluster << sbi->cluster_bits;
}
sinfo->slot_off = pos;
- sinfo->i_pos = i_pos;
sinfo->de = de;
sinfo->bh = bh;
+ sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
return 0;
_
Add a `:'.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/misc.c | 2 +-
1 files changed, 1 insertion(+), 1 deletion(-)
diff -puN fs/fat/misc.c~sync08-fat_tweak9 fs/fat/misc.c
--- linux-2.6.11/fs/fat/misc.c~sync08-fat_tweak9 2005-03-06 02:38:03.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/misc.c 2005-03-06 02:38:04.000000000 +0900
@@ -48,7 +48,7 @@ void fat_clusters_flush(struct super_blo
bh = sb_bread(sb, sbi->fsinfo_sector);
if (bh == NULL) {
- printk(KERN_ERR "FAT bread failed in fat_clusters_flush\n");
+ printk(KERN_ERR "FAT: bread failed in fat_clusters_flush\n");
return;
}
_
a) If old_dir == new_dir, we don't need to update the ".." entry,
so this doesn't touch it if unneeded.
b) old algorithm is using
1) add a new entry (doen't point the data cluster yet).
2) remove a old entry.
3) switch the data cluster to new entry.
4) update a ".." entry
this order lose the data cluster when between 2) and 3).
Instead of above, this is using
1) add a new entry (doen't point the data cluster yet).
2) switch the data cluster to new entry.
3) update a ".." entry if needed.
4) remove a old entry.
this order would not lose the data cluster, but on disk metadata is
corrupted on some point (later, fsck would recover this corruption
without losing the data).
c) use synchronous update.
d) Fix the corrupted directory check created by 1 of new algorithm.
1) Fix fat_bmap(). If directory's ->i_start == 0, fat_bmap() is
handling it as root directory, this removes that strange behavior.
2) On mkdir() path if directory's ->i_start == 0, returns -EIO.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/cache.c | 4 -
fs/fat/dir.c | 9 +++-
fs/fat/misc.c | 2
fs/msdos/namei.c | 112 ++++++++++++++++++++++++++++++++++++++++++-------------
fs/vfat/namei.c | 101 +++++++++++++++++++++++++++++++++++--------------
5 files changed, 170 insertions(+), 58 deletions(-)
diff -puN fs/fat/cache.c~sync08-fat_tweak8 fs/fat/cache.c
--- linux-2.6.11/fs/fat/cache.c~sync08-fat_tweak8 2005-03-06 02:37:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/cache.c 2005-03-06 02:37:32.000000000 +0900
@@ -303,9 +303,7 @@ int fat_bmap(struct inode *inode, sector
int cluster, offset;
*phys = 0;
- if ((sbi->fat_bits != 32) &&
- (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
- !MSDOS_I(inode)->i_start))) {
+ if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO)) {
if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits))
*phys = sector + sbi->dir_start;
return 0;
diff -puN fs/fat/dir.c~sync08-fat_tweak8 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync08-fat_tweak8 2005-03-06 02:37:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:37:32.000000000 +0900
@@ -1172,8 +1172,15 @@ int fat_add_entries(struct inode *dir, v
free_slots = nr_bhs = 0;
}
}
- if ((dir->i_ino == MSDOS_ROOT_INO) && (sbi->fat_bits != 32))
+ if (dir->i_ino == MSDOS_ROOT_INO) {
+ if (sbi->fat_bits != 32)
+ goto error;
+ } else if (MSDOS_I(dir)->i_start == 0) {
+ printk(KERN_ERR "FAT: Corrupted directory (i_pos %lld)\n",
+ MSDOS_I(dir)->i_pos);
+ err = -EIO;
goto error;
+ }
found:
err = 0;
diff -puN fs/fat/misc.c~sync08-fat_tweak8 fs/fat/misc.c
--- linux-2.6.11/fs/fat/misc.c~sync08-fat_tweak8 2005-03-06 02:37:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/misc.c 2005-03-06 02:37:32.000000000 +0900
@@ -33,6 +33,8 @@ void fat_fs_panic(struct super_block *s,
}
}
+EXPORT_SYMBOL(fat_fs_panic);
+
/* Flushes the number of free clusters on FAT32 */
/* XXX: Need to write one per FSINFO block. Currently only writes 1 */
void fat_clusters_flush(struct super_block *sb)
diff -puN fs/msdos/namei.c~sync08-fat_tweak8 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync08-fat_tweak8 2005-03-06 02:37:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c 2005-03-06 02:37:32.000000000 +0900
@@ -456,9 +456,9 @@ static int do_msdos_rename(struct inode
struct inode *old_inode, *new_inode;
struct fat_slot_info old_sinfo, sinfo;
struct timespec ts;
- int err, is_dir;
+ int err, old_attrs, is_dir, update_dotdot, corrupt = 0;
- old_sinfo.bh = dotdot_bh = NULL;
+ old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode;
@@ -469,7 +469,8 @@ static int do_msdos_rename(struct inode
}
is_dir = S_ISDIR(old_inode->i_mode);
- if (is_dir) {
+ update_dotdot = (is_dir && old_dir != new_dir);
+ if (update_dotdot) {
if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
&dotdot_i_pos) < 0) {
err = -EIO;
@@ -477,9 +478,9 @@ static int do_msdos_rename(struct inode
}
}
+ old_attrs = MSDOS_I(old_inode)->i_attrs;
err = fat_scan(new_dir, new_name, &sinfo);
if (!err) {
- brelse(sinfo.bh);
if (!new_inode) {
/* "foo" -> ".foo" case. just change the ATTR_HIDDEN */
if (sinfo.de != old_sinfo.de) {
@@ -490,11 +491,21 @@ static int do_msdos_rename(struct inode
MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
else
MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
- mark_inode_dirty(old_inode);
+ if (IS_DIRSYNC(old_dir)) {
+ err = fat_sync_inode(old_inode);
+ if (err) {
+ MSDOS_I(old_inode)->i_attrs = old_attrs;
+ goto out;
+ }
+ } else
+ mark_inode_dirty(old_inode);
old_dir->i_version++;
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
- mark_inode_dirty(old_dir);
+ if (IS_DIRSYNC(old_dir))
+ (void)fat_sync_inode(old_dir);
+ else
+ mark_inode_dirty(old_dir);
goto out;
}
}
@@ -520,47 +531,96 @@ static int do_msdos_rename(struct inode
&ts, &sinfo);
if (err)
goto out;
- brelse(sinfo.bh);
}
new_dir->i_version++;
- err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
- old_sinfo.bh = NULL;
- if (err)
- goto out;
- if (is_dir)
- old_dir->i_nlink--;
fat_detach(old_inode);
fat_attach(old_inode, sinfo.i_pos);
if (is_hid)
MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
else
MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
- mark_inode_dirty(old_inode);
-
- old_dir->i_version++;
- old_dir->i_ctime = old_dir->i_mtime = ts;
- mark_inode_dirty(old_dir);
+ if (IS_DIRSYNC(new_dir)) {
+ err = fat_sync_inode(old_inode);
+ if (err)
+ goto error_inode;
+ } else
+ mark_inode_dirty(old_inode);
- if (new_inode) {
- new_inode->i_nlink--;
- new_inode->i_ctime = ts;
- }
- if (is_dir) {
+ if (update_dotdot) {
int start = MSDOS_I(new_dir)->i_logstart;
dotdot_de->start = cpu_to_le16(start);
dotdot_de->starthi = cpu_to_le16(start >> 16);
mark_buffer_dirty(dotdot_bh);
+ if (IS_DIRSYNC(new_dir)) {
+ err = sync_dirty_buffer(dotdot_bh);
+ if (err)
+ goto error_dotdot;
+ }
+ old_dir->i_nlink--;
+ if (!new_inode)
+ new_dir->i_nlink++;
+ }
- if (new_inode)
- new_inode->i_nlink--;
+ err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
+ old_sinfo.bh = NULL;
+ if (err)
+ goto error_dotdot;
+ old_dir->i_version++;
+ old_dir->i_ctime = old_dir->i_mtime = ts;
+ if (IS_DIRSYNC(old_dir))
+ (void)fat_sync_inode(old_dir);
+ else
+ mark_inode_dirty(old_dir);
+
+ if (new_inode) {
+ if (is_dir)
+ new_inode->i_nlink -= 2;
else
- new_dir->i_nlink++;
+ new_inode->i_nlink--;
+ new_inode->i_ctime = ts;
}
out:
+ brelse(sinfo.bh);
brelse(dotdot_bh);
brelse(old_sinfo.bh);
return err;
+
+error_dotdot:
+ /* data cluster is shared, serious corruption */
+ corrupt = 1;
+
+ if (update_dotdot) {
+ int start = MSDOS_I(old_dir)->i_logstart;
+ dotdot_de->start = cpu_to_le16(start);
+ dotdot_de->starthi = cpu_to_le16(start >> 16);
+ mark_buffer_dirty(dotdot_bh);
+ corrupt |= sync_dirty_buffer(dotdot_bh);
+ }
+error_inode:
+ fat_detach(old_inode);
+ fat_attach(old_inode, old_sinfo.i_pos);
+ MSDOS_I(old_inode)->i_attrs = old_attrs;
+ if (new_inode) {
+ fat_attach(new_inode, sinfo.i_pos);
+ if (corrupt)
+ corrupt |= fat_sync_inode(new_inode);
+ } else {
+ /*
+ * If new entry was not sharing the data cluster, it
+ * shouldn't be serious corruption.
+ */
+ int err2 = fat_remove_entries(new_dir, &sinfo);
+ if (corrupt)
+ corrupt |= err2;
+ sinfo.bh = NULL;
+ }
+ if (corrupt < 0) {
+ fat_fs_panic(new_dir->i_sb,
+ "%s: Filesystem corrupted (i_pos %lld)",
+ __FUNCTION__, sinfo.i_pos);
+ }
+ goto out;
}
/***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
diff -puN fs/vfat/namei.c~sync08-fat_tweak8 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync08-fat_tweak8 2005-03-06 02:37:32.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:37:32.000000000 +0900
@@ -890,11 +890,11 @@ static int vfat_rename(struct inode *old
struct msdos_dir_entry *dotdot_de;
loff_t dotdot_i_pos;
struct inode *old_inode, *new_inode;
- int err, is_dir;
struct fat_slot_info old_sinfo, sinfo;
struct timespec ts;
+ int err, is_dir, update_dotdot, corrupt = 0;
- old_sinfo.bh = dotdot_bh = NULL;
+ old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode;
lock_kernel();
@@ -903,7 +903,8 @@ static int vfat_rename(struct inode *old
goto out;
is_dir = S_ISDIR(old_inode->i_mode);
- if (is_dir) {
+ update_dotdot = (is_dir && old_dir != new_dir);
+ if (update_dotdot) {
if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
&dotdot_i_pos) < 0) {
err = -EIO;
@@ -912,11 +913,10 @@ static int vfat_rename(struct inode *old
}
ts = CURRENT_TIME_SEC;
- if (new_dentry->d_inode) {
+ if (new_inode) {
err = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
if (err)
goto out;
- brelse(sinfo.bh);
if (MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
/* WTF??? Cry and fail. */
printk(KERN_WARNING "vfat_rename: fs corrupted\n");
@@ -934,48 +934,93 @@ static int vfat_rename(struct inode *old
&ts, &sinfo);
if (err)
goto out;
- brelse(sinfo.bh);
}
new_dir->i_version++;
- err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
- old_sinfo.bh = NULL;
- if (err)
- goto out;
- if (is_dir)
- old_dir->i_nlink--;
fat_detach(old_inode);
fat_attach(old_inode, sinfo.i_pos);
- mark_inode_dirty(old_inode);
-
- old_dir->i_version++;
- old_dir->i_ctime = old_dir->i_mtime = ts;
- mark_inode_dirty(old_dir);
-
- if (new_inode) {
- new_inode->i_nlink--;
- new_inode->i_ctime = ts;
- }
+ if (IS_DIRSYNC(new_dir)) {
+ err = fat_sync_inode(old_inode);
+ if (err)
+ goto error_inode;
+ } else
+ mark_inode_dirty(old_inode);
- if (is_dir) {
+ if (update_dotdot) {
int start = MSDOS_I(new_dir)->i_logstart;
dotdot_de->start = cpu_to_le16(start);
dotdot_de->starthi = cpu_to_le16(start >> 16);
mark_buffer_dirty(dotdot_bh);
- if (new_dir->i_sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(dotdot_bh);
+ if (IS_DIRSYNC(new_dir)) {
+ err = sync_dirty_buffer(dotdot_bh);
+ if (err)
+ goto error_dotdot;
+ }
+ old_dir->i_nlink--;
+ if (!new_inode)
+ new_dir->i_nlink++;
+ }
- if (new_inode)
- new_inode->i_nlink--;
+ err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
+ old_sinfo.bh = NULL;
+ if (err)
+ goto error_dotdot;
+ old_dir->i_version++;
+ old_dir->i_ctime = old_dir->i_mtime = ts;
+ if (IS_DIRSYNC(old_dir))
+ (void)fat_sync_inode(old_dir);
+ else
+ mark_inode_dirty(old_dir);
+
+ if (new_inode) {
+ if (is_dir)
+ new_inode->i_nlink -= 2;
else
- new_dir->i_nlink++;
+ new_inode->i_nlink--;
+ new_inode->i_ctime = ts;
}
out:
+ brelse(sinfo.bh);
brelse(dotdot_bh);
brelse(old_sinfo.bh);
unlock_kernel();
return err;
+
+error_dotdot:
+ /* data cluster is shared, serious corruption */
+ corrupt = 1;
+
+ if (update_dotdot) {
+ int start = MSDOS_I(old_dir)->i_logstart;
+ dotdot_de->start = cpu_to_le16(start);
+ dotdot_de->starthi = cpu_to_le16(start >> 16);
+ mark_buffer_dirty(dotdot_bh);
+ corrupt |= sync_dirty_buffer(dotdot_bh);
+ }
+error_inode:
+ fat_detach(old_inode);
+ fat_attach(old_inode, old_sinfo.i_pos);
+ if (new_inode) {
+ fat_attach(new_inode, sinfo.i_pos);
+ if (corrupt)
+ corrupt |= fat_sync_inode(new_inode);
+ } else {
+ /*
+ * If new entry was not sharing the data cluster, it
+ * shouldn't be serious corruption.
+ */
+ int err2 = fat_remove_entries(new_dir, &sinfo);
+ if (corrupt)
+ corrupt |= err2;
+ sinfo.bh = NULL;
+ }
+ if (corrupt < 0) {
+ fat_fs_panic(new_dir->i_sb,
+ "%s: Filesystem corrupted (i_pos %lld)",
+ __FUNCTION__, sinfo.i_pos);
+ }
+ goto out;
}
static struct inode_operations vfat_dir_inode_operations = {
_
The msdos_add_entry() use similar interface to vfat_add_entry().
And use a same timestamp on some operations path.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/msdos/namei.c | 162 ++++++++++++++++++++++++++++---------------------------
1 files changed, 84 insertions(+), 78 deletions(-)
diff -puN fs/msdos/namei.c~sync07-fat_dir4 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync07-fat_dir4 2005-03-06 02:36:50.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c 2005-03-06 02:36:50.000000000 +0900
@@ -253,31 +253,38 @@ out:
/***** Creates a directory entry (name is already formatted). */
static int msdos_add_entry(struct inode *dir, const unsigned char *name,
- struct buffer_head **bh,
- struct msdos_dir_entry **de,
- loff_t *i_pos, int is_dir, int is_hid)
+ int is_dir, int is_hid, struct timespec *ts,
+ struct fat_slot_info *sinfo)
{
- int res;
+ struct msdos_dir_entry de;
+ __le16 time, date;
+ int offset;
- res = fat_add_entries(dir, 1, bh, de, i_pos);
- if (res < 0)
- return res;
+ memcpy(de.name, name, MSDOS_NAME);
+ de.attr = is_dir ? ATTR_DIR : ATTR_ARCH;
+ if (is_hid)
+ de.attr |= ATTR_HIDDEN;
+ de.lcase = 0;
+ fat_date_unix2dos(ts->tv_sec, &time, &date);
+ de.time = de.ctime = time;
+ de.date = de.cdate = de.adate = date;
+ de.ctime_cs = 0;
+ de.start = 0;
+ de.starthi = 0;
+ de.size = 0;
+
+ offset = fat_add_entries(dir, 1, &sinfo->bh, &sinfo->de, &sinfo->i_pos);
+ if (offset < 0)
+ return offset;
+ sinfo->slot_off = offset;
+ sinfo->nr_slots = 1;
- /*
- * XXX all times should be set by caller upon successful completion.
- */
- dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ memcpy(sinfo->de, &de, sizeof(de));
+ mark_buffer_dirty(sinfo->bh);
+
+ dir->i_ctime = dir->i_mtime = *ts;
mark_inode_dirty(dir);
- memcpy((*de)->name, name, MSDOS_NAME);
- (*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
- if (is_hid)
- (*de)->attr |= ATTR_HIDDEN;
- (*de)->start = 0;
- (*de)->starthi = 0;
- fat_date_unix2dos(dir->i_mtime.tv_sec, &(*de)->time, &(*de)->date);
- (*de)->size = 0;
- mark_buffer_dirty(*bh);
return 0;
}
@@ -286,45 +293,43 @@ static int msdos_create(struct inode *di
struct nameidata *nd)
{
struct super_block *sb = dir->i_sb;
- struct fat_slot_info sinfo;
- struct buffer_head *bh;
- struct msdos_dir_entry *de;
struct inode *inode;
- loff_t i_pos;
- int res, is_hid;
+ struct fat_slot_info sinfo;
+ struct timespec ts;
unsigned char msdos_name[MSDOS_NAME];
+ int err, is_hid;
lock_kernel();
- res = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
+
+ err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
msdos_name, &MSDOS_SB(sb)->options);
- if (res < 0) {
- unlock_kernel();
- return res;
- }
+ if (err)
+ goto out;
is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
/* Have to do it due to foo vs. .foo conflicts */
if (!fat_scan(dir, msdos_name, &sinfo)) {
brelse(sinfo.bh);
- unlock_kernel();
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
- res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid);
- if (res) {
- unlock_kernel();
- return res;
- }
- inode = fat_build_inode(sb, de, i_pos);
- brelse(bh);
+ ts = CURRENT_TIME_SEC;
+ err = msdos_add_entry(dir, msdos_name, 0, is_hid, &ts, &sinfo);
+ if (err)
+ goto out;
+ inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+ brelse(sinfo.bh);
if (IS_ERR(inode)) {
- unlock_kernel();
- return PTR_ERR(inode);
+ err = PTR_ERR(inode);
+ goto out;
}
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
- mark_inode_dirty(inode);
+ inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
+ /* timestamp is already written, so mark_inode_dirty() is unneeded. */
+
d_instantiate(dentry, inode);
+out:
unlock_kernel();
- return 0;
+ return err;
}
/***** Remove a directory */
@@ -367,65 +372,63 @@ static int msdos_mkdir(struct inode *dir
{
struct super_block *sb = dir->i_sb;
struct fat_slot_info sinfo;
- struct buffer_head *bh;
- struct msdos_dir_entry *de;
struct inode *inode;
- int res, is_hid;
unsigned char msdos_name[MSDOS_NAME];
- loff_t i_pos;
+ struct timespec ts;
+ int err, is_hid;
lock_kernel();
- res = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
+
+ err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
msdos_name, &MSDOS_SB(sb)->options);
- if (res < 0) {
- unlock_kernel();
- return res;
- }
+ if (err)
+ goto out;
is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
/* foo vs .foo situation */
if (!fat_scan(dir, msdos_name, &sinfo)) {
brelse(sinfo.bh);
- res = -EINVAL;
- goto out_unlock;
+ err = -EINVAL;
+ goto out;
}
- res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid);
- if (res)
- goto out_unlock;
- inode = fat_build_inode(dir->i_sb, de, i_pos);
+ ts = CURRENT_TIME_SEC;
+ err = msdos_add_entry(dir, msdos_name, 1, is_hid, &ts, &sinfo);
+ if (err)
+ goto out;
+ inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
if (IS_ERR(inode)) {
- brelse(bh);
- res = PTR_ERR(inode);
- goto out_unlock;
+ brelse(sinfo.bh);
+ err = PTR_ERR(inode);
+ goto out;
}
+ inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
+ /* timestamp is already written, so mark_inode_dirty() is unneeded. */
dir->i_nlink++;
inode->i_nlink = 2; /* no need to mark them dirty */
- res = fat_new_dir(inode, dir, 0);
- if (res)
+ err = fat_new_dir(inode, dir, 0);
+ if (err)
goto mkdir_error;
- brelse(bh);
+ brelse(sinfo.bh);
d_instantiate(dentry, inode);
- res = 0;
-
-out_unlock:
+out:
unlock_kernel();
- return res;
+ return err;
mkdir_error:
inode->i_nlink = 0;
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = ts;
dir->i_nlink--;
mark_inode_dirty(inode);
mark_inode_dirty(dir);
- de->name[0] = DELETED_FLAG;
- mark_buffer_dirty(bh);
- brelse(bh);
+ sinfo.de->name[0] = DELETED_FLAG;
+ mark_buffer_dirty(sinfo.bh);
+ brelse(sinfo.bh);
fat_detach(inode);
iput(inode);
- goto out_unlock;
+ goto out;
}
/***** Unlink a file */
@@ -465,6 +468,7 @@ static int do_msdos_rename(struct inode
loff_t dotdot_i_pos;
struct inode *old_inode, *new_inode;
struct fat_slot_info old_sinfo, sinfo;
+ struct timespec ts;
int err, is_dir;
old_sinfo.bh = dotdot_bh = NULL;
@@ -507,6 +511,8 @@ static int do_msdos_rename(struct inode
goto out;
}
}
+
+ ts = CURRENT_TIME_SEC;
if (new_inode) {
if (err)
goto out;
@@ -523,8 +529,8 @@ static int do_msdos_rename(struct inode
}
fat_detach(new_inode);
} else {
- err = msdos_add_entry(new_dir, new_name, &sinfo.bh, &sinfo.de,
- &sinfo.i_pos, is_dir, is_hid);
+ err = msdos_add_entry(new_dir, new_name, is_dir, is_hid,
+ &ts, &sinfo);
if (err)
goto out;
brelse(sinfo.bh);
@@ -546,12 +552,12 @@ static int do_msdos_rename(struct inode
mark_inode_dirty(old_inode);
old_dir->i_version++;
- old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+ old_dir->i_ctime = old_dir->i_mtime = ts;
mark_inode_dirty(old_dir);
if (new_inode) {
new_inode->i_nlink--;
- new_inode->i_ctime = CURRENT_TIME_SEC;
+ new_inode->i_ctime = ts;
mark_inode_dirty(new_inode);
}
if (is_dir) {
_
Fix a missing error check for sync_buffer_dirty().
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/inode.c | 18 ++++++++++--------
1 files changed, 10 insertions(+), 8 deletions(-)
diff -puN fs/fat/inode.c~sync08-fat_tweak6 fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~sync08-fat_tweak6 2005-03-06 02:37:26.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c 2005-03-06 02:37:26.000000000 +0900
@@ -463,18 +463,20 @@ static int fat_write_inode(struct inode
struct buffer_head *bh;
struct msdos_dir_entry *raw_entry;
loff_t i_pos;
+ int err = 0;
retry:
i_pos = MSDOS_I(inode)->i_pos;
- if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) {
+ if (inode->i_ino == MSDOS_ROOT_INO || !i_pos)
return 0;
- }
+
lock_kernel();
- if (!(bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits))) {
+ bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits);
+ if (!bh) {
printk(KERN_ERR "FAT: unable to read inode block "
"for updating (i_pos %lld)\n", i_pos);
- unlock_kernel();
- return -EIO;
+ err = -EIO;
+ goto out;
}
spin_lock(&sbi->inode_hash_lock);
if (i_pos != MSDOS_I(inode)->i_pos) {
@@ -502,11 +504,11 @@ retry:
spin_unlock(&sbi->inode_hash_lock);
mark_buffer_dirty(bh);
if (wait)
- sync_dirty_buffer(bh);
+ err = sync_dirty_buffer(bh);
brelse(bh);
+out:
unlock_kernel();
-
- return 0;
+ return err;
}
int fat_sync_inode(struct inode *inode)
_
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/msdos/namei.c | 37 +++++++++++++++++--------------------
1 files changed, 17 insertions(+), 20 deletions(-)
diff -puN fs/msdos/namei.c~sync07-fat_dir7 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync07-fat_dir7 2005-03-06 02:37:00.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c 2005-03-06 02:37:00.000000000 +0900
@@ -346,16 +346,15 @@ static int msdos_rmdir(struct inode *dir
if (err)
goto out;
- sinfo.de->name[0] = DELETED_FLAG;
- mark_buffer_dirty(sinfo.bh);
- brelse(sinfo.bh);
- fat_detach(inode);
+ err = fat_remove_entries(dir, &sinfo); /* and releases bh */
+ if (err)
+ goto out;
+ dir->i_nlink--;
+
inode->i_nlink = 0;
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = CURRENT_TIME_SEC;
+ fat_detach(inode);
mark_inode_dirty(inode);
-
- dir->i_nlink--;
- mark_inode_dirty(dir);
out:
unlock_kernel();
@@ -430,18 +429,16 @@ static int msdos_unlink(struct inode *di
lock_kernel();
err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
if (err)
- goto unlink_done;
+ goto out;
- sinfo.de->name[0] = DELETED_FLAG;
- mark_buffer_dirty(sinfo.bh);
- brelse(sinfo.bh);
- fat_detach(inode);
+ err = fat_remove_entries(dir, &sinfo); /* and releases bh */
+ if (err)
+ goto out;
inode->i_nlink = 0;
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = CURRENT_TIME_SEC;
+ fat_detach(inode);
mark_inode_dirty(inode);
-
- mark_inode_dirty(dir);
-unlink_done:
+out:
unlock_kernel();
return err;
@@ -526,10 +523,10 @@ static int do_msdos_rename(struct inode
}
new_dir->i_version++;
- old_sinfo.de->name[0] = DELETED_FLAG;
- mark_buffer_dirty(old_sinfo.bh);
- brelse(old_sinfo.bh);
+ err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
old_sinfo.bh = NULL;
+ if (err)
+ goto out;
if (is_dir)
old_dir->i_nlink--;
fat_detach(old_inode);
_
In order not to write out the same block repeatedly, rewrite the
fat_add_entries().
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/dir.c | 261 ++++++++++++++++++++++++++++++++++-------------
fs/msdos/namei.c | 13 --
fs/vfat/namei.c | 35 ------
include/linux/msdos_fs.h | 5
4 files changed, 198 insertions(+), 116 deletions(-)
diff -puN fs/fat/dir.c~sync07-fat_dir6 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync07-fat_dir6 2005-03-06 02:36:56.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:36:56.000000000 +0900
@@ -981,94 +981,211 @@ error:
EXPORT_SYMBOL(fat_alloc_new_dir);
-static struct buffer_head *fat_extend_dir(struct inode *inode)
+static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots,
+ int *nr_cluster, struct msdos_dir_entry **de,
+ struct buffer_head **bh, loff_t *i_pos)
{
- struct super_block *sb = inode->i_sb;
- struct buffer_head *bh, *res = NULL;
- int err, cluster, sec_per_clus = MSDOS_SB(sb)->sec_per_clus;
- sector_t sector, last_sector;
-
- if (MSDOS_SB(sb)->fat_bits != 32) {
- if (inode->i_ino == MSDOS_ROOT_INO)
- return ERR_PTR(-ENOSPC);
- }
+ struct super_block *sb = dir->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+ sector_t blknr, start_blknr, last_blknr;
+ unsigned long size, copy;
+ int err, i, n, offset, cluster[2];
+
+ /*
+ * The minimum cluster size is 512bytes, and maximum entry
+ * size is 32*slots (672bytes). So, iff the cluster size is
+ * 512bytes, we may need two clusters.
+ */
+ size = nr_slots * sizeof(struct msdos_dir_entry);
+ *nr_cluster = (size + (sbi->cluster_size - 1)) >> sbi->cluster_bits;
+ BUG_ON(*nr_cluster > 2);
- err = fat_alloc_clusters(inode, &cluster, 1);
+ err = fat_alloc_clusters(dir, cluster, *nr_cluster);
if (err)
- return ERR_PTR(err);
- err = fat_chain_add(inode, cluster, 1);
- if (err) {
- fat_free_clusters(inode, cluster);
- return ERR_PTR(err);
- }
+ goto error;
- sector = fat_clus_to_blknr(MSDOS_SB(sb), cluster);
- last_sector = sector + sec_per_clus;
- for ( ; sector < last_sector; sector++) {
- if ((bh = sb_getblk(sb, sector))) {
- memset(bh->b_data, 0, sb->s_blocksize);
- set_buffer_uptodate(bh);
- mark_buffer_dirty(bh);
- if (sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(bh);
- if (!res)
- res = bh;
- else
- brelse(bh);
+ /*
+ * First stage: Fill the directory entry. NOTE: This cluster
+ * is not referenced from any inode yet, so updates order is
+ * not important.
+ */
+ i = n = copy = 0;
+ do {
+ start_blknr = blknr = fat_clus_to_blknr(sbi, cluster[i]);
+ last_blknr = start_blknr + sbi->sec_per_clus;
+ while (blknr < last_blknr) {
+ bhs[n] = sb_getblk(sb, blknr);
+ if (!bhs[n]) {
+ err = -ENOMEM;
+ goto error_nomem;
+ }
+
+ /* fill the directory entry */
+ copy = min(size, sb->s_blocksize);
+ memcpy(bhs[n]->b_data, slots, copy);
+ slots += copy;
+ size -= copy;
+ set_buffer_uptodate(bhs[n]);
+ mark_buffer_dirty(bhs[n]);
+ if (!size)
+ break;
+ n++;
+ blknr++;
}
- }
- if (res == NULL)
- res = ERR_PTR(-EIO);
- if (inode->i_size & (sb->s_blocksize - 1)) {
- fat_fs_panic(sb, "Odd directory size");
- inode->i_size = (inode->i_size + sb->s_blocksize)
- & ~((loff_t)sb->s_blocksize - 1);
- }
- inode->i_size += MSDOS_SB(sb)->cluster_size;
- MSDOS_I(inode)->mmu_private += MSDOS_SB(sb)->cluster_size;
+ } while (++i < *nr_cluster);
- return res;
-}
+ memset(bhs[n]->b_data + copy, 0, sb->s_blocksize - copy);
+ offset = copy - sizeof(struct msdos_dir_entry);
+ get_bh(bhs[n]);
+ *bh = bhs[n];
+ *de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
+ *i_pos = ((loff_t)blknr << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
-/* This assumes that size of cluster is above the 32*slots */
+ /* Second stage: clear the rest of cluster, and write outs */
+ err = fat_zeroed_cluster(dir, start_blknr, ++n, bhs, MAX_BUF_PER_PAGE);
+ if (err)
+ goto error_free;
-int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
- struct msdos_dir_entry **de, loff_t *i_pos)
-{
- struct super_block *sb = dir->i_sb;
- loff_t offset, curr;
- int row;
- struct buffer_head *new_bh;
+ return cluster[0];
- offset = curr = 0;
+error_free:
+ brelse(*bh);
*bh = NULL;
- row = 0;
- while (fat_get_entry(dir, &curr, bh, de, i_pos) > -1) {
+ n = 0;
+error_nomem:
+ for (i = 0; i < n; i++)
+ bforget(bhs[i]);
+ fat_free_clusters(dir, cluster[0]);
+error:
+ return err;
+}
+
+int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
+ struct fat_slot_info *sinfo)
+{
+ struct super_block *sb = dir->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ struct buffer_head *bh, *prev, *bhs[3]; /* 32*slots (672bytes) */
+ struct msdos_dir_entry *de;
+ int err, free_slots, i, nr_bhs;
+ loff_t pos, i_pos;
+
+ sinfo->nr_slots = nr_slots;
+
+ /* First stage: search free direcotry entries */
+ free_slots = nr_bhs = 0;
+ bh = prev = NULL;
+ pos = 0;
+ err = -ENOSPC;
+ while (fat_get_entry(dir, &pos, &bh, &de, &i_pos) > -1) {
/* check the maximum size of directory */
- if (curr >= FAT_MAX_DIR_SIZE) {
- brelse(*bh);
- return -ENOSPC;
- }
+ if (pos >= FAT_MAX_DIR_SIZE)
+ goto error;
- if (IS_FREE((*de)->name)) {
- if (++row == slots)
- return offset;
+ if (IS_FREE(de->name)) {
+ if (prev != bh) {
+ get_bh(bh);
+ bhs[nr_bhs] = prev = bh;
+ nr_bhs++;
+ }
+ free_slots++;
+ if (free_slots == nr_slots)
+ goto found;
} else {
- row = 0;
- offset = curr;
+ for (i = 0; i < nr_bhs; i++)
+ brelse(bhs[i]);
+ prev = NULL;
+ free_slots = nr_bhs = 0;
}
}
- if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32))
- return -ENOSPC;
- new_bh = fat_extend_dir(dir);
- if (IS_ERR(new_bh))
- return PTR_ERR(new_bh);
- brelse(new_bh);
- do {
- fat_get_entry(dir, &curr, bh, de, i_pos);
- } while (++row < slots);
+ if ((dir->i_ino == MSDOS_ROOT_INO) && (sbi->fat_bits != 32))
+ goto error;
+
+found:
+ err = 0;
+ pos -= free_slots * sizeof(*de);
+ nr_slots -= free_slots;
+ if (free_slots) {
+ /*
+ * Second stage: filling the free entries with new entries.
+ * NOTE: If this slots has shortname, first, we write
+ * the long name slots, then write the short name.
+ */
+ int size = free_slots * sizeof(*de);
+ int offset = pos & (sb->s_blocksize - 1);
+ int long_bhs = nr_bhs - (nr_slots == 0);
+
+ /* Fill the long name slots. */
+ for (i = 0; i < long_bhs; i++) {
+ int copy = min_t(int, sb->s_blocksize - offset, size);
+ memcpy(bhs[i]->b_data + offset, slots, copy);
+ mark_buffer_dirty(bhs[i]);
+ offset = 0;
+ slots += copy;
+ size -= copy;
+ }
+ if (long_bhs && IS_DIRSYNC(dir))
+ err = fat_sync_bhs(bhs, long_bhs);
+ if (!err && i < nr_bhs) {
+ /* Fill the short name slot. */
+ int copy = min_t(int, sb->s_blocksize - offset, size);
+ memcpy(bhs[i]->b_data + offset, slots, copy);
+ mark_buffer_dirty(bhs[i]);
+ if (IS_DIRSYNC(dir))
+ err = sync_dirty_buffer(bhs[i]);
+ }
+ for (i = 0; i < nr_bhs; i++)
+ brelse(bhs[i]);
+ if (err)
+ goto error_remove;
+ }
+
+ if (nr_slots) {
+ int cluster, nr_cluster;
- return offset;
+ /*
+ * Third stage: allocate the cluster for new entries.
+ * And initialize the cluster with new entries, then
+ * add the cluster to dir.
+ */
+ cluster = fat_add_new_entries(dir, slots, nr_slots, &nr_cluster,
+ &de, &bh, &i_pos);
+ if (cluster < 0) {
+ err = cluster;
+ goto error_remove;
+ }
+ err = fat_chain_add(dir, cluster, nr_cluster);
+ if (err) {
+ fat_free_clusters(dir, cluster);
+ goto error_remove;
+ }
+ if (dir->i_size & (sbi->cluster_size - 1)) {
+ fat_fs_panic(sb, "Odd directory size");
+ dir->i_size = (dir->i_size + sbi->cluster_size - 1)
+ & ~((loff_t)sbi->cluster_size - 1);
+ }
+ dir->i_size += nr_cluster << sbi->cluster_bits;
+ MSDOS_I(dir)->mmu_private += nr_cluster << sbi->cluster_bits;
+ }
+ sinfo->slot_off = pos;
+ sinfo->i_pos = i_pos;
+ sinfo->de = de;
+ sinfo->bh = bh;
+
+ return 0;
+
+error:
+ brelse(bh);
+ for (i = 0; i < nr_bhs; i++)
+ brelse(bhs[i]);
+ return err;
+
+error_remove:
+ brelse(bh);
+ if (free_slots)
+ __fat_remove_entries(dir, pos, free_slots);
+ return err;
}
EXPORT_SYMBOL(fat_add_entries);
diff -puN fs/msdos/namei.c~sync07-fat_dir6 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync07-fat_dir6 2005-03-06 02:36:56.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c 2005-03-06 02:36:56.000000000 +0900
@@ -258,7 +258,7 @@ static int msdos_add_entry(struct inode
{
struct msdos_dir_entry de;
__le16 time, date;
- int offset;
+ int err;
memcpy(de.name, name, MSDOS_NAME);
de.attr = is_dir ? ATTR_DIR : ATTR_ARCH;
@@ -273,14 +273,9 @@ static int msdos_add_entry(struct inode
de.starthi = cpu_to_le16(cluster >> 16);
de.size = 0;
- offset = fat_add_entries(dir, 1, &sinfo->bh, &sinfo->de, &sinfo->i_pos);
- if (offset < 0)
- return offset;
- sinfo->slot_off = offset;
- sinfo->nr_slots = 1;
-
- memcpy(sinfo->de, &de, sizeof(de));
- mark_buffer_dirty(sinfo->bh);
+ err = fat_add_entries(dir, &de, 1, sinfo);
+ if (err)
+ return err;
dir->i_ctime = dir->i_mtime = *ts;
mark_inode_dirty(dir);
diff -puN fs/vfat/namei.c~sync07-fat_dir6 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync07-fat_dir6 2005-03-06 02:36:56.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:36:56.000000000 +0900
@@ -661,14 +661,9 @@ static int vfat_add_entry(struct inode *
int cluster, struct timespec *ts,
struct fat_slot_info *sinfo)
{
- struct super_block *sb = dir->i_sb;
struct msdos_dir_slot *slots;
unsigned int len;
- int err, i, nr_slots;
- loff_t offset;
- struct msdos_dir_entry *de, *dummy_de;
- struct buffer_head *bh, *dummy_bh;
- loff_t dummy_i_pos;
+ int err, nr_slots;
len = vfat_striptail_len(qname);
if (len == 0)
@@ -683,37 +678,13 @@ static int vfat_add_entry(struct inode *
if (err)
goto cleanup;
- /* build the empty directory entry of number of slots */
- offset =
- fat_add_entries(dir, nr_slots, &dummy_bh, &dummy_de, &dummy_i_pos);
- if (offset < 0) {
- err = offset;
+ err = fat_add_entries(dir, slots, nr_slots, sinfo);
+ if (err)
goto cleanup;
- }
- brelse(dummy_bh);
-
- /* Now create the new entry */
- bh = NULL;
- for (i = 0; i < nr_slots; i++) {
- if (fat_get_entry(dir, &offset, &bh, &de, &sinfo->i_pos) < 0) {
- err = -EIO;
- goto cleanup;
- }
- memcpy(de, slots + i, sizeof(struct msdos_dir_slot));
- mark_buffer_dirty(bh);
- if (sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(bh);
- }
/* update timestamp */
dir->i_ctime = dir->i_mtime = dir->i_atime = *ts;
mark_inode_dirty(dir);
-
- /* slots can't be less than 1 */
- sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * nr_slots;
- sinfo->nr_slots = nr_slots;
- sinfo->de = de;
- sinfo->bh = bh;
cleanup:
kfree(slots);
return err;
diff -puN include/linux/msdos_fs.h~sync07-fat_dir6 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync07-fat_dir6 2005-03-06 02:36:56.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:56.000000000 +0900
@@ -324,9 +324,6 @@ extern int fat_bmap(struct inode *inode,
extern struct file_operations fat_dir_operations;
extern int fat_search_long(struct inode *inode, const unsigned char *name,
int name_len, struct fat_slot_info *sinfo);
-extern int fat_add_entries(struct inode *dir, int slots,
- struct buffer_head **bh,
- struct msdos_dir_entry **de, loff_t *i_pos);
extern int fat_dir_empty(struct inode *dir);
extern int fat_subdirs(struct inode *dir);
extern int fat_scan(struct inode *dir, const unsigned char *name,
@@ -334,6 +331,8 @@ extern int fat_scan(struct inode *dir, c
extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
struct msdos_dir_entry **de, loff_t *i_pos);
extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts);
+extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
+ struct fat_slot_info *sinfo);
extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
/* fat/fatent.c */
_
Cleans up the msdos_rename(). (use the logic similar to vfat_rename().)
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/msdos/namei.c | 175 +++++++++++++++++++++++++++----------------------------
1 files changed, 89 insertions(+), 86 deletions(-)
diff -puN fs/msdos/namei.c~sync07-fat_dir3 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync07-fat_dir3 2005-03-06 02:36:47.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c 2005-03-06 02:36:47.000000000 +0900
@@ -458,146 +458,149 @@ unlink_done:
static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
struct dentry *old_dentry,
struct inode *new_dir, unsigned char *new_name,
- struct dentry *new_dentry,
- struct buffer_head *old_bh,
- struct msdos_dir_entry *old_de, loff_t old_i_pos,
- int is_hid)
-{
- struct fat_slot_info sinfo;
- struct buffer_head *new_bh = NULL, *dotdot_bh = NULL;
- struct msdos_dir_entry *new_de, *dotdot_de;
+ struct dentry *new_dentry, int is_hid)
+{
+ struct buffer_head *dotdot_bh;
+ struct msdos_dir_entry *dotdot_de;
+ loff_t dotdot_i_pos;
struct inode *old_inode, *new_inode;
- loff_t new_i_pos, dotdot_i_pos;
- int error;
- int is_dir;
+ struct fat_slot_info old_sinfo, sinfo;
+ int err, is_dir;
+ old_sinfo.bh = dotdot_bh = NULL;
old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode;
- is_dir = S_ISDIR(old_inode->i_mode);
- error = fat_scan(new_dir, new_name, &sinfo);
- if (!error) {
- new_i_pos = sinfo.i_pos;
- new_bh = sinfo.bh;
- new_de = sinfo.de;
- if (!new_inode)
- goto degenerate_case;
+ err = fat_scan(old_dir, old_name, &old_sinfo);
+ if (err) {
+ err = -EIO;
+ goto out;
}
+
+ is_dir = S_ISDIR(old_inode->i_mode);
if (is_dir) {
- if (new_inode) {
- error = fat_dir_empty(new_inode);
- if (error)
- goto out;
- }
if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
&dotdot_i_pos) < 0) {
- error = -EIO;
+ err = -EIO;
goto out;
}
}
- if (!new_bh) {
- error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de,
- &new_i_pos, is_dir, is_hid);
- if (error)
+
+ err = fat_scan(new_dir, new_name, &sinfo);
+ if (!err) {
+ brelse(sinfo.bh);
+ if (!new_inode) {
+ /* "foo" -> ".foo" case. just change the ATTR_HIDDEN */
+ if (sinfo.de != old_sinfo.de) {
+ err = -EINVAL;
+ goto out;
+ }
+ if (is_hid)
+ MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
+ else
+ MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
+ mark_inode_dirty(old_inode);
+
+ old_dir->i_version++;
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+ mark_inode_dirty(old_dir);
goto out;
+ }
}
- new_dir->i_version++;
-
- /* There we go */
+ if (new_inode) {
+ if (err)
+ goto out;
+ if (MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
+ /* WTF??? Cry and fail. */
+ printk(KERN_WARNING "msdos_rename: fs corrupted\n");
+ goto out;
+ }
- if (new_inode)
+ if (is_dir) {
+ err = fat_dir_empty(new_inode);
+ if (err)
+ goto out;
+ }
fat_detach(new_inode);
- old_de->name[0] = DELETED_FLAG;
- mark_buffer_dirty(old_bh);
+ } else {
+ err = msdos_add_entry(new_dir, new_name, &sinfo.bh, &sinfo.de,
+ &sinfo.i_pos, is_dir, is_hid);
+ if (err)
+ goto out;
+ brelse(sinfo.bh);
+ }
+ new_dir->i_version++;
+
+ old_sinfo.de->name[0] = DELETED_FLAG;
+ mark_buffer_dirty(old_sinfo.bh);
+ brelse(old_sinfo.bh);
+ old_sinfo.bh = NULL;
+ if (is_dir)
+ old_dir->i_nlink--;
fat_detach(old_inode);
- fat_attach(old_inode, new_i_pos);
+ fat_attach(old_inode, sinfo.i_pos);
if (is_hid)
MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
else
MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
mark_inode_dirty(old_inode);
+
old_dir->i_version++;
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(old_dir);
+
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(new_inode);
}
- if (dotdot_bh) {
- dotdot_de->start = cpu_to_le16(MSDOS_I(new_dir)->i_logstart);
- dotdot_de->starthi =
- cpu_to_le16((MSDOS_I(new_dir)->i_logstart) >> 16);
+ if (is_dir) {
+ int start = MSDOS_I(new_dir)->i_logstart;
+ dotdot_de->start = cpu_to_le16(start);
+ dotdot_de->starthi = cpu_to_le16(start >> 16);
mark_buffer_dirty(dotdot_bh);
- old_dir->i_nlink--;
- mark_inode_dirty(old_dir);
+
if (new_inode) {
new_inode->i_nlink--;
- mark_inode_dirty(new_inode);
} else {
new_dir->i_nlink++;
mark_inode_dirty(new_dir);
}
}
- error = 0;
out:
- brelse(new_bh);
brelse(dotdot_bh);
- return error;
-
-degenerate_case:
- error = -EINVAL;
- if (new_de != old_de)
- goto out;
- brelse(new_bh);
- if (is_hid)
- MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
- else
- MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
- mark_inode_dirty(old_inode);
- old_dir->i_version++;
- old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
- mark_inode_dirty(old_dir);
- return 0;
+ brelse(old_sinfo.bh);
+ return err;
}
/***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
- struct fat_slot_info sinfo;
- int error, is_hid, old_hid; /* if new file and old file are hidden */
unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
+ int err, is_hid;
lock_kernel();
- error = msdos_format_name(old_dentry->d_name.name,
- old_dentry->d_name.len, old_msdos_name,
- &MSDOS_SB(old_dir->i_sb)->options);
- if (error < 0)
- goto rename_done;
- error = msdos_format_name(new_dentry->d_name.name,
- new_dentry->d_name.len, new_msdos_name,
- &MSDOS_SB(new_dir->i_sb)->options);
- if (error < 0)
- goto rename_done;
+
+ err = msdos_format_name(old_dentry->d_name.name,
+ old_dentry->d_name.len, old_msdos_name,
+ &MSDOS_SB(old_dir->i_sb)->options);
+ if (err)
+ goto out;
+ err = msdos_format_name(new_dentry->d_name.name,
+ new_dentry->d_name.len, new_msdos_name,
+ &MSDOS_SB(new_dir->i_sb)->options);
+ if (err)
+ goto out;
is_hid =
(new_dentry->d_name.name[0] == '.') && (new_msdos_name[0] != '.');
- old_hid =
- (old_dentry->d_name.name[0] == '.') && (old_msdos_name[0] != '.');
- error = fat_scan(old_dir, old_msdos_name, &sinfo);
- if (error < 0)
- goto rename_done;
-
- error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
- new_dir, new_msdos_name, new_dentry,
- sinfo.bh, sinfo.de, sinfo.i_pos, is_hid);
- brelse(sinfo.bh);
-
-rename_done:
+ err = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
+ new_dir, new_msdos_name, new_dentry, is_hid);
+out:
unlock_kernel();
- return error;
+ return err;
}
static struct inode_operations msdos_dir_inode_operations = {
_
Use "struct fat_slot_info" for fat_scan(). But ".." entry can not provide
valid informations for inode, so add the fat_get_dotdot_entry() as
special case.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/dir.c | 41 +++++++++++++++++-----
fs/fat/inode.c | 2 -
fs/msdos/namei.c | 84 ++++++++++++++++++++++++++---------------------
fs/vfat/namei.c | 16 +++-----
include/linux/msdos_fs.h | 5 +-
5 files changed, 88 insertions(+), 60 deletions(-)
diff -puN fs/fat/dir.c~sync06-fat_dir-cleanup5 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync06-fat_dir-cleanup5 2005-03-06 02:36:35.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:36:35.000000000 +0900
@@ -510,9 +510,9 @@ ParseLong:
j = last_u;
lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry);
- if (!memcmp(de->name,MSDOS_DOT,11))
+ if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME))
inum = inode->i_ino;
- else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
+ else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
inum = parent_ino(filp->f_dentry);
} else {
struct inode *tmp = fat_iget(sb, i_pos);
@@ -695,6 +695,26 @@ static int fat_get_short_entry(struct in
return -ENOENT;
}
+/*
+ * The ".." entry can not provide the "struct fat_slot_info" informations
+ * for inode. So, this function provide the some informations only.
+ */
+int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
+ struct msdos_dir_entry **de, loff_t *i_pos)
+{
+ loff_t offset;
+
+ offset = 0;
+ *bh = NULL;
+ while (fat_get_short_entry(dir, &offset, bh, de, i_pos) >= 0) {
+ if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME))
+ return 0;
+ }
+ return -ENOENT;
+}
+
+EXPORT_SYMBOL(fat_get_dotdot_entry);
+
/* See if directory is empty */
int fat_dir_empty(struct inode *dir)
{
@@ -744,16 +764,17 @@ int fat_subdirs(struct inode *dir)
* Returns an error code or zero.
*/
int fat_scan(struct inode *dir, const unsigned char *name,
- struct buffer_head **bh, struct msdos_dir_entry **de,
- loff_t *i_pos)
+ struct fat_slot_info *sinfo)
{
- loff_t cpos;
-
- *bh = NULL;
- cpos = 0;
- while (fat_get_short_entry(dir, &cpos, bh, de, i_pos) >= 0) {
- if (!strncmp((*de)->name, name, MSDOS_NAME))
+ sinfo->slot_off = 0;
+ sinfo->bh = NULL;
+ while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh,
+ &sinfo->de, &sinfo->i_pos) >= 0) {
+ if (!strncmp(sinfo->de->name, name, MSDOS_NAME)) {
+ sinfo->slot_off -= sizeof(*sinfo->de);
+ sinfo->nr_slots = 1;
return 0;
+ }
}
return -ENOENT;
}
diff -puN fs/fat/inode.c~sync06-fat_dir-cleanup5 fs/fat/inode.c
--- linux-2.6.11/fs/fat/inode.c~sync06-fat_dir-cleanup5 2005-03-06 02:36:35.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/inode.c 2005-03-06 02:36:35.000000000 +0900
@@ -654,7 +654,7 @@ static struct dentry *fat_get_parent(str
lock_kernel();
- err = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &i_pos);
+ err = fat_get_dotdot_entry(child->d_inode, &bh, &de, &i_pos);
if (err) {
parent = ERR_PTR(err);
goto out;
diff -puN fs/msdos/namei.c~sync06-fat_dir-cleanup5 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync06-fat_dir-cleanup5 2005-03-06 02:36:35.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c 2005-03-06 02:36:35.000000000 +0900
@@ -140,26 +140,33 @@ static int msdos_find(struct inode *dir,
struct buffer_head **bh, struct msdos_dir_entry **de,
loff_t *i_pos)
{
+ struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
+ struct fat_slot_info sinfo;
unsigned char msdos_name[MSDOS_NAME];
- char dotsOK;
- int res;
+ int err;
- dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
- res = msdos_format_name(name, len, msdos_name,
- &MSDOS_SB(dir->i_sb)->options);
- if (res < 0)
+ err = msdos_format_name(name, len, msdos_name, &sbi->options);
+ if (err)
return -ENOENT;
- res = fat_scan(dir, msdos_name, bh, de, i_pos);
- if (!res && dotsOK) {
+
+ err = fat_scan(dir, msdos_name, &sinfo);
+ if (!err && sbi->options.dotsOK) {
if (name[0] == '.') {
- if (!((*de)->attr & ATTR_HIDDEN))
- res = -ENOENT;
+ if (!(sinfo.de->attr & ATTR_HIDDEN))
+ err = -ENOENT;
} else {
- if ((*de)->attr & ATTR_HIDDEN)
- res = -ENOENT;
+ if (sinfo.de->attr & ATTR_HIDDEN)
+ err = -ENOENT;
}
+ if (err)
+ brelse(sinfo.bh);
}
- return res;
+ if (!err) {
+ *i_pos = sinfo.i_pos;
+ *de = sinfo.de;
+ *bh = sinfo.bh;
+ }
+ return err;
}
/*
@@ -289,6 +296,7 @@ static int msdos_create(struct inode *di
struct nameidata *nd)
{
struct super_block *sb = dir->i_sb;
+ struct fat_slot_info sinfo;
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct inode *inode;
@@ -305,18 +313,18 @@ static int msdos_create(struct inode *di
}
is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
/* Have to do it due to foo vs. .foo conflicts */
- if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) {
- brelse(bh);
+ if (!fat_scan(dir, msdos_name, &sinfo)) {
+ brelse(sinfo.bh);
unlock_kernel();
return -EINVAL;
}
- inode = NULL;
+
res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid);
if (res) {
unlock_kernel();
return res;
}
- inode = fat_build_inode(dir->i_sb, de, i_pos);
+ inode = fat_build_inode(sb, de, i_pos);
brelse(bh);
if (IS_ERR(inode)) {
unlock_kernel();
@@ -372,6 +380,7 @@ rmdir_done:
static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct super_block *sb = dir->i_sb;
+ struct fat_slot_info sinfo;
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct inode *inode;
@@ -388,8 +397,11 @@ static int msdos_mkdir(struct inode *dir
}
is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
/* foo vs .foo situation */
- if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0)
- goto out_exist;
+ if (!fat_scan(dir, msdos_name, &sinfo)) {
+ brelse(sinfo.bh);
+ res = -EINVAL;
+ goto out_unlock;
+ }
res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid);
if (res)
@@ -400,7 +412,6 @@ static int msdos_mkdir(struct inode *dir
res = PTR_ERR(inode);
goto out_unlock;
}
- res = 0;
dir->i_nlink++;
inode->i_nlink = 2; /* no need to mark them dirty */
@@ -408,7 +419,6 @@ static int msdos_mkdir(struct inode *dir
res = fat_new_dir(inode, dir, 0);
if (res)
goto mkdir_error;
-
brelse(bh);
d_instantiate(dentry, inode);
res = 0;
@@ -429,11 +439,6 @@ mkdir_error:
fat_detach(inode);
iput(inode);
goto out_unlock;
-
-out_exist:
- brelse(bh);
- res = -EINVAL;
- goto out_unlock;
}
/***** Unlink a file */
@@ -474,6 +479,7 @@ static int do_msdos_rename(struct inode
struct msdos_dir_entry *old_de, loff_t old_i_pos,
int is_hid)
{
+ struct fat_slot_info sinfo;
struct buffer_head *new_bh = NULL, *dotdot_bh = NULL;
struct msdos_dir_entry *new_de, *dotdot_de;
struct inode *old_inode, *new_inode;
@@ -485,17 +491,22 @@ static int do_msdos_rename(struct inode
new_inode = new_dentry->d_inode;
is_dir = S_ISDIR(old_inode->i_mode);
- if (fat_scan(new_dir, new_name, &new_bh, &new_de, &new_i_pos) >= 0 &&
- !new_inode)
- goto degenerate_case;
+ error = fat_scan(new_dir, new_name, &sinfo);
+ if (!error) {
+ new_i_pos = sinfo.i_pos;
+ new_bh = sinfo.bh;
+ new_de = sinfo.de;
+ if (!new_inode)
+ goto degenerate_case;
+ }
if (is_dir) {
if (new_inode) {
error = fat_dir_empty(new_inode);
if (error)
goto out;
}
- if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
- &dotdot_de, &dotdot_i_pos) < 0) {
+ if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
+ &dotdot_i_pos) < 0) {
error = -EIO;
goto out;
}
@@ -554,6 +565,7 @@ degenerate_case:
error = -EINVAL;
if (new_de != old_de)
goto out;
+ brelse(new_bh);
if (is_hid)
MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
else
@@ -569,9 +581,7 @@ degenerate_case:
static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
- struct buffer_head *old_bh;
- struct msdos_dir_entry *old_de;
- loff_t old_i_pos;
+ struct fat_slot_info sinfo;
int error, is_hid, old_hid; /* if new file and old file are hidden */
unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
@@ -592,14 +602,14 @@ static int msdos_rename(struct inode *ol
old_hid =
(old_dentry->d_name.name[0] == '.') && (old_msdos_name[0] != '.');
- error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_i_pos);
+ error = fat_scan(old_dir, old_msdos_name, &sinfo);
if (error < 0)
goto rename_done;
error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
new_dir, new_msdos_name, new_dentry,
- old_bh, old_de, old_i_pos, is_hid);
- brelse(old_bh);
+ sinfo.bh, sinfo.de, sinfo.i_pos, is_hid);
+ brelse(sinfo.bh);
rename_done:
unlock_kernel();
diff -puN fs/vfat/namei.c~sync06-fat_dir-cleanup5 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync06-fat_dir-cleanup5 2005-03-06 02:36:35.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:36:35.000000000 +0900
@@ -208,15 +208,11 @@ static int vfat_valid_longname(const uns
static int vfat_find_form(struct inode *dir, unsigned char *name)
{
- struct msdos_dir_entry *de;
- struct buffer_head *bh = NULL;
- loff_t i_pos;
- int res;
-
- res = fat_scan(dir, name, &bh, &de, &i_pos);
- brelse(bh);
- if (res < 0)
+ struct fat_slot_info sinfo;
+ int err = fat_scan(dir, name, &sinfo);
+ if (err)
return -ENOENT;
+ brelse(sinfo.bh);
return 0;
}
@@ -938,8 +934,8 @@ static int vfat_rename(struct inode *old
is_dir = S_ISDIR(old_inode->i_mode);
if (is_dir) {
- if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
- &dotdot_de, &dotdot_i_pos) < 0) {
+ if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
+ &dotdot_i_pos) < 0) {
err = -EIO;
goto out;
}
diff -puN include/linux/msdos_fs.h~sync06-fat_dir-cleanup5 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync06-fat_dir-cleanup5 2005-03-06 02:36:35.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:35.000000000 +0900
@@ -331,8 +331,9 @@ extern int fat_new_dir(struct inode *dir
extern int fat_dir_empty(struct inode *dir);
extern int fat_subdirs(struct inode *dir);
extern int fat_scan(struct inode *dir, const unsigned char *name,
- struct buffer_head **res_bh,
- struct msdos_dir_entry **res_de, loff_t *i_pos);
+ struct fat_slot_info *sinfo);
+extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
+ struct msdos_dir_entry **de, loff_t *i_pos);
extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
/* fat/fatent.c */
_
Instead of
mark_inode_dirty(inode);
if (IS_SYNC(inode))
fat_sync_inode(inode);
use this
if (IS_SYNC(inode))
fat_sync_inode(inode);
else
mark_inode_dirty(inode);
And if occurs a error, restore the ->i_start and ->i_logstart.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/file.c | 40 +++++++++++++++++++++++-----------------
1 files changed, 23 insertions(+), 17 deletions(-)
diff -puN fs/fat/file.c~sync08-fat_tweak5 fs/fat/file.c
--- linux-2.6.11/fs/fat/file.c~sync08-fat_tweak5 2005-03-06 02:37:23.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/file.c 2005-03-06 02:37:24.000000000 +0900
@@ -212,7 +212,7 @@ EXPORT_SYMBOL(fat_notify_change);
static int fat_free(struct inode *inode, int skip)
{
struct super_block *sb = inode->i_sb;
- int ret, wait;
+ int err, wait, free_start, i_start, i_logstart;
if (MSDOS_I(inode)->i_start == 0)
return 0;
@@ -223,7 +223,7 @@ static int fat_free(struct inode *inode,
wait = IS_DIRSYNC(inode);
if (skip) {
struct fat_entry fatent;
- int fclus, dclus;
+ int ret, fclus, dclus;
ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus);
if (ret < 0)
@@ -242,8 +242,7 @@ static int fat_free(struct inode *inode,
__FUNCTION__, MSDOS_I(inode)->i_pos);
ret = -EIO;
} else if (ret > 0) {
- int err = fat_ent_write(inode, &fatent, FAT_ENT_EOF,
- wait);
+ err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait);
if (err)
ret = err;
}
@@ -251,24 +250,36 @@ static int fat_free(struct inode *inode,
if (ret < 0)
return ret;
+ free_start = ret;
+ i_start = i_logstart = 0;
fat_cache_inval_inode(inode);
} else {
fat_cache_inval_inode(inode);
- ret = MSDOS_I(inode)->i_start;
+ i_start = free_start = MSDOS_I(inode)->i_start;
+ i_logstart = MSDOS_I(inode)->i_logstart;
MSDOS_I(inode)->i_start = 0;
MSDOS_I(inode)->i_logstart = 0;
- if (wait) {
- int err = fat_sync_inode(inode);
- if (err)
- return err;
- } else
- mark_inode_dirty(inode);
}
+ MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ if (wait) {
+ err = fat_sync_inode(inode);
+ if (err)
+ goto error;
+ } else
+ mark_inode_dirty(inode);
inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);
/* Freeing the remained cluster chain */
- return fat_free_clusters(inode, ret);
+ return fat_free_clusters(inode, free_start);
+
+error:
+ if (i_start) {
+ MSDOS_I(inode)->i_start = i_start;
+ MSDOS_I(inode)->i_logstart = i_logstart;
+ }
+ return err;
}
void fat_truncate(struct inode *inode)
@@ -288,12 +299,7 @@ void fat_truncate(struct inode *inode)
lock_kernel();
fat_free(inode, nr_clusters);
- MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
unlock_kernel();
- inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
- mark_inode_dirty(inode);
- if (IS_SYNC(inode))
- fat_sync_inode(inode);
}
struct inode_operations fat_file_inode_operations = {
_
With this change, ->mkdir() uses the correct updating order.
Signed-off-by: OGAWA Hirofumi <[email protected]>
---
fs/fat/dir.c | 155 +++++++++++++++++++++++++++++++++--------------
fs/fat/fatent.c | 3
fs/msdos/namei.c | 54 +++++++---------
fs/vfat/namei.c | 59 ++++++++---------
include/linux/msdos_fs.h | 2
5 files changed, 169 insertions(+), 104 deletions(-)
diff -puN fs/fat/dir.c~sync07-fat_dir5 fs/fat/dir.c
--- linux-2.6.11/fs/fat/dir.c~sync07-fat_dir5 2005-03-06 02:36:53.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/dir.c 2005-03-06 02:36:53.000000000 +0900
@@ -869,6 +869,118 @@ int fat_remove_entries(struct inode *dir
EXPORT_SYMBOL(fat_remove_entries);
+static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used,
+ struct buffer_head **bhs, int nr_bhs)
+{
+ struct super_block *sb = dir->i_sb;
+ sector_t last_blknr = blknr + MSDOS_SB(sb)->sec_per_clus;
+ int err, i, n;
+
+ /* Zeroing the unused blocks on this cluster */
+ blknr += nr_used;
+ n = nr_used;
+ while (blknr < last_blknr) {
+ bhs[n] = sb_getblk(sb, blknr);
+ if (!bhs[n]) {
+ err = -ENOMEM;
+ goto error;
+ }
+ memset(bhs[n]->b_data, 0, sb->s_blocksize);
+ set_buffer_uptodate(bhs[n]);
+ mark_buffer_dirty(bhs[n]);
+
+ n++;
+ blknr++;
+ if (n == nr_bhs) {
+ if (IS_DIRSYNC(dir)) {
+ err = fat_sync_bhs(bhs, n);
+ if (err)
+ goto error;
+ }
+ for (i = 0; i < n; i++)
+ brelse(bhs[i]);
+ n = 0;
+ }
+ }
+ if (IS_DIRSYNC(dir)) {
+ err = fat_sync_bhs(bhs, n);
+ if (err)
+ goto error;
+ }
+ for (i = 0; i < n; i++)
+ brelse(bhs[i]);
+
+ return 0;
+
+error:
+ for (i = 0; i < n; i++)
+ bforget(bhs[i]);
+ return err;
+}
+
+int fat_alloc_new_dir(struct inode *dir, struct timespec *ts)
+{
+ struct super_block *sb = dir->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ struct buffer_head *bhs[MAX_BUF_PER_PAGE];
+ struct msdos_dir_entry *de;
+ sector_t blknr;
+ __le16 date, time;
+ int err, cluster;
+
+ err = fat_alloc_clusters(dir, &cluster, 1);
+ if (err)
+ goto error;
+
+ blknr = fat_clus_to_blknr(sbi, cluster);
+ bhs[0] = sb_getblk(sb, blknr);
+ if (!bhs[0]) {
+ err = -ENOMEM;
+ goto error_free;
+ }
+
+ fat_date_unix2dos(ts->tv_sec, &time, &date);
+
+ de = (struct msdos_dir_entry *)bhs[0]->b_data;
+ /* filling the new directory slots ("." and ".." entries) */
+ memcpy(de[0].name, MSDOS_DOT, MSDOS_NAME);
+ memcpy(de[1].name, MSDOS_DOTDOT, MSDOS_NAME);
+ de->attr = de[1].attr = ATTR_DIR;
+ de[0].lcase = de[1].lcase = 0;
+ de[0].time = de[1].time = time;
+ de[0].date = de[1].date = date;
+ de[0].ctime_cs = de[1].ctime_cs = 0;
+ if (sbi->options.isvfat) {
+ /* extra timestamps */
+ de[0].ctime = de[1].ctime = time;
+ de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date;
+ } else {
+ de[0].ctime = de[1].ctime = 0;
+ de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0;
+ }
+ de[0].start = cpu_to_le16(cluster);
+ de[0].starthi = cpu_to_le16(cluster >> 16);
+ de[1].start = cpu_to_le16(MSDOS_I(dir)->i_logstart);
+ de[1].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart >> 16);
+ de[0].size = de[1].size = 0;
+ memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de));
+ set_buffer_uptodate(bhs[0]);
+ mark_buffer_dirty(bhs[0]);
+
+ err = fat_zeroed_cluster(dir, blknr, 1, bhs, MAX_BUF_PER_PAGE);
+ if (err)
+ goto error_free;
+
+ return cluster;
+
+error_free:
+ fat_free_clusters(dir, cluster);
+error:
+ return err;
+}
+
+EXPORT_SYMBOL(fat_alloc_new_dir);
+
static struct buffer_head *fat_extend_dir(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
@@ -960,46 +1072,3 @@ int fat_add_entries(struct inode *dir,in
}
EXPORT_SYMBOL(fat_add_entries);
-
-int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
-{
- struct super_block *sb = dir->i_sb;
- struct buffer_head *bh;
- struct msdos_dir_entry *de;
- __le16 date, time;
-
- bh = fat_extend_dir(dir);
- if (IS_ERR(bh))
- return PTR_ERR(bh);
-
- /* zeroed out, so... */
- fat_date_unix2dos(dir->i_mtime.tv_sec, &time, &date);
- de = (struct msdos_dir_entry *)bh->b_data;
- memcpy(de[0].name, MSDOS_DOT, MSDOS_NAME);
- memcpy(de[1].name, MSDOS_DOTDOT, MSDOS_NAME);
- de[0].attr = de[1].attr = ATTR_DIR;
- de[0].time = de[1].time = time;
- de[0].date = de[1].date = date;
- if (is_vfat) {
- /* extra timestamps */
- de[0].ctime = de[1].ctime = time;
- de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date;
- }
- de[0].start = cpu_to_le16(MSDOS_I(dir)->i_logstart);
- de[0].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart >> 16);
- de[1].start = cpu_to_le16(MSDOS_I(parent)->i_logstart);
- de[1].starthi = cpu_to_le16(MSDOS_I(parent)->i_logstart >> 16);
- mark_buffer_dirty(bh);
- if (sb->s_flags & MS_SYNCHRONOUS)
- sync_dirty_buffer(bh);
- brelse(bh);
-
- dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
- mark_inode_dirty(dir);
- if (IS_SYNC(dir))
- fat_sync_inode(dir);
-
- return 0;
-}
-
-EXPORT_SYMBOL(fat_new_dir);
diff -puN fs/fat/fatent.c~sync07-fat_dir5 fs/fat/fatent.c
--- linux-2.6.11/fs/fat/fatent.c~sync07-fat_dir5 2005-03-06 02:36:53.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/fat/fatent.c 2005-03-06 02:36:53.000000000 +0900
@@ -3,6 +3,7 @@
* Released under GPL v2.
*/
+#include <linux/module.h>
#include <linux/fs.h>
#include <linux/msdos_fs.h>
@@ -577,6 +578,8 @@ error:
return err;
}
+EXPORT_SYMBOL(fat_free_clusters);
+
int fat_count_free_clusters(struct super_block *sb)
{
struct msdos_sb_info *sbi = MSDOS_SB(sb);
diff -puN fs/msdos/namei.c~sync07-fat_dir5 fs/msdos/namei.c
--- linux-2.6.11/fs/msdos/namei.c~sync07-fat_dir5 2005-03-06 02:36:53.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/msdos/namei.c 2005-03-06 02:36:53.000000000 +0900
@@ -253,8 +253,8 @@ out:
/***** Creates a directory entry (name is already formatted). */
static int msdos_add_entry(struct inode *dir, const unsigned char *name,
- int is_dir, int is_hid, struct timespec *ts,
- struct fat_slot_info *sinfo)
+ int is_dir, int is_hid, int cluster,
+ struct timespec *ts, struct fat_slot_info *sinfo)
{
struct msdos_dir_entry de;
__le16 time, date;
@@ -269,8 +269,8 @@ static int msdos_add_entry(struct inode
de.time = de.ctime = time;
de.date = de.cdate = de.adate = date;
de.ctime_cs = 0;
- de.start = 0;
- de.starthi = 0;
+ de.start = cpu_to_le16(cluster);
+ de.starthi = cpu_to_le16(cluster >> 16);
de.size = 0;
offset = fat_add_entries(dir, 1, &sinfo->bh, &sinfo->de, &sinfo->i_pos);
@@ -314,7 +314,7 @@ static int msdos_create(struct inode *di
}
ts = CURRENT_TIME_SEC;
- err = msdos_add_entry(dir, msdos_name, 0, is_hid, &ts, &sinfo);
+ err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo);
if (err)
goto out;
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
@@ -375,7 +375,7 @@ static int msdos_mkdir(struct inode *dir
struct inode *inode;
unsigned char msdos_name[MSDOS_NAME];
struct timespec ts;
- int err, is_hid;
+ int err, is_hid, cluster;
lock_kernel();
@@ -392,43 +392,37 @@ static int msdos_mkdir(struct inode *dir
}
ts = CURRENT_TIME_SEC;
- err = msdos_add_entry(dir, msdos_name, 1, is_hid, &ts, &sinfo);
- if (err)
+ cluster = fat_alloc_new_dir(dir, &ts);
+ if (cluster < 0) {
+ err = cluster;
goto out;
+ }
+ err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
+ if (err)
+ goto out_free;
+ dir->i_nlink++;
+
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+ brelse(sinfo.bh);
if (IS_ERR(inode)) {
- brelse(sinfo.bh);
err = PTR_ERR(inode);
+ /* the directory was completed, just return a error */
goto out;
}
+ inode->i_nlink = 2; /* no need to mark them dirty */
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
- dir->i_nlink++;
- inode->i_nlink = 2; /* no need to mark them dirty */
+ d_instantiate(dentry, inode);
- err = fat_new_dir(inode, dir, 0);
- if (err)
- goto mkdir_error;
- brelse(sinfo.bh);
+ unlock_kernel();
+ return 0;
- d_instantiate(dentry, inode);
+out_free:
+ fat_free_clusters(dir, cluster);
out:
unlock_kernel();
return err;
-
-mkdir_error:
- inode->i_nlink = 0;
- inode->i_ctime = dir->i_ctime = dir->i_mtime = ts;
- dir->i_nlink--;
- mark_inode_dirty(inode);
- mark_inode_dirty(dir);
- sinfo.de->name[0] = DELETED_FLAG;
- mark_buffer_dirty(sinfo.bh);
- brelse(sinfo.bh);
- fat_detach(inode);
- iput(inode);
- goto out;
}
/***** Unlink a file */
@@ -529,7 +523,7 @@ static int do_msdos_rename(struct inode
}
fat_detach(new_inode);
} else {
- err = msdos_add_entry(new_dir, new_name, is_dir, is_hid,
+ err = msdos_add_entry(new_dir, new_name, is_dir, is_hid, 0,
&ts, &sinfo);
if (err)
goto out;
diff -puN fs/vfat/namei.c~sync07-fat_dir5 fs/vfat/namei.c
--- linux-2.6.11/fs/vfat/namei.c~sync07-fat_dir5 2005-03-06 02:36:53.000000000 +0900
+++ linux-2.6.11-hirofumi/fs/vfat/namei.c 2005-03-06 02:36:53.000000000 +0900
@@ -658,7 +658,7 @@ out_free:
}
static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,
- struct timespec *ts,
+ int cluster, struct timespec *ts,
struct fat_slot_info *sinfo)
{
struct super_block *sb = dir->i_sb;
@@ -678,7 +678,7 @@ static int vfat_add_entry(struct inode *
if (slots == NULL)
return -ENOMEM;
- err = vfat_build_slots(dir, qname->name, len, is_dir, 0, ts,
+ err = vfat_build_slots(dir, qname->name, len, is_dir, cluster, ts,
slots, &nr_slots);
if (err)
goto cleanup;
@@ -787,9 +787,11 @@ static int vfat_create(struct inode *dir
lock_kernel();
ts = CURRENT_TIME_SEC;
- err = vfat_add_entry(dir, &dentry->d_name, 0, &ts, &sinfo);
+ err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo);
if (err)
goto out;
+ dir->i_version++;
+
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh);
if (IS_ERR(inode)) {
@@ -800,7 +802,6 @@ static int vfat_create(struct inode *dir
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
- dir->i_version++;
dentry->d_time = dentry->d_parent->d_inode->i_version;
d_instantiate(dentry, inode);
out:
@@ -866,50 +867,48 @@ out:
static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct super_block *sb = dir->i_sb;
- struct inode *inode = NULL;
+ struct inode *inode;
struct fat_slot_info sinfo;
struct timespec ts;
- int err;
+ int err, cluster;
lock_kernel();
ts = CURRENT_TIME_SEC;
- err = vfat_add_entry(dir, &dentry->d_name, 1, &ts, &sinfo);
- if (err)
+ cluster = fat_alloc_new_dir(dir, &ts);
+ if (cluster < 0) {
+ err = cluster;
goto out;
+ }
+ err = vfat_add_entry(dir, &dentry->d_name, 1, cluster, &ts, &sinfo);
+ if (err)
+ goto out_free;
+ dir->i_version++;
+ dir->i_nlink++;
+
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+ brelse(sinfo.bh);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
- goto out_brelse;
+ /* the directory was completed, just return a error */
+ goto out;
}
inode->i_version++;
+ inode->i_nlink = 2; /* no need to mark them dirty */
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
- dir->i_version++;
- dir->i_nlink++;
- inode->i_nlink = 2; /* no need to mark them dirty */
- err = fat_new_dir(inode, dir, 1);
- if (err)
- goto mkdir_failed;
-
dentry->d_time = dentry->d_parent->d_inode->i_version;
d_instantiate(dentry, inode);
-out_brelse:
- brelse(sinfo.bh);
+
+ unlock_kernel();
+ return 0;
+
+out_free:
+ fat_free_clusters(dir, cluster);
out:
unlock_kernel();
return err;
-
-mkdir_failed:
- inode->i_nlink = 0;
- inode->i_mtime = inode->i_atime = ts;
- fat_detach(inode);
- mark_inode_dirty(inode);
- fat_remove_entries(dir, &sinfo); /* and releases bh */
- iput(inode);
- dir->i_nlink--;
- goto out;
}
static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -959,8 +958,8 @@ static int vfat_rename(struct inode *old
}
fat_detach(new_inode);
} else {
- err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, &ts,
- &sinfo);
+ err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, 0,
+ &ts, &sinfo);
if (err)
goto out;
brelse(sinfo.bh);
diff -puN include/linux/msdos_fs.h~sync07-fat_dir5 include/linux/msdos_fs.h
--- linux-2.6.11/include/linux/msdos_fs.h~sync07-fat_dir5 2005-03-06 02:36:53.000000000 +0900
+++ linux-2.6.11-hirofumi/include/linux/msdos_fs.h 2005-03-06 02:36:53.000000000 +0900
@@ -327,13 +327,13 @@ extern int fat_search_long(struct inode
extern int fat_add_entries(struct inode *dir, int slots,
struct buffer_head **bh,
struct msdos_dir_entry **de, loff_t *i_pos);
-extern int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat);
extern int fat_dir_empty(struct inode *dir);
extern int fat_subdirs(struct inode *dir);
extern int fat_scan(struct inode *dir, const unsigned char *name,
struct fat_slot_info *sinfo);
extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
struct msdos_dir_entry **de, loff_t *i_pos);
+extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts);
extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
/* fat/fatent.c */
_
[It seems that my first e-mail was lost, so this is re-post. If you
received duplicated email, sorry.]
Hi,
These patches adds the `-o sync' and `-o dirsync' supports to fatfs.
If user specified that option, the fatfs does traditional ordered
updates by using synchronous writes. If compared to before, these
patches will show a improvement of robustness I think.
`-o sync' - writes all buffers out before returning from syscall.
`-o dirsync' - writes the directory's metadata, and unreferencing
operations of data block.
remaining to be done
fat_generic_ioctl(), fat_notify_change(),
ATTR_ARCH of fat_xxx_write[v],
and probably, filling hole in cont_prepare_write(),
NOTE: Since fatfs doesn't have link-count, unfortunately ->rename() is
not safe order at all. It may make the shared blocks, but user
shouldn't lose the data by ->rename().
Please apply.
--
OGAWA Hirofumi <[email protected]>
On Sun, Mar 06, 2005 at 03:42:28AM +0900, OGAWA Hirofumi wrote:
> +/* <linux/videotext.h> has used 0x72 ('r') in collision, so skip a few */
These ioctls in videotext.h have been removed with 2.6.11. They were not used anywhere in the
kernel.
Michael
[email protected] (Michael Geng) writes:
> On Sun, Mar 06, 2005 at 03:42:28AM +0900, OGAWA Hirofumi wrote:
>> +/* <linux/videotext.h> has used 0x72 ('r') in collision, so skip a few */
>
> These ioctls in videotext.h have been removed with 2.6.11. They were not used anywhere in the
> kernel.
Thanks. I think we still had better skip them, because the app such
as strace can handle it easily.
--
OGAWA Hirofumi <[email protected]>
On Sun, Mar 06, 2005 at 04:53:29PM +0100, Michael Geng wrote:
> On Sun, Mar 06, 2005 at 03:42:28AM +0900, OGAWA Hirofumi wrote:
> > +/* <linux/videotext.h> has used 0x72 ('r') in collision, so skip a few */
>
> These ioctls in videotext.h have been removed with 2.6.11. They were not used anywhere in the
> kernel.
I'd rather avoid the collision anyway.
On Sun, Mar 06, 2005 at 03:56:51AM +0900, OGAWA Hirofumi wrote:
>
> Since MSDOS_SB() is inline function, it increases text size at each calls.
> I don't know whether there is __attribute__ for avoiding this.
If you mark it pure the compile should be smart enough to optimize way
multiple invocations - heck for an inline it should be smart enough without
annotaitons..
Anyway, your new version looks much more readable.
> 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);
}
Christoph Hellwig <[email protected]> writes:
>> mark_buffer_dirty(bh);
>> + if (sb->s_flags & MS_SYNCHRONOUS)
>> + sync_dirty_buffer(bh);
>
> These three lines are duplicated a lot. I think you want a helper ala:
>
> static inline void fat_buffer_modified(struct super_block *sb,
> struct buffer_head *bh)
> {
> mark_buffer_dirty(bh);
> if (sb->s_flags & MS_SYNCHRONOUS)
> sync_dirty_buffer(bh);
> }
Yes, I may want the following helper. However I'll put it as is for now.
static inline void fat_buffer_modified(struct super_block *sb,
struct buffer_head *bh, int wait)
{
int err = 0;
mark_buffer_dirty(bh);
if (wait)
err = sync_dirty_buffer(bh);
return err;
}
--
OGAWA Hirofumi <[email protected]>
On Sun, Mar 06, 2005 at 03:56:51AM +0900, OGAWA Hirofumi wrote:
>
> Since MSDOS_SB() is inline function, it increases text size at each calls.
> I don't know whether there is __attribute__ for avoiding this.
>
> This removes the multiple call.
>...
"inline" in the kernel is (for recent gcc's) mapped to
__attribute__((always_inline)), and therefore the
"static inline struct msdos_sb_info *MSDOS_SB" does exactly the opposite
of what you want.
You'd have to move this into a .c file to remove the "inline".
But considering that the whole function is
static inline struct msdos_sb_info *MSDOS_SB(struct super_block *sb)
{
return sb->s_fs_info;
}
I'm quite surprised that there's any problem with it.
cu
Adrian
--
"Is there not promise of rain?" Ling Tan asked suddenly out
of the darkness. There had been need of rain for many days.
"Only a promise," Lao Er said.
Pearl S. Buck - Dragon Seed
Adrian Bunk <[email protected]> writes:
> On Sun, Mar 06, 2005 at 03:56:51AM +0900, OGAWA Hirofumi wrote:
>>
>> Since MSDOS_SB() is inline function, it increases text size at each calls.
>> I don't know whether there is __attribute__ for avoiding this.
>>
>> This removes the multiple call.
>>...
[...]
> static inline struct msdos_sb_info *MSDOS_SB(struct super_block *sb)
> {
> return sb->s_fs_info;
> }
>
> I'm quite surprised that there's any problem with it.
Whoops, actually the cause was not inline. Sorry.
#define MSDOS_SB(x) ((struct msdos_sb_info *)(x)->s_fs_info)
was same result. This just needed my patch.
--
OGAWA Hirofumi <[email protected]>