aboutsummaryrefslogtreecommitdiff
path: root/fs/sysv/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysv/inode.c')
-rw-r--r--fs/sysv/inode.c121
1 files changed, 65 insertions, 56 deletions
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index c5d60de0658..88956309cc8 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -21,24 +21,22 @@
* the superblock.
*/
-#include <linux/smp_lock.h>
#include <linux/highuid.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
+#include <linux/writeback.h>
+#include <linux/namei.h>
#include <asm/byteorder.h>
#include "sysv.h"
-/* This is only called on sync() and umount(), when s_dirt=1. */
-static void sysv_write_super(struct super_block *sb)
+static int sysv_sync_fs(struct super_block *sb, int wait)
{
struct sysv_sb_info *sbi = SYSV_SB(sb);
unsigned long time = get_seconds(), old_time;
- lock_kernel();
- if (sb->s_flags & MS_RDONLY)
- goto clean;
+ mutex_lock(&sbi->s_lock);
/*
* If we are going to write out the super block,
@@ -52,18 +50,19 @@ static void sysv_write_super(struct super_block *sb)
*sbi->s_sb_time = cpu_to_fs32(sbi, time);
mark_buffer_dirty(sbi->s_bh2);
}
-clean:
- sb->s_dirt = 0;
- unlock_kernel();
+
+ mutex_unlock(&sbi->s_lock);
+
+ return 0;
}
static int sysv_remount(struct super_block *sb, int *flags, char *data)
{
struct sysv_sb_info *sbi = SYSV_SB(sb);
+
+ sync_filesystem(sb);
if (sbi->s_forced_ro)
*flags |= MS_RDONLY;
- if (!(*flags & MS_RDONLY))
- sb->s_dirt = 1;
return 0;
}
@@ -89,6 +88,7 @@ static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
struct sysv_sb_info *sbi = SYSV_SB(sb);
+ u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
buf->f_type = sb->s_magic;
buf->f_bsize = sb->s_blocksize;
@@ -97,6 +97,8 @@ static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_files = sbi->s_ninodes;
buf->f_ffree = sysv_count_free_inodes(sb);
buf->f_namelen = SYSV_NAMELEN;
+ buf->f_fsid.val[0] = (u32)id;
+ buf->f_fsid.val[1] = (u32)(id >> 32);
return 0;
}
@@ -163,8 +165,11 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
if (inode->i_blocks) {
inode->i_op = &sysv_symlink_inode_operations;
inode->i_mapping->a_ops = &sysv_aops;
- } else
+ } else {
inode->i_op = &sysv_fast_symlink_inode_operations;
+ nd_terminate_link(SYSV_I(inode)->i_data, inode->i_size,
+ sizeof(SYSV_I(inode)->i_data) - 1);
+ }
} else
init_special_inode(inode, inode->i_mode, rdev);
}
@@ -198,9 +203,9 @@ struct inode *sysv_iget(struct super_block *sb, unsigned int ino)
}
/* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */
inode->i_mode = fs16_to_cpu(sbi, raw_inode->i_mode);
- inode->i_uid = (uid_t)fs16_to_cpu(sbi, raw_inode->i_uid);
- inode->i_gid = (gid_t)fs16_to_cpu(sbi, raw_inode->i_gid);
- inode->i_nlink = fs16_to_cpu(sbi, raw_inode->i_nlink);
+ i_uid_write(inode, (uid_t)fs16_to_cpu(sbi, raw_inode->i_uid));
+ i_gid_write(inode, (gid_t)fs16_to_cpu(sbi, raw_inode->i_gid));
+ set_nlink(inode, fs16_to_cpu(sbi, raw_inode->i_nlink));
inode->i_size = fs32_to_cpu(sbi, raw_inode->i_size);
inode->i_atime.tv_sec = fs32_to_cpu(sbi, raw_inode->i_atime);
inode->i_mtime.tv_sec = fs32_to_cpu(sbi, raw_inode->i_mtime);
@@ -229,7 +234,7 @@ bad_inode:
return ERR_PTR(-EIO);
}
-static struct buffer_head * sysv_update_inode(struct inode * inode)
+static int __sysv_write_inode(struct inode *inode, int wait)
{
struct super_block * sb = inode->i_sb;
struct sysv_sb_info * sbi = SYSV_SB(sb);
@@ -237,22 +242,23 @@ static struct buffer_head * sysv_update_inode(struct inode * inode)
struct sysv_inode * raw_inode;
struct sysv_inode_info * si;
unsigned int ino, block;
+ int err = 0;
ino = inode->i_ino;
if (!ino || ino > sbi->s_ninodes) {
printk("Bad inode number on dev %s: %d is out of range\n",
inode->i_sb->s_id, ino);
- return NULL;
+ return -EIO;
}
raw_inode = sysv_raw_inode(sb, ino, &bh);
if (!raw_inode) {
printk("unable to read i-node block\n");
- return NULL;
+ return -EIO;
}
raw_inode->i_mode = cpu_to_fs16(sbi, inode->i_mode);
- raw_inode->i_uid = cpu_to_fs16(sbi, fs_high2lowuid(inode->i_uid));
- raw_inode->i_gid = cpu_to_fs16(sbi, fs_high2lowgid(inode->i_gid));
+ raw_inode->i_uid = cpu_to_fs16(sbi, fs_high2lowuid(i_uid_read(inode)));
+ raw_inode->i_gid = cpu_to_fs16(sbi, fs_high2lowgid(i_gid_read(inode)));
raw_inode->i_nlink = cpu_to_fs16(sbi, inode->i_nlink);
raw_inode->i_size = cpu_to_fs32(sbi, inode->i_size);
raw_inode->i_atime = cpu_to_fs32(sbi, inode->i_atime.tv_sec);
@@ -266,47 +272,39 @@ static struct buffer_head * sysv_update_inode(struct inode * inode)
write3byte(sbi, (u8 *)&si->i_data[block],
&raw_inode->i_data[3*block]);
mark_buffer_dirty(bh);
- return bh;
-}
-
-int sysv_write_inode(struct inode * inode, int wait)
-{
- struct buffer_head *bh;
- lock_kernel();
- bh = sysv_update_inode(inode);
+ if (wait) {
+ sync_dirty_buffer(bh);
+ if (buffer_req(bh) && !buffer_uptodate(bh)) {
+ printk ("IO error syncing sysv inode [%s:%08x]\n",
+ sb->s_id, ino);
+ err = -EIO;
+ }
+ }
brelse(bh);
- unlock_kernel();
return 0;
}
-int sysv_sync_inode(struct inode * inode)
+int sysv_write_inode(struct inode *inode, struct writeback_control *wbc)
{
- int err = 0;
- struct buffer_head *bh;
+ return __sysv_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
+}
- bh = sysv_update_inode(inode);
- if (bh && buffer_dirty(bh)) {
- sync_dirty_buffer(bh);
- if (buffer_req(bh) && !buffer_uptodate(bh)) {
- printk ("IO error syncing sysv inode [%s:%08lx]\n",
- inode->i_sb->s_id, inode->i_ino);
- err = -1;
- }
- }
- else if (!bh)
- err = -1;
- brelse (bh);
- return err;
+int sysv_sync_inode(struct inode *inode)
+{
+ return __sysv_write_inode(inode, 1);
}
-static void sysv_delete_inode(struct inode *inode)
+static void sysv_evict_inode(struct inode *inode)
{
- truncate_inode_pages(&inode->i_data, 0);
- inode->i_size = 0;
- sysv_truncate(inode);
- lock_kernel();
- sysv_free_inode(inode);
- unlock_kernel();
+ truncate_inode_pages_final(&inode->i_data);
+ if (!inode->i_nlink) {
+ inode->i_size = 0;
+ sysv_truncate(inode);
+ }
+ invalidate_inode_buffers(inode);
+ clear_inode(inode);
+ if (!inode->i_nlink)
+ sysv_free_inode(inode);
}
static struct kmem_cache *sysv_inode_cachep;
@@ -321,12 +319,18 @@ static struct inode *sysv_alloc_inode(struct super_block *sb)
return &si->vfs_inode;
}
-static void sysv_destroy_inode(struct inode *inode)
+static void sysv_i_callback(struct rcu_head *head)
{
+ struct inode *inode = container_of(head, struct inode, i_rcu);
kmem_cache_free(sysv_inode_cachep, SYSV_I(inode));
}
-static void init_once(struct kmem_cache *cachep, void *p)
+static void sysv_destroy_inode(struct inode *inode)
+{
+ call_rcu(&inode->i_rcu, sysv_i_callback);
+}
+
+static void init_once(void *p)
{
struct sysv_inode_info *si = (struct sysv_inode_info *)p;
@@ -337,9 +341,9 @@ const struct super_operations sysv_sops = {
.alloc_inode = sysv_alloc_inode,
.destroy_inode = sysv_destroy_inode,
.write_inode = sysv_write_inode,
- .delete_inode = sysv_delete_inode,
+ .evict_inode = sysv_evict_inode,
.put_super = sysv_put_super,
- .write_super = sysv_write_super,
+ .sync_fs = sysv_sync_fs,
.remount_fs = sysv_remount,
.statfs = sysv_statfs,
};
@@ -357,5 +361,10 @@ int __init sysv_init_icache(void)
void sysv_destroy_icache(void)
{
+ /*
+ * Make sure all delayed rcu free inodes are flushed before we
+ * destroy cache.
+ */
+ rcu_barrier();
kmem_cache_destroy(sysv_inode_cachep);
}