summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorAndrew Morton <akpm@zip.com.au>2002-05-27 05:13:29 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-05-27 05:13:29 -0700
commitbb772c58ab8542b34162f356faac2ed18fb7afe4 (patch)
treecba428387bc8268d704ee4fea4fff9f8418e2c2c /fs
parent7d608fac351b06ae0192bba9e116a965c2f35c5d (diff)
[PATCH] dirsync
An implementation of directory-synchronous mounts. I sent this out some months ago and it didn't generate a lot of interest. Later we had one of the usual cheery exchanges with Wietse Venema (postfix development) and he agreed that directory synchronous mounts were something that he could use, and that there was benefit in implementing them in Linux. If you choose to apply this I'll push the 2.4 patch. Patch against e2fsprogs-1.26: http://www.zip.com.au/~akpm/linux/dirsync/e2fsprogs-1.26.patch Patch against util-linux-2.11n: http://www.zip.com.au/~akpm/linux/dirsync/util-linux-2.11n.patch The kernel patch includes implementations for ext2 and ext3. It's pretty simple. - When dirsync is in operation against a directory, the following operations are synchronous within that directory: create, link, unlink, symlink, mkdir, rmdir, mknod, rename (synchronous if either the source or dest directory is dirsync). - dirsync is a subset of sync. So `mount -o sync' or `chattr +S' give you everything which `mount -o dirsync' or `chattr +D' gives, plus synchronous file writes. - ext2's inode.i_attr_flags is unused, and is removed. - mount /dev/foo /mnt/bar -o dirsync works as expected. - An ext2 or ext3 directory tree can be set dirsync with `chattr +D -R'. - dirsync is maintained as new directories are created under a `chattr +D' directory. Like `chattr +S'. - Other filesystems can trivially be taught about dirsync. It's just a matter of replacing `IS_SYNC(inode)' with `IS_DIRSYNC(inode)' in the directory update functions. IS_SYNC will still be honoured when IS_DIRSYNC is used. - Non-directory files do not have their dirsync flag propagated. So an S_ISREG file which is created inside a dirsync directory will not have its dirsync bit set. chattr needs to do this as well. - There was a bit of version skew between e2fsprogs' idea of the inode flags and the kernel's. That is sorted out here. - `lsattr' shows the dirsync flag as "D". The letter "D" was previously being used for Compressed_Dirty_File. I changed Compressed_Dirty_File to use "Z". Is that OK? The mount(2) manpage needs to be taught about MS_DIRSYNC.
Diffstat (limited to 'fs')
-rw-r--r--fs/ext2/dir.c2
-rw-r--r--fs/ext2/ialloc.c5
-rw-r--r--fs/ext2/inode.c21
-rw-r--r--fs/ext2/ioctl.c3
-rw-r--r--fs/ext3/ialloc.c7
-rw-r--r--fs/ext3/inode.c17
-rw-r--r--fs/ext3/ioctl.c3
-rw-r--r--fs/ext3/namei.c16
-rw-r--r--fs/inode.c9
-rw-r--r--fs/namespace.c1
10 files changed, 46 insertions, 38 deletions
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index abce0f410b4c..9789a5bcf932 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -68,7 +68,7 @@ static int ext2_commit_chunk(struct page *page, unsigned from, unsigned to)
int err = 0;
dir->i_version = ++event;
page->mapping->a_ops->commit_write(NULL, page, from, to);
- if (IS_SYNC(dir))
+ if (IS_DIRSYNC(dir))
err = write_one_page(page, 1);
else
unlock_page(page);
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index e721d2618ed3..26f53a854a9b 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -429,6 +429,9 @@ repeat:
ei->i_flags = EXT2_I(dir)->i_flags;
if (S_ISLNK(mode))
ei->i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL);
+ /* dirsync is only applied to directories */
+ if (!S_ISDIR(mode))
+ ei->i_flags &= ~EXT2_DIRSYNC_FL;
ei->i_faddr = 0;
ei->i_frag_no = 0;
ei->i_frag_size = 0;
@@ -443,6 +446,8 @@ repeat:
ei->i_dir_start_lookup = 0;
if (ei->i_flags & EXT2_SYNC_FL)
inode->i_flags |= S_SYNC;
+ if (ei->i_flags & EXT2_DIRSYNC_FL)
+ inode->i_flags |= S_DIRSYNC;
inode->i_generation = EXT2_SB(sb)->s_next_generation++;
insert_inode_hash(inode);
mark_inode_dirty(inode);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 90a328070b73..089d4955d6d9 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -58,7 +58,7 @@ void ext2_delete_inode (struct inode * inode)
goto no_delete;
EXT2_I(inode)->i_dtime = CURRENT_TIME;
mark_inode_dirty(inode);
- ext2_update_inode(inode, IS_SYNC(inode));
+ ext2_update_inode(inode, inode_needs_sync(inode));
inode->i_size = 0;
if (inode->i_blocks)
@@ -905,7 +905,7 @@ do_indirects:
;
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- if (IS_SYNC(inode)) {
+ if (inode_needs_sync(inode)) {
sync_mapping_buffers(inode->i_mapping);
ext2_sync_inode (inode);
} else {
@@ -1039,23 +1039,14 @@ void ext2_read_inode (struct inode * inode)
init_special_inode(inode, inode->i_mode,
le32_to_cpu(raw_inode->i_block[0]));
brelse (bh);
- inode->i_attr_flags = 0;
- if (ei->i_flags & EXT2_SYNC_FL) {
- inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS;
+ if (ei->i_flags & EXT2_SYNC_FL)
inode->i_flags |= S_SYNC;
- }
- if (ei->i_flags & EXT2_APPEND_FL) {
- inode->i_attr_flags |= ATTR_FLAG_APPEND;
+ if (ei->i_flags & EXT2_APPEND_FL)
inode->i_flags |= S_APPEND;
- }
- if (ei->i_flags & EXT2_IMMUTABLE_FL) {
- inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;
+ if (ei->i_flags & EXT2_IMMUTABLE_FL)
inode->i_flags |= S_IMMUTABLE;
- }
- if (ei->i_flags & EXT2_NOATIME_FL) {
- inode->i_attr_flags |= ATTR_FLAG_NOATIME;
+ if (ei->i_flags & EXT2_NOATIME_FL)
inode->i_flags |= S_NOATIME;
- }
return;
bad_inode:
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 680eb331a821..7f75479b2694 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -36,6 +36,9 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
if (get_user(flags, (int *) arg))
return -EFAULT;
+ if (!S_ISDIR(inode->i_mode))
+ flags &= ~EXT2_DIRSYNC_FL;
+
oldflags = ei->i_flags;
/*
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index 2740c88a715d..ab990f502fe3 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -490,6 +490,9 @@ repeat:
ei->i_flags = EXT3_I(dir)->i_flags & ~EXT3_INDEX_FL;
if (S_ISLNK(mode))
ei->i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL);
+ /* dirsync only applies to directories */
+ if (!S_ISDIR(mode))
+ ei->i_flags &= ~EXT3_DIRSYNC_FL;
#ifdef EXT3_FRAGMENTS
ei->i_faddr = 0;
ei->i_frag_no = 0;
@@ -506,7 +509,9 @@ repeat:
if (ei->i_flags & EXT3_SYNC_FL)
inode->i_flags |= S_SYNC;
- if (IS_SYNC(inode))
+ if (ei->i_flags & EXT3_DIRSYNC_FL)
+ inode->i_flags |= S_DIRSYNC;
+ if (IS_DIRSYNC(inode))
handle->h_sync = 1;
insert_inode_hash(inode);
inode->i_generation = sb->u.ext3_sb.s_next_generation++;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 17797234bdd6..239d4d22aea1 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -2160,23 +2160,14 @@ void ext3_read_inode(struct inode * inode)
} else
init_special_inode(inode, inode->i_mode,
le32_to_cpu(iloc.raw_inode->i_block[0]));
- /* inode->i_attr_flags = 0; unused */
- if (ei->i_flags & EXT3_SYNC_FL) {
- /* inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS; unused */
+ if (ei->i_flags & EXT3_SYNC_FL)
inode->i_flags |= S_SYNC;
- }
- if (ei->i_flags & EXT3_APPEND_FL) {
- /* inode->i_attr_flags |= ATTR_FLAG_APPEND; unused */
+ if (ei->i_flags & EXT3_APPEND_FL)
inode->i_flags |= S_APPEND;
- }
- if (ei->i_flags & EXT3_IMMUTABLE_FL) {
- /* inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE; unused */
+ if (ei->i_flags & EXT3_IMMUTABLE_FL)
inode->i_flags |= S_IMMUTABLE;
- }
- if (ei->i_flags & EXT3_NOATIME_FL) {
- /* inode->i_attr_flags |= ATTR_FLAG_NOATIME; unused */
+ if (ei->i_flags & EXT3_NOATIME_FL)
inode->i_flags |= S_NOATIME;
- }
return;
bad_inode:
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index beca674d3d73..189853645a5d 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -43,6 +43,9 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
if (get_user(flags, (int *) arg))
return -EFAULT;
+ if (!S_ISDIR(inode->i_mode))
+ flags &= ~EXT3_DIRSYNC_FL;
+
oldflags = ei->i_flags;
/* The JOURNAL_DATA flag is modifiable only by root */
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index e4ea096063c9..5480619fd800 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -502,7 +502,7 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode)
return PTR_ERR(handle);
}
- if (IS_SYNC(dir))
+ if (IS_DIRSYNC(dir))
handle->h_sync = 1;
inode = ext3_new_inode (handle, dir, mode);
@@ -533,7 +533,7 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry,
return PTR_ERR(handle);
}
- if (IS_SYNC(dir))
+ if (IS_DIRSYNC(dir))
handle->h_sync = 1;
inode = ext3_new_inode (handle, dir, mode);
@@ -566,7 +566,7 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
return PTR_ERR(handle);
}
- if (IS_SYNC(dir))
+ if (IS_DIRSYNC(dir))
handle->h_sync = 1;
inode = ext3_new_inode (handle, dir, S_IFDIR);
@@ -860,7 +860,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry)
if (!bh)
goto end_rmdir;
- if (IS_SYNC(dir))
+ if (IS_DIRSYNC(dir))
handle->h_sync = 1;
inode = dentry->d_inode;
@@ -916,7 +916,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
return PTR_ERR(handle);
}
- if (IS_SYNC(dir))
+ if (IS_DIRSYNC(dir))
handle->h_sync = 1;
retval = -ENOENT;
@@ -975,7 +975,7 @@ static int ext3_symlink (struct inode * dir,
return PTR_ERR(handle);
}
- if (IS_SYNC(dir))
+ if (IS_DIRSYNC(dir))
handle->h_sync = 1;
inode = ext3_new_inode (handle, dir, S_IFLNK|S_IRWXUGO);
@@ -1033,7 +1033,7 @@ static int ext3_link (struct dentry * old_dentry,
return PTR_ERR(handle);
}
- if (IS_SYNC(dir))
+ if (IS_DIRSYNC(dir))
handle->h_sync = 1;
inode->i_ctime = CURRENT_TIME;
@@ -1073,7 +1073,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
return PTR_ERR(handle);
}
- if (IS_SYNC(old_dir) || IS_SYNC(new_dir))
+ if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
handle->h_sync = 1;
old_bh = ext3_find_entry (old_dentry, &old_de);
diff --git a/fs/inode.c b/fs/inode.c
index 16f1ddb001ad..9fca16d59ee8 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -981,6 +981,15 @@ void update_atime (struct inode *inode)
do_atime_update(inode);
} /* End Function update_atime */
+int inode_needs_sync(struct inode *inode)
+{
+ if (IS_SYNC(inode))
+ return 1;
+ if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode))
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL(inode_needs_sync);
/*
* Quota functions that want to walk the inode lists..
diff --git a/fs/namespace.c b/fs/namespace.c
index 64515aa0025e..2487e47de2da 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -197,6 +197,7 @@ static int show_vfsmnt(struct seq_file *m, void *v)
char *str;
} fs_info[] = {
{ MS_SYNCHRONOUS, ",sync" },
+ { MS_DIRSYNC, ",dirsync" },
{ MS_MANDLOCK, ",mand" },
{ MS_NOATIME, ",noatime" },
{ MS_NODIRATIME, ",nodiratime" },