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 */
_
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to