aboutsummaryrefslogtreecommitdiff
path: root/fs/bfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/bfs/inode.c')
-rw-r--r--fs/bfs/inode.c202
1 files changed, 85 insertions, 117 deletions
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 6f60336c662..7041ac35ace 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -12,9 +12,9 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
+#include <linux/writeback.h>
#include <asm/uaccess.h>
#include "bfs.h"
@@ -30,7 +30,6 @@ MODULE_LICENSE("GPL");
#define dprintf(x...)
#endif
-static void bfs_write_super(struct super_block *s);
void dump_imap(const char *prefix, struct super_block *s);
struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
@@ -41,7 +40,7 @@ struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
int block, off;
inode = iget_locked(sb, ino);
- if (IS_ERR(inode))
+ if (!inode)
return ERR_PTR(-ENOMEM);
if (!(inode->i_state & I_NEW))
return inode;
@@ -77,9 +76,9 @@ struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
BFS_I(inode)->i_sblock = le32_to_cpu(di->i_sblock);
BFS_I(inode)->i_eblock = le32_to_cpu(di->i_eblock);
BFS_I(inode)->i_dsk_ino = le16_to_cpu(di->i_ino);
- inode->i_uid = le32_to_cpu(di->i_uid);
- inode->i_gid = le32_to_cpu(di->i_gid);
- inode->i_nlink = le32_to_cpu(di->i_nlink);
+ i_uid_write(inode, le32_to_cpu(di->i_uid));
+ i_gid_write(inode, le32_to_cpu(di->i_gid));
+ set_nlink(inode, le32_to_cpu(di->i_nlink));
inode->i_size = BFS_FILESIZE(di);
inode->i_blocks = BFS_FILEBLOCKS(di);
inode->i_atime.tv_sec = le32_to_cpu(di->i_atime);
@@ -98,35 +97,40 @@ error:
return ERR_PTR(-EIO);
}
-static int bfs_write_inode(struct inode *inode, int wait)
+static struct bfs_inode *find_inode(struct super_block *sb, u16 ino, struct buffer_head **p)
+{
+ if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(sb)->si_lasti)) {
+ printf("Bad inode number %s:%08x\n", sb->s_id, ino);
+ return ERR_PTR(-EIO);
+ }
+
+ ino -= BFS_ROOT_INO;
+
+ *p = sb_bread(sb, 1 + ino / BFS_INODES_PER_BLOCK);
+ if (!*p) {
+ printf("Unable to read inode %s:%08x\n", sb->s_id, ino);
+ return ERR_PTR(-EIO);
+ }
+
+ return (struct bfs_inode *)(*p)->b_data + ino % BFS_INODES_PER_BLOCK;
+}
+
+static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc)
{
struct bfs_sb_info *info = BFS_SB(inode->i_sb);
unsigned int ino = (u16)inode->i_ino;
unsigned long i_sblock;
struct bfs_inode *di;
struct buffer_head *bh;
- int block, off;
int err = 0;
dprintf("ino=%08x\n", ino);
- if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(inode->i_sb)->si_lasti)) {
- printf("Bad inode number %s:%08x\n", inode->i_sb->s_id, ino);
- return -EIO;
- }
+ di = find_inode(inode->i_sb, ino, &bh);
+ if (IS_ERR(di))
+ return PTR_ERR(di);
mutex_lock(&info->bfs_lock);
- block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;
- bh = sb_bread(inode->i_sb, block);
- if (!bh) {
- printf("Unable to read inode %s:%08x\n",
- inode->i_sb->s_id, ino);
- mutex_unlock(&info->bfs_lock);
- return -EIO;
- }
-
- off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
- di = (struct bfs_inode *)bh->b_data + off;
if (ino == BFS_ROOT_INO)
di->i_vtype = cpu_to_le32(BFS_VDIR);
@@ -135,8 +139,8 @@ static int bfs_write_inode(struct inode *inode, int wait)
di->i_ino = cpu_to_le16(ino);
di->i_mode = cpu_to_le32(inode->i_mode);
- di->i_uid = cpu_to_le32(inode->i_uid);
- di->i_gid = cpu_to_le32(inode->i_gid);
+ di->i_uid = cpu_to_le32(i_uid_read(inode));
+ di->i_gid = cpu_to_le32(i_gid_read(inode));
di->i_nlink = cpu_to_le32(inode->i_nlink);
di->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
di->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
@@ -147,7 +151,7 @@ static int bfs_write_inode(struct inode *inode, int wait)
di->i_eoffset = cpu_to_le32(i_sblock * BFS_BSIZE + inode->i_size - 1);
mark_buffer_dirty(bh);
- if (wait) {
+ if (wbc->sync_mode == WB_SYNC_ALL) {
sync_dirty_buffer(bh);
if (buffer_req(bh) && !buffer_uptodate(bh))
err = -EIO;
@@ -157,41 +161,31 @@ static int bfs_write_inode(struct inode *inode, int wait)
return err;
}
-static void bfs_delete_inode(struct inode *inode)
+static void bfs_evict_inode(struct inode *inode)
{
unsigned long ino = inode->i_ino;
struct bfs_inode *di;
struct buffer_head *bh;
- int block, off;
struct super_block *s = inode->i_sb;
struct bfs_sb_info *info = BFS_SB(s);
struct bfs_inode_info *bi = BFS_I(inode);
dprintf("ino=%08lx\n", ino);
- truncate_inode_pages(&inode->i_data, 0);
+ truncate_inode_pages_final(&inode->i_data);
+ invalidate_inode_buffers(inode);
+ clear_inode(inode);
- if ((ino < BFS_ROOT_INO) || (ino > info->si_lasti)) {
- printf("invalid ino=%08lx\n", ino);
+ if (inode->i_nlink)
return;
- }
-
- inode->i_size = 0;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
- mutex_lock(&info->bfs_lock);
- mark_inode_dirty(inode);
- block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;
- bh = sb_bread(s, block);
- if (!bh) {
- printf("Unable to read inode %s:%08lx\n",
- inode->i_sb->s_id, ino);
- mutex_unlock(&info->bfs_lock);
+ di = find_inode(s, inode->i_ino, &bh);
+ if (IS_ERR(di))
return;
- }
- off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
- di = (struct bfs_inode *)bh->b_data + off;
- memset((void *)di, 0, sizeof(struct bfs_inode));
+
+ mutex_lock(&info->bfs_lock);
+ /* clear on-disk inode */
+ memset(di, 0, sizeof(struct bfs_inode));
mark_buffer_dirty(bh);
brelse(bh);
@@ -208,32 +202,9 @@ static void bfs_delete_inode(struct inode *inode)
* "last block of the last file" even if there is no
* real file there, saves us 1 gap.
*/
- if (info->si_lf_eblk == bi->i_eblock) {
+ if (info->si_lf_eblk == bi->i_eblock)
info->si_lf_eblk = bi->i_sblock - 1;
- mark_buffer_dirty(info->si_sbh);
- }
mutex_unlock(&info->bfs_lock);
- clear_inode(inode);
-}
-
-static int bfs_sync_fs(struct super_block *sb, int wait)
-{
- struct bfs_sb_info *info = BFS_SB(sb);
-
- mutex_lock(&info->bfs_lock);
- mark_buffer_dirty(info->si_sbh);
- sb->s_dirt = 0;
- mutex_unlock(&info->bfs_lock);
-
- return 0;
-}
-
-static void bfs_write_super(struct super_block *sb)
-{
- if (!(sb->s_flags & MS_RDONLY))
- bfs_sync_fs(sb, 1);
- else
- sb->s_dirt = 0;
}
static void bfs_put_super(struct super_block *s)
@@ -243,18 +214,10 @@ static void bfs_put_super(struct super_block *s)
if (!info)
return;
- lock_kernel();
-
- if (s->s_dirt)
- bfs_write_super(s);
-
- brelse(info->si_sbh);
mutex_destroy(&info->bfs_lock);
kfree(info->si_imap);
kfree(info);
s->s_fs_info = NULL;
-
- unlock_kernel();
}
static int bfs_statfs(struct dentry *dentry, struct kstatfs *buf)
@@ -285,11 +248,17 @@ static struct inode *bfs_alloc_inode(struct super_block *sb)
return &bi->vfs_inode;
}
-static void bfs_destroy_inode(struct inode *inode)
+static void bfs_i_callback(struct rcu_head *head)
{
+ struct inode *inode = container_of(head, struct inode, i_rcu);
kmem_cache_free(bfs_inode_cachep, BFS_I(inode));
}
+static void bfs_destroy_inode(struct inode *inode)
+{
+ call_rcu(&inode->i_rcu, bfs_i_callback);
+}
+
static void init_once(void *foo)
{
struct bfs_inode_info *bi = foo;
@@ -297,7 +266,7 @@ static void init_once(void *foo)
inode_init_once(&bi->vfs_inode);
}
-static int init_inodecache(void)
+static int __init init_inodecache(void)
{
bfs_inode_cachep = kmem_cache_create("bfs_inode_cache",
sizeof(struct bfs_inode_info),
@@ -311,6 +280,11 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
+ /*
+ * Make sure all delayed rcu free inodes are flushed before we
+ * destroy cache.
+ */
+ rcu_barrier();
kmem_cache_destroy(bfs_inode_cachep);
}
@@ -318,10 +292,8 @@ static const struct super_operations bfs_sops = {
.alloc_inode = bfs_alloc_inode,
.destroy_inode = bfs_destroy_inode,
.write_inode = bfs_write_inode,
- .delete_inode = bfs_delete_inode,
+ .evict_inode = bfs_evict_inode,
.put_super = bfs_put_super,
- .write_super = bfs_write_super,
- .sync_fs = bfs_sync_fs,
.statfs = bfs_statfs,
};
@@ -348,40 +320,40 @@ void dump_imap(const char *prefix, struct super_block *s)
static int bfs_fill_super(struct super_block *s, void *data, int silent)
{
- struct buffer_head *bh;
+ struct buffer_head *bh, *sbh;
struct bfs_super_block *bfs_sb;
struct inode *inode;
unsigned i, imap_len;
struct bfs_sb_info *info;
- long ret = -EINVAL;
+ int ret = -EINVAL;
unsigned long i_sblock, i_eblock, i_eoff, s_size;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
+ mutex_init(&info->bfs_lock);
s->s_fs_info = info;
sb_set_blocksize(s, BFS_BSIZE);
- bh = sb_bread(s, 0);
- if(!bh)
+ sbh = sb_bread(s, 0);
+ if (!sbh)
goto out;
- bfs_sb = (struct bfs_super_block *)bh->b_data;
+ bfs_sb = (struct bfs_super_block *)sbh->b_data;
if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) {
if (!silent)
printf("No BFS filesystem on %s (magic=%08x)\n",
s->s_id, le32_to_cpu(bfs_sb->s_magic));
- goto out;
+ goto out1;
}
if (BFS_UNCLEAN(bfs_sb, s) && !silent)
printf("%s is unclean, continuing\n", s->s_id);
s->s_magic = BFS_MAGIC;
- info->si_sbh = bh;
if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end)) {
printf("Superblock is corrupted\n");
- goto out;
+ goto out1;
}
info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE) /
@@ -390,7 +362,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
imap_len = (info->si_lasti / 8) + 1;
info->si_imap = kzalloc(imap_len, GFP_KERNEL);
if (!info->si_imap)
- goto out;
+ goto out1;
for (i = 0; i < BFS_ROOT_INO; i++)
set_bit(i, info->si_imap);
@@ -398,15 +370,12 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
inode = bfs_iget(s, BFS_ROOT_INO);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
- kfree(info->si_imap);
- goto out;
+ goto out2;
}
- s->s_root = d_alloc_root(inode);
+ s->s_root = d_make_root(inode);
if (!s->s_root) {
- iput(inode);
ret = -ENOMEM;
- kfree(info->si_imap);
- goto out;
+ goto out2;
}
info->si_blocks = (le32_to_cpu(bfs_sb->s_end) + 1) >> BFS_BSIZE_BITS;
@@ -419,10 +388,8 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
bh = sb_bread(s, info->si_blocks - 1);
if (!bh) {
printf("Last block not available: %lu\n", info->si_blocks - 1);
- iput(inode);
ret = -EIO;
- kfree(info->si_imap);
- goto out;
+ goto out3;
}
brelse(bh);
@@ -459,11 +426,8 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
printf("Inode 0x%08x corrupted\n", i);
brelse(bh);
- s->s_root = NULL;
- kfree(info->si_imap);
- kfree(info);
- s->s_fs_info = NULL;
- return -EIO;
+ ret = -EIO;
+ goto out3;
}
if (!di->i_ino) {
@@ -478,34 +442,38 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
info->si_lf_eblk = eblock;
}
brelse(bh);
- if (!(s->s_flags & MS_RDONLY)) {
- mark_buffer_dirty(info->si_sbh);
- s->s_dirt = 1;
- }
+ brelse(sbh);
dump_imap("read_super", s);
- mutex_init(&info->bfs_lock);
return 0;
+out3:
+ dput(s->s_root);
+ s->s_root = NULL;
+out2:
+ kfree(info->si_imap);
+out1:
+ brelse(sbh);
out:
- brelse(bh);
+ mutex_destroy(&info->bfs_lock);
kfree(info);
s->s_fs_info = NULL;
return ret;
}
-static int bfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+static struct dentry *bfs_mount(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, bfs_fill_super, mnt);
+ return mount_bdev(fs_type, flags, dev_name, data, bfs_fill_super);
}
static struct file_system_type bfs_fs_type = {
.owner = THIS_MODULE,
.name = "bfs",
- .get_sb = bfs_get_sb,
+ .mount = bfs_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
+MODULE_ALIAS_FS("bfs");
static int __init init_bfs_fs(void)
{