From 7942b919f7321f95a777d396ff7894a7a83dc9b0 Mon Sep 17 00:00:00 2001 From: Koji Sato Date: Mon, 6 Apr 2009 19:01:41 -0700 Subject: nilfs2: ioctl operations This adds userland interface implemented with ioctl. Signed-off-by: Koji Sato Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nilfs2/ioctl.c | 941 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 941 insertions(+) create mode 100644 fs/nilfs2/ioctl.c (limited to 'fs/nilfs2/ioctl.c') diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c new file mode 100644 index 000000000000..35ba60ea9617 --- /dev/null +++ b/fs/nilfs2/ioctl.c @@ -0,0 +1,941 @@ +/* + * ioctl.c - NILFS ioctl operations. + * + * Copyright (C) 2007, 2008 Nippon Telegraph and Telephone Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Written by Koji Sato . + */ + +#include +#include +#include /* lock_kernel(), unlock_kernel() */ +#include /* capable() */ +#include /* copy_from_user(), copy_to_user() */ +#include +#include "nilfs.h" +#include "segment.h" +#include "bmap.h" +#include "cpfile.h" +#include "sufile.h" +#include "dat.h" + + +#define KMALLOC_SIZE_MIN 4096 /* 4KB */ +#define KMALLOC_SIZE_MAX 131072 /* 128 KB */ + +static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, + struct nilfs_argv *argv, int dir, + ssize_t (*dofunc)(struct the_nilfs *, + int, int, + void *, size_t, size_t)) +{ + void *buf; + size_t ksize, maxmembs, total, n; + ssize_t nr; + int ret, i; + + if (argv->v_nmembs == 0) + return 0; + + for (ksize = KMALLOC_SIZE_MAX; ksize >= KMALLOC_SIZE_MIN; ksize /= 2) { + buf = kmalloc(ksize, GFP_NOFS); + if (buf != NULL) + break; + } + if (ksize < KMALLOC_SIZE_MIN) + return -ENOMEM; + maxmembs = ksize / argv->v_size; + + ret = 0; + total = 0; + for (i = 0; i < argv->v_nmembs; i += n) { + n = (argv->v_nmembs - i < maxmembs) ? + argv->v_nmembs - i : maxmembs; + if ((dir & _IOC_WRITE) && + copy_from_user(buf, + (void __user *)argv->v_base + argv->v_size * i, + argv->v_size * n)) { + ret = -EFAULT; + break; + } + nr = (*dofunc)(nilfs, argv->v_index + i, argv->v_flags, buf, + argv->v_size, n); + if (nr < 0) { + ret = nr; + break; + } + if ((dir & _IOC_READ) && + copy_to_user( + (void __user *)argv->v_base + argv->v_size * i, + buf, argv->v_size * nr)) { + ret = -EFAULT; + break; + } + total += nr; + } + argv->v_nmembs = total; + + kfree(buf); + return ret; +} + +static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, + unsigned int cmd, void __user *argp) +{ + struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile; + struct nilfs_transaction_info ti; + struct nilfs_cpmode cpmode; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&cpmode, argp, sizeof(cpmode))) + return -EFAULT; + + nilfs_transaction_begin(inode->i_sb, &ti, 0); + ret = nilfs_cpfile_change_cpmode( + cpfile, cpmode.cm_cno, cpmode.cm_mode); + nilfs_transaction_end(inode->i_sb, !ret); + return ret; +} + +static int +nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, + unsigned int cmd, void __user *argp) +{ + struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile; + struct nilfs_transaction_info ti; + __u64 cno; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&cno, argp, sizeof(cno))) + return -EFAULT; + + nilfs_transaction_begin(inode->i_sb, &ti, 0); + ret = nilfs_cpfile_delete_checkpoint(cpfile, cno); + nilfs_transaction_end(inode->i_sb, !ret); + return ret; +} + +static ssize_t +nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, int index, int flags, + void *buf, size_t size, size_t nmembs) +{ + return nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, index, flags, buf, + nmembs); +} + +static int nilfs_ioctl_get_cpinfo(struct inode *inode, struct file *filp, + unsigned int cmd, void __user *argp) +{ + struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; + struct nilfs_argv argv; + struct nilfs_transaction_info ti; + int ret; + + if (copy_from_user(&argv, argp, sizeof(argv))) + return -EFAULT; + + nilfs_transaction_begin(inode->i_sb, &ti, 0); + ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), + nilfs_ioctl_do_get_cpinfo); + nilfs_transaction_end(inode->i_sb, 0); + + if (copy_to_user(argp, &argv, sizeof(argv))) + ret = -EFAULT; + return ret; +} + +static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp, + unsigned int cmd, void __user *argp) +{ + struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile; + struct nilfs_cpstat cpstat; + struct nilfs_transaction_info ti; + int ret; + + nilfs_transaction_begin(inode->i_sb, &ti, 0); + ret = nilfs_cpfile_get_stat(cpfile, &cpstat); + nilfs_transaction_end(inode->i_sb, 0); + if (ret < 0) + return ret; + + if (copy_to_user(argp, &cpstat, sizeof(cpstat))) + ret = -EFAULT; + return ret; +} + +static ssize_t +nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, int index, int flags, + void *buf, size_t size, size_t nmembs) +{ + return nilfs_sufile_get_suinfo(nilfs->ns_sufile, index, buf, nmembs); +} + +static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp, + unsigned int cmd, void __user *argp) +{ + struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; + struct nilfs_argv argv; + struct nilfs_transaction_info ti; + int ret; + + if (copy_from_user(&argv, argp, sizeof(argv))) + return -EFAULT; + + nilfs_transaction_begin(inode->i_sb, &ti, 0); + ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), + nilfs_ioctl_do_get_suinfo); + nilfs_transaction_end(inode->i_sb, 0); + + if (copy_to_user(argp, &argv, sizeof(argv))) + ret = -EFAULT; + return ret; +} + +static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp, + unsigned int cmd, void __user *argp) +{ + struct inode *sufile = NILFS_SB(inode->i_sb)->s_nilfs->ns_sufile; + struct nilfs_sustat sustat; + struct nilfs_transaction_info ti; + int ret; + + nilfs_transaction_begin(inode->i_sb, &ti, 0); + ret = nilfs_sufile_get_stat(sufile, &sustat); + nilfs_transaction_end(inode->i_sb, 0); + if (ret < 0) + return ret; + + if (copy_to_user(argp, &sustat, sizeof(sustat))) + ret = -EFAULT; + return ret; +} + +static ssize_t +nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, int index, int flags, + void *buf, size_t size, size_t nmembs) +{ + return nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs); +} + +static int nilfs_ioctl_get_vinfo(struct inode *inode, struct file *filp, + unsigned int cmd, void __user *argp) +{ + struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; + struct nilfs_argv argv; + struct nilfs_transaction_info ti; + int ret; + + if (copy_from_user(&argv, argp, sizeof(argv))) + return -EFAULT; + + nilfs_transaction_begin(inode->i_sb, &ti, 0); + ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), + nilfs_ioctl_do_get_vinfo); + nilfs_transaction_end(inode->i_sb, 0); + + if (copy_to_user(argp, &argv, sizeof(argv))) + ret = -EFAULT; + return ret; +} + +static ssize_t +nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, int index, int flags, + void *buf, size_t size, size_t nmembs) +{ + struct inode *dat = nilfs_dat_inode(nilfs); + struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; + struct nilfs_bdesc *bdescs = buf; + int ret, i; + + for (i = 0; i < nmembs; i++) { + ret = nilfs_bmap_lookup_at_level(bmap, + bdescs[i].bd_offset, + bdescs[i].bd_level + 1, + &bdescs[i].bd_blocknr); + if (ret < 0) { + if (ret != -ENOENT) + return ret; + bdescs[i].bd_blocknr = 0; + } + } + return nmembs; +} + +static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp, + unsigned int cmd, void __user *argp) +{ + struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; + struct nilfs_argv argv; + struct nilfs_transaction_info ti; + int ret; + + if (copy_from_user(&argv, argp, sizeof(argv))) + return -EFAULT; + + nilfs_transaction_begin(inode->i_sb, &ti, 0); + ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), + nilfs_ioctl_do_get_bdescs); + nilfs_transaction_end(inode->i_sb, 0); + + if (copy_to_user(argp, &argv, sizeof(argv))) + ret = -EFAULT; + return ret; +} + +static int nilfs_ioctl_move_inode_block(struct inode *inode, + struct nilfs_vdesc *vdesc, + struct list_head *buffers) +{ + struct buffer_head *bh; + int ret; + + if (vdesc->vd_flags == 0) + ret = nilfs_gccache_submit_read_data( + inode, vdesc->vd_offset, vdesc->vd_blocknr, + vdesc->vd_vblocknr, &bh); + else + ret = nilfs_gccache_submit_read_node( + inode, vdesc->vd_blocknr, vdesc->vd_vblocknr, &bh); + + if (unlikely(ret < 0)) { + if (ret == -ENOENT) + printk(KERN_CRIT + "%s: invalid virtual block address (%s): " + "ino=%llu, cno=%llu, offset=%llu, " + "blocknr=%llu, vblocknr=%llu\n", + __func__, vdesc->vd_flags ? "node" : "data", + (unsigned long long)vdesc->vd_ino, + (unsigned long long)vdesc->vd_cno, + (unsigned long long)vdesc->vd_offset, + (unsigned long long)vdesc->vd_blocknr, + (unsigned long long)vdesc->vd_vblocknr); + return ret; + } + bh->b_private = vdesc; + list_add_tail(&bh->b_assoc_buffers, buffers); + return 0; +} + +static ssize_t +nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, int index, int flags, + void *buf, size_t size, size_t nmembs) +{ + struct inode *inode; + struct nilfs_vdesc *vdesc; + struct buffer_head *bh, *n; + LIST_HEAD(buffers); + ino_t ino; + __u64 cno; + int i, ret; + + for (i = 0, vdesc = buf; i < nmembs; ) { + ino = vdesc->vd_ino; + cno = vdesc->vd_cno; + inode = nilfs_gc_iget(nilfs, ino, cno); + if (unlikely(inode == NULL)) { + ret = -ENOMEM; + goto failed; + } + do { + ret = nilfs_ioctl_move_inode_block(inode, vdesc, + &buffers); + if (unlikely(ret < 0)) + goto failed; + vdesc++; + } while (++i < nmembs && + vdesc->vd_ino == ino && vdesc->vd_cno == cno); + } + + list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { + ret = nilfs_gccache_wait_and_mark_dirty(bh); + if (unlikely(ret < 0)) { + if (ret == -EEXIST) { + vdesc = bh->b_private; + printk(KERN_CRIT + "%s: conflicting %s buffer: " + "ino=%llu, cno=%llu, offset=%llu, " + "blocknr=%llu, vblocknr=%llu\n", + __func__, + vdesc->vd_flags ? "node" : "data", + (unsigned long long)vdesc->vd_ino, + (unsigned long long)vdesc->vd_cno, + (unsigned long long)vdesc->vd_offset, + (unsigned long long)vdesc->vd_blocknr, + (unsigned long long)vdesc->vd_vblocknr); + } + goto failed; + } + list_del_init(&bh->b_assoc_buffers); + bh->b_private = NULL; + brelse(bh); + } + return nmembs; + + failed: + list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { + list_del_init(&bh->b_assoc_buffers); + bh->b_private = NULL; + brelse(bh); + } + return ret; +} + +static inline int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs, + struct nilfs_argv *argv, + int dir) +{ + return nilfs_ioctl_wrap_copy(nilfs, argv, dir, + nilfs_ioctl_do_move_blocks); +} + +static ssize_t +nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, int index, + int flags, void *buf, size_t size, + size_t nmembs) +{ + struct inode *cpfile = nilfs->ns_cpfile; + struct nilfs_period *periods = buf; + int ret, i; + + for (i = 0; i < nmembs; i++) { + ret = nilfs_cpfile_delete_checkpoints( + cpfile, periods[i].p_start, periods[i].p_end); + if (ret < 0) + return ret; + } + return nmembs; +} + +static inline int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs, + struct nilfs_argv *argv, + int dir) +{ + return nilfs_ioctl_wrap_copy(nilfs, argv, dir, + nilfs_ioctl_do_delete_checkpoints); +} + +static ssize_t +nilfs_ioctl_do_free_vblocknrs(struct the_nilfs *nilfs, int index, int flags, + void *buf, size_t size, size_t nmembs) +{ + int ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs); + + return (ret < 0) ? ret : nmembs; +} + +static inline int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs, + struct nilfs_argv *argv, + int dir) +{ + return nilfs_ioctl_wrap_copy(nilfs, argv, dir, + nilfs_ioctl_do_free_vblocknrs); +} + +static ssize_t +nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, int index, int flags, + void *buf, size_t size, size_t nmembs) +{ + struct inode *dat = nilfs_dat_inode(nilfs); + struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; + struct nilfs_bdesc *bdescs = buf; + int ret, i; + + for (i = 0; i < nmembs; i++) { + /* XXX: use macro or inline func to check liveness */ + ret = nilfs_bmap_lookup_at_level(bmap, + bdescs[i].bd_offset, + bdescs[i].bd_level + 1, + &bdescs[i].bd_blocknr); + if (ret < 0) { + if (ret != -ENOENT) + return ret; + bdescs[i].bd_blocknr = 0; + } + if (bdescs[i].bd_blocknr != bdescs[i].bd_oblocknr) + /* skip dead block */ + continue; + if (bdescs[i].bd_level == 0) { + ret = nilfs_mdt_mark_block_dirty(dat, + bdescs[i].bd_offset); + if (ret < 0) { + BUG_ON(ret == -ENOENT); + return ret; + } + } else { + ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset, + bdescs[i].bd_level); + if (ret < 0) { + BUG_ON(ret == -ENOENT); + return ret; + } + } + } + return nmembs; +} + +static inline int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, + struct nilfs_argv *argv, + int dir) +{ + return nilfs_ioctl_wrap_copy(nilfs, argv, dir, + nilfs_ioctl_do_mark_blocks_dirty); +} + +static ssize_t +nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, int index, int flags, + void *buf, size_t size, size_t nmembs) +{ + struct nilfs_sb_info *sbi = nilfs_get_writer(nilfs); + int ret; + + BUG_ON(!sbi); + ret = nilfs_segctor_add_segments_to_be_freed( + NILFS_SC(sbi), buf, nmembs); + nilfs_put_writer(nilfs); + + return (ret < 0) ? ret : nmembs; +} + +static inline int nilfs_ioctl_free_segments(struct the_nilfs *nilfs, + struct nilfs_argv *argv, + int dir) +{ + return nilfs_ioctl_wrap_copy(nilfs, argv, dir, + nilfs_ioctl_do_free_segments); +} + +int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, + void __user *argp) +{ + struct nilfs_argv argv[5]; + int dir, ret; + + if (copy_from_user(argv, argp, sizeof(argv))) + return -EFAULT; + + dir = _IOC_WRITE; + ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], dir); + if (ret < 0) + goto out_move_blks; + ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], dir); + if (ret < 0) + goto out_del_cps; + ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], dir); + if (ret < 0) + goto out_free_vbns; + ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], dir); + if (ret < 0) + goto out_free_vbns; + ret = nilfs_ioctl_free_segments(nilfs, &argv[4], dir); + if (ret < 0) + goto out_free_segs; + + return 0; + + out_free_segs: + BUG(); /* XXX: not implemented yet */ + out_free_vbns: + BUG();/* XXX: not implemented yet */ + out_del_cps: + BUG();/* XXX: not implemented yet */ + out_move_blks: + nilfs_remove_all_gcinode(nilfs); + return ret; +} + +static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, + unsigned int cmd, void __user *argp) +{ + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + ret = nilfs_clean_segments(inode->i_sb, argp); + clear_nilfs_cond_nongc_write(NILFS_SB(inode->i_sb)->s_nilfs); + return ret; +} + +static int nilfs_ioctl_test_cond(struct the_nilfs *nilfs, int cond) +{ + return (cond & NILFS_TIMEDWAIT_SEG_WRITE) && + nilfs_cond_nongc_write(nilfs); +} + +static void nilfs_ioctl_clear_cond(struct the_nilfs *nilfs, int cond) +{ + if (cond & NILFS_TIMEDWAIT_SEG_WRITE) + clear_nilfs_cond_nongc_write(nilfs); +} + +static int nilfs_ioctl_timedwait(struct inode *inode, struct file *filp, + unsigned int cmd, void __user *argp) +{ + struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; + struct nilfs_wait_cond wc; + long ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&wc, argp, sizeof(wc))) + return -EFAULT; + + unlock_kernel(); + ret = wc.wc_flags ? + wait_event_interruptible_timeout( + nilfs->ns_cleanerd_wq, + nilfs_ioctl_test_cond(nilfs, wc.wc_cond), + timespec_to_jiffies(&wc.wc_timeout)) : + wait_event_interruptible( + nilfs->ns_cleanerd_wq, + nilfs_ioctl_test_cond(nilfs, wc.wc_cond)); + lock_kernel(); + nilfs_ioctl_clear_cond(nilfs, wc.wc_cond); + + if (ret > 0) { + jiffies_to_timespec(ret, &wc.wc_timeout); + if (copy_to_user(argp, &wc, sizeof(wc))) + return -EFAULT; + return 0; + } + if (ret != 0) + return -EINTR; + + return wc.wc_flags ? -ETIME : 0; +} + +static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, + unsigned int cmd, void __user *argp) +{ + __u64 cno; + int ret; + + ret = nilfs_construct_segment(inode->i_sb); + if (ret < 0) + return ret; + + if (argp != NULL) { + cno = NILFS_SB(inode->i_sb)->s_nilfs->ns_cno - 1; + if (copy_to_user(argp, &cno, sizeof(cno))) + return -EFAULT; + } + return 0; +} + +int nilfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void * __user *)arg; + + switch (cmd) { + case NILFS_IOCTL_CHANGE_CPMODE: + return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp); + case NILFS_IOCTL_DELETE_CHECKPOINT: + return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp); + case NILFS_IOCTL_GET_CPINFO: + return nilfs_ioctl_get_cpinfo(inode, filp, cmd, argp); + case NILFS_IOCTL_GET_CPSTAT: + return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp); + case NILFS_IOCTL_GET_SUINFO: + return nilfs_ioctl_get_suinfo(inode, filp, cmd, argp); + case NILFS_IOCTL_GET_SUSTAT: + return nilfs_ioctl_get_sustat(inode, filp, cmd, argp); + case NILFS_IOCTL_GET_VINFO: + /* XXX: rename to ??? */ + return nilfs_ioctl_get_vinfo(inode, filp, cmd, argp); + case NILFS_IOCTL_GET_BDESCS: + return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp); + case NILFS_IOCTL_CLEAN_SEGMENTS: + return nilfs_ioctl_clean_segments(inode, filp, cmd, argp); + case NILFS_IOCTL_TIMEDWAIT: + return nilfs_ioctl_timedwait(inode, filp, cmd, argp); + case NILFS_IOCTL_SYNC: + return nilfs_ioctl_sync(inode, filp, cmd, argp); + default: + return -ENOTTY; + } +} + +/* compat_ioctl */ +#ifdef CONFIG_COMPAT +#include + +static int nilfs_compat_locked_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int ret; + + lock_kernel(); + ret = nilfs_ioctl(inode, filp, cmd, arg); + unlock_kernel(); + return ret; +} + +static int +nilfs_compat_ioctl_uargv32_to_uargv(struct nilfs_argv32 __user *uargv32, + struct nilfs_argv __user *uargv) +{ + compat_uptr_t base; + compat_size_t nmembs, size; + compat_int_t index, flags; + + if (get_user(base, &uargv32->v_base) || + put_user(compat_ptr(base), &uargv->v_base) || + get_user(nmembs, &uargv32->v_nmembs) || + put_user(nmembs, &uargv->v_nmembs) || + get_user(size, &uargv32->v_size) || + put_user(size, &uargv->v_size) || + get_user(index, &uargv32->v_index) || + put_user(index, &uargv->v_index) || + get_user(flags, &uargv32->v_flags) || + put_user(flags, &uargv->v_flags)) + return -EFAULT; + return 0; +} + +static int +nilfs_compat_ioctl_uargv_to_uargv32(struct nilfs_argv __user *uargv, + struct nilfs_argv32 __user *uargv32) +{ + size_t nmembs; + + if (get_user(nmembs, &uargv->v_nmembs) || + put_user(nmembs, &uargv32->v_nmembs)) + return -EFAULT; + return 0; +} + +static int +nilfs_compat_ioctl_get_by_argv(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct nilfs_argv __user *uargv; + struct nilfs_argv32 __user *uargv32; + int ret; + + uargv = compat_alloc_user_space(sizeof(struct nilfs_argv)); + uargv32 = compat_ptr(arg); + ret = nilfs_compat_ioctl_uargv32_to_uargv(uargv32, uargv); + if (ret < 0) + return ret; + + ret = nilfs_compat_locked_ioctl(inode, filp, cmd, (unsigned long)uargv); + if (ret < 0) + return ret; + + return nilfs_compat_ioctl_uargv_to_uargv32(uargv, uargv32); +} + +static int +nilfs_compat_ioctl_change_cpmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct nilfs_cpmode __user *ucpmode; + struct nilfs_cpmode32 __user *ucpmode32; + int mode; + + ucpmode = compat_alloc_user_space(sizeof(struct nilfs_cpmode)); + ucpmode32 = compat_ptr(arg); + if (copy_in_user(&ucpmode->cm_cno, &ucpmode32->cm_cno, + sizeof(__u64)) || + get_user(mode, &ucpmode32->cm_mode) || + put_user(mode, &ucpmode->cm_mode)) + return -EFAULT; + + return nilfs_compat_locked_ioctl( + inode, filp, cmd, (unsigned long)ucpmode); +} + + +static inline int +nilfs_compat_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + return nilfs_compat_locked_ioctl(inode, filp, cmd, arg); +} + +static inline int +nilfs_compat_ioctl_get_cpinfo(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg); +} + +static inline int +nilfs_compat_ioctl_get_cpstat(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + return nilfs_compat_locked_ioctl(inode, filp, cmd, arg); +} + +static inline int +nilfs_compat_ioctl_get_suinfo(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg); +} + +static int +nilfs_compat_ioctl_get_sustat(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct nilfs_sustat __user *usustat; + struct nilfs_sustat32 __user *usustat32; + time_t ctime, nongc_ctime; + int ret; + + usustat = compat_alloc_user_space(sizeof(struct nilfs_sustat)); + ret = nilfs_compat_locked_ioctl(inode, filp, cmd, + (unsigned long)usustat); + if (ret < 0) + return ret; + + usustat32 = compat_ptr(arg); + if (copy_in_user(&usustat32->ss_nsegs, &usustat->ss_nsegs, + sizeof(__u64)) || + copy_in_user(&usustat32->ss_ncleansegs, &usustat->ss_ncleansegs, + sizeof(__u64)) || + copy_in_user(&usustat32->ss_ndirtysegs, &usustat->ss_ndirtysegs, + sizeof(__u64)) || + get_user(ctime, &usustat->ss_ctime) || + put_user(ctime, &usustat32->ss_ctime) || + get_user(nongc_ctime, &usustat->ss_nongc_ctime) || + put_user(nongc_ctime, &usustat32->ss_nongc_ctime)) + return -EFAULT; + return 0; +} + +static inline int +nilfs_compat_ioctl_get_vinfo(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg); +} + +static inline int +nilfs_compat_ioctl_get_bdescs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg); +} + +static int +nilfs_compat_ioctl_clean_segments(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct nilfs_argv __user *uargv; + struct nilfs_argv32 __user *uargv32; + int i, ret; + + uargv = compat_alloc_user_space(sizeof(struct nilfs_argv) * 5); + uargv32 = compat_ptr(arg); + for (i = 0; i < 5; i++) { + ret = nilfs_compat_ioctl_uargv32_to_uargv(&uargv32[i], + &uargv[i]); + if (ret < 0) + return ret; + } + return nilfs_compat_locked_ioctl( + inode, filp, cmd, (unsigned long)uargv); +} + +static int +nilfs_compat_ioctl_timedwait(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct nilfs_wait_cond __user *uwcond; + struct nilfs_wait_cond32 __user *uwcond32; + struct timespec ts; + int cond, flags, ret; + + uwcond = compat_alloc_user_space(sizeof(struct nilfs_wait_cond)); + uwcond32 = compat_ptr(arg); + if (get_user(cond, &uwcond32->wc_cond) || + put_user(cond, &uwcond->wc_cond) || + get_user(flags, &uwcond32->wc_flags) || + put_user(flags, &uwcond->wc_flags) || + get_user(ts.tv_sec, &uwcond32->wc_timeout.tv_sec) || + get_user(ts.tv_nsec, &uwcond32->wc_timeout.tv_nsec) || + put_user(ts.tv_sec, &uwcond->wc_timeout.tv_sec) || + put_user(ts.tv_nsec, &uwcond->wc_timeout.tv_nsec)) + return -EFAULT; + + ret = nilfs_compat_locked_ioctl(inode, filp, cmd, + (unsigned long)uwcond); + if (ret < 0) + return ret; + + if (get_user(ts.tv_sec, &uwcond->wc_timeout.tv_sec) || + get_user(ts.tv_nsec, &uwcond->wc_timeout.tv_nsec) || + put_user(ts.tv_sec, &uwcond32->wc_timeout.tv_sec) || + put_user(ts.tv_nsec, &uwcond32->wc_timeout.tv_nsec)) + return -EFAULT; + + return 0; +} + +static int nilfs_compat_ioctl_sync(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + return nilfs_compat_locked_ioctl(inode, filp, cmd, arg); +} + +long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = filp->f_dentry->d_inode; + + switch (cmd) { + case NILFS_IOCTL32_CHANGE_CPMODE: + return nilfs_compat_ioctl_change_cpmode( + inode, filp, NILFS_IOCTL_CHANGE_CPMODE, arg); + case NILFS_IOCTL_DELETE_CHECKPOINT: + return nilfs_compat_ioctl_delete_checkpoint( + inode, filp, cmd, arg); + case NILFS_IOCTL32_GET_CPINFO: + return nilfs_compat_ioctl_get_cpinfo( + inode, filp, NILFS_IOCTL_GET_CPINFO, arg); + case NILFS_IOCTL_GET_CPSTAT: + return nilfs_compat_ioctl_get_cpstat(inode, filp, cmd, arg); + case NILFS_IOCTL32_GET_SUINFO: + return nilfs_compat_ioctl_get_suinfo( + inode, filp, NILFS_IOCTL_GET_SUINFO, arg); + case NILFS_IOCTL32_GET_SUSTAT: + return nilfs_compat_ioctl_get_sustat( + inode, filp, NILFS_IOCTL_GET_SUSTAT, arg); + case NILFS_IOCTL32_GET_VINFO: + return nilfs_compat_ioctl_get_vinfo( + inode, filp, NILFS_IOCTL_GET_VINFO, arg); + case NILFS_IOCTL32_GET_BDESCS: + return nilfs_compat_ioctl_get_bdescs( + inode, filp, NILFS_IOCTL_GET_BDESCS, arg); + case NILFS_IOCTL32_CLEAN_SEGMENTS: + return nilfs_compat_ioctl_clean_segments( + inode, filp, NILFS_IOCTL_CLEAN_SEGMENTS, arg); + case NILFS_IOCTL32_TIMEDWAIT: + return nilfs_compat_ioctl_timedwait( + inode, filp, NILFS_IOCTL_TIMEDWAIT, arg); + case NILFS_IOCTL_SYNC: + return nilfs_compat_ioctl_sync(inode, filp, cmd, arg); + default: + return -ENOIOCTLCMD; + } +} +#endif -- cgit v1.2.3-59-g8ed1b From 3358b4aaa84fd4c1cdd64391875e92cbb8afeb29 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 6 Apr 2009 19:01:43 -0700 Subject: nilfs2: fix problems of memory allocation in ioctl This is another patch for fixing the following problems of a memory copy function in nilfs2 ioctl: (1) It tries to allocate 128KB size of memory even for small objects. (2) Though the function repeatedly tries large memory allocations while reducing the size, GFP_NOWAIT flag is not specified. This increases the possibility of system memory shortage. (3) During the retries of (2), verbose warnings are printed because _GFP_NOWARN flag is not used for the kmalloc calls. The first patch was still doing large allocations by kmalloc which are repeatedly tried while reducing the size. Andi Kleen told me that using copy_from_user for large memory is not good from the viewpoint of preempt latency: On Fri, 12 Dec 2008 21:24:11 +0100, Andi Kleen wrote: > > In the current interface, each data item is copied twice: one is to > > the allocated memory from user space (via copy_from_user), and another > > For such large copies it is better to use multiple smaller (e.g. 4K) > copy user, that gives better real time preempt latencies. Each cfu has a > cond_resched(), but only one, not multiple times in the inner loop. He also advised me that: On Sun, 14 Dec 2008 16:13:27 +0100, Andi Kleen wrote: > Better would be if you could go to PAGE_SIZE. order 0 allocations > are typically the fastest / least likely to stall. > > Also in this case it's a good idea to use __get_free_pages() > directly, kmalloc tends to be become less efficient at larger > sizes. For the function in question, the size of buffer memory can be reduced since the buffer is repeatedly used for a number of small objects. On the other hand, it may incur large preempt latencies for larger buffer because a copy_from_user (and a copy_to_user) was applied only once each cycle. With that, this revision uses the order 0 allocations with __get_free_pages() to fix the original problems. Cc: Andi Kleen Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nilfs2/ioctl.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'fs/nilfs2/ioctl.c') diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 35ba60ea9617..02e91e167ca2 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -34,9 +34,6 @@ #include "dat.h" -#define KMALLOC_SIZE_MIN 4096 /* 4KB */ -#define KMALLOC_SIZE_MAX 131072 /* 128 KB */ - static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, struct nilfs_argv *argv, int dir, ssize_t (*dofunc)(struct the_nilfs *, @@ -44,21 +41,20 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, void *, size_t, size_t)) { void *buf; - size_t ksize, maxmembs, total, n; + size_t maxmembs, total, n; ssize_t nr; int ret, i; if (argv->v_nmembs == 0) return 0; - for (ksize = KMALLOC_SIZE_MAX; ksize >= KMALLOC_SIZE_MIN; ksize /= 2) { - buf = kmalloc(ksize, GFP_NOFS); - if (buf != NULL) - break; - } - if (ksize < KMALLOC_SIZE_MIN) + if (argv->v_size > PAGE_SIZE) + return -EINVAL; + + buf = (void *)__get_free_pages(GFP_NOFS, 0); + if (unlikely(!buf)) return -ENOMEM; - maxmembs = ksize / argv->v_size; + maxmembs = PAGE_SIZE / argv->v_size; ret = 0; total = 0; @@ -89,7 +85,7 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, } argv->v_nmembs = total; - kfree(buf); + free_pages((unsigned long)buf, 0); return ret; } -- cgit v1.2.3-59-g8ed1b From 47420c799830d4676e544dbec56b2a7f787528f5 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 6 Apr 2009 19:01:45 -0700 Subject: nilfs2: avoid double error caused by nilfs_transaction_end Pekka Enberg pointed out that double error handlings found after nilfs_transaction_end() can be avoided by separating abort operation: OK, I don't understand this. The only way nilfs_transaction_end() can fail is if we have NILFS_TI_SYNC set and we fail to construct the segment. But why do we want to construct a segment if we don't commit? I guess what I'm asking is why don't we have a separate nilfs_transaction_abort() function that can't fail for the erroneous case to avoid this double error value tracking thing? This does the separation and renames nilfs_transaction_end() to nilfs_transaction_commit() for clarification. Since, some calls of these functions were used just for exclusion control against the segment constructor, they are replaced with semaphore operations. Acked-by: Pekka Enberg Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nilfs2/inode.c | 23 +++++++++------- fs/nilfs2/ioctl.c | 58 +++++++++++++++++++++++----------------- fs/nilfs2/mdt.c | 5 +++- fs/nilfs2/namei.c | 74 +++++++++++++++++++++++++++++++++++---------------- fs/nilfs2/nilfs.h | 3 ++- fs/nilfs2/segment.c | 43 +++++++++++++++++++----------- fs/nilfs2/the_nilfs.h | 4 +-- 7 files changed, 135 insertions(+), 75 deletions(-) (limited to 'fs/nilfs2/ioctl.c') diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 289d1798decb..4bf1e2c5bac6 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -77,7 +77,6 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff, goto out; err = nilfs_bmap_insert(ii->i_bmap, (unsigned long)blkoff, (unsigned long)bh_result); - nilfs_transaction_end(inode->i_sb, !err); if (unlikely(err != 0)) { if (err == -EEXIST) { /* @@ -100,8 +99,10 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff, inode->i_ino); err = -EIO; } + nilfs_transaction_abort(inode->i_sb); goto out; } + nilfs_transaction_commit(inode->i_sb); /* never fails */ /* Error handling should be detailed */ set_buffer_new(bh_result); map_bh(bh_result, inode->i_sb, 0); /* dbn must be changed @@ -203,7 +204,7 @@ static int nilfs_write_begin(struct file *file, struct address_space *mapping, err = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, nilfs_get_block); if (unlikely(err)) - nilfs_transaction_end(inode->i_sb, 0); + nilfs_transaction_abort(inode->i_sb); return err; } @@ -221,7 +222,7 @@ static int nilfs_write_end(struct file *file, struct address_space *mapping, copied = generic_write_end(file, mapping, pos, len, copied, page, fsdata); nilfs_set_file_dirty(NILFS_SB(inode->i_sb), inode, nr_dirty); - err = nilfs_transaction_end(inode->i_sb, 1); + err = nilfs_transaction_commit(inode->i_sb); return err ? : copied; } @@ -641,7 +642,7 @@ void nilfs_truncate(struct inode *inode) nilfs_set_transaction_flag(NILFS_TI_SYNC); nilfs_set_file_dirty(NILFS_SB(sb), inode, 0); - nilfs_transaction_end(sb, 1); + nilfs_transaction_commit(sb); /* May construct a logical segment and may fail in sync mode. But truncate has no return value. */ } @@ -669,7 +670,7 @@ void nilfs_delete_inode(struct inode *inode) /* nilfs_free_inode() marks inode buffer dirty */ if (IS_SYNC(inode)) nilfs_set_transaction_flag(NILFS_TI_SYNC); - nilfs_transaction_end(sb, 1); + nilfs_transaction_commit(sb); /* May construct a logical segment and may fail in sync mode. But delete_inode has no return value. */ } @@ -679,7 +680,7 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) struct nilfs_transaction_info ti; struct inode *inode = dentry->d_inode; struct super_block *sb = inode->i_sb; - int err, err2; + int err; err = inode_change_ok(inode, iattr); if (err) @@ -691,8 +692,12 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) err = inode_setattr(inode, iattr); if (!err && (iattr->ia_valid & ATTR_MODE)) err = nilfs_acl_chmod(inode); - err2 = nilfs_transaction_end(sb, 1); - return err ? : err2; + if (likely(!err)) + err = nilfs_transaction_commit(sb); + else + nilfs_transaction_abort(sb); + + return err; } int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode, @@ -817,5 +822,5 @@ void nilfs_dirty_inode(struct inode *inode) nilfs_transaction_begin(inode->i_sb, &ti, 0); if (likely(inode->i_ino != NILFS_SKETCH_INO)) nilfs_mark_inode_dirty(inode); - nilfs_transaction_end(inode->i_sb, 1); /* never fails */ + nilfs_transaction_commit(inode->i_sb); /* never fails */ } diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 02e91e167ca2..5ce06a01c7ec 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -105,7 +105,11 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, nilfs_transaction_begin(inode->i_sb, &ti, 0); ret = nilfs_cpfile_change_cpmode( cpfile, cpmode.cm_cno, cpmode.cm_mode); - nilfs_transaction_end(inode->i_sb, !ret); + if (unlikely(ret < 0)) { + nilfs_transaction_abort(inode->i_sb); + return ret; + } + nilfs_transaction_commit(inode->i_sb); /* never fails */ return ret; } @@ -125,7 +129,11 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, nilfs_transaction_begin(inode->i_sb, &ti, 0); ret = nilfs_cpfile_delete_checkpoint(cpfile, cno); - nilfs_transaction_end(inode->i_sb, !ret); + if (unlikely(ret < 0)) { + nilfs_transaction_abort(inode->i_sb); + return ret; + } + nilfs_transaction_commit(inode->i_sb); /* never fails */ return ret; } @@ -142,16 +150,17 @@ static int nilfs_ioctl_get_cpinfo(struct inode *inode, struct file *filp, { struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; struct nilfs_argv argv; - struct nilfs_transaction_info ti; int ret; if (copy_from_user(&argv, argp, sizeof(argv))) return -EFAULT; - nilfs_transaction_begin(inode->i_sb, &ti, 0); + down_read(&nilfs->ns_segctor_sem); ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), nilfs_ioctl_do_get_cpinfo); - nilfs_transaction_end(inode->i_sb, 0); + up_read(&nilfs->ns_segctor_sem); + if (ret < 0) + return ret; if (copy_to_user(argp, &argv, sizeof(argv))) ret = -EFAULT; @@ -161,14 +170,13 @@ static int nilfs_ioctl_get_cpinfo(struct inode *inode, struct file *filp, static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp, unsigned int cmd, void __user *argp) { - struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile; + struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; struct nilfs_cpstat cpstat; - struct nilfs_transaction_info ti; int ret; - nilfs_transaction_begin(inode->i_sb, &ti, 0); - ret = nilfs_cpfile_get_stat(cpfile, &cpstat); - nilfs_transaction_end(inode->i_sb, 0); + down_read(&nilfs->ns_segctor_sem); + ret = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat); + up_read(&nilfs->ns_segctor_sem); if (ret < 0) return ret; @@ -189,16 +197,17 @@ static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp, { struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; struct nilfs_argv argv; - struct nilfs_transaction_info ti; int ret; if (copy_from_user(&argv, argp, sizeof(argv))) return -EFAULT; - nilfs_transaction_begin(inode->i_sb, &ti, 0); + down_read(&nilfs->ns_segctor_sem); ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), nilfs_ioctl_do_get_suinfo); - nilfs_transaction_end(inode->i_sb, 0); + up_read(&nilfs->ns_segctor_sem); + if (ret < 0) + return ret; if (copy_to_user(argp, &argv, sizeof(argv))) ret = -EFAULT; @@ -208,14 +217,13 @@ static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp, static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp, unsigned int cmd, void __user *argp) { - struct inode *sufile = NILFS_SB(inode->i_sb)->s_nilfs->ns_sufile; + struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; struct nilfs_sustat sustat; - struct nilfs_transaction_info ti; int ret; - nilfs_transaction_begin(inode->i_sb, &ti, 0); - ret = nilfs_sufile_get_stat(sufile, &sustat); - nilfs_transaction_end(inode->i_sb, 0); + down_read(&nilfs->ns_segctor_sem); + ret = nilfs_sufile_get_stat(nilfs->ns_sufile, &sustat); + up_read(&nilfs->ns_segctor_sem); if (ret < 0) return ret; @@ -236,16 +244,17 @@ static int nilfs_ioctl_get_vinfo(struct inode *inode, struct file *filp, { struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; struct nilfs_argv argv; - struct nilfs_transaction_info ti; int ret; if (copy_from_user(&argv, argp, sizeof(argv))) return -EFAULT; - nilfs_transaction_begin(inode->i_sb, &ti, 0); + down_read(&nilfs->ns_segctor_sem); ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), nilfs_ioctl_do_get_vinfo); - nilfs_transaction_end(inode->i_sb, 0); + up_read(&nilfs->ns_segctor_sem); + if (ret < 0) + return ret; if (copy_to_user(argp, &argv, sizeof(argv))) ret = -EFAULT; @@ -280,16 +289,17 @@ static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp, { struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; struct nilfs_argv argv; - struct nilfs_transaction_info ti; int ret; if (copy_from_user(&argv, argp, sizeof(argv))) return -EFAULT; - nilfs_transaction_begin(inode->i_sb, &ti, 0); + down_read(&nilfs->ns_segctor_sem); ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), nilfs_ioctl_do_get_bdescs); - nilfs_transaction_end(inode->i_sb, 0); + up_read(&nilfs->ns_segctor_sem); + if (ret < 0) + return ret; if (copy_to_user(argp, &argv, sizeof(argv))) ret = -EFAULT; diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 6ab847578615..e0a632b86feb 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -123,7 +123,10 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block, brelse(bh); failed_unlock: - nilfs_transaction_end(sb, !err); + if (likely(!err)) + err = nilfs_transaction_commit(sb); + else + nilfs_transaction_abort(sb); if (writer) nilfs_put_writer(nilfs); out: diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 95d1b29bff3c..df70dadb336f 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -109,7 +109,7 @@ static int nilfs_create(struct inode *dir, struct dentry *dentry, int mode, { struct inode *inode; struct nilfs_transaction_info ti; - int err, err2; + int err; err = nilfs_transaction_begin(dir->i_sb, &ti, 1); if (err) @@ -123,8 +123,12 @@ static int nilfs_create(struct inode *dir, struct dentry *dentry, int mode, mark_inode_dirty(inode); err = nilfs_add_nondir(dentry, inode); } - err2 = nilfs_transaction_end(dir->i_sb, !err); - return err ? : err2; + if (!err) + err = nilfs_transaction_commit(dir->i_sb); + else + nilfs_transaction_abort(dir->i_sb); + + return err; } static int @@ -132,7 +136,7 @@ nilfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { struct inode *inode; struct nilfs_transaction_info ti; - int err, err2; + int err; if (!new_valid_dev(rdev)) return -EINVAL; @@ -147,8 +151,12 @@ nilfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) mark_inode_dirty(inode); err = nilfs_add_nondir(dentry, inode); } - err2 = nilfs_transaction_end(dir->i_sb, !err); - return err ? : err2; + if (!err) + err = nilfs_transaction_commit(dir->i_sb); + else + nilfs_transaction_abort(dir->i_sb); + + return err; } static int nilfs_symlink(struct inode *dir, struct dentry *dentry, @@ -158,7 +166,7 @@ static int nilfs_symlink(struct inode *dir, struct dentry *dentry, struct super_block *sb = dir->i_sb; unsigned l = strlen(symname)+1; struct inode *inode; - int err, err2; + int err; if (l > sb->s_blocksize) return -ENAMETOOLONG; @@ -184,8 +192,12 @@ static int nilfs_symlink(struct inode *dir, struct dentry *dentry, err = nilfs_add_nondir(dentry, inode); out: - err2 = nilfs_transaction_end(dir->i_sb, !err); - return err ? : err2; + if (!err) + err = nilfs_transaction_commit(dir->i_sb); + else + nilfs_transaction_abort(dir->i_sb); + + return err; out_fail: inode_dec_link_count(inode); @@ -198,7 +210,7 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, { struct inode *inode = old_dentry->d_inode; struct nilfs_transaction_info ti; - int err, err2; + int err; if (inode->i_nlink >= NILFS_LINK_MAX) return -EMLINK; @@ -212,15 +224,19 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, atomic_inc(&inode->i_count); err = nilfs_add_nondir(dentry, inode); - err2 = nilfs_transaction_end(dir->i_sb, !err); - return err ? : err2; + if (!err) + err = nilfs_transaction_commit(dir->i_sb); + else + nilfs_transaction_abort(dir->i_sb); + + return err; } static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { struct inode *inode; struct nilfs_transaction_info ti; - int err, err2; + int err; if (dir->i_nlink >= NILFS_LINK_MAX) return -EMLINK; @@ -252,8 +268,12 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) d_instantiate(dentry, inode); out: - err2 = nilfs_transaction_end(dir->i_sb, !err); - return err ? : err2; + if (!err) + err = nilfs_transaction_commit(dir->i_sb); + else + nilfs_transaction_abort(dir->i_sb); + + return err; out_fail: inode_dec_link_count(inode); @@ -270,7 +290,7 @@ static int nilfs_unlink(struct inode *dir, struct dentry *dentry) struct nilfs_dir_entry *de; struct page *page; struct nilfs_transaction_info ti; - int err, err2; + int err; err = nilfs_transaction_begin(dir->i_sb, &ti, 0); if (err) @@ -300,15 +320,19 @@ static int nilfs_unlink(struct inode *dir, struct dentry *dentry) inode_dec_link_count(inode); err = 0; out: - err2 = nilfs_transaction_end(dir->i_sb, !err); - return err ? : err2; + if (!err) + err = nilfs_transaction_commit(dir->i_sb); + else + nilfs_transaction_abort(dir->i_sb); + + return err; } static int nilfs_rmdir(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct nilfs_transaction_info ti; - int err, err2; + int err; err = nilfs_transaction_begin(dir->i_sb, &ti, 0); if (err) @@ -323,8 +347,12 @@ static int nilfs_rmdir(struct inode *dir, struct dentry *dentry) inode_dec_link_count(dir); } } - err2 = nilfs_transaction_end(dir->i_sb, !err); - return err ? : err2; + if (!err) + err = nilfs_transaction_commit(dir->i_sb); + else + nilfs_transaction_abort(dir->i_sb); + + return err; } static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry, @@ -404,7 +432,7 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry, inode_dec_link_count(old_dir); } - err = nilfs_transaction_end(old_dir->i_sb, 1); + err = nilfs_transaction_commit(old_dir->i_sb); return err; out_dir: @@ -416,7 +444,7 @@ out_old: kunmap(old_page); page_cache_release(old_page); out: - nilfs_transaction_end(old_dir->i_sb, 0); + nilfs_transaction_abort(old_dir->i_sb); return err; } diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 17458ad4a809..48c070676cc5 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -166,7 +166,8 @@ struct nilfs_transaction_info { int nilfs_transaction_begin(struct super_block *, struct nilfs_transaction_info *, int); -int nilfs_transaction_end(struct super_block *, int); +int nilfs_transaction_commit(struct super_block *); +void nilfs_transaction_abort(struct super_block *); static inline void nilfs_set_transaction_flag(unsigned int flag) { diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index ad65a737aff4..6d66c5cb7b51 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -163,8 +163,8 @@ static int nilfs_prepare_segment_lock(struct nilfs_transaction_info *ti) else { /* * If journal_info field is occupied by other FS, - * we save it and restore on nilfs_transaction_end(). - * But this should never happen. + * it is saved and will be restored on + * nilfs_transaction_commit(). */ printk(KERN_WARNING "NILFS warning: journal info from a different " @@ -195,7 +195,7 @@ static int nilfs_prepare_segment_lock(struct nilfs_transaction_info *ti) * * nilfs_transaction_begin() acquires a reader/writer semaphore, called * the segment semaphore, to make a segment construction and write tasks - * exclusive. The function is used with nilfs_transaction_end() in pairs. + * exclusive. The function is used with nilfs_transaction_commit() in pairs. * The region enclosed by these two functions can be nested. To avoid a * deadlock, the semaphore is only acquired or released in the outermost call. * @@ -212,8 +212,6 @@ static int nilfs_prepare_segment_lock(struct nilfs_transaction_info *ti) * * %-ENOMEM - Insufficient memory available. * - * %-ERESTARTSYS - Interrupted - * * %-ENOSPC - No space left on device */ int nilfs_transaction_begin(struct super_block *sb, @@ -248,16 +246,17 @@ int nilfs_transaction_begin(struct super_block *sb, } /** - * nilfs_transaction_end - end indivisible file operations. + * nilfs_transaction_commit - commit indivisible file operations. * @sb: super block - * @commit: commit flag (0 for no change) * - * nilfs_transaction_end() releases the read semaphore which is - * acquired by nilfs_transaction_begin(). Its releasing is only done - * in outermost call of this function. If the nilfs_transaction_info - * was allocated dynamically, it is given back to a slab cache. + * nilfs_transaction_commit() releases the read semaphore which is + * acquired by nilfs_transaction_begin(). This is only performed + * in outermost call of this function. If a commit flag is set, + * nilfs_transaction_commit() sets a timer to start the segment + * constructor. If a sync flag is set, it starts construction + * directly. */ -int nilfs_transaction_end(struct super_block *sb, int commit) +int nilfs_transaction_commit(struct super_block *sb) { struct nilfs_transaction_info *ti = current->journal_info; struct nilfs_sb_info *sbi; @@ -265,9 +264,7 @@ int nilfs_transaction_end(struct super_block *sb, int commit) int err = 0; BUG_ON(ti == NULL || ti->ti_magic != NILFS_TI_MAGIC); - - if (commit) - ti->ti_flags |= NILFS_TI_COMMIT; + ti->ti_flags |= NILFS_TI_COMMIT; if (ti->ti_count > 0) { ti->ti_count--; return 0; @@ -291,6 +288,22 @@ int nilfs_transaction_end(struct super_block *sb, int commit) return err; } +void nilfs_transaction_abort(struct super_block *sb) +{ + struct nilfs_transaction_info *ti = current->journal_info; + + BUG_ON(ti == NULL || ti->ti_magic != NILFS_TI_MAGIC); + if (ti->ti_count > 0) { + ti->ti_count--; + return; + } + up_read(&NILFS_SB(sb)->s_nilfs->ns_segctor_sem); + + current->journal_info = ti->ti_save; + if (ti->ti_flags & NILFS_TI_DYNAMIC_ALLOC) + kmem_cache_free(nilfs_transaction_cachep, ti); +} + void nilfs_relax_pressure_in_lock(struct super_block *sb) { struct nilfs_sb_info *sbi = NILFS_SB(sb); diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index dee8d83e0549..9cd3c113f052 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -112,8 +112,8 @@ struct the_nilfs { /* * Following fields are dedicated to a writable FS-instance. * Except for the period seeking checkpoint, code outside the segment - * constructor must lock a segment semaphore with transaction_begin() - * and transaction_end(), when accessing these fields. + * constructor must lock a segment semaphore while accessing these + * fields. * The writable FS-instance is sole during a lifetime of the_nilfs. */ u64 ns_seg_seq; -- cgit v1.2.3-59-g8ed1b From b028fcfc4cd198a6aa1ffcfb872073ccc1db3459 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 6 Apr 2009 19:01:47 -0700 Subject: nilfs2: fix gc failure on volumes keeping numerous snapshots This resolves the following failure of nilfs2 cleaner daemon: nilfs_cleanerd[20670]: cannot clean segments: No such file or directory nilfs_cleanerd[20670]: shutdown When creating thousands of snapshots, the cleaner daemon had rarely died as above due to an error returned from the kernel code. After applying the recent patch which fixed memory allocation problems in ioctl (Message-Id: <20081215.155840.105124170.ryusuke@osrg.net>), the problem gets more frequent. It turned out to be a bug of nilfs_ioctl_wrap_copy function and one of its callback routines to read out information of snapshots; if the nilfs_ioctl_wrap_copy function divided a large read request into multiple requests, the second and later requests have failed since a restart position on snapshot meta data was not properly set forward. It's a deficiency of the callback interface that cannot pass the restart position among multiple requests. This patch fixes the issue by allowing nilfs_ioctl_wrap_copy and snapshot read functions to exchange a position argument. Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nilfs2/cpfile.c | 24 ++++++++++++++---------- fs/nilfs2/cpfile.h | 2 +- fs/nilfs2/ioctl.c | 38 +++++++++++++++++++++++--------------- 3 files changed, 38 insertions(+), 26 deletions(-) (limited to 'fs/nilfs2/ioctl.c') diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 82462acd06ee..a4c9550fd774 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c @@ -422,20 +422,20 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 cno, return ret; } -static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 cno, +static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, struct nilfs_cpinfo *ci, size_t nci) { struct buffer_head *bh; struct nilfs_cpfile_header *header; struct nilfs_checkpoint *cp; - __u64 curr, next; + __u64 curr = *cnop, next; unsigned long curr_blkoff, next_blkoff; void *kaddr; int n, ret; down_read(&NILFS_MDT(cpfile)->mi_sem); - if (cno == 0) { + if (curr == 0) { ret = nilfs_cpfile_get_header_block(cpfile, &bh); if (ret < 0) goto out; @@ -448,8 +448,11 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 cno, ret = 0; goto out; } - } else - curr = cno; + } else if (unlikely(curr == ~(__u64)0)) { + ret = 0; + goto out; + } + curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr); ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh); if (ret < 0) @@ -461,7 +464,7 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 cno, nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, &ci[n]); next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); if (next == 0) { - curr = next; + curr = ~(__u64)0; /* Terminator */ n++; break; } @@ -480,6 +483,7 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 cno, } kunmap_atomic(kaddr, KM_USER0); brelse(bh); + *cnop = curr; ret = n; out: @@ -494,15 +498,15 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 cno, * @ci: * @nci: */ -ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, - __u64 cno, int mode, + +ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, struct nilfs_cpinfo *ci, size_t nci) { switch (mode) { case NILFS_CHECKPOINT: - return nilfs_cpfile_do_get_cpinfo(cpfile, cno, ci, nci); + return nilfs_cpfile_do_get_cpinfo(cpfile, *cnop, ci, nci); case NILFS_SNAPSHOT: - return nilfs_cpfile_do_get_ssinfo(cpfile, cno, ci, nci); + return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci); default: return -EINVAL; } diff --git a/fs/nilfs2/cpfile.h b/fs/nilfs2/cpfile.h index f097e90fcb20..1a8a1008c342 100644 --- a/fs/nilfs2/cpfile.h +++ b/fs/nilfs2/cpfile.h @@ -39,7 +39,7 @@ int nilfs_cpfile_delete_checkpoint(struct inode *, __u64); int nilfs_cpfile_change_cpmode(struct inode *, __u64, int); int nilfs_cpfile_is_snapshot(struct inode *, __u64); int nilfs_cpfile_get_stat(struct inode *, struct nilfs_cpstat *); -ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64, int, +ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64 *, int, struct nilfs_cpinfo *, size_t); #endif /* _NILFS_CPFILE_H */ diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 5ce06a01c7ec..d9e3990f9589 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -37,13 +37,14 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, struct nilfs_argv *argv, int dir, ssize_t (*dofunc)(struct the_nilfs *, - int, int, + __u64 *, int, void *, size_t, size_t)) { void *buf; size_t maxmembs, total, n; ssize_t nr; int ret, i; + __u64 pos, ppos; if (argv->v_nmembs == 0) return 0; @@ -58,6 +59,7 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, ret = 0; total = 0; + pos = argv->v_index; for (i = 0; i < argv->v_nmembs; i += n) { n = (argv->v_nmembs - i < maxmembs) ? argv->v_nmembs - i : maxmembs; @@ -68,8 +70,9 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, ret = -EFAULT; break; } - nr = (*dofunc)(nilfs, argv->v_index + i, argv->v_flags, buf, - argv->v_size, n); + ppos = pos; + nr = (*dofunc)(nilfs, &pos, argv->v_flags, buf, argv->v_size, + n); if (nr < 0) { ret = nr; break; @@ -82,6 +85,10 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, break; } total += nr; + if ((size_t)nr < n) + break; + if (pos == ppos) + pos += n; } argv->v_nmembs = total; @@ -138,10 +145,10 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, } static ssize_t -nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, int index, int flags, +nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, void *buf, size_t size, size_t nmembs) { - return nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, index, flags, buf, + return nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf, nmembs); } @@ -186,10 +193,10 @@ static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp, } static ssize_t -nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, int index, int flags, +nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, void *buf, size_t size, size_t nmembs) { - return nilfs_sufile_get_suinfo(nilfs->ns_sufile, index, buf, nmembs); + return nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, nmembs); } static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp, @@ -233,7 +240,7 @@ static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp, } static ssize_t -nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, int index, int flags, +nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, void *buf, size_t size, size_t nmembs) { return nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs); @@ -262,7 +269,7 @@ static int nilfs_ioctl_get_vinfo(struct inode *inode, struct file *filp, } static ssize_t -nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, int index, int flags, +nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags, void *buf, size_t size, size_t nmembs) { struct inode *dat = nilfs_dat_inode(nilfs); @@ -341,7 +348,7 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode, } static ssize_t -nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, int index, int flags, +nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, __u64 *posp, int flags, void *buf, size_t size, size_t nmembs) { struct inode *inode; @@ -413,7 +420,7 @@ static inline int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs, } static ssize_t -nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, int index, +nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, __u64 *posp, int flags, void *buf, size_t size, size_t nmembs) { @@ -439,7 +446,7 @@ static inline int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs, } static ssize_t -nilfs_ioctl_do_free_vblocknrs(struct the_nilfs *nilfs, int index, int flags, +nilfs_ioctl_do_free_vblocknrs(struct the_nilfs *nilfs, __u64 *posp, int flags, void *buf, size_t size, size_t nmembs) { int ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs); @@ -456,8 +463,9 @@ static inline int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs, } static ssize_t -nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, int index, int flags, - void *buf, size_t size, size_t nmembs) +nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, __u64 *posp, + int flags, void *buf, size_t size, + size_t nmembs) { struct inode *dat = nilfs_dat_inode(nilfs); struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; @@ -506,7 +514,7 @@ static inline int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, } static ssize_t -nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, int index, int flags, +nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, __u64 *posp, int flags, void *buf, size_t size, size_t nmembs) { struct nilfs_sb_info *sbi = nilfs_get_writer(nilfs); -- cgit v1.2.3-59-g8ed1b From 8acfbf0939e98cc77dab94c24899c9930ddd1e13 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Mon, 6 Apr 2009 19:01:49 -0700 Subject: nilfs2: clean up indirect function calling conventions This cleans up the strange indirect function calling convention used in nilfs to follow the normal kernel coding style. Signed-off-by: Pekka Enberg Acked-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nilfs2/bmap.c | 46 ++++++++++++++++++++-------------------- fs/nilfs2/btree.c | 62 +++++++++++++++++++++++++++--------------------------- fs/nilfs2/direct.c | 28 ++++++++++++------------ fs/nilfs2/ioctl.c | 2 +- 4 files changed, 69 insertions(+), 69 deletions(-) (limited to 'fs/nilfs2/ioctl.c') diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index 6fe72addc9c5..24638e059bf3 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -38,11 +38,11 @@ int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level, int ret; down_read(&bmap->b_sem); - ret = (*bmap->b_ops->bop_lookup)(bmap, key, level, ptrp); + ret = bmap->b_ops->bop_lookup(bmap, key, level, ptrp); if (ret < 0) goto out; if (bmap->b_pops->bpop_translate != NULL) { - ret = (*bmap->b_pops->bpop_translate)(bmap, *ptrp, &ptr); + ret = bmap->b_pops->bpop_translate(bmap, *ptrp, &ptr); if (ret < 0) goto out; *ptrp = ptr; @@ -94,9 +94,9 @@ static int nilfs_bmap_do_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) int ret, n; if (bmap->b_ops->bop_check_insert != NULL) { - ret = (*bmap->b_ops->bop_check_insert)(bmap, key); + ret = bmap->b_ops->bop_check_insert(bmap, key); if (ret > 0) { - n = (*bmap->b_ops->bop_gather_data)( + n = bmap->b_ops->bop_gather_data( bmap, keys, ptrs, NILFS_BMAP_SMALL_HIGH + 1); if (n < 0) return n; @@ -111,7 +111,7 @@ static int nilfs_bmap_do_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) return ret; } - return (*bmap->b_ops->bop_insert)(bmap, key, ptr); + return bmap->b_ops->bop_insert(bmap, key, ptr); } /** @@ -151,9 +151,9 @@ static int nilfs_bmap_do_delete(struct nilfs_bmap *bmap, __u64 key) int ret, n; if (bmap->b_ops->bop_check_delete != NULL) { - ret = (*bmap->b_ops->bop_check_delete)(bmap, key); + ret = bmap->b_ops->bop_check_delete(bmap, key); if (ret > 0) { - n = (*bmap->b_ops->bop_gather_data)( + n = bmap->b_ops->bop_gather_data( bmap, keys, ptrs, NILFS_BMAP_LARGE_LOW + 1); if (n < 0) return n; @@ -168,7 +168,7 @@ static int nilfs_bmap_do_delete(struct nilfs_bmap *bmap, __u64 key) return ret; } - return (*bmap->b_ops->bop_delete)(bmap, key); + return bmap->b_ops->bop_delete(bmap, key); } int nilfs_bmap_last_key(struct nilfs_bmap *bmap, unsigned long *key) @@ -177,7 +177,7 @@ int nilfs_bmap_last_key(struct nilfs_bmap *bmap, unsigned long *key) int ret; down_read(&bmap->b_sem); - ret = (*bmap->b_ops->bop_last_key)(bmap, &lastkey); + ret = bmap->b_ops->bop_last_key(bmap, &lastkey); if (!ret) *key = lastkey; up_read(&bmap->b_sem); @@ -216,7 +216,7 @@ static int nilfs_bmap_do_truncate(struct nilfs_bmap *bmap, unsigned long key) __u64 lastkey; int ret; - ret = (*bmap->b_ops->bop_last_key)(bmap, &lastkey); + ret = bmap->b_ops->bop_last_key(bmap, &lastkey); if (ret < 0) { if (ret == -ENOENT) ret = 0; @@ -227,7 +227,7 @@ static int nilfs_bmap_do_truncate(struct nilfs_bmap *bmap, unsigned long key) ret = nilfs_bmap_do_delete(bmap, lastkey); if (ret < 0) return ret; - ret = (*bmap->b_ops->bop_last_key)(bmap, &lastkey); + ret = bmap->b_ops->bop_last_key(bmap, &lastkey); if (ret < 0) { if (ret == -ENOENT) ret = 0; @@ -272,7 +272,7 @@ void nilfs_bmap_clear(struct nilfs_bmap *bmap) { down_write(&bmap->b_sem); if (bmap->b_ops->bop_clear != NULL) - (*bmap->b_ops->bop_clear)(bmap); + bmap->b_ops->bop_clear(bmap); up_write(&bmap->b_sem); } @@ -296,7 +296,7 @@ int nilfs_bmap_propagate(struct nilfs_bmap *bmap, struct buffer_head *bh) int ret; down_write(&bmap->b_sem); - ret = (*bmap->b_ops->bop_propagate)(bmap, bh); + ret = bmap->b_ops->bop_propagate(bmap, bh); up_write(&bmap->b_sem); return ret; } @@ -310,7 +310,7 @@ void nilfs_bmap_lookup_dirty_buffers(struct nilfs_bmap *bmap, struct list_head *listp) { if (bmap->b_ops->bop_lookup_dirty_buffers != NULL) - (*bmap->b_ops->bop_lookup_dirty_buffers)(bmap, listp); + bmap->b_ops->bop_lookup_dirty_buffers(bmap, listp); } /** @@ -340,7 +340,7 @@ int nilfs_bmap_assign(struct nilfs_bmap *bmap, int ret; down_write(&bmap->b_sem); - ret = (*bmap->b_ops->bop_assign)(bmap, bh, blocknr, binfo); + ret = bmap->b_ops->bop_assign(bmap, bh, blocknr, binfo); up_write(&bmap->b_sem); return ret; } @@ -369,7 +369,7 @@ int nilfs_bmap_mark(struct nilfs_bmap *bmap, __u64 key, int level) return 0; down_write(&bmap->b_sem); - ret = (*bmap->b_ops->bop_mark)(bmap, key, level); + ret = bmap->b_ops->bop_mark(bmap, key, level); up_write(&bmap->b_sem); return ret; } @@ -572,12 +572,12 @@ int nilfs_bmap_prepare_update(struct nilfs_bmap *bmap, { int ret; - ret = (*bmap->b_pops->bpop_prepare_end_ptr)(bmap, oldreq); + ret = bmap->b_pops->bpop_prepare_end_ptr(bmap, oldreq); if (ret < 0) return ret; - ret = (*bmap->b_pops->bpop_prepare_alloc_ptr)(bmap, newreq); + ret = bmap->b_pops->bpop_prepare_alloc_ptr(bmap, newreq); if (ret < 0) - (*bmap->b_pops->bpop_abort_end_ptr)(bmap, oldreq); + bmap->b_pops->bpop_abort_end_ptr(bmap, oldreq); return ret; } @@ -586,16 +586,16 @@ void nilfs_bmap_commit_update(struct nilfs_bmap *bmap, union nilfs_bmap_ptr_req *oldreq, union nilfs_bmap_ptr_req *newreq) { - (*bmap->b_pops->bpop_commit_end_ptr)(bmap, oldreq); - (*bmap->b_pops->bpop_commit_alloc_ptr)(bmap, newreq); + bmap->b_pops->bpop_commit_end_ptr(bmap, oldreq); + bmap->b_pops->bpop_commit_alloc_ptr(bmap, newreq); } void nilfs_bmap_abort_update(struct nilfs_bmap *bmap, union nilfs_bmap_ptr_req *oldreq, union nilfs_bmap_ptr_req *newreq) { - (*bmap->b_pops->bpop_abort_end_ptr)(bmap, oldreq); - (*bmap->b_pops->bpop_abort_alloc_ptr)(bmap, newreq); + bmap->b_pops->bpop_abort_end_ptr(bmap, oldreq); + bmap->b_pops->bpop_abort_alloc_ptr(bmap, newreq); } static int nilfs_bmap_translate_v(const struct nilfs_bmap *bmap, __u64 ptr, diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 893f0190a61f..53f0d4c31cb0 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -902,9 +902,9 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, /* allocate a new ptr for data block */ if (btree->bt_ops->btop_find_target != NULL) path[level].bp_newreq.bpr_ptr = - (*btree->bt_ops->btop_find_target)(btree, path, key); + btree->bt_ops->btop_find_target(btree, path, key); - ret = (*btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr)( + ret = btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr( &btree->bt_bmap, &path[level].bp_newreq); if (ret < 0) goto err_out_data; @@ -965,7 +965,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, /* split */ path[level].bp_newreq.bpr_ptr = path[level - 1].bp_newreq.bpr_ptr + 1; - ret = (*btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr)( + ret = btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr( &btree->bt_bmap, &path[level].bp_newreq); if (ret < 0) goto err_out_child_node; @@ -997,7 +997,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, /* grow */ path[level].bp_newreq.bpr_ptr = path[level - 1].bp_newreq.bpr_ptr + 1; - ret = (*btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr)( + ret = btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr( &btree->bt_bmap, &path[level].bp_newreq); if (ret < 0) goto err_out_child_node; @@ -1026,17 +1026,17 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, /* error */ err_out_curr_node: - (*btree->bt_bmap.b_pops->bpop_abort_alloc_ptr)(&btree->bt_bmap, - &path[level].bp_newreq); + btree->bt_bmap.b_pops->bpop_abort_alloc_ptr(&btree->bt_bmap, + &path[level].bp_newreq); err_out_child_node: for (level--; level > NILFS_BTREE_LEVEL_DATA; level--) { nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_sib_bh); - (*btree->bt_bmap.b_pops->bpop_abort_alloc_ptr)( + btree->bt_bmap.b_pops->bpop_abort_alloc_ptr( &btree->bt_bmap, &path[level].bp_newreq); } - (*btree->bt_bmap.b_pops->bpop_abort_alloc_ptr)(&btree->bt_bmap, + btree->bt_bmap.b_pops->bpop_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq); err_out_data: *levelp = level; @@ -1053,14 +1053,14 @@ static void nilfs_btree_commit_insert(struct nilfs_btree *btree, set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr)); ptr = path[NILFS_BTREE_LEVEL_DATA].bp_newreq.bpr_ptr; if (btree->bt_ops->btop_set_target != NULL) - (*btree->bt_ops->btop_set_target)(btree, key, ptr); + btree->bt_ops->btop_set_target(btree, key, ptr); for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { if (btree->bt_bmap.b_pops->bpop_commit_alloc_ptr != NULL) { - (*btree->bt_bmap.b_pops->bpop_commit_alloc_ptr)( + btree->bt_bmap.b_pops->bpop_commit_alloc_ptr( &btree->bt_bmap, &path[level - 1].bp_newreq); } - (*path[level].bp_op)(btree, path, level, &key, &ptr); + path[level].bp_op(btree, path, level, &key, &ptr); } if (!nilfs_bmap_dirty(&btree->bt_bmap)) @@ -1304,7 +1304,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, nilfs_btree_node_get_ptr(btree, node, path[level].bp_index); if (btree->bt_bmap.b_pops->bpop_prepare_end_ptr != NULL) { - ret = (*btree->bt_bmap.b_pops->bpop_prepare_end_ptr)( + ret = btree->bt_bmap.b_pops->bpop_prepare_end_ptr( &btree->bt_bmap, &path[level].bp_oldreq); if (ret < 0) goto err_out_child_node; @@ -1385,7 +1385,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, path[level].bp_oldreq.bpr_ptr = nilfs_btree_node_get_ptr(btree, node, path[level].bp_index); if (btree->bt_bmap.b_pops->bpop_prepare_end_ptr != NULL) { - ret = (*btree->bt_bmap.b_pops->bpop_prepare_end_ptr)( + ret = btree->bt_bmap.b_pops->bpop_prepare_end_ptr( &btree->bt_bmap, &path[level].bp_oldreq); if (ret < 0) goto err_out_child_node; @@ -1402,13 +1402,13 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, /* error */ err_out_curr_node: if (btree->bt_bmap.b_pops->bpop_abort_end_ptr != NULL) - (*btree->bt_bmap.b_pops->bpop_abort_end_ptr)( + btree->bt_bmap.b_pops->bpop_abort_end_ptr( &btree->bt_bmap, &path[level].bp_oldreq); err_out_child_node: for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--) { nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); if (btree->bt_bmap.b_pops->bpop_abort_end_ptr != NULL) - (*btree->bt_bmap.b_pops->bpop_abort_end_ptr)( + btree->bt_bmap.b_pops->bpop_abort_end_ptr( &btree->bt_bmap, &path[level].bp_oldreq); } *levelp = level; @@ -1424,9 +1424,9 @@ static void nilfs_btree_commit_delete(struct nilfs_btree *btree, for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { if (btree->bt_bmap.b_pops->bpop_commit_end_ptr != NULL) - (*btree->bt_bmap.b_pops->bpop_commit_end_ptr)( + btree->bt_bmap.b_pops->bpop_commit_end_ptr( &btree->bt_bmap, &path[level].bp_oldreq); - (*path[level].bp_op)(btree, path, level, NULL, NULL); + path[level].bp_op(btree, path, level, NULL, NULL); } if (!nilfs_bmap_dirty(&btree->bt_bmap)) @@ -1589,8 +1589,8 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, /* cannot find near ptr */ if (btree->bt_ops->btop_find_target != NULL) dreq->bpr_ptr - = (*btree->bt_ops->btop_find_target)(btree, NULL, key); - ret = (*bmap->b_pops->bpop_prepare_alloc_ptr)(bmap, dreq); + = btree->bt_ops->btop_find_target(btree, NULL, key); + ret = bmap->b_pops->bpop_prepare_alloc_ptr(bmap, dreq); if (ret < 0) return ret; @@ -1598,7 +1598,7 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, stats->bs_nblocks++; if (nreq != NULL) { nreq->bpr_ptr = dreq->bpr_ptr + 1; - ret = (*bmap->b_pops->bpop_prepare_alloc_ptr)(bmap, nreq); + ret = bmap->b_pops->bpop_prepare_alloc_ptr(bmap, nreq); if (ret < 0) goto err_out_dreq; @@ -1615,9 +1615,9 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, /* error */ err_out_nreq: - (*bmap->b_pops->bpop_abort_alloc_ptr)(bmap, nreq); + bmap->b_pops->bpop_abort_alloc_ptr(bmap, nreq); err_out_dreq: - (*bmap->b_pops->bpop_abort_alloc_ptr)(bmap, dreq); + bmap->b_pops->bpop_abort_alloc_ptr(bmap, dreq); stats->bs_nblocks = 0; return ret; @@ -1638,7 +1638,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, /* free resources */ if (bmap->b_ops->bop_clear != NULL) - (*bmap->b_ops->bop_clear)(bmap); + bmap->b_ops->bop_clear(bmap); /* ptr must be a pointer to a buffer head. */ set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr)); @@ -1648,8 +1648,8 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, nilfs_btree_init(bmap, low, high); if (nreq != NULL) { if (bmap->b_pops->bpop_commit_alloc_ptr != NULL) { - (*bmap->b_pops->bpop_commit_alloc_ptr)(bmap, dreq); - (*bmap->b_pops->bpop_commit_alloc_ptr)(bmap, nreq); + bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); + bmap->b_pops->bpop_commit_alloc_ptr(bmap, nreq); } /* create child node at level 1 */ @@ -1673,7 +1673,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, 2, 1, &keys[0], &tmpptr); } else { if (bmap->b_pops->bpop_commit_alloc_ptr != NULL) - (*bmap->b_pops->bpop_commit_alloc_ptr)(bmap, dreq); + bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); /* create root node at level 1 */ node = nilfs_btree_get_root(btree); @@ -1686,7 +1686,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, } if (btree->bt_ops->btop_set_target != NULL) - (*btree->bt_ops->btop_set_target)(btree, key, dreq->bpr_ptr); + btree->bt_ops->btop_set_target(btree, key, dreq->bpr_ptr); } /** @@ -1937,7 +1937,7 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap, goto out; } - ret = (*btree->bt_ops->btop_propagate)(btree, path, level, bh); + ret = btree->bt_ops->btop_propagate(btree, path, level, bh); out: nilfs_btree_clear_path(btree, path); @@ -2073,11 +2073,11 @@ static int nilfs_btree_assign_v(struct nilfs_btree *btree, ptr = nilfs_btree_node_get_ptr(btree, parent, path[level + 1].bp_index); req.bpr_ptr = ptr; - ret = (*btree->bt_bmap.b_pops->bpop_prepare_start_ptr)(&btree->bt_bmap, + ret = btree->bt_bmap.b_pops->bpop_prepare_start_ptr(&btree->bt_bmap, &req); if (ret < 0) return ret; - (*btree->bt_bmap.b_pops->bpop_commit_start_ptr)(&btree->bt_bmap, + btree->bt_bmap.b_pops->bpop_commit_start_ptr(&btree->bt_bmap, &req, blocknr); key = nilfs_btree_node_get_key(btree, parent, @@ -2121,7 +2121,7 @@ static int nilfs_btree_assign(struct nilfs_bmap *bmap, goto out; } - ret = (*btree->bt_ops->btop_assign)(btree, path, level, bh, + ret = btree->bt_ops->btop_assign(btree, path, level, bh, blocknr, binfo); out: diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c index 303d7f1982f9..e3ec24850089 100644 --- a/fs/nilfs2/direct.c +++ b/fs/nilfs2/direct.c @@ -91,8 +91,8 @@ static int nilfs_direct_prepare_insert(struct nilfs_direct *direct, int ret; if (direct->d_ops->dop_find_target != NULL) - req->bpr_ptr = (*direct->d_ops->dop_find_target)(direct, key); - ret = (*direct->d_bmap.b_pops->bpop_prepare_alloc_ptr)(&direct->d_bmap, + req->bpr_ptr = direct->d_ops->dop_find_target(direct, key); + ret = direct->d_bmap.b_pops->bpop_prepare_alloc_ptr(&direct->d_bmap, req); if (ret < 0) return ret; @@ -112,7 +112,7 @@ static void nilfs_direct_commit_insert(struct nilfs_direct *direct, set_buffer_nilfs_volatile(bh); if (direct->d_bmap.b_pops->bpop_commit_alloc_ptr != NULL) - (*direct->d_bmap.b_pops->bpop_commit_alloc_ptr)( + direct->d_bmap.b_pops->bpop_commit_alloc_ptr( &direct->d_bmap, req); nilfs_direct_set_ptr(direct, key, req->bpr_ptr); @@ -120,7 +120,7 @@ static void nilfs_direct_commit_insert(struct nilfs_direct *direct, nilfs_bmap_set_dirty(&direct->d_bmap); if (direct->d_ops->dop_set_target != NULL) - (*direct->d_ops->dop_set_target)(direct, key, req->bpr_ptr); + direct->d_ops->dop_set_target(direct, key, req->bpr_ptr); } static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) @@ -154,7 +154,7 @@ static int nilfs_direct_prepare_delete(struct nilfs_direct *direct, if (direct->d_bmap.b_pops->bpop_prepare_end_ptr != NULL) { req->bpr_ptr = nilfs_direct_get_ptr(direct, key); - ret = (*direct->d_bmap.b_pops->bpop_prepare_end_ptr)( + ret = direct->d_bmap.b_pops->bpop_prepare_end_ptr( &direct->d_bmap, req); if (ret < 0) return ret; @@ -169,7 +169,7 @@ static void nilfs_direct_commit_delete(struct nilfs_direct *direct, __u64 key) { if (direct->d_bmap.b_pops->bpop_commit_end_ptr != NULL) - (*direct->d_bmap.b_pops->bpop_commit_end_ptr)( + direct->d_bmap.b_pops->bpop_commit_end_ptr( &direct->d_bmap, req); nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR); } @@ -255,13 +255,13 @@ int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, /* no need to allocate any resource for conversion */ /* delete */ - ret = (*bmap->b_ops->bop_delete)(bmap, key); + ret = bmap->b_ops->bop_delete(bmap, key); if (ret < 0) return ret; /* free resources */ if (bmap->b_ops->bop_clear != NULL) - (*bmap->b_ops->bop_clear)(bmap); + bmap->b_ops->bop_clear(bmap); /* convert */ direct = (struct nilfs_direct *)bmap; @@ -314,7 +314,7 @@ static int nilfs_direct_propagate(const struct nilfs_bmap *bmap, direct = (struct nilfs_direct *)bmap; return (direct->d_ops->dop_propagate != NULL) ? - (*direct->d_ops->dop_propagate)(direct, bh) : + direct->d_ops->dop_propagate(direct, bh) : 0; } @@ -328,12 +328,12 @@ static int nilfs_direct_assign_v(struct nilfs_direct *direct, int ret; req.bpr_ptr = ptr; - ret = (*direct->d_bmap.b_pops->bpop_prepare_start_ptr)( + ret = direct->d_bmap.b_pops->bpop_prepare_start_ptr( &direct->d_bmap, &req); if (ret < 0) return ret; - (*direct->d_bmap.b_pops->bpop_commit_start_ptr)(&direct->d_bmap, - &req, blocknr); + direct->d_bmap.b_pops->bpop_commit_start_ptr(&direct->d_bmap, + &req, blocknr); binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr); binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key); @@ -370,8 +370,8 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap, ptr = nilfs_direct_get_ptr(direct, key); BUG_ON(ptr == NILFS_BMAP_INVALID_PTR); - return (*direct->d_ops->dop_assign)(direct, key, ptr, bh, - blocknr, binfo); + return direct->d_ops->dop_assign(direct, key, ptr, bh, + blocknr, binfo); } static const struct nilfs_bmap_operations nilfs_direct_ops = { diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index d9e3990f9589..9e4d9e64c8ff 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -71,7 +71,7 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, break; } ppos = pos; - nr = (*dofunc)(nilfs, &pos, argv->v_flags, buf, argv->v_size, + nr = dofunc(nilfs, &pos, argv->v_flags, buf, argv->v_size, n); if (nr < 0) { ret = nr; -- cgit v1.2.3-59-g8ed1b From 1088dcf4c3a0a27fdad5214781d5084b11405238 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 6 Apr 2009 19:01:51 -0700 Subject: nilfs2: remove timedwait ioctl command This removes NILFS_IOCTL_TIMEDWAIT command from ioctl interface along with the related flags and wait queue. The command is terrible because it just sleeps in the ioctl. I prefer to avoid this by devising means of event polling in userland program. By reconsidering the userland GC daemon, I found this is possible without changing behaviour of the daemon and sacrificing efficiency. Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nilfs2/ioctl.c | 95 +---------------------------------------------- fs/nilfs2/segment.c | 5 +-- fs/nilfs2/the_nilfs.c | 1 - fs/nilfs2/the_nilfs.h | 6 --- include/linux/nilfs2_fs.h | 22 ----------- 5 files changed, 2 insertions(+), 127 deletions(-) (limited to 'fs/nilfs2/ioctl.c') diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 9e4d9e64c8ff..85a291ccc1be 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -578,62 +578,9 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, unsigned int cmd, void __user *argp) { - int ret; - if (!capable(CAP_SYS_ADMIN)) return -EPERM; - - ret = nilfs_clean_segments(inode->i_sb, argp); - clear_nilfs_cond_nongc_write(NILFS_SB(inode->i_sb)->s_nilfs); - return ret; -} - -static int nilfs_ioctl_test_cond(struct the_nilfs *nilfs, int cond) -{ - return (cond & NILFS_TIMEDWAIT_SEG_WRITE) && - nilfs_cond_nongc_write(nilfs); -} - -static void nilfs_ioctl_clear_cond(struct the_nilfs *nilfs, int cond) -{ - if (cond & NILFS_TIMEDWAIT_SEG_WRITE) - clear_nilfs_cond_nongc_write(nilfs); -} - -static int nilfs_ioctl_timedwait(struct inode *inode, struct file *filp, - unsigned int cmd, void __user *argp) -{ - struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; - struct nilfs_wait_cond wc; - long ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (copy_from_user(&wc, argp, sizeof(wc))) - return -EFAULT; - - unlock_kernel(); - ret = wc.wc_flags ? - wait_event_interruptible_timeout( - nilfs->ns_cleanerd_wq, - nilfs_ioctl_test_cond(nilfs, wc.wc_cond), - timespec_to_jiffies(&wc.wc_timeout)) : - wait_event_interruptible( - nilfs->ns_cleanerd_wq, - nilfs_ioctl_test_cond(nilfs, wc.wc_cond)); - lock_kernel(); - nilfs_ioctl_clear_cond(nilfs, wc.wc_cond); - - if (ret > 0) { - jiffies_to_timespec(ret, &wc.wc_timeout); - if (copy_to_user(argp, &wc, sizeof(wc))) - return -EFAULT; - return 0; - } - if (ret != 0) - return -EINTR; - - return wc.wc_flags ? -ETIME : 0; + return nilfs_clean_segments(inode->i_sb, argp); } static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, @@ -679,8 +626,6 @@ int nilfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp); case NILFS_IOCTL_CLEAN_SEGMENTS: return nilfs_ioctl_clean_segments(inode, filp, cmd, argp); - case NILFS_IOCTL_TIMEDWAIT: - return nilfs_ioctl_timedwait(inode, filp, cmd, argp); case NILFS_IOCTL_SYNC: return nilfs_ioctl_sync(inode, filp, cmd, argp); default: @@ -871,41 +816,6 @@ nilfs_compat_ioctl_clean_segments(struct inode *inode, struct file *filp, inode, filp, cmd, (unsigned long)uargv); } -static int -nilfs_compat_ioctl_timedwait(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct nilfs_wait_cond __user *uwcond; - struct nilfs_wait_cond32 __user *uwcond32; - struct timespec ts; - int cond, flags, ret; - - uwcond = compat_alloc_user_space(sizeof(struct nilfs_wait_cond)); - uwcond32 = compat_ptr(arg); - if (get_user(cond, &uwcond32->wc_cond) || - put_user(cond, &uwcond->wc_cond) || - get_user(flags, &uwcond32->wc_flags) || - put_user(flags, &uwcond->wc_flags) || - get_user(ts.tv_sec, &uwcond32->wc_timeout.tv_sec) || - get_user(ts.tv_nsec, &uwcond32->wc_timeout.tv_nsec) || - put_user(ts.tv_sec, &uwcond->wc_timeout.tv_sec) || - put_user(ts.tv_nsec, &uwcond->wc_timeout.tv_nsec)) - return -EFAULT; - - ret = nilfs_compat_locked_ioctl(inode, filp, cmd, - (unsigned long)uwcond); - if (ret < 0) - return ret; - - if (get_user(ts.tv_sec, &uwcond->wc_timeout.tv_sec) || - get_user(ts.tv_nsec, &uwcond->wc_timeout.tv_nsec) || - put_user(ts.tv_sec, &uwcond32->wc_timeout.tv_sec) || - put_user(ts.tv_nsec, &uwcond32->wc_timeout.tv_nsec)) - return -EFAULT; - - return 0; -} - static int nilfs_compat_ioctl_sync(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -943,9 +853,6 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case NILFS_IOCTL32_CLEAN_SEGMENTS: return nilfs_compat_ioctl_clean_segments( inode, filp, NILFS_IOCTL_CLEAN_SEGMENTS, arg); - case NILFS_IOCTL32_TIMEDWAIT: - return nilfs_compat_ioctl_timedwait( - inode, filp, NILFS_IOCTL_TIMEDWAIT, arg); case NILFS_IOCTL_SYNC: return nilfs_compat_ioctl_sync(inode, filp, cmd, arg); default: diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 6d66c5cb7b51..5db12d774a03 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -2114,11 +2114,8 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) nilfs_drop_collected_inodes(&sci->sc_gc_inodes); if (update_sr) nilfs_commit_gcdat_inode(nilfs); - } else { + } else nilfs->ns_nongc_ctime = sci->sc_seg_ctime; - set_nilfs_cond_nongc_write(nilfs); - wake_up(&nilfs->ns_cleanerd_wq); - } sci->sc_nblk_inc += sci->sc_nblk_this_inc; diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 852e0bf3a3c5..69b625586226 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -73,7 +73,6 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) nilfs->ns_gc_inodes_h = NULL; INIT_LIST_HEAD(&nilfs->ns_used_segments); init_rwsem(&nilfs->ns_segctor_sem); - init_waitqueue_head(&nilfs->ns_cleanerd_wq); return nilfs; } diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 9cd3c113f052..75da37306964 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -37,7 +37,6 @@ enum { THE_NILFS_LOADED, /* Roll-back/roll-forward has done and the latest checkpoint was loaded */ THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */ - THE_NILFS_COND_NONGC_WRITE, /* Condition to wake up cleanerd */ }; /** @@ -74,7 +73,6 @@ enum { * @ns_gc_dat: shadow inode of the DAT file inode for GC * @ns_gc_inodes: dummy inodes to keep live blocks * @ns_gc_inodes_h: hash list to keep dummy inode holding live blocks - * @ns_cleanerd_wq: wait queue for cleanerd * @ns_blocksize_bits: bit length of block size * @ns_nsegments: number of segments in filesystem * @ns_blocks_per_segment: number of blocks per segment @@ -151,9 +149,6 @@ struct the_nilfs { struct list_head ns_gc_inodes; struct hlist_head *ns_gc_inodes_h; - /* cleanerd */ - wait_queue_head_t ns_cleanerd_wq; - /* Disk layout information (static) */ unsigned int ns_blocksize_bits; unsigned long ns_nsegments; @@ -186,7 +181,6 @@ static inline int nilfs_##name(struct the_nilfs *nilfs) \ THE_NILFS_FNS(INIT, init) THE_NILFS_FNS(LOADED, loaded) THE_NILFS_FNS(DISCONTINUED, discontinued) -THE_NILFS_FNS(COND_NONGC_WRITE, cond_nongc_write) void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); struct the_nilfs *alloc_nilfs(struct block_device *); diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h index e38fad2f7c0b..b0a6b39eedbc 100644 --- a/include/linux/nilfs2_fs.h +++ b/include/linux/nilfs2_fs.h @@ -763,18 +763,6 @@ struct nilfs_bdesc { __u32 bd_level; }; -#define NILFS_TIMEDWAIT_WRITE_LOCKED 0x1 -#define NILFS_TIMEDWAIT_SEG_WRITE 0x2 - -/** - * struct nilfs_wait_cond - - */ -struct nilfs_wait_cond { - int wc_cond; - int wc_flags; - struct timespec wc_timeout; -}; - #define NILFS_IOCTL_IDENT 'n' #define NILFS_IOCTL_CHANGE_CPMODE \ @@ -795,8 +783,6 @@ struct nilfs_wait_cond { _IOWR(NILFS_IOCTL_IDENT, 0x87, struct nilfs_argv) #define NILFS_IOCTL_CLEAN_SEGMENTS \ _IOW(NILFS_IOCTL_IDENT, 0x88, struct nilfs_argv[5]) -#define NILFS_IOCTL_TIMEDWAIT \ - _IOWR(NILFS_IOCTL_IDENT, 0x89, struct nilfs_wait_cond) #define NILFS_IOCTL_SYNC \ _IOR(NILFS_IOCTL_IDENT, 0x8A, __u64) #define NILFS_IOCTL_RESIZE \ @@ -827,12 +813,6 @@ struct nilfs_sustat32 { compat_time_t ss_nongc_ctime; }; -struct nilfs_wait_cond32 { - compat_int_t wc_cond; - compat_int_t wc_flags; - struct compat_timespec wc_timeout; -}; - #define NILFS_IOCTL32_CHANGE_CPMODE \ _IOW(NILFS_IOCTL_IDENT, 0x80, struct nilfs_cpmode32) #define NILFS_IOCTL32_GET_CPINFO \ @@ -847,8 +827,6 @@ struct nilfs_wait_cond32 { _IOWR(NILFS_IOCTL_IDENT, 0x87, struct nilfs_argv32) #define NILFS_IOCTL32_CLEAN_SEGMENTS \ _IOW(NILFS_IOCTL_IDENT, 0x88, struct nilfs_argv32[5]) -#define NILFS_IOCTL32_TIMEDWAIT \ - _IOWR(NILFS_IOCTL_IDENT, 0x89, struct nilfs_wait_cond32) #endif /* CONFIG_COMPAT */ #endif /* _LINUX_NILFS_FS_H */ -- cgit v1.2.3-59-g8ed1b From dc498d09be28172846cacded35ca2378222a8c7b Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 6 Apr 2009 19:01:52 -0700 Subject: nilfs2: use fixed sized types for ioctl structures Nilfs ioctl had structures not having fixed sized types such as: struct nilfs_argv { void *v_base; size_t v_nmembs; size_t v_size; int v_index; int v_flags; }; Further, some of them are wrongly aligned: e.g. struct nilfs_cpmode { __u64 cm_cno; int cm_mode; }; The size of wrongly aligned structures varies depending on architectures, and it breaks the identity of ioctl commands, which leads to arch dependent errors. Previously, these are compensated by using compat_ioctl. This fixes these problems and allows removal of compat ioctl. Since this will change sizes of those structures, binary compatibility for the past utilities will once break; new utilities have to be used instead. However, it would be helpful to avoid platform dependent problems in the long term. Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nilfs2/ioctl.c | 11 +++++------ include/linux/nilfs2_fs.h | 23 ++++++++++++++--------- 2 files changed, 19 insertions(+), 15 deletions(-) (limited to 'fs/nilfs2/ioctl.c') diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 85a291ccc1be..7fbd9fe1d035 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -41,6 +41,7 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, void *, size_t, size_t)) { void *buf; + void __user *base = (void __user *)(unsigned long)argv->v_base; size_t maxmembs, total, n; ssize_t nr; int ret, i; @@ -64,9 +65,8 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, n = (argv->v_nmembs - i < maxmembs) ? argv->v_nmembs - i : maxmembs; if ((dir & _IOC_WRITE) && - copy_from_user(buf, - (void __user *)argv->v_base + argv->v_size * i, - argv->v_size * n)) { + copy_from_user(buf, base + argv->v_size * i, + argv->v_size * n)) { ret = -EFAULT; break; } @@ -78,9 +78,8 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, break; } if ((dir & _IOC_READ) && - copy_to_user( - (void __user *)argv->v_base + argv->v_size * i, - buf, argv->v_size * nr)) { + copy_to_user(base + argv->v_size * i, buf, + argv->v_size * nr)) { ret = -EFAULT; break; } diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h index b0a6b39eedbc..8fb64ce285fd 100644 --- a/include/linux/nilfs2_fs.h +++ b/include/linux/nilfs2_fs.h @@ -499,6 +499,7 @@ NILFS_CHECKPOINT_FNS(SKETCH, sketch) /** * struct nilfs_cpinfo - checkpoint information * @ci_flags: flags + * @ci_pad: padding * @ci_cno: checkpoint number * @ci_create: creation timestamp * @ci_nblk_inc: number of blocks incremented by this checkpoint @@ -508,6 +509,7 @@ NILFS_CHECKPOINT_FNS(SKETCH, sketch) */ struct nilfs_cpinfo { __u32 ci_flags; + __u32 ci_pad; __u64 ci_cno; __u64 ci_create; __u64 ci_nblk_inc; @@ -668,7 +670,8 @@ enum { */ struct nilfs_cpmode { __u64 cm_cno; - int cm_mode; + __u32 cm_mode; + __u32 cm_pad; }; /** @@ -676,15 +679,15 @@ struct nilfs_cpmode { * @v_base: * @v_nmembs: * @v_size: - * @v_index: * @v_flags: + * @v_index: */ struct nilfs_argv { - void *v_base; - size_t v_nmembs; /* number of members */ - size_t v_size; /* size of members */ - int v_index; - int v_flags; + __u64 v_base; + __u32 v_nmembs; /* number of members */ + __u16 v_size; /* size of members */ + __u16 v_flags; + __u64 v_index; }; /** @@ -721,8 +724,8 @@ struct nilfs_sustat { __u64 ss_nsegs; __u64 ss_ncleansegs; __u64 ss_ndirtysegs; - time_t ss_ctime; - time_t ss_nongc_ctime; + __u64 ss_ctime; + __u64 ss_nongc_ctime; }; /** @@ -750,6 +753,7 @@ struct nilfs_vdesc { __u64 vd_blocknr; __u64 vd_offset; __u32 vd_flags; + __u32 vd_pad; }; /** @@ -761,6 +765,7 @@ struct nilfs_bdesc { __u64 bd_blocknr; __u64 bd_offset; __u32 bd_level; + __u32 bd_pad; }; #define NILFS_IOCTL_IDENT 'n' -- cgit v1.2.3-59-g8ed1b From 8082d36aed26c4fb6ed43e4008303682eabf839e Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 6 Apr 2009 19:01:53 -0700 Subject: nilfs2: remove compat ioctl code This removes compat code from the nilfs ioctls and applies the same function for both .ioctl and .compat_ioctl file operations. Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nilfs2/dir.c | 2 +- fs/nilfs2/file.c | 2 +- fs/nilfs2/ioctl.c | 228 ---------------------------------------------- fs/nilfs2/nilfs.h | 1 - include/linux/nilfs2_fs.h | 41 --------- 5 files changed, 2 insertions(+), 272 deletions(-) (limited to 'fs/nilfs2/ioctl.c') diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index 1b7e6ddabbeb..393316cd3cad 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c @@ -704,7 +704,7 @@ struct file_operations nilfs_dir_operations = { .readdir = nilfs_readdir, .ioctl = nilfs_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = nilfs_compat_ioctl, + .compat_ioctl = nilfs_ioctl, #endif /* CONFIG_COMPAT */ .fsync = nilfs_sync_file, diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c index cd38124372f3..a2bd962ebd85 100644 --- a/fs/nilfs2/file.c +++ b/fs/nilfs2/file.c @@ -142,7 +142,7 @@ struct file_operations nilfs_file_operations = { .aio_write = generic_file_aio_write, .ioctl = nilfs_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = nilfs_compat_ioctl, + .compat_ioctl = nilfs_ioctl, #endif /* CONFIG_COMPAT */ .mmap = nilfs_file_mmap, .open = generic_file_open, diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 7fbd9fe1d035..33aff8842ce9 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -631,231 +631,3 @@ int nilfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return -ENOTTY; } } - -/* compat_ioctl */ -#ifdef CONFIG_COMPAT -#include - -static int nilfs_compat_locked_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - int ret; - - lock_kernel(); - ret = nilfs_ioctl(inode, filp, cmd, arg); - unlock_kernel(); - return ret; -} - -static int -nilfs_compat_ioctl_uargv32_to_uargv(struct nilfs_argv32 __user *uargv32, - struct nilfs_argv __user *uargv) -{ - compat_uptr_t base; - compat_size_t nmembs, size; - compat_int_t index, flags; - - if (get_user(base, &uargv32->v_base) || - put_user(compat_ptr(base), &uargv->v_base) || - get_user(nmembs, &uargv32->v_nmembs) || - put_user(nmembs, &uargv->v_nmembs) || - get_user(size, &uargv32->v_size) || - put_user(size, &uargv->v_size) || - get_user(index, &uargv32->v_index) || - put_user(index, &uargv->v_index) || - get_user(flags, &uargv32->v_flags) || - put_user(flags, &uargv->v_flags)) - return -EFAULT; - return 0; -} - -static int -nilfs_compat_ioctl_uargv_to_uargv32(struct nilfs_argv __user *uargv, - struct nilfs_argv32 __user *uargv32) -{ - size_t nmembs; - - if (get_user(nmembs, &uargv->v_nmembs) || - put_user(nmembs, &uargv32->v_nmembs)) - return -EFAULT; - return 0; -} - -static int -nilfs_compat_ioctl_get_by_argv(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct nilfs_argv __user *uargv; - struct nilfs_argv32 __user *uargv32; - int ret; - - uargv = compat_alloc_user_space(sizeof(struct nilfs_argv)); - uargv32 = compat_ptr(arg); - ret = nilfs_compat_ioctl_uargv32_to_uargv(uargv32, uargv); - if (ret < 0) - return ret; - - ret = nilfs_compat_locked_ioctl(inode, filp, cmd, (unsigned long)uargv); - if (ret < 0) - return ret; - - return nilfs_compat_ioctl_uargv_to_uargv32(uargv, uargv32); -} - -static int -nilfs_compat_ioctl_change_cpmode(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct nilfs_cpmode __user *ucpmode; - struct nilfs_cpmode32 __user *ucpmode32; - int mode; - - ucpmode = compat_alloc_user_space(sizeof(struct nilfs_cpmode)); - ucpmode32 = compat_ptr(arg); - if (copy_in_user(&ucpmode->cm_cno, &ucpmode32->cm_cno, - sizeof(__u64)) || - get_user(mode, &ucpmode32->cm_mode) || - put_user(mode, &ucpmode->cm_mode)) - return -EFAULT; - - return nilfs_compat_locked_ioctl( - inode, filp, cmd, (unsigned long)ucpmode); -} - - -static inline int -nilfs_compat_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - return nilfs_compat_locked_ioctl(inode, filp, cmd, arg); -} - -static inline int -nilfs_compat_ioctl_get_cpinfo(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg); -} - -static inline int -nilfs_compat_ioctl_get_cpstat(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - return nilfs_compat_locked_ioctl(inode, filp, cmd, arg); -} - -static inline int -nilfs_compat_ioctl_get_suinfo(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg); -} - -static int -nilfs_compat_ioctl_get_sustat(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct nilfs_sustat __user *usustat; - struct nilfs_sustat32 __user *usustat32; - time_t ctime, nongc_ctime; - int ret; - - usustat = compat_alloc_user_space(sizeof(struct nilfs_sustat)); - ret = nilfs_compat_locked_ioctl(inode, filp, cmd, - (unsigned long)usustat); - if (ret < 0) - return ret; - - usustat32 = compat_ptr(arg); - if (copy_in_user(&usustat32->ss_nsegs, &usustat->ss_nsegs, - sizeof(__u64)) || - copy_in_user(&usustat32->ss_ncleansegs, &usustat->ss_ncleansegs, - sizeof(__u64)) || - copy_in_user(&usustat32->ss_ndirtysegs, &usustat->ss_ndirtysegs, - sizeof(__u64)) || - get_user(ctime, &usustat->ss_ctime) || - put_user(ctime, &usustat32->ss_ctime) || - get_user(nongc_ctime, &usustat->ss_nongc_ctime) || - put_user(nongc_ctime, &usustat32->ss_nongc_ctime)) - return -EFAULT; - return 0; -} - -static inline int -nilfs_compat_ioctl_get_vinfo(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg); -} - -static inline int -nilfs_compat_ioctl_get_bdescs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg); -} - -static int -nilfs_compat_ioctl_clean_segments(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct nilfs_argv __user *uargv; - struct nilfs_argv32 __user *uargv32; - int i, ret; - - uargv = compat_alloc_user_space(sizeof(struct nilfs_argv) * 5); - uargv32 = compat_ptr(arg); - for (i = 0; i < 5; i++) { - ret = nilfs_compat_ioctl_uargv32_to_uargv(&uargv32[i], - &uargv[i]); - if (ret < 0) - return ret; - } - return nilfs_compat_locked_ioctl( - inode, filp, cmd, (unsigned long)uargv); -} - -static int nilfs_compat_ioctl_sync(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - return nilfs_compat_locked_ioctl(inode, filp, cmd, arg); -} - -long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct inode *inode = filp->f_dentry->d_inode; - - switch (cmd) { - case NILFS_IOCTL32_CHANGE_CPMODE: - return nilfs_compat_ioctl_change_cpmode( - inode, filp, NILFS_IOCTL_CHANGE_CPMODE, arg); - case NILFS_IOCTL_DELETE_CHECKPOINT: - return nilfs_compat_ioctl_delete_checkpoint( - inode, filp, cmd, arg); - case NILFS_IOCTL32_GET_CPINFO: - return nilfs_compat_ioctl_get_cpinfo( - inode, filp, NILFS_IOCTL_GET_CPINFO, arg); - case NILFS_IOCTL_GET_CPSTAT: - return nilfs_compat_ioctl_get_cpstat(inode, filp, cmd, arg); - case NILFS_IOCTL32_GET_SUINFO: - return nilfs_compat_ioctl_get_suinfo( - inode, filp, NILFS_IOCTL_GET_SUINFO, arg); - case NILFS_IOCTL32_GET_SUSTAT: - return nilfs_compat_ioctl_get_sustat( - inode, filp, NILFS_IOCTL_GET_SUSTAT, arg); - case NILFS_IOCTL32_GET_VINFO: - return nilfs_compat_ioctl_get_vinfo( - inode, filp, NILFS_IOCTL_GET_VINFO, arg); - case NILFS_IOCTL32_GET_BDESCS: - return nilfs_compat_ioctl_get_bdescs( - inode, filp, NILFS_IOCTL_GET_BDESCS, arg); - case NILFS_IOCTL32_CLEAN_SEGMENTS: - return nilfs_compat_ioctl_clean_segments( - inode, filp, NILFS_IOCTL_CLEAN_SEGMENTS, arg); - case NILFS_IOCTL_SYNC: - return nilfs_compat_ioctl_sync(inode, filp, cmd, arg); - default: - return -ENOIOCTLCMD; - } -} -#endif diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 48c070676cc5..f767644a7242 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -243,7 +243,6 @@ extern int nilfs_sync_file(struct file *, struct dentry *, int); /* ioctl.c */ int nilfs_ioctl(struct inode *, struct file *, unsigned int, unsigned long); -long nilfs_compat_ioctl(struct file *, unsigned int, unsigned long); int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *, void __user *); /* inode.c */ diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h index 8fb64ce285fd..306c446e694e 100644 --- a/include/linux/nilfs2_fs.h +++ b/include/linux/nilfs2_fs.h @@ -793,45 +793,4 @@ struct nilfs_bdesc { #define NILFS_IOCTL_RESIZE \ _IOW(NILFS_IOCTL_IDENT, 0x8B, __u64) -/* compat_ioctl */ -#ifdef CONFIG_COMPAT -#include - -struct nilfs_cpmode32 { - __u64 cm_cno; - compat_int_t cm_mode; -}; - -struct nilfs_argv32 { - compat_caddr_t v_base; - compat_size_t v_nmembs; - compat_size_t v_size; - compat_int_t v_index; - compat_int_t v_flags; -}; - -struct nilfs_sustat32 { - __u64 ss_nsegs; - __u64 ss_ncleansegs; - __u64 ss_ndirtysegs; - compat_time_t ss_ctime; - compat_time_t ss_nongc_ctime; -}; - -#define NILFS_IOCTL32_CHANGE_CPMODE \ - _IOW(NILFS_IOCTL_IDENT, 0x80, struct nilfs_cpmode32) -#define NILFS_IOCTL32_GET_CPINFO \ - _IOR(NILFS_IOCTL_IDENT, 0x82, struct nilfs_argv32) -#define NILFS_IOCTL32_GET_SUINFO \ - _IOR(NILFS_IOCTL_IDENT, 0x84, struct nilfs_argv32) -#define NILFS_IOCTL32_GET_SUSTAT \ - _IOR(NILFS_IOCTL_IDENT, 0x85, struct nilfs_sustat32) -#define NILFS_IOCTL32_GET_VINFO \ - _IOWR(NILFS_IOCTL_IDENT, 0x86, struct nilfs_argv32) -#define NILFS_IOCTL32_GET_BDESCS \ - _IOWR(NILFS_IOCTL_IDENT, 0x87, struct nilfs_argv32) -#define NILFS_IOCTL32_CLEAN_SEGMENTS \ - _IOW(NILFS_IOCTL_IDENT, 0x88, struct nilfs_argv32[5]) -#endif /* CONFIG_COMPAT */ - #endif /* _LINUX_NILFS_FS_H */ -- cgit v1.2.3-59-g8ed1b From 7a9461939a46345860622ea36ff267ee4446f00f Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 6 Apr 2009 19:01:53 -0700 Subject: nilfs2: use unlocked_ioctl Pekka Enberg suggested converting ->ioctl operations to use ->unlocked_ioctl to avoid BKL. The conversion was verified to be safe, so I will take it on this occasion. Cc: Pekka Enberg Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nilfs2/dir.c | 2 +- fs/nilfs2/file.c | 2 +- fs/nilfs2/ioctl.c | 4 ++-- fs/nilfs2/nilfs.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'fs/nilfs2/ioctl.c') diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index 393316cd3cad..54100acc1102 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c @@ -702,7 +702,7 @@ struct file_operations nilfs_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .readdir = nilfs_readdir, - .ioctl = nilfs_ioctl, + .unlocked_ioctl = nilfs_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = nilfs_ioctl, #endif /* CONFIG_COMPAT */ diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c index a2bd962ebd85..6bd84a0d8238 100644 --- a/fs/nilfs2/file.c +++ b/fs/nilfs2/file.c @@ -140,7 +140,7 @@ struct file_operations nilfs_file_operations = { .write = do_sync_write, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, - .ioctl = nilfs_ioctl, + .unlocked_ioctl = nilfs_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = nilfs_ioctl, #endif /* CONFIG_COMPAT */ diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 33aff8842ce9..cfb27892ffe8 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -600,9 +600,9 @@ static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, return 0; } -int nilfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { + struct inode *inode = filp->f_dentry->d_inode; void __user *argp = (void * __user *)arg; switch (cmd) { diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index f767644a7242..d08fb1ce5012 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -242,7 +242,7 @@ extern void nilfs_set_link(struct inode *, struct nilfs_dir_entry *, extern int nilfs_sync_file(struct file *, struct dentry *, int); /* ioctl.c */ -int nilfs_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +long nilfs_ioctl(struct file *, unsigned int, unsigned long); int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *, void __user *); /* inode.c */ -- cgit v1.2.3-59-g8ed1b From 1f5abe7e7dbcd83e73212c6cb135a6106cea6a0b Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 6 Apr 2009 19:01:55 -0700 Subject: nilfs2: replace BUG_ON and BUG calls triggerable from ioctl Pekka Enberg advised me: > It would be nice if BUG(), BUG_ON(), and panic() calls would be > converted to proper error handling using WARN_ON() calls. The BUG() > call in nilfs_cpfile_delete_checkpoints(), for example, looks to be > triggerable from user-space via the ioctl() system call. This will follow the comment and keep them to a minimum. Acked-by: Pekka Enberg Signed-off-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nilfs2/btree.c | 27 +++++++----------- fs/nilfs2/cpfile.c | 38 +++++++++++++------------ fs/nilfs2/dat.c | 15 +++++----- fs/nilfs2/direct.c | 13 +++++++-- fs/nilfs2/inode.c | 19 ++++--------- fs/nilfs2/ioctl.c | 63 ++++++++++++++++++++++++++++-------------- fs/nilfs2/mdt.c | 4 +-- fs/nilfs2/nilfs.h | 1 - fs/nilfs2/page.c | 10 +++---- fs/nilfs2/recovery.c | 3 -- fs/nilfs2/segment.c | 78 ++++++++++++++++------------------------------------ fs/nilfs2/sufile.c | 25 ++++++++++------- fs/nilfs2/super.c | 8 ++++-- 13 files changed, 144 insertions(+), 160 deletions(-) (limited to 'fs/nilfs2/ioctl.c') diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 53f0d4c31cb0..6b37a2767293 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -425,7 +425,6 @@ static int nilfs_btree_node_lookup(const struct nilfs_btree *btree, index++; out: - BUG_ON(indexp == NULL); *indexp = index; return s == 0; @@ -477,8 +476,6 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree, __u64 ptr; int level, index, found, ret; - BUG_ON(minlevel <= NILFS_BTREE_LEVEL_DATA); - node = nilfs_btree_get_root(btree); level = nilfs_btree_node_get_level(btree, node); if ((level < minlevel) || @@ -505,7 +502,7 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree, if (index < nilfs_btree_node_nchildren_max(btree, node)) ptr = nilfs_btree_node_get_ptr(btree, node, index); else { - BUG_ON(found || level != NILFS_BTREE_LEVEL_NODE_MIN); + WARN_ON(found || level != NILFS_BTREE_LEVEL_NODE_MIN); /* insert */ ptr = NILFS_BMAP_INVALID_PTR; } @@ -1366,7 +1363,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, } else { /* no siblings */ /* the only child of the root node */ - BUG_ON(level != nilfs_btree_height(btree) - 2); + WARN_ON(level != nilfs_btree_height(btree) - 2); if (nilfs_btree_node_get_nchildren(btree, node) - 1 <= NILFS_BTREE_ROOT_NCHILDREN_MAX) { path[level].bp_op = nilfs_btree_shrink; @@ -1543,7 +1540,7 @@ static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, break; case 3: nchildren = nilfs_btree_node_get_nchildren(btree, root); - BUG_ON(nchildren > 1); + WARN_ON(nchildren > 1); ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); ret = nilfs_bmap_get_block(bmap, ptr, &bh); if (ret < 0) @@ -1552,7 +1549,7 @@ static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, break; default: node = NULL; - BUG(); + return -EINVAL; } nchildren = nilfs_btree_node_get_nchildren(btree, node); @@ -1833,14 +1830,13 @@ static int nilfs_btree_prepare_propagate_v(struct nilfs_btree *btree, while ((++level < nilfs_btree_height(btree) - 1) && !buffer_dirty(path[level].bp_bh)) { - BUG_ON(buffer_nilfs_volatile(path[level].bp_bh)); + WARN_ON(buffer_nilfs_volatile(path[level].bp_bh)); ret = nilfs_btree_prepare_update_v(btree, path, level); if (ret < 0) goto out; } /* success */ - BUG_ON(maxlevelp == NULL); *maxlevelp = level - 1; return 0; @@ -1909,7 +1905,7 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap, __u64 key; int level, ret; - BUG_ON(!buffer_dirty(bh)); + WARN_ON(!buffer_dirty(bh)); btree = (struct nilfs_btree *)bmap; path = nilfs_btree_alloc_path(btree); @@ -1928,12 +1924,9 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap, ret = nilfs_btree_do_lookup(btree, path, key, NULL, level + 1); if (ret < 0) { - /* BUG_ON(ret == -ENOENT); */ - if (ret == -ENOENT) { + if (unlikely(ret == -ENOENT)) printk(KERN_CRIT "%s: key = %llu, level == %d\n", __func__, (unsigned long long)key, level); - BUG(); - } goto out; } @@ -2117,7 +2110,7 @@ static int nilfs_btree_assign(struct nilfs_bmap *bmap, ret = nilfs_btree_do_lookup(btree, path, key, NULL, level + 1); if (ret < 0) { - BUG_ON(ret == -ENOENT); + WARN_ON(ret == -ENOENT); goto out; } @@ -2175,12 +2168,12 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level) ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level + 1); if (ret < 0) { - BUG_ON(ret == -ENOENT); + WARN_ON(ret == -ENOENT); goto out; } ret = nilfs_bmap_get_block(&btree->bt_bmap, ptr, &bh); if (ret < 0) { - BUG_ON(ret == -ENOENT); + WARN_ON(ret == -ENOENT); goto out; } diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 218b34418508..e90b60dfced9 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c @@ -40,10 +40,7 @@ nilfs_cpfile_checkpoints_per_block(const struct inode *cpfile) static unsigned long nilfs_cpfile_get_blkoff(const struct inode *cpfile, __u64 cno) { - __u64 tcno; - - BUG_ON(cno == 0); /* checkpoint number 0 is invalid */ - tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1; + __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1; do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile)); return (unsigned long)tcno; } @@ -96,7 +93,7 @@ nilfs_cpfile_block_sub_valid_checkpoints(const struct inode *cpfile, struct nilfs_checkpoint *cp = kaddr + bh_offset(bh); unsigned int count; - BUG_ON(le32_to_cpu(cp->cp_checkpoints_count) < n); + WARN_ON(le32_to_cpu(cp->cp_checkpoints_count) < n); count = le32_to_cpu(cp->cp_checkpoints_count) - n; cp->cp_checkpoints_count = cpu_to_le32(count); return count; @@ -178,6 +175,8 @@ static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile, * %-ENOMEM - Insufficient amount of memory available. * * %-ENOENT - No such checkpoint. + * + * %-EINVAL - invalid checkpoint. */ int nilfs_cpfile_get_checkpoint(struct inode *cpfile, __u64 cno, @@ -191,8 +190,9 @@ int nilfs_cpfile_get_checkpoint(struct inode *cpfile, void *kaddr; int ret; - BUG_ON(cno < 1 || cno > nilfs_mdt_cno(cpfile) || - (cno < nilfs_mdt_cno(cpfile) && create)); + if (unlikely(cno < 1 || cno > nilfs_mdt_cno(cpfile) || + (cno < nilfs_mdt_cno(cpfile) && create))) + return -EINVAL; down_write(&NILFS_MDT(cpfile)->mi_sem); @@ -288,12 +288,11 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, unsigned long tnicps; int ret, ncps, nicps, count, i; - if ((start == 0) || (start > end)) { - printk(KERN_CRIT "%s: start = %llu, end = %llu\n", - __func__, - (unsigned long long)start, - (unsigned long long)end); - BUG(); + if (unlikely(start == 0 || start > end)) { + printk(KERN_ERR "%s: invalid range of checkpoint numbers: " + "[%llu, %llu)\n", __func__, + (unsigned long long)start, (unsigned long long)end); + return -EINVAL; } /* cannot delete the latest checkpoint */ @@ -323,7 +322,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, cpfile, cno, cp_bh, kaddr); nicps = 0; for (i = 0; i < ncps; i++, cp = (void *)cp + cpsz) { - BUG_ON(nilfs_checkpoint_snapshot(cp)); + WARN_ON(nilfs_checkpoint_snapshot(cp)); if (!nilfs_checkpoint_invalid(cp)) { nilfs_checkpoint_set_invalid(cp); nicps++; @@ -393,6 +392,8 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, int n, ret; int ncps, i; + if (cno == 0) + return -ENOENT; /* checkpoint number 0 is invalid */ down_read(&NILFS_MDT(cpfile)->mi_sem); for (n = 0; cno < cur_cno && n < nci; cno += ncps) { @@ -532,9 +533,6 @@ int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno) ssize_t nci; int ret; - /* checkpoint number 0 is invalid */ - if (cno == 0) - return -ENOENT; nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, 1); if (nci < 0) return nci; @@ -582,6 +580,8 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno) void *kaddr; int ret; + if (cno == 0) + return -ENOENT; /* checkpoint number 0 is invalid */ down_write(&NILFS_MDT(cpfile)->mi_sem); ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); @@ -698,6 +698,8 @@ static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno) void *kaddr; int ret; + if (cno == 0) + return -ENOENT; /* checkpoint number 0 is invalid */ down_write(&NILFS_MDT(cpfile)->mi_sem); ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); @@ -813,6 +815,8 @@ int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno) void *kaddr; int ret; + if (cno == 0) + return -ENOENT; /* checkpoint number 0 is invalid */ down_read(&NILFS_MDT(cpfile)->mi_sem); ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh); diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index 9360920f7d38..bb8a5818e7f1 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c @@ -135,7 +135,7 @@ int nilfs_dat_prepare_start(struct inode *dat, struct nilfs_palloc_req *req) int ret; ret = nilfs_dat_prepare_entry(dat, req, 0); - BUG_ON(ret == -ENOENT); + WARN_ON(ret == -ENOENT); return ret; } @@ -157,7 +157,6 @@ void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req, (unsigned long long)le64_to_cpu(entry->de_start), (unsigned long long)le64_to_cpu(entry->de_end), (unsigned long long)le64_to_cpu(entry->de_blocknr)); - BUG(); } entry->de_blocknr = cpu_to_le64(blocknr); kunmap_atomic(kaddr, KM_USER0); @@ -180,7 +179,7 @@ int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req) ret = nilfs_dat_prepare_entry(dat, req, 0); if (ret < 0) { - BUG_ON(ret == -ENOENT); + WARN_ON(ret == -ENOENT); return ret; } @@ -216,7 +215,7 @@ void nilfs_dat_commit_end(struct inode *dat, struct nilfs_palloc_req *req, end = start = le64_to_cpu(entry->de_start); if (!dead) { end = nilfs_mdt_cno(dat); - BUG_ON(start > end); + WARN_ON(start > end); } entry->de_end = cpu_to_le64(end); blocknr = le64_to_cpu(entry->de_blocknr); @@ -324,14 +323,16 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr) return ret; kaddr = kmap_atomic(entry_bh->b_page, KM_USER0); entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr); - if (entry->de_blocknr == cpu_to_le64(0)) { + if (unlikely(entry->de_blocknr == cpu_to_le64(0))) { printk(KERN_CRIT "%s: vbn = %llu, [%llu, %llu)\n", __func__, (unsigned long long)vblocknr, (unsigned long long)le64_to_cpu(entry->de_start), (unsigned long long)le64_to_cpu(entry->de_end)); - BUG(); + kunmap_atomic(kaddr, KM_USER0); + brelse(entry_bh); + return -EINVAL; } - BUG_ON(blocknr == 0); + WARN_ON(blocknr == 0); entry->de_blocknr = cpu_to_le64(blocknr); kunmap_atomic(kaddr, KM_USER0); diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c index e3ec24850089..c6379e482781 100644 --- a/fs/nilfs2/direct.c +++ b/fs/nilfs2/direct.c @@ -210,7 +210,6 @@ static int nilfs_direct_last_key(const struct nilfs_bmap *bmap, __u64 *keyp) if (lastkey == NILFS_DIRECT_KEY_MAX + 1) return -ENOENT; - BUG_ON(keyp == NULL); *keyp = lastkey; return 0; @@ -366,9 +365,17 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap, direct = (struct nilfs_direct *)bmap; key = nilfs_bmap_data_get_key(bmap, *bh); - BUG_ON(key > NILFS_DIRECT_KEY_MAX); + if (unlikely(key > NILFS_DIRECT_KEY_MAX)) { + printk(KERN_CRIT "%s: invalid key: %llu\n", __func__, + (unsigned long long)key); + return -EINVAL; + } ptr = nilfs_direct_get_ptr(direct, key); - BUG_ON(ptr == NILFS_BMAP_INVALID_PTR); + if (unlikely(ptr == NILFS_BMAP_INVALID_PTR)) { + printk(KERN_CRIT "%s: invalid pointer: %llu\n", __func__, + (unsigned long long)ptr); + return -EINVAL; + } return direct->d_ops->dop_assign(direct, key, ptr, bh, blocknr, binfo); diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 4bf1e2c5bac6..b6536bb2a324 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -61,12 +61,6 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff, map_bh(bh_result, inode->i_sb, blknum); goto out; } - if (unlikely(ret == 1)) { - printk(KERN_ERR "nilfs_get_block: bmap_lookup returns " - "buffer_head pointer (blkoff=%llu, blknum=%lu)\n", - (unsigned long long)blkoff, blknum); - BUG(); - } /* data block was not found */ if (ret == -ENOENT && create) { struct nilfs_transaction_info ti; @@ -85,14 +79,14 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff, * However, the page having this block must * be locked in this case. */ - printk(KERN_ERR + printk(KERN_WARNING "nilfs_get_block: a race condition " "while inserting a data block. " "(inode number=%lu, file block " "offset=%llu)\n", inode->i_ino, (unsigned long long)blkoff); - BUG(); + err = 0; } else if (err == -EINVAL) { nilfs_error(inode->i_sb, __func__, "broken bmap (inode=%lu)\n", @@ -621,7 +615,6 @@ void nilfs_truncate(struct inode *inode) struct nilfs_transaction_info ti; struct super_block *sb = inode->i_sb; struct nilfs_inode_info *ii = NILFS_I(inode); - int ret; if (!test_bit(NILFS_I_BMAP, &ii->i_state)) return; @@ -630,8 +623,7 @@ void nilfs_truncate(struct inode *inode) blocksize = sb->s_blocksize; blkoff = (inode->i_size + blocksize - 1) >> sb->s_blocksize_bits; - ret = nilfs_transaction_begin(sb, &ti, 0); - BUG_ON(ret); + nilfs_transaction_begin(sb, &ti, 0); /* never fails */ block_truncate_page(inode->i_mapping, inode->i_size, nilfs_get_block); @@ -652,7 +644,6 @@ void nilfs_delete_inode(struct inode *inode) struct nilfs_transaction_info ti; struct super_block *sb = inode->i_sb; struct nilfs_inode_info *ii = NILFS_I(inode); - int err; if (unlikely(is_bad_inode(inode))) { if (inode->i_data.nrpages) @@ -660,8 +651,8 @@ void nilfs_delete_inode(struct inode *inode) clear_inode(inode); return; } - err = nilfs_transaction_begin(sb, &ti, 0); - BUG_ON(err); + nilfs_transaction_begin(sb, &ti, 0); /* never fails */ + if (inode->i_data.nrpages) truncate_inode_pages(&inode->i_data, 0); diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index cfb27892ffe8..108d281ebca5 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -489,14 +489,14 @@ nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, __u64 *posp, ret = nilfs_mdt_mark_block_dirty(dat, bdescs[i].bd_offset); if (ret < 0) { - BUG_ON(ret == -ENOENT); + WARN_ON(ret == -ENOENT); return ret; } } else { ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset, bdescs[i].bd_level); if (ret < 0) { - BUG_ON(ret == -ENOENT); + WARN_ON(ret == -ENOENT); return ret; } } @@ -519,7 +519,8 @@ nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, __u64 *posp, int flags, struct nilfs_sb_info *sbi = nilfs_get_writer(nilfs); int ret; - BUG_ON(!sbi); + if (unlikely(!sbi)) + return -EROFS; ret = nilfs_segctor_add_segments_to_be_freed( NILFS_SC(sbi), buf, nmembs); nilfs_put_writer(nilfs); @@ -539,6 +540,7 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, void __user *argp) { struct nilfs_argv argv[5]; + const char *msg; int dir, ret; if (copy_from_user(argv, argp, sizeof(argv))) @@ -546,31 +548,50 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, dir = _IOC_WRITE; ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], dir); - if (ret < 0) - goto out_move_blks; + if (ret < 0) { + msg = "cannot read source blocks"; + goto failed; + } ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], dir); - if (ret < 0) - goto out_del_cps; + if (ret < 0) { + /* + * can safely abort because checkpoints can be removed + * independently. + */ + msg = "cannot delete checkpoints"; + goto failed; + } ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], dir); - if (ret < 0) - goto out_free_vbns; + if (ret < 0) { + /* + * can safely abort because DAT file is updated atomically + * using a copy-on-write technique. + */ + msg = "cannot delete virtual blocks from DAT file"; + goto failed; + } ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], dir); - if (ret < 0) - goto out_free_vbns; + if (ret < 0) { + /* + * can safely abort because the operation is nondestructive. + */ + msg = "cannot mark copying blocks dirty"; + goto failed; + } ret = nilfs_ioctl_free_segments(nilfs, &argv[4], dir); - if (ret < 0) - goto out_free_segs; - + if (ret < 0) { + /* + * can safely abort because this operation is atomic. + */ + msg = "cannot set segments to be freed"; + goto failed; + } return 0; - out_free_segs: - BUG(); /* XXX: not implemented yet */ - out_free_vbns: - BUG();/* XXX: not implemented yet */ - out_del_cps: - BUG();/* XXX: not implemented yet */ - out_move_blks: + failed: nilfs_remove_all_gcinode(nilfs); + printk(KERN_ERR "NILFS: GC failed during preparation: %s: err=%d\n", + msg, ret); return ret; } diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index e0a632b86feb..47dd815433fd 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -154,10 +154,8 @@ nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff, ret = -EBUSY; goto failed_bh; } - } else { - BUG_ON(mode != READ); + } else /* mode == READ */ lock_buffer(bh); - } if (buffer_uptodate(bh)) { unlock_buffer(bh); diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index d08fb1ce5012..a7f5bc724e33 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -173,7 +173,6 @@ static inline void nilfs_set_transaction_flag(unsigned int flag) { struct nilfs_transaction_info *ti = current->journal_info; - BUG_ON(!ti); ti->ti_flags |= flag; } diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index 7b18be8cd47a..1bfbba9c0e9a 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c @@ -417,7 +417,7 @@ repeat: dpage = find_lock_page(dmap, offset); if (dpage) { /* override existing page on the destination cache */ - BUG_ON(PageDirty(dpage)); + WARN_ON(PageDirty(dpage)); nilfs_copy_page(dpage, page, 0); unlock_page(dpage); page_cache_release(dpage); @@ -427,17 +427,15 @@ repeat: /* move the page to the destination cache */ spin_lock_irq(&smap->tree_lock); page2 = radix_tree_delete(&smap->page_tree, offset); - if (unlikely(page2 != page)) - NILFS_PAGE_BUG(page, "page removal failed " - "(offset=%lu, page2=%p)", - offset, page2); + WARN_ON(page2 != page); + smap->nrpages--; spin_unlock_irq(&smap->tree_lock); spin_lock_irq(&dmap->tree_lock); err = radix_tree_insert(&dmap->page_tree, offset, page); if (unlikely(err < 0)) { - BUG_ON(err == -EEXIST); + WARN_ON(err == -EEXIST); page->mapping = NULL; page_cache_release(page); /* for cache */ } else { diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index a4253f34e138..ef387b19682c 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c @@ -92,9 +92,6 @@ static int nilfs_warn_segment_error(int err) printk(KERN_WARNING "NILFS warning: No super root in the last segment\n"); break; - case NILFS_SEG_VALID: - default: - BUG(); } return -EINVAL; } diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 24d0fbd4271c..9a87410985b9 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -334,8 +334,7 @@ static void nilfs_transaction_lock(struct nilfs_sb_info *sbi, { struct nilfs_transaction_info *cur_ti = current->journal_info; - BUG_ON(cur_ti); - BUG_ON(!ti); + WARN_ON(cur_ti); ti->ti_flags = NILFS_TI_WRITER; ti->ti_count = 0; ti->ti_save = cur_ti; @@ -546,8 +545,6 @@ static int nilfs_collect_file_data(struct nilfs_sc_info *sci, { int err; - /* BUG_ON(!buffer_dirty(bh)); */ - /* excluded by scan_dirty_data_buffers() */ err = nilfs_bmap_propagate(NILFS_I(inode)->i_bmap, bh); if (unlikely(err < 0)) return nilfs_handle_bmap_error(err, __func__, inode, @@ -566,8 +563,6 @@ static int nilfs_collect_file_node(struct nilfs_sc_info *sci, { int err; - /* BUG_ON(!buffer_dirty(bh)); */ - /* excluded by scan_dirty_node_buffers() */ err = nilfs_bmap_propagate(NILFS_I(inode)->i_bmap, bh); if (unlikely(err < 0)) return nilfs_handle_bmap_error(err, __func__, inode, @@ -579,7 +574,7 @@ static int nilfs_collect_file_bmap(struct nilfs_sc_info *sci, struct buffer_head *bh, struct inode *inode) { - BUG_ON(!buffer_dirty(bh)); + WARN_ON(!buffer_dirty(bh)); return nilfs_segctor_add_file_block(sci, bh, inode, sizeof(__le64)); } @@ -628,7 +623,7 @@ static int nilfs_collect_dat_data(struct nilfs_sc_info *sci, static int nilfs_collect_dat_bmap(struct nilfs_sc_info *sci, struct buffer_head *bh, struct inode *inode) { - BUG_ON(!buffer_dirty(bh)); + WARN_ON(!buffer_dirty(bh)); return nilfs_segctor_add_file_block(sci, bh, inode, sizeof(struct nilfs_binfo_dat)); } @@ -862,9 +857,9 @@ static int nilfs_segctor_create_checkpoint(struct nilfs_sc_info *sci) nilfs_mdt_mark_dirty(nilfs->ns_cpfile); nilfs_cpfile_put_checkpoint( nilfs->ns_cpfile, nilfs->ns_cno, bh_cp); - } else { - BUG_ON(err == -EINVAL || err == -ENOENT); - } + } else + WARN_ON(err == -EINVAL || err == -ENOENT); + return err; } @@ -879,7 +874,7 @@ static int nilfs_segctor_fill_in_checkpoint(struct nilfs_sc_info *sci) err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, nilfs->ns_cno, 0, &raw_cp, &bh_cp); if (unlikely(err)) { - BUG_ON(err == -EINVAL || err == -ENOENT); + WARN_ON(err == -EINVAL || err == -ENOENT); goto failed_ibh; } raw_cp->cp_snapshot_list.ssl_next = 0; @@ -944,7 +939,6 @@ static void nilfs_fill_in_super_root_crc(struct buffer_head *bh_sr, u32 seed) (struct nilfs_super_root *)bh_sr->b_data; u32 crc; - BUG_ON(NILFS_SR_BYTES > bh_sr->b_size); crc = crc32_le(seed, (unsigned char *)raw_sr + sizeof(raw_sr->sr_sum), NILFS_SR_BYTES - sizeof(raw_sr->sr_sum)); @@ -1022,8 +1016,7 @@ static void nilfs_segctor_cancel_free_segments(struct nilfs_sc_info *sci, if (!(ent->flags & NILFS_SLH_FREED)) break; err = nilfs_sufile_cancel_free(sufile, ent->segnum); - BUG_ON(err); - + WARN_ON(err); /* do not happen */ ent->flags &= ~NILFS_SLH_FREED; } } @@ -1472,7 +1465,7 @@ static int nilfs_segctor_extend_segments(struct nilfs_sc_info *sci, failed: list_for_each_entry_safe(segbuf, n, &list, sb_list) { ret = nilfs_sufile_free(sufile, segbuf->sb_nextnum); - BUG_ON(ret); + WARN_ON(ret); /* never fails */ list_del_init(&segbuf->sb_list); nilfs_segbuf_free(segbuf); } @@ -1488,7 +1481,7 @@ static void nilfs_segctor_free_incomplete_segments(struct nilfs_sc_info *sci, segbuf = NILFS_FIRST_SEGBUF(&sci->sc_segbufs); if (nilfs->ns_nextnum != segbuf->sb_nextnum) { ret = nilfs_sufile_free(nilfs->ns_sufile, segbuf->sb_nextnum); - BUG_ON(ret); + WARN_ON(ret); /* never fails */ } if (segbuf->sb_io_error) { /* Case 1: The first segment failed */ @@ -1504,7 +1497,7 @@ static void nilfs_segctor_free_incomplete_segments(struct nilfs_sc_info *sci, list_for_each_entry_continue(segbuf, &sci->sc_segbufs, sb_list) { ret = nilfs_sufile_free(nilfs->ns_sufile, segbuf->sb_nextnum); - BUG_ON(ret); + WARN_ON(ret); /* never fails */ if (!done && segbuf->sb_io_error) { if (segbuf->sb_segnum != nilfs->ns_nextnum) /* Case 2: extended segment (!= next) failed */ @@ -1558,7 +1551,7 @@ static void nilfs_segctor_update_segusage(struct nilfs_sc_info *sci, list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) { ret = nilfs_sufile_get_segment_usage(sufile, segbuf->sb_segnum, &raw_su, &bh_su); - BUG_ON(ret); /* always succeed because bh_su is dirty */ + WARN_ON(ret); /* always succeed because bh_su is dirty */ live_blocks = segbuf->sb_sum.nblocks + (segbuf->sb_pseg_start - segbuf->sb_fseg_start); raw_su->su_lastmod = cpu_to_le64(sci->sc_seg_ctime); @@ -1579,7 +1572,7 @@ static void nilfs_segctor_cancel_segusage(struct nilfs_sc_info *sci, segbuf = NILFS_FIRST_SEGBUF(&sci->sc_segbufs); ret = nilfs_sufile_get_segment_usage(sufile, segbuf->sb_segnum, &raw_su, &bh_su); - BUG_ON(ret); /* always succeed because bh_su is dirty */ + WARN_ON(ret); /* always succeed because bh_su is dirty */ raw_su->su_nblocks = cpu_to_le32(segbuf->sb_pseg_start - segbuf->sb_fseg_start); nilfs_sufile_put_segment_usage(sufile, segbuf->sb_segnum, bh_su); @@ -1587,7 +1580,7 @@ static void nilfs_segctor_cancel_segusage(struct nilfs_sc_info *sci, list_for_each_entry_continue(segbuf, &sci->sc_segbufs, sb_list) { ret = nilfs_sufile_get_segment_usage(sufile, segbuf->sb_segnum, &raw_su, &bh_su); - BUG_ON(ret); /* always succeed */ + WARN_ON(ret); /* always succeed */ raw_su->su_nblocks = 0; nilfs_sufile_put_segment_usage(sufile, segbuf->sb_segnum, bh_su); @@ -1606,7 +1599,7 @@ static void nilfs_segctor_truncate_segments(struct nilfs_sc_info *sci, list_del_init(&segbuf->sb_list); sci->sc_segbuf_nblocks -= segbuf->sb_rest_blocks; ret = nilfs_sufile_free(sufile, segbuf->sb_nextnum); - BUG_ON(ret); + WARN_ON(ret); nilfs_segbuf_free(segbuf); } } @@ -1923,7 +1916,6 @@ static int nilfs_page_has_uncleared_buffer(struct page *page) static void __nilfs_end_page_io(struct page *page, int err) { - /* BUG_ON(err > 0); */ if (!err) { if (!nilfs_page_buffers_clean(page)) __set_page_dirty_nobuffers(page); @@ -2262,7 +2254,7 @@ static int nilfs_segctor_deactivate_segments(struct nilfs_sc_info *sci, if (unlikely(err)) goto failed; nilfs_segment_usage_clear_active(ent->raw_su); - BUG_ON(!buffer_dirty(ent->bh_su)); + WARN_ON(!buffer_dirty(ent->bh_su)); } return 0; @@ -2340,7 +2332,6 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) /* Avoid empty segment */ if (sci->sc_stage.scnt == NILFS_ST_DONE && NILFS_SEG_EMPTY(&sci->sc_curseg->sb_sum)) { - BUG_ON(mode == SC_LSEG_SR); nilfs_segctor_end_construction(sci, nilfs, 1); goto out; } @@ -2479,9 +2470,8 @@ int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *sci, struct inode *sufile = nilfs->ns_sufile; LIST_HEAD(list); __u64 *pnum; - const char *flag_name; size_t i; - int err, err2 = 0; + int err; for (pnum = segnum, i = 0; i < nsegs; pnum++, i++) { ent = nilfs_alloc_segment_entry(*pnum); @@ -2495,32 +2485,12 @@ int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *sci, if (unlikely(err)) goto failed; - if (unlikely(le32_to_cpu(ent->raw_su->su_flags) != - (1UL << NILFS_SEGMENT_USAGE_DIRTY))) { - if (nilfs_segment_usage_clean(ent->raw_su)) - flag_name = "clean"; - else if (nilfs_segment_usage_active(ent->raw_su)) - flag_name = "active"; - else if (nilfs_segment_usage_volatile_active( - ent->raw_su)) - flag_name = "volatile active"; - else if (!nilfs_segment_usage_dirty(ent->raw_su)) - flag_name = "non-dirty"; - else - flag_name = "erroneous"; - - printk(KERN_ERR - "NILFS: %s segment is requested to be cleaned " - "(segnum=%llu)\n", - flag_name, (unsigned long long)ent->segnum); - err2 = -EINVAL; - } + if (unlikely(!nilfs_segment_usage_dirty(ent->raw_su))) + printk(KERN_WARNING "NILFS: unused segment is " + "requested to be cleaned (segnum=%llu)\n", + (unsigned long long)ent->segnum); nilfs_close_segment_entry(ent, sufile); } - if (unlikely(err2)) { - err = err2; - goto failed; - } list_splice(&list, sci->sc_cleaning_segments.prev); return 0; @@ -2705,8 +2675,6 @@ struct nilfs_segctor_req { static void nilfs_segctor_accept(struct nilfs_sc_info *sci, struct nilfs_segctor_req *req) { - BUG_ON(!sci); - req->sc_err = req->sb_err = 0; spin_lock(&sci->sc_state_lock); req->seq_accepted = sci->sc_seq_request; @@ -3107,7 +3075,7 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) if (flag || nilfs_segctor_confirm(sci)) nilfs_segctor_write_out(sci); - BUG_ON(!list_empty(&sci->sc_copied_buffers)); + WARN_ON(!list_empty(&sci->sc_copied_buffers)); if (!list_empty(&sci->sc_dirty_files)) { nilfs_warning(sbi->s_super, __func__, @@ -3120,7 +3088,7 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) if (!list_empty(&sci->sc_cleaning_segments)) nilfs_dispose_segment_list(&sci->sc_cleaning_segments); - BUG_ON(!list_empty(&sci->sc_segbufs)); + WARN_ON(!list_empty(&sci->sc_segbufs)); if (sci->sc_sketch_inode) { iput(sci->sc_sketch_inode); diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c index cc714c72b138..4cf47e03a3ab 100644 --- a/fs/nilfs2/sufile.c +++ b/fs/nilfs2/sufile.c @@ -231,10 +231,11 @@ int nilfs_sufile_cancel_free(struct inode *sufile, __u64 segnum) kaddr = kmap_atomic(su_bh->b_page, KM_USER0); su = nilfs_sufile_block_get_segment_usage( sufile, segnum, su_bh, kaddr); - if (!nilfs_segment_usage_clean(su)) { - printk(KERN_CRIT "%s: segment %llu must be clean\n", + if (unlikely(!nilfs_segment_usage_clean(su))) { + printk(KERN_WARNING "%s: segment %llu must be clean\n", __func__, (unsigned long long)segnum); - BUG(); + kunmap_atomic(kaddr, KM_USER0); + goto out_su_bh; } nilfs_segment_usage_set_dirty(su); kunmap_atomic(kaddr, KM_USER0); @@ -249,11 +250,10 @@ int nilfs_sufile_cancel_free(struct inode *sufile, __u64 segnum) nilfs_mdt_mark_buffer_dirty(su_bh); nilfs_mdt_mark_dirty(sufile); + out_su_bh: brelse(su_bh); - out_header: brelse(header_bh); - out_sem: up_write(&NILFS_MDT(sufile)->mi_sem); return ret; @@ -317,7 +317,7 @@ int nilfs_sufile_freev(struct inode *sufile, __u64 *segnum, size_t nsegs) kaddr = kmap_atomic(su_bh[i]->b_page, KM_USER0); su = nilfs_sufile_block_get_segment_usage( sufile, segnum[i], su_bh[i], kaddr); - BUG_ON(nilfs_segment_usage_error(su)); + WARN_ON(nilfs_segment_usage_error(su)); nilfs_segment_usage_set_clean(su); kunmap_atomic(kaddr, KM_USER0); nilfs_mdt_mark_buffer_dirty(su_bh[i]); @@ -385,8 +385,8 @@ int nilfs_sufile_get_segment_usage(struct inode *sufile, __u64 segnum, int ret; /* segnum is 0 origin */ - BUG_ON(segnum >= nilfs_sufile_get_nsegments(sufile)); - + if (segnum >= nilfs_sufile_get_nsegments(sufile)) + return -EINVAL; down_write(&NILFS_MDT(sufile)->mi_sem); ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1, &bh); if (ret < 0) @@ -515,6 +515,8 @@ int nilfs_sufile_get_ncleansegs(struct inode *sufile, unsigned long *nsegsp) * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. + * + * %-EINVAL - Invalid segment usage number. */ int nilfs_sufile_set_error(struct inode *sufile, __u64 segnum) { @@ -524,8 +526,11 @@ int nilfs_sufile_set_error(struct inode *sufile, __u64 segnum) void *kaddr; int ret; - BUG_ON(segnum >= nilfs_sufile_get_nsegments(sufile)); - + if (unlikely(segnum >= nilfs_sufile_get_nsegments(sufile))) { + printk(KERN_WARNING "%s: invalid segment number: %llu\n", + __func__, (unsigned long long)segnum); + return -EINVAL; + } down_write(&NILFS_MDT(sufile)->mi_sem); ret = nilfs_sufile_get_header_block(sufile, &header_bh); diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 2f0e9f7bf152..d0639a6aae9e 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -841,8 +841,11 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, if (sb->s_flags & MS_RDONLY) { if (nilfs_test_opt(sbi, SNAPSHOT)) { - if (!nilfs_cpfile_is_snapshot(nilfs->ns_cpfile, - sbi->s_snapshot_cno)) { + err = nilfs_cpfile_is_snapshot(nilfs->ns_cpfile, + sbi->s_snapshot_cno); + if (err < 0) + goto failed_sbi; + if (!err) { printk(KERN_ERR "NILFS: The specified checkpoint is " "not a snapshot " @@ -1163,7 +1166,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, } else { struct nilfs_sb_info *sbi = NILFS_SB(s); - BUG_ON(!sbi || !sbi->s_nilfs); /* * s_umount protects super_block from unmount process; * It covers pointers of nilfs_sb_info and the_nilfs. -- cgit v1.2.3-59-g8ed1b