diff options
Diffstat (limited to 'fs')
282 files changed, 8179 insertions, 8736 deletions
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index c295ba786ed..f0c7de78e20 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h @@ -41,8 +41,8 @@ extern struct file_system_type v9fs_fs_type; extern const struct address_space_operations v9fs_addr_operations; extern const struct file_operations v9fs_file_operations; extern const struct file_operations v9fs_dir_operations; -extern struct dentry_operations v9fs_dentry_operations; -extern struct dentry_operations v9fs_cached_dentry_operations; +extern const struct dentry_operations v9fs_dentry_operations; +extern const struct dentry_operations v9fs_cached_dentry_operations; struct inode *v9fs_get_inode(struct super_block *sb, int mode); ino_t v9fs_qid2ino(struct p9_qid *qid); diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index 06dcc7c4f23..d74325295b1 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -104,12 +104,12 @@ void v9fs_dentry_release(struct dentry *dentry) } } -struct dentry_operations v9fs_cached_dentry_operations = { +const struct dentry_operations v9fs_cached_dentry_operations = { .d_delete = v9fs_cached_dentry_delete, .d_release = v9fs_dentry_release, }; -struct dentry_operations v9fs_dentry_operations = { +const struct dentry_operations v9fs_dentry_operations = { .d_delete = v9fs_dentry_delete, .d_release = v9fs_dentry_release, }; diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 93212e40221..5f8ab8adb5f 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -168,8 +168,9 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, p9stat_free(st); kfree(st); -P9_DPRINTK(P9_DEBUG_VFS, " return simple set mount\n"); - return simple_set_mnt(mnt, sb); +P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); + simple_set_mnt(mnt, sb); + return 0; release_sb: if (sb) { diff --git a/fs/Kconfig b/fs/Kconfig index 93945dd0b1a..cef8b18ceaa 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -56,61 +56,7 @@ endif # BLOCK source "fs/notify/Kconfig" -config QUOTA - bool "Quota support" - help - If you say Y here, you will be able to set per user limits for disk - usage (also called disk quotas). Currently, it works for the - ext2, ext3, and reiserfs file system. ext3 also supports journalled - quotas for which you don't need to run quotacheck(8) after an unclean - shutdown. - For further details, read the Quota mini-HOWTO, available from - <http://www.tldp.org/docs.html#howto>, or the documentation provided - with the quota tools. Probably the quota support is only useful for - multi user systems. If unsure, say N. - -config QUOTA_NETLINK_INTERFACE - bool "Report quota messages through netlink interface" - depends on QUOTA && NET - help - If you say Y here, quota warnings (about exceeding softlimit, reaching - hardlimit, etc.) will be reported through netlink interface. If unsure, - say Y. - -config PRINT_QUOTA_WARNING - bool "Print quota warnings to console (OBSOLETE)" - depends on QUOTA - default y - help - If you say Y here, quota warnings (about exceeding softlimit, reaching - hardlimit, etc.) will be printed to the process' controlling terminal. - Note that this behavior is currently deprecated and may go away in - future. Please use notification via netlink socket instead. - -# Generic support for tree structured quota files. Seleted when needed. -config QUOTA_TREE - tristate - -config QFMT_V1 - tristate "Old quota format support" - depends on QUOTA - help - This quota format was (is) used by kernels earlier than 2.4.22. If - you have quota working and you don't want to convert to new quota - format say Y here. - -config QFMT_V2 - tristate "Quota format v2 support" - depends on QUOTA - select QUOTA_TREE - help - This quota format allows using quotas with 32-bit UIDs/GIDs. If you - need this functionality say Y here. - -config QUOTACTL - bool - depends on XFS_QUOTA || QUOTA - default y +source "fs/quota/Kconfig" source "fs/autofs/Kconfig" source "fs/autofs4/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index dc20db34867..6e82a307bcd 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -51,11 +51,7 @@ obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o obj-$(CONFIG_NFS_COMMON) += nfs_common/ obj-$(CONFIG_GENERIC_ACL) += generic_acl.o -obj-$(CONFIG_QUOTA) += dquot.o -obj-$(CONFIG_QFMT_V1) += quota_v1.o -obj-$(CONFIG_QFMT_V2) += quota_v2.o -obj-$(CONFIG_QUOTA_TREE) += quota_tree.o -obj-$(CONFIG_QUOTACTL) += quota.o +obj-y += quota/ obj-$(CONFIG_PROC_FS) += proc/ obj-y += partitions/ diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h index 831157502d5..e0a85dbeeb8 100644 --- a/fs/adfs/adfs.h +++ b/fs/adfs/adfs.h @@ -86,7 +86,7 @@ void __adfs_error(struct super_block *sb, const char *function, /* dir_*.c */ extern const struct inode_operations adfs_dir_inode_operations; extern const struct file_operations adfs_dir_operations; -extern struct dentry_operations adfs_dentry_operations; +extern const struct dentry_operations adfs_dentry_operations; extern struct adfs_dir_ops adfs_f_dir_ops; extern struct adfs_dir_ops adfs_fplus_dir_ops; diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index 85a30e92980..e867ccf3724 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c @@ -263,7 +263,7 @@ adfs_compare(struct dentry *parent, struct qstr *entry, struct qstr *name) return 0; } -struct dentry_operations adfs_dentry_operations = { +const struct dentry_operations adfs_dentry_operations = { .d_hash = adfs_hash, .d_compare = adfs_compare, }; diff --git a/fs/affs/affs.h b/fs/affs/affs.h index e9ec915f755..1a2d5e3c7f4 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h @@ -199,8 +199,7 @@ extern const struct address_space_operations affs_symlink_aops; extern const struct address_space_operations affs_aops; extern const struct address_space_operations affs_aops_ofs; -extern struct dentry_operations affs_dentry_operations; -extern struct dentry_operations affs_dentry_operations_intl; +extern const struct dentry_operations affs_dentry_operations; static inline void affs_set_blocksize(struct super_block *sb, int size) diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index 805573005de..7d0f0a30f7a 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -179,14 +179,18 @@ affs_remove_link(struct dentry *dentry) affs_lock_dir(dir); affs_fix_dcache(dentry, link_ino); retval = affs_remove_hash(dir, link_bh); - if (retval) + if (retval) { + affs_unlock_dir(dir); goto done; + } mark_buffer_dirty_inode(link_bh, inode); memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32); retval = affs_insert_hash(dir, bh); - if (retval) + if (retval) { + affs_unlock_dir(dir); goto done; + } mark_buffer_dirty_inode(bh, inode); affs_unlock_dir(dir); diff --git a/fs/affs/namei.c b/fs/affs/namei.c index cfcf1b6cf82..960d336ec69 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -19,12 +19,12 @@ static int affs_intl_toupper(int ch); static int affs_intl_hash_dentry(struct dentry *, struct qstr *); static int affs_intl_compare_dentry(struct dentry *, struct qstr *, struct qstr *); -struct dentry_operations affs_dentry_operations = { +const struct dentry_operations affs_dentry_operations = { .d_hash = affs_hash_dentry, .d_compare = affs_compare_dentry, }; -static struct dentry_operations affs_intl_dentry_operations = { +static const struct dentry_operations affs_intl_dentry_operations = { .d_hash = affs_intl_hash_dentry, .d_compare = affs_intl_compare_dentry, }; diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 99cf390641f..9bd757774c9 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -62,7 +62,7 @@ const struct inode_operations afs_dir_inode_operations = { .setattr = afs_setattr, }; -static struct dentry_operations afs_fs_dentry_operations = { +static const struct dentry_operations afs_fs_dentry_operations = { .d_revalidate = afs_d_revalidate, .d_delete = afs_d_delete, .d_release = afs_d_release, diff --git a/fs/afs/proc.c b/fs/afs/proc.c index 7578c1ab9e0..8630615e57f 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c @@ -146,7 +146,6 @@ int afs_proc_init(void) proc_afs = proc_mkdir("fs/afs", NULL); if (!proc_afs) goto error_dir; - proc_afs->owner = THIS_MODULE; p = proc_create("cells", 0, proc_afs, &afs_proc_cells_fops); if (!p) @@ -443,7 +443,7 @@ static struct kiocb *__aio_get_req(struct kioctx *ctx) req->private = NULL; req->ki_iovec = NULL; INIT_LIST_HEAD(&req->ki_run_list); - req->ki_eventfd = ERR_PTR(-EINVAL); + req->ki_eventfd = NULL; /* Check if the completion queue has enough free space to * accept an event from this io. @@ -485,8 +485,6 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req) { assert_spin_locked(&ctx->ctx_lock); - if (!IS_ERR(req->ki_eventfd)) - fput(req->ki_eventfd); if (req->ki_dtor) req->ki_dtor(req); if (req->ki_iovec != &req->ki_inline_vec) @@ -508,8 +506,11 @@ static void aio_fput_routine(struct work_struct *data) list_del(&req->ki_list); spin_unlock_irq(&fput_lock); - /* Complete the fput */ - __fput(req->ki_filp); + /* Complete the fput(s) */ + if (req->ki_filp != NULL) + __fput(req->ki_filp); + if (req->ki_eventfd != NULL) + __fput(req->ki_eventfd); /* Link the iocb into the context's free list */ spin_lock_irq(&ctx->ctx_lock); @@ -527,12 +528,14 @@ static void aio_fput_routine(struct work_struct *data) */ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) { + int schedule_putreq = 0; + dprintk(KERN_DEBUG "aio_put(%p): f_count=%ld\n", req, atomic_long_read(&req->ki_filp->f_count)); assert_spin_locked(&ctx->ctx_lock); - req->ki_users --; + req->ki_users--; BUG_ON(req->ki_users < 0); if (likely(req->ki_users)) return 0; @@ -540,10 +543,23 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) req->ki_cancel = NULL; req->ki_retry = NULL; - /* Must be done under the lock to serialise against cancellation. - * Call this aio_fput as it duplicates fput via the fput_work. + /* + * Try to optimize the aio and eventfd file* puts, by avoiding to + * schedule work in case it is not __fput() time. In normal cases, + * we would not be holding the last reference to the file*, so + * this function will be executed w/out any aio kthread wakeup. */ - if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) { + if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) + schedule_putreq++; + else + req->ki_filp = NULL; + if (req->ki_eventfd != NULL) { + if (unlikely(atomic_long_dec_and_test(&req->ki_eventfd->f_count))) + schedule_putreq++; + else + req->ki_eventfd = NULL; + } + if (unlikely(schedule_putreq)) { get_ioctx(ctx); spin_lock(&fput_lock); list_add(&req->ki_list, &fput_head); @@ -571,7 +587,7 @@ int aio_put_req(struct kiocb *req) static struct kioctx *lookup_ioctx(unsigned long ctx_id) { struct mm_struct *mm = current->mm; - struct kioctx *ctx = NULL; + struct kioctx *ctx, *ret = NULL; struct hlist_node *n; rcu_read_lock(); @@ -579,12 +595,13 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id) hlist_for_each_entry_rcu(ctx, n, &mm->ioctx_list, list) { if (ctx->user_id == ctx_id && !ctx->dead) { get_ioctx(ctx); + ret = ctx; break; } } rcu_read_unlock(); - return ctx; + return ret; } /* @@ -1009,7 +1026,7 @@ int aio_complete(struct kiocb *iocb, long res, long res2) * eventfd. The eventfd_signal() function is safe to be called * from IRQ context. */ - if (!IS_ERR(iocb->ki_eventfd)) + if (iocb->ki_eventfd != NULL) eventfd_signal(iocb->ki_eventfd, 1); put_rq: @@ -1608,6 +1625,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd); if (IS_ERR(req->ki_eventfd)) { ret = PTR_ERR(req->ki_eventfd); + req->ki_eventfd = NULL; goto out_put_req; } } diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 3bbdb9d0237..1dd96d4406c 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -48,7 +48,7 @@ static struct file_system_type anon_inode_fs_type = { .get_sb = anon_inodefs_get_sb, .kill_sb = kill_anon_super, }; -static struct dentry_operations anon_inodefs_dentry_operations = { +static const struct dentry_operations anon_inodefs_dentry_operations = { .d_delete = anon_inodefs_delete_dentry, }; diff --git a/fs/attr.c b/fs/attr.c index f4360192a93..9fe1b1bd30a 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -173,7 +173,8 @@ int notify_change(struct dentry * dentry, struct iattr * attr) if (!error) { if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) - error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; + error = vfs_dq_transfer(inode, attr) ? + -EDQUOT : 0; if (!error) error = inode_setattr(inode, attr); } diff --git a/fs/autofs/root.c b/fs/autofs/root.c index 8aacade5695..4a1401cea0a 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -192,7 +192,7 @@ static int autofs_revalidate(struct dentry * dentry, struct nameidata *nd) return 1; } -static struct dentry_operations autofs_dentry_operations = { +static const struct dentry_operations autofs_dentry_operations = { .d_revalidate = autofs_revalidate, }; diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index a76803108d0..b7ff33c6310 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -186,6 +186,8 @@ int autofs4_expire_wait(struct dentry *dentry); int autofs4_expire_run(struct super_block *, struct vfsmount *, struct autofs_sb_info *, struct autofs_packet_expire __user *); +int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, + struct autofs_sb_info *sbi, int when); int autofs4_expire_multi(struct super_block *, struct vfsmount *, struct autofs_sb_info *, int __user *); struct dentry *autofs4_expire_direct(struct super_block *sb, diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index 025e105bffe..9e5ae8a4f5c 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c @@ -525,40 +525,13 @@ static int autofs_dev_ioctl_expire(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { - struct dentry *dentry; struct vfsmount *mnt; - int err = -EAGAIN; int how; how = param->expire.how; mnt = fp->f_path.mnt; - if (autofs_type_trigger(sbi->type)) - dentry = autofs4_expire_direct(sbi->sb, mnt, sbi, how); - else - dentry = autofs4_expire_indirect(sbi->sb, mnt, sbi, how); - - if (dentry) { - struct autofs_info *ino = autofs4_dentry_ino(dentry); - - /* - * This is synchronous because it makes the daemon a - * little easier - */ - err = autofs4_wait(sbi, dentry, NFY_EXPIRE); - - spin_lock(&sbi->fs_lock); - if (ino->flags & AUTOFS_INF_MOUNTPOINT) { - ino->flags &= ~AUTOFS_INF_MOUNTPOINT; - sbi->sb->s_root->d_mounted++; - } - ino->flags &= ~AUTOFS_INF_EXPIRING; - complete_all(&ino->expire_complete); - spin_unlock(&sbi->fs_lock); - dput(dentry); - } - - return err; + return autofs4_do_expire_multi(sbi->sb, mnt, sbi, how); } /* Check if autofs mount point is in use */ diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index e3bd50776f9..75f7ddacf7d 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -478,22 +478,16 @@ int autofs4_expire_run(struct super_block *sb, return ret; } -/* Call repeatedly until it returns -EAGAIN, meaning there's nothing - more to be done */ -int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt, - struct autofs_sb_info *sbi, int __user *arg) +int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, + struct autofs_sb_info *sbi, int when) { struct dentry *dentry; int ret = -EAGAIN; - int do_now = 0; - - if (arg && get_user(do_now, arg)) - return -EFAULT; if (autofs_type_trigger(sbi->type)) - dentry = autofs4_expire_direct(sb, mnt, sbi, do_now); + dentry = autofs4_expire_direct(sb, mnt, sbi, when); else - dentry = autofs4_expire_indirect(sb, mnt, sbi, do_now); + dentry = autofs4_expire_indirect(sb, mnt, sbi, when); if (dentry) { struct autofs_info *ino = autofs4_dentry_ino(dentry); @@ -516,3 +510,16 @@ int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt, return ret; } +/* Call repeatedly until it returns -EAGAIN, meaning there's nothing + more to be done */ +int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt, + struct autofs_sb_info *sbi, int __user *arg) +{ + int do_now = 0; + + if (arg && get_user(do_now, arg)) + return -EFAULT; + + return autofs4_do_expire_multi(sb, mnt, sbi, do_now); +} + diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 716e12b627b..69c8142da83 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -310,7 +310,7 @@ static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi) return ino; } -static struct dentry_operations autofs4_sb_dentry_operations = { +static const struct dentry_operations autofs4_sb_dentry_operations = { .d_release = autofs4_dentry_release, }; diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 2a41c2a7fc5..e383bf0334f 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -349,13 +349,13 @@ void autofs4_dentry_release(struct dentry *de) } /* For dentries of directories in the root dir */ -static struct dentry_operations autofs4_root_dentry_operations = { +static const struct dentry_operations autofs4_root_dentry_operations = { .d_revalidate = autofs4_revalidate, .d_release = autofs4_dentry_release, }; /* For other dentries */ -static struct dentry_operations autofs4_dentry_operations = { +static const struct dentry_operations autofs4_dentry_operations = { .d_revalidate = autofs4_revalidate, .d_release = autofs4_dentry_release, }; @@ -485,22 +485,6 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); - expiring = autofs4_lookup_expiring(sbi, dentry->d_parent, &dentry->d_name); - if (expiring) { - /* - * If we are racing with expire the request might not - * be quite complete but the directory has been removed - * so it must have been successful, so just wait for it. - */ - ino = autofs4_dentry_ino(expiring); - autofs4_expire_wait(expiring); - spin_lock(&sbi->lookup_lock); - if (!list_empty(&ino->expiring)) - list_del_init(&ino->expiring); - spin_unlock(&sbi->lookup_lock); - dput(expiring); - } - unhashed = autofs4_lookup_active(sbi, dentry->d_parent, &dentry->d_name); if (unhashed) dentry = unhashed; @@ -538,14 +522,31 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s } if (!oz_mode) { + mutex_unlock(&dir->i_mutex); + expiring = autofs4_lookup_expiring(sbi, + dentry->d_parent, + &dentry->d_name); + if (expiring) { + /* + * If we are racing with expire the request might not + * be quite complete but the directory has been removed + * so it must have been successful, so just wait for it. + */ + ino = autofs4_dentry_ino(expiring); + autofs4_expire_wait(expiring); + spin_lock(&sbi->lookup_lock); + if (!list_empty(&ino->expiring)) + list_del_init(&ino->expiring); + spin_unlock(&sbi->lookup_lock); + dput(expiring); + } + spin_lock(&dentry->d_lock); dentry->d_flags |= DCACHE_AUTOFS_PENDING; spin_unlock(&dentry->d_lock); - if (dentry->d_op && dentry->d_op->d_revalidate) { - mutex_unlock(&dir->i_mutex); + if (dentry->d_op && dentry->d_op->d_revalidate) (dentry->d_op->d_revalidate)(dentry, nd); - mutex_lock(&dir->i_mutex); - } + mutex_lock(&dir->i_mutex); } /* diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index 549b0144da1..31c46a241ba 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c @@ -26,23 +26,23 @@ #include <linux/workqueue.h> static struct kmem_cache *bio_integrity_slab __read_mostly; +static mempool_t *bio_integrity_pool; +static struct bio_set *integrity_bio_set; static struct workqueue_struct *kintegrityd_wq; /** - * bio_integrity_alloc_bioset - Allocate integrity payload and attach it to bio + * bio_integrity_alloc - Allocate integrity payload and attach it to bio * @bio: bio to attach integrity metadata to * @gfp_mask: Memory allocation mask * @nr_vecs: Number of integrity metadata scatter-gather elements - * @bs: bio_set to allocate from * * Description: This function prepares a bio for attaching integrity * metadata. nr_vecs specifies the maximum number of pages containing * integrity metadata that can be attached. */ -struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio, - gfp_t gfp_mask, - unsigned int nr_vecs, - struct bio_set *bs) +struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, + gfp_t gfp_mask, + unsigned int nr_vecs) { struct bio_integrity_payload *bip; struct bio_vec *iv; @@ -50,7 +50,7 @@ struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio, BUG_ON(bio == NULL); - bip = mempool_alloc(bs->bio_integrity_pool, gfp_mask); + bip = mempool_alloc(bio_integrity_pool, gfp_mask); if (unlikely(bip == NULL)) { printk(KERN_ERR "%s: could not alloc bip\n", __func__); return NULL; @@ -58,10 +58,10 @@ struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio, memset(bip, 0, sizeof(*bip)); - iv = bvec_alloc_bs(gfp_mask, nr_vecs, &idx, bs); + iv = bvec_alloc_bs(gfp_mask, nr_vecs, &idx, integrity_bio_set); if (unlikely(iv == NULL)) { printk(KERN_ERR "%s: could not alloc bip_vec\n", __func__); - mempool_free(bip, bs->bio_integrity_pool); + mempool_free(bip, bio_integrity_pool); return NULL; } @@ -72,35 +72,16 @@ struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio, return bip; } -EXPORT_SYMBOL(bio_integrity_alloc_bioset); - -/** - * bio_integrity_alloc - Allocate integrity payload and attach it to bio - * @bio: bio to attach integrity metadata to - * @gfp_mask: Memory allocation mask - * @nr_vecs: Number of integrity metadata scatter-gather elements - * - * Description: This function prepares a bio for attaching integrity - * metadata. nr_vecs specifies the maximum number of pages containing - * integrity metadata that can be attached. - */ -struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, - gfp_t gfp_mask, - unsigned int nr_vecs) -{ - return bio_integrity_alloc_bioset(bio, gfp_mask, nr_vecs, fs_bio_set); -} EXPORT_SYMBOL(bio_integrity_alloc); /** * bio_integrity_free - Free bio integrity payload * @bio: bio containing bip to be freed - * @bs: bio_set this bio was allocated from * * Description: Used to free the integrity portion of a bio. Usually * called from bio_free(). */ -void bio_integrity_free(struct bio *bio, struct bio_set *bs) +void bio_integrity_free(struct bio *bio) { struct bio_integrity_payload *bip = bio->bi_integrity; @@ -111,8 +92,8 @@ void bio_integrity_free(struct bio *bio, struct bio_set *bs) && bip->bip_buf != NULL) kfree(bip->bip_buf); - bvec_free_bs(bs, bip->bip_vec, bip->bip_pool); - mempool_free(bip, bs->bio_integrity_pool); + bvec_free_bs(integrity_bio_set, bip->bip_vec, bip->bip_pool); + mempool_free(bip, bio_integrity_pool); bio->bi_integrity = NULL; } @@ -685,19 +666,18 @@ EXPORT_SYMBOL(bio_integrity_split); * bio_integrity_clone - Callback for cloning bios with integrity metadata * @bio: New bio * @bio_src: Original bio - * @bs: bio_set to allocate bip from + * @gfp_mask: Memory allocation mask * * Description: Called to allocate a bip when cloning a bio */ -int bio_integrity_clone(struct bio *bio, struct bio *bio_src, - struct bio_set *bs) +int bio_integrity_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp_mask) { struct bio_integrity_payload *bip_src = bio_src->bi_integrity; struct bio_integrity_payload *bip; BUG_ON(bip_src == NULL); - bip = bio_integrity_alloc_bioset(bio, GFP_NOIO, bip_src->bip_vcnt, bs); + bip = bio_integrity_alloc(bio, gfp_mask, bip_src->bip_vcnt); if (bip == NULL) return -EIO; @@ -713,37 +693,25 @@ int bio_integrity_clone(struct bio *bio, struct bio *bio_src, } EXPORT_SYMBOL(bio_integrity_clone); -int bioset_integrity_create(struct bio_set *bs, int pool_size) +static int __init bio_integrity_init(void) { - bs->bio_integrity_pool = mempool_create_slab_pool(pool_size, - bio_integrity_slab); - if (!bs->bio_integrity_pool) - return -1; - - return 0; -} -EXPORT_SYMBOL(bioset_integrity_create); + kintegrityd_wq = create_workqueue("kintegrityd"); -void bioset_integrity_free(struct bio_set *bs) -{ - if (bs->bio_integrity_pool) - mempool_destroy(bs->bio_integrity_pool); -} -EXPORT_SYMBOL(bioset_integrity_free); + if (!kintegrityd_wq) + panic("Failed to create kintegrityd\n"); -void __init bio_integrity_init_slab(void) -{ bio_integrity_slab = KMEM_CACHE(bio_integrity_payload, SLAB_HWCACHE_ALIGN|SLAB_PANIC); -} -static int __init integrity_init(void) -{ - kintegrityd_wq = create_workqueue("kintegrityd"); + bio_integrity_pool = mempool_create_slab_pool(BIO_POOL_SIZE, + bio_integrity_slab); + if (!bio_integrity_pool) + panic("bio_integrity: can't allocate bip pool\n"); - if (!kintegrityd_wq) - panic("Failed to create kintegrityd\n"); + integrity_bio_set = bioset_create(BIO_POOL_SIZE, 0); + if (!integrity_bio_set) + panic("bio_integrity: can't allocate bio_set\n"); return 0; } -subsys_initcall(integrity_init); +subsys_initcall(bio_integrity_init); @@ -248,7 +248,7 @@ void bio_free(struct bio *bio, struct bio_set *bs) bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio)); if (bio_integrity(bio)) - bio_integrity_free(bio, bs); + bio_integrity_free(bio); /* * If we have front padding, adjust the bio pointer before freeing @@ -301,48 +301,51 @@ void bio_init(struct bio *bio) **/ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs) { + struct bio_vec *bvl = NULL; struct bio *bio = NULL; - void *uninitialized_var(p); + unsigned long idx = 0; + void *p = NULL; if (bs) { p = mempool_alloc(bs->bio_pool, gfp_mask); - - if (p) - bio = p + bs->front_pad; - } else + if (!p) + goto err; + bio = p + bs->front_pad; + } else { bio = kmalloc(sizeof(*bio), gfp_mask); + if (!bio) + goto err; + } - if (likely(bio)) { - struct bio_vec *bvl = NULL; - - bio_init(bio); - if (likely(nr_iovecs)) { - unsigned long uninitialized_var(idx); - - if (nr_iovecs <= BIO_INLINE_VECS) { - idx = 0; - bvl = bio->bi_inline_vecs; - nr_iovecs = BIO_INLINE_VECS; - } else { - bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx, - bs); - nr_iovecs = bvec_nr_vecs(idx); - } - if (unlikely(!bvl)) { - if (bs) - mempool_free(p, bs->bio_pool); - else - kfree(bio); - bio = NULL; - goto out; - } - bio->bi_flags |= idx << BIO_POOL_OFFSET; - bio->bi_max_vecs = nr_iovecs; - } - bio->bi_io_vec = bvl; + bio_init(bio); + + if (unlikely(!nr_iovecs)) + goto out_set; + + if (nr_iovecs <= BIO_INLINE_VECS) { + bvl = bio->bi_inline_vecs; + nr_iovecs = BIO_INLINE_VECS; + } else { + bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx, bs); + if (unlikely(!bvl)) + goto err_free; + + nr_iovecs = bvec_nr_vecs(idx); } -out: + bio->bi_flags |= idx << BIO_POOL_OFFSET; + bio->bi_max_vecs = nr_iovecs; +out_set: + bio->bi_io_vec = bvl; + return bio; + +err_free: + if (bs) + mempool_free(p, bs->bio_pool); + else + kfree(bio); +err: + return NULL; } struct bio *bio_alloc(gfp_t gfp_mask, int nr_iovecs) @@ -463,10 +466,12 @@ struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask) if (bio_integrity(bio)) { int ret; - ret = bio_integrity_clone(b, bio, fs_bio_set); + ret = bio_integrity_clone(b, bio, gfp_mask); - if (ret < 0) + if (ret < 0) { + bio_put(b); return NULL; + } } return b; @@ -1524,7 +1529,6 @@ void bioset_free(struct bio_set *bs) if (bs->bio_pool) mempool_destroy(bs->bio_pool); - bioset_integrity_free(bs); biovec_free_pools(bs); bio_put_slab(bs); @@ -1565,9 +1569,6 @@ struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad) if (!bs->bio_pool) goto bad; - if (bioset_integrity_create(bs, pool_size)) - goto bad; - if (!biovec_create_pools(bs, pool_size)) return bs; @@ -1584,6 +1585,13 @@ static void __init biovec_init_slabs(void) int size; struct biovec_slab *bvs = bvec_slabs + i; +#ifndef CONFIG_BLK_DEV_INTEGRITY + if (bvs->nr_vecs <= BIO_INLINE_VECS) { + bvs->slab = NULL; + continue; + } +#endif + size = bvs->nr_vecs * sizeof(struct bio_vec); bvs->slab = kmem_cache_create(bvs->name, size, 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); @@ -1598,7 +1606,6 @@ static int __init init_bio(void) if (!bio_slabs) panic("bio: can't allocate bios\n"); - bio_integrity_init_slab(); biovec_init_slabs(); fs_bio_set = bioset_create(BIO_POOL_SIZE, 0); diff --git a/fs/block_dev.c b/fs/block_dev.c index b3c1efff5e1..8c3c6899ccf 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/blkpg.h> #include <linux/buffer_head.h> +#include <linux/pagevec.h> #include <linux/writeback.h> #include <linux/mpage.h> #include <linux/mount.h> @@ -174,6 +175,151 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, iov, offset, nr_segs, blkdev_get_blocks, NULL); } +/* + * Write out and wait upon all the dirty data associated with a block + * device via its mapping. Does not take the superblock lock. + */ +int sync_blockdev(struct block_device *bdev) +{ + int ret = 0; + + if (bdev) + ret = filemap_write_and_wait(bdev->bd_inode->i_mapping); + return ret; +} +EXPORT_SYMBOL(sync_blockdev); + +/* + * Write out and wait upon all dirty data associated with this + * device. Filesystem data as well as the underlying block + * device. Takes the superblock lock. + */ +int fsync_bdev(struct block_device *bdev) +{ + struct super_block *sb = get_super(bdev); + if (sb) { + int res = fsync_super(sb); + drop_super(sb); + return res; + } + return sync_blockdev(bdev); +} + +/** + * freeze_bdev -- lock a filesystem and force it into a consistent state + * @bdev: blockdevice to lock + * + * This takes the block device bd_mount_sem to make sure no new mounts + * happen on bdev until thaw_bdev() is called. + * If a superblock is found on this device, we take the s_umount semaphore + * on it to make sure nobody unmounts until the snapshot creation is done. + * The reference counter (bd_fsfreeze_count) guarantees that only the last + * unfreeze process can unfreeze the frozen filesystem actually when multiple + * freeze requests arrive simultaneously. It counts up in freeze_bdev() and + * count down in thaw_bdev(). When it becomes 0, thaw_bdev() will unfreeze + * actually. + */ +struct super_block *freeze_bdev(struct block_device *bdev) +{ + struct super_block *sb; + int error = 0; + + mutex_lock(&bdev->bd_fsfreeze_mutex); + if (bdev->bd_fsfreeze_count > 0) { + bdev->bd_fsfreeze_count++; + sb = get_super(bdev); + mutex_unlock(&bdev->bd_fsfreeze_mutex); + return sb; + } + bdev->bd_fsfreeze_count++; + + down(&bdev->bd_mount_sem); + sb = get_super(bdev); + if (sb && !(sb->s_flags & MS_RDONLY)) { + sb->s_frozen = SB_FREEZE_WRITE; + smp_wmb(); + + __fsync_super(sb); + + sb->s_frozen = SB_FREEZE_TRANS; + smp_wmb(); + + sync_blockdev(sb->s_bdev); + + if (sb->s_op->freeze_fs) { + error = sb->s_op->freeze_fs(sb); + if (error) { + printk(KERN_ERR + "VFS:Filesystem freeze failed\n"); + sb->s_frozen = SB_UNFROZEN; + drop_super(sb); + up(&bdev->bd_mount_sem); + bdev->bd_fsfreeze_count--; + mutex_unlock(&bdev->bd_fsfreeze_mutex); + return ERR_PTR(error); + } + } + } + + sync_blockdev(bdev); + mutex_unlock(&bdev->bd_fsfreeze_mutex); + + return sb; /* thaw_bdev releases s->s_umount and bd_mount_sem */ +} +EXPORT_SYMBOL(freeze_bdev); + +/** + * thaw_bdev -- unlock filesystem + * @bdev: blockdevice to unlock + * @sb: associated superblock + * + * Unlocks the filesystem and marks it writeable again after freeze_bdev(). + */ +int thaw_bdev(struct block_device *bdev, struct super_block *sb) +{ + int error = 0; + + mutex_lock(&bdev->bd_fsfreeze_mutex); + if (!bdev->bd_fsfreeze_count) { + mutex_unlock(&bdev->bd_fsfreeze_mutex); + return -EINVAL; + } + + bdev->bd_fsfreeze_count--; + if (bdev->bd_fsfreeze_count > 0) { + if (sb) + drop_super(sb); + mutex_unlock(&bdev->bd_fsfreeze_mutex); + return 0; + } + + if (sb) { + BUG_ON(sb->s_bdev != bdev); + if (!(sb->s_flags & MS_RDONLY)) { + if (sb->s_op->unfreeze_fs) { + error = sb->s_op->unfreeze_fs(sb); + if (error) { + printk(KERN_ERR + "VFS:Filesystem thaw failed\n"); + sb->s_frozen = SB_FREEZE_TRANS; + bdev->bd_fsfreeze_count++; + mutex_unlock(&bdev->bd_fsfreeze_mutex); + return error; + } + } + sb->s_frozen = SB_UNFROZEN; + smp_wmb(); + wake_up(&sb->s_wait_unfrozen); + } + drop_super(sb); + } + + up(&bdev->bd_mount_sem); + mutex_unlock(&bdev->bd_fsfreeze_mutex); + return 0; +} +EXPORT_SYMBOL(thaw_bdev); + static int blkdev_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page, blkdev_get_block, wbc); diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 82491ba8fa4..7dd1b6d0bf3 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -784,7 +784,14 @@ struct btrfs_fs_info { struct list_head dirty_cowonly_roots; struct btrfs_fs_devices *fs_devices; + + /* + * the space_info list is almost entirely read only. It only changes + * when we add a new raid type to the FS, and that happens + * very rarely. RCU is used to protect it. + */ struct list_head space_info; + spinlock_t delalloc_lock; spinlock_t new_trans_lock; u64 delalloc_bytes; @@ -1797,6 +1804,8 @@ int btrfs_cleanup_reloc_trees(struct btrfs_root *root); int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len); u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags); void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde); +void btrfs_clear_space_info_full(struct btrfs_fs_info *info); + int btrfs_check_metadata_free_space(struct btrfs_root *root); int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode, u64 bytes); @@ -2051,7 +2060,7 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset, unsigned long btrfs_force_ra(struct address_space *mapping, struct file_ra_state *ra, struct file *file, pgoff_t offset, pgoff_t last_index); -int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page); +int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); int btrfs_readpage(struct file *file, struct page *page); void btrfs_delete_inode(struct inode *inode); void btrfs_put_inode(struct inode *inode); diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 3e18175248e..6ec80c0fc86 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2385,7 +2385,7 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) unsigned long thresh = 32 * 1024 * 1024; tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; - if (current_is_pdflush() || current->flags & PF_MEMALLOC) + if (current->flags & PF_MEMALLOC) return; num_dirty = count_range_bits(tree, &start, (u64)-1, diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9abf81f71c4..fefe83ad205 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -20,6 +20,7 @@ #include <linux/writeback.h> #include <linux/blkdev.h> #include <linux/sort.h> +#include <linux/rcupdate.h> #include "compat.h" #include "hash.h" #include "crc32c.h" @@ -330,13 +331,33 @@ static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info, { struct list_head *head = &info->space_info; struct btrfs_space_info *found; - list_for_each_entry(found, head, list) { - if (found->flags == flags) + + rcu_read_lock(); + list_for_each_entry_rcu(found, head, list) { + if (found->flags == flags) { + rcu_read_unlock(); return found; + } } + rcu_read_unlock(); return NULL; } +/* + * after adding space to the filesystem, we need to clear the full flags + * on all the space infos. + */ +void btrfs_clear_space_info_full(struct btrfs_fs_info *info) +{ + struct list_head *head = &info->space_info; + struct btrfs_space_info *found; + + rcu_read_lock(); + list_for_each_entry_rcu(found, head, list) + found->full = 0; + rcu_read_unlock(); +} + static u64 div_factor(u64 num, int factor) { if (factor == 10) @@ -1903,7 +1924,6 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, if (!found) return -ENOMEM; - list_add(&found->list, &info->space_info); INIT_LIST_HEAD(&found->block_groups); init_rwsem(&found->groups_sem); spin_lock_init(&found->lock); @@ -1917,6 +1937,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, found->full = 0; found->force_alloc = 0; *space_info = found; + list_add_rcu(&found->list, &info->space_info); return 0; } @@ -6320,6 +6341,7 @@ out: int btrfs_free_block_groups(struct btrfs_fs_info *info) { struct btrfs_block_group_cache *block_group; + struct btrfs_space_info *space_info; struct rb_node *n; spin_lock(&info->block_group_cache_lock); @@ -6341,6 +6363,23 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) spin_lock(&info->block_group_cache_lock); } spin_unlock(&info->block_group_cache_lock); + + /* now that all the block groups are freed, go through and + * free all the space_info structs. This is only called during + * the final stages of unmount, and so we know nobody is + * using them. We call synchronize_rcu() once before we start, + * just to be on the safe side. + */ + synchronize_rcu(); + + while(!list_empty(&info->space_info)) { + space_info = list_entry(info->space_info.next, + struct btrfs_space_info, + list); + + list_del(&space_info->list); + kfree(space_info); + } return 0; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 7d4f948bc22..17e608c4dc7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4292,8 +4292,9 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset) * beyond EOF, then the page is guaranteed safe against truncation until we * unlock the page. */ -int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page) +int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { + struct page *page = vmf->page; struct inode *inode = fdentry(vma->vm_file)->d_inode; struct btrfs_root *root = BTRFS_I(inode)->root; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; @@ -4306,10 +4307,15 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page) u64 page_end; ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE); - if (ret) + if (ret) { + if (ret == -ENOMEM) + ret = VM_FAULT_OOM; + else /* -ENOSPC, -EIO, etc */ + ret = VM_FAULT_SIGBUS; goto out; + } - ret = -EINVAL; + ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */ again: lock_page(page); size = i_size_read(inode); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 1316139bf9e..dd06e18e5aa 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1374,6 +1374,12 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) ret = btrfs_add_device(trans, root, device); } + /* + * we've got more storage, clear any full flags on the space + * infos + */ + btrfs_clear_space_info_full(root->fs_info); + unlock_chunks(root); btrfs_commit_transaction(trans, root); @@ -1459,6 +1465,8 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans, device->fs_devices->total_rw_bytes += diff; device->total_bytes = new_size; + btrfs_clear_space_info_full(device->dev_root->fs_info); + return btrfs_update_device(trans, device); } diff --git a/fs/buffer.c b/fs/buffer.c index 9f697419ed8..f5f8b15a6e4 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -166,151 +166,6 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate) } /* - * Write out and wait upon all the dirty data associated with a block - * device via its mapping. Does not take the superblock lock. - */ -int sync_blockdev(struct block_device *bdev) -{ - int ret = 0; - - if (bdev) - ret = filemap_write_and_wait(bdev->bd_inode->i_mapping); - return ret; -} -EXPORT_SYMBOL(sync_blockdev); - -/* - * Write out and wait upon all dirty data associated with this - * device. Filesystem data as well as the underlying block - * device. Takes the superblock lock. - */ -int fsync_bdev(struct block_device *bdev) -{ - struct super_block *sb = get_super(bdev); - if (sb) { - int res = fsync_super(sb); - drop_super(sb); - return res; - } - return sync_blockdev(bdev); -} - -/** - * freeze_bdev -- lock a filesystem and force it into a consistent state - * @bdev: blockdevice to lock - * - * This takes the block device bd_mount_sem to make sure no new mounts - * happen on bdev until thaw_bdev() is called. - * If a superblock is found on this device, we take the s_umount semaphore - * on it to make sure nobody unmounts until the snapshot creation is done. - * The reference counter (bd_fsfreeze_count) guarantees that only the last - * unfreeze process can unfreeze the frozen filesystem actually when multiple - * freeze requests arrive simultaneously. It counts up in freeze_bdev() and - * count down in thaw_bdev(). When it becomes 0, thaw_bdev() will unfreeze - * actually. - */ -struct super_block *freeze_bdev(struct block_device *bdev) -{ - struct super_block *sb; - int error = 0; - - mutex_lock(&bdev->bd_fsfreeze_mutex); - if (bdev->bd_fsfreeze_count > 0) { - bdev->bd_fsfreeze_count++; - sb = get_super(bdev); - mutex_unlock(&bdev->bd_fsfreeze_mutex); - return sb; - } - bdev->bd_fsfreeze_count++; - - down(&bdev->bd_mount_sem); - sb = get_super(bdev); - if (sb && !(sb->s_flags & MS_RDONLY)) { - sb->s_frozen = SB_FREEZE_WRITE; - smp_wmb(); - - __fsync_super(sb); - - sb->s_frozen = SB_FREEZE_TRANS; - smp_wmb(); - - sync_blockdev(sb->s_bdev); - - if (sb->s_op->freeze_fs) { - error = sb->s_op->freeze_fs(sb); - if (error) { - printk(KERN_ERR - "VFS:Filesystem freeze failed\n"); - sb->s_frozen = SB_UNFROZEN; - drop_super(sb); - up(&bdev->bd_mount_sem); - bdev->bd_fsfreeze_count--; - mutex_unlock(&bdev->bd_fsfreeze_mutex); - return ERR_PTR(error); - } - } - } - - sync_blockdev(bdev); - mutex_unlock(&bdev->bd_fsfreeze_mutex); - - return sb; /* thaw_bdev releases s->s_umount and bd_mount_sem */ -} -EXPORT_SYMBOL(freeze_bdev); - -/** - * thaw_bdev -- unlock filesystem - * @bdev: blockdevice to unlock - * @sb: associated superblock - * - * Unlocks the filesystem and marks it writeable again after freeze_bdev(). - */ -int thaw_bdev(struct block_device *bdev, struct super_block *sb) -{ - int error = 0; - - mutex_lock(&bdev->bd_fsfreeze_mutex); - if (!bdev->bd_fsfreeze_count) { - mutex_unlock(&bdev->bd_fsfreeze_mutex); - return -EINVAL; - } - - bdev->bd_fsfreeze_count--; - if (bdev->bd_fsfreeze_count > 0) { - if (sb) - drop_super(sb); - mutex_unlock(&bdev->bd_fsfreeze_mutex); - return 0; - } - - if (sb) { - BUG_ON(sb->s_bdev != bdev); - if (!(sb->s_flags & MS_RDONLY)) { - if (sb->s_op->unfreeze_fs) { - error = sb->s_op->unfreeze_fs(sb); - if (error) { - printk(KERN_ERR - "VFS:Filesystem thaw failed\n"); - sb->s_frozen = SB_FREEZE_TRANS; - bdev->bd_fsfreeze_count++; - mutex_unlock(&bdev->bd_fsfreeze_mutex); - return error; - } - } - sb->s_frozen = SB_UNFROZEN; - smp_wmb(); - wake_up(&sb->s_wait_unfrozen); - } - drop_super(sb); - } - - up(&bdev->bd_mount_sem); - mutex_unlock(&bdev->bd_fsfreeze_mutex); - return 0; -} -EXPORT_SYMBOL(thaw_bdev); - -/* * Various filesystems appear to want __find_get_block to be non-blocking. * But it's the page lock which protects the buffers. To get around this, * we get exclusion from try_to_free_buffers with the blockdev mapping's @@ -435,7 +290,7 @@ static void free_more_memory(void) &zone); if (zone) try_to_free_pages(node_zonelist(nid, GFP_NOFS), 0, - GFP_NOFS); + GFP_NOFS, NULL); } } @@ -692,6 +547,39 @@ repeat: return err; } +void do_thaw_all(unsigned long unused) +{ + struct super_block *sb; + char b[BDEVNAME_SIZE]; + + spin_lock(&sb_lock); +restart: + list_for_each_entry(sb, &super_blocks, s_list) { + sb->s_count++; + spin_unlock(&sb_lock); + down_read(&sb->s_umount); + while (sb->s_bdev && !thaw_bdev(sb->s_bdev, sb)) + printk(KERN_WARNING "Emergency Thaw on %s\n", + bdevname(sb->s_bdev, b)); + up_read(&sb->s_umount); + spin_lock(&sb_lock); + if (__put_super_and_need_restart(sb)) + goto restart; + } + spin_unlock(&sb_lock); + printk(KERN_WARNING "Emergency Thaw complete\n"); +} + +/** + * emergency_thaw_all -- forcibly thaw every frozen filesystem + * + * Used for emergency unfreeze of all filesystems via SysRq + */ +void emergency_thaw_all(void) +{ + pdflush_operation(do_thaw_all, 0); +} + /** * sync_mapping_buffers - write out & wait upon a mapping's "associated" buffers * @mapping: the mapping which wants those buffers written @@ -760,33 +648,18 @@ EXPORT_SYMBOL(mark_buffer_dirty_inode); * If warn is true, then emit a warning if the page is not uptodate and has * not been truncated. */ -static int __set_page_dirty(struct page *page, +static void __set_page_dirty(struct page *page, struct address_space *mapping, int warn) { - if (unlikely(!mapping)) - return !TestSetPageDirty(page); - - if (TestSetPageDirty(page)) - return 0; - spin_lock_irq(&mapping->tree_lock); if (page->mapping) { /* Race with truncate? */ WARN_ON_ONCE(warn && !PageUptodate(page)); - - if (mapping_cap_account_dirty(mapping)) { - __inc_zone_page_state(page, NR_FILE_DIRTY); - __inc_bdi_stat(mapping->backing_dev_info, - BDI_RECLAIMABLE); - task_dirty_inc(current); - task_io_account_write(PAGE_CACHE_SIZE); - } + account_page_dirtied(page, mapping); radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); } spin_unlock_irq(&mapping->tree_lock); __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); - - return 1; } /* @@ -816,6 +689,7 @@ static int __set_page_dirty(struct page *page, */ int __set_page_dirty_buffers(struct page *page) { + int newly_dirty; struct address_space *mapping = page_mapping(page); if (unlikely(!mapping)) @@ -831,9 +705,12 @@ int __set_page_dirty_buffers(struct page *page) bh = bh->b_this_page; } while (bh != head); } + newly_dirty = !TestSetPageDirty(page); spin_unlock(&mapping->private_lock); - return __set_page_dirty(page, mapping, 1); + if (newly_dirty) + __set_page_dirty(page, mapping, 1); + return newly_dirty; } EXPORT_SYMBOL(__set_page_dirty_buffers); @@ -1262,8 +1139,11 @@ void mark_buffer_dirty(struct buffer_head *bh) return; } - if (!test_set_buffer_dirty(bh)) - __set_page_dirty(bh->b_page, page_mapping(bh->b_page), 0); + if (!test_set_buffer_dirty(bh)) { + struct page *page = bh->b_page; + if (!TestSetPageDirty(page)) + __set_page_dirty(page, page_mapping(page), 0); + } } /* @@ -2466,13 +2346,14 @@ int block_commit_write(struct page *page, unsigned from, unsigned to) * unlock the page. */ int -block_page_mkwrite(struct vm_area_struct *vma, struct page *page, +block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, get_block_t get_block) { + struct page *page = vmf->page; struct inode *inode = vma->vm_file->f_path.dentry->d_inode; unsigned long end; loff_t size; - int ret = -EINVAL; + int ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */ lock_page(page); size = i_size_read(inode); @@ -2492,6 +2373,13 @@ block_page_mkwrite(struct vm_area_struct *vma, struct page *page, if (!ret) ret = block_commit_write(page, 0, end); + if (unlikely(ret)) { + if (ret == -ENOMEM) + ret = VM_FAULT_OOM; + else /* -ENOSPC, -EIO, etc */ + ret = VM_FAULT_SIGBUS; + } + out_unlock: unlock_page(page); return ret; diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 851388fafc7..65984006192 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -6,7 +6,16 @@ the server to treat subsequent connections, especially those that are authenticated as guest, as reconnections, invalidating the earlier user's smb session. This fix allows cifs to mount multiple times to the same server with different userids without risking invalidating earlier -established security contexts. +established security contexts. fsync now sends SMB Flush operation +to better ensure that we wait for server to write all of the data to +server disk (not just write it over the network). Add new mount +parameter to allow user to disable sending the (slow) SMB flush on +fsync if desired (fsync still flushes all cached write data to the server). +Posix file open support added (turned off after one attempt if server +fails to support it properly, as with Samba server versions prior to 3.3.2) +Fix "redzone overwritten" bug in cifs_put_tcon (CIFSTcon may allocate too +little memory for the "nativeFileSystem" field returned by the server +during mount). Version 1.56 ------------ diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 341a98965bd..6994a0f54f0 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -118,6 +118,18 @@ config CIFS_DEBUG2 option can be turned off unless you are debugging cifs problems. If unsure, say N. +config CIFS_DFS_UPCALL + bool "DFS feature support" + depends on CIFS && KEYS + help + Distributed File System (DFS) support is used to access shares + transparently in an enterprise name space, even if the share + moves to a different server. This feature also enables + an upcall mechanism for CIFS which contacts userspace helper + utilities to provide server name resolution (host names to + IP addresses) which is needed for implicit mounts of DFS junction + points. If unsure, say N. + config CIFS_EXPERIMENTAL bool "CIFS Experimental Features (EXPERIMENTAL)" depends on CIFS && EXPERIMENTAL @@ -131,12 +143,3 @@ config CIFS_EXPERIMENTAL (which is disabled by default). See the file fs/cifs/README for more details. If unsure, say N. -config CIFS_DFS_UPCALL - bool "DFS feature support (EXPERIMENTAL)" - depends on CIFS_EXPERIMENTAL - depends on KEYS - help - Enables an upcall mechanism for CIFS which contacts userspace - helper utilities to provide server name resolution (host names to - IP addresses) which is needed for implicit mounts of DFS junction - points. If unsure, say N. diff --git a/fs/cifs/README b/fs/cifs/README index da4515e3be2..07434181623 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -472,6 +472,19 @@ A partial list of the supported mount options follows: even if the cifs server would support posix advisory locks. "forcemand" is accepted as a shorter form of this mount option. + nostrictsync If this mount option is set, when an application does an + fsync call then the cifs client does not send an SMB Flush + to the server (to force the server to write all dirty data + for this file immediately to disk), although cifs still sends + all dirty (cached) file data to the server and waits for the + server to respond to the write. Since SMB Flush can be + very slow, and some servers may be reliable enough (to risk + delaying slightly flushing the data to disk on the server), + turning on this option may be useful to improve performance for + applications that fsync too much, at a small risk of server + crash. If this mount option is not set, by default cifs will + send an SMB flush request (and wait for a response) on every + fsync call. nodfs Disable DFS (global name space support) even if the server claims to support it. This can help work around a problem with parsing of DFS paths with Samba server @@ -692,13 +705,14 @@ require this helper. Note that NTLMv2 security (which does not require the cifs.upcall helper program), instead of using Kerberos, is sufficient for some use cases. -Enabling DFS support (used to access shares transparently in an MS-DFS -global name space) requires that CONFIG_CIFS_EXPERIMENTAL be enabled. In -addition, DFS support for target shares which are specified as UNC +DFS support allows transparent redirection to shares in an MS-DFS name space. +In addition, DFS support for target shares which are specified as UNC names which begin with host names (rather than IP addresses) requires a user space helper (such as cifs.upcall) to be present in order to translate host names to ip address, and the user space helper must also -be configured in the file /etc/request-key.conf +be configured in the file /etc/request-key.conf. Samba, Windows servers and +many NAS appliances support DFS as a way of constructing a global name +space to ease network configuration and improve reliability. To use cifs Kerberos and DFS support, the Linux keyutils package should be installed and something like the following lines should be added to the diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 490e34bbf27..7f19fefd3d4 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -340,6 +340,8 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) seq_printf(m, "\nWrites: %d Bytes: %lld", atomic_read(&tcon->num_writes), (long long)(tcon->bytes_written)); + seq_printf(m, "\nFlushes: %d", + atomic_read(&tcon->num_flushes)); seq_printf(m, "\nLocks: %d HardLinks: %d " "Symlinks: %d", atomic_read(&tcon->num_locks), @@ -402,7 +404,6 @@ cifs_proc_init(void) if (proc_fs_cifs == NULL) return; - proc_fs_cifs->owner = THIS_MODULE; proc_create("DebugData", 0, proc_fs_cifs, &cifs_debug_data_proc_fops); #ifdef CONFIG_CIFS_STATS diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 85c0a74d034..5fdbf8a1447 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -104,9 +104,9 @@ static char *cifs_get_share_name(const char *node_name) /** - * compose_mount_options - creates mount options for refferral + * cifs_compose_mount_options - creates mount options for refferral * @sb_mountdata: parent/root DFS mount options (template) - * @dentry: point where we are going to mount + * @fullpath: full path in UNC format * @ref: server's referral * @devname: pointer for saving device name * @@ -116,8 +116,8 @@ static char *cifs_get_share_name(const char *node_name) * Returns: pointer to new mount options or ERR_PTR. * Caller is responcible for freeing retunrned value if it is not error. */ -static char *compose_mount_options(const char *sb_mountdata, - struct dentry *dentry, +char *cifs_compose_mount_options(const char *sb_mountdata, + const char *fullpath, const struct dfs_info3_param *ref, char **devname) { @@ -128,7 +128,6 @@ static char *compose_mount_options(const char *sb_mountdata, char *srvIP = NULL; char sep = ','; int off, noff; - char *fullpath; if (sb_mountdata == NULL) return ERR_PTR(-EINVAL); @@ -202,17 +201,6 @@ static char *compose_mount_options(const char *sb_mountdata, goto compose_mount_options_err; } - /* - * this function gives us a path with a double backslash prefix. We - * require a single backslash for DFS. Temporarily increment fullpath - * to put it in the proper form and decrement before freeing it. - */ - fullpath = build_path_from_dentry(dentry); - if (!fullpath) { - rc = -ENOMEM; - goto compose_mount_options_err; - } - ++fullpath; tkn_e = strchr(tkn_e + 1, '\\'); if (tkn_e || (strlen(fullpath) - ref->path_consumed)) { strncat(mountdata, &sep, 1); @@ -221,8 +209,6 @@ static char *compose_mount_options(const char *sb_mountdata, strcat(mountdata, tkn_e + 1); strcat(mountdata, fullpath + ref->path_consumed); } - --fullpath; - kfree(fullpath); /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/ /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/ @@ -245,10 +231,20 @@ static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, struct vfsmount *mnt; char *mountdata; char *devname = NULL; + char *fullpath; cifs_sb = CIFS_SB(dentry->d_inode->i_sb); - mountdata = compose_mount_options(cifs_sb->mountdata, - dentry, ref, &devname); + /* + * this function gives us a path with a double backslash prefix. We + * require a single backslash for DFS. + */ + fullpath = build_path_from_dentry(dentry); + if (!fullpath) + return ERR_PTR(-ENOMEM); + + mountdata = cifs_compose_mount_options(cifs_sb->mountdata, + fullpath + 1, ref, &devname); + kfree(fullpath); if (IS_ERR(mountdata)) return (struct vfsmount *)mountdata; diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index c4c306f7b06..4797787c6a4 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -32,6 +32,7 @@ #define CIFS_MOUNT_OVERR_GID 0x800 /* override gid returned from server */ #define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */ #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ +#define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 13ea53251dc..38491fd3871 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -606,7 +606,8 @@ cifs_get_sb(struct file_system_type *fs_type, return rc; } sb->s_flags |= MS_ACTIVE; - return simple_set_mnt(mnt, sb); + simple_set_mnt(mnt, sb); + return 0; } static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 2b1d28a9ee2..77e190dc288 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -78,8 +78,8 @@ extern int cifs_dir_open(struct inode *inode, struct file *file); extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); /* Functions related to dir entries */ -extern struct dentry_operations cifs_dentry_ops; -extern struct dentry_operations cifs_ci_dentry_ops; +extern const struct dentry_operations cifs_dentry_ops; +extern const struct dentry_operations cifs_ci_dentry_ops; /* Functions related to symlinks */ extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index e004f6db5fc..9fbf4dff5da 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -254,6 +254,7 @@ struct cifsTconInfo { atomic_t num_smbs_sent; atomic_t num_writes; atomic_t num_reads; + atomic_t num_flushes; atomic_t num_oplock_brks; atomic_t num_opens; atomic_t num_closes; @@ -298,6 +299,7 @@ struct cifsTconInfo { bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol for this mount even if server would support */ bool local_lease:1; /* check leases (only) on local system not remote */ + bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ bool need_reconnect:1; /* connection reset, tid now invalid */ /* BB add field for back pointer to sb struct(s)? */ }; diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index b4e2e9f0ee3..b370489c8da 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifspdu.h * - * Copyright (c) International Business Machines Corp., 2002,2008 + * Copyright (c) International Business Machines Corp., 2002,2009 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -23,6 +23,7 @@ #define _CIFSPDU_H #include <net/sock.h> +#include "smbfsctl.h" #ifdef CONFIG_CIFS_WEAK_PW_HASH #define LANMAN_PROT 0 @@ -34,15 +35,15 @@ #define POSIX_PROT (CIFS_PROT+1) #define BAD_PROT 0xFFFF -/* SMB command codes */ -/* - * Some commands have minimal (wct=0,bcc=0), or uninteresting, responses +/* SMB command codes: + * Note some commands have minimal (wct=0,bcc=0), or uninteresting, responses * (ie which include no useful data other than the SMB error code itself). - * Knowing this helps avoid response buffer allocations and copy in some cases + * This can allow us to avoid response buffer allocations and copy in some cases */ #define SMB_COM_CREATE_DIRECTORY 0x00 /* trivial response */ #define SMB_COM_DELETE_DIRECTORY 0x01 /* trivial response */ #define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */ +#define SMB_COM_FLUSH 0x05 /* triv req/rsp */ #define SMB_COM_DELETE 0x06 /* trivial response */ #define SMB_COM_RENAME 0x07 /* trivial response */ #define SMB_COM_QUERY_INFORMATION 0x08 /* aka getattr */ @@ -790,6 +791,12 @@ typedef struct smb_com_close_rsp { __u16 ByteCount; /* bct = 0 */ } __attribute__((packed)) CLOSE_RSP; +typedef struct smb_com_flush_req { + struct smb_hdr hdr; /* wct = 1 */ + __u16 FileID; + __u16 ByteCount; /* 0 */ +} __attribute__((packed)) FLUSH_REQ; + typedef struct smb_com_findclose_req { struct smb_hdr hdr; /* wct = 1 */ __u16 FileID; @@ -1924,19 +1931,19 @@ typedef struct smb_com_transaction2_get_dfs_refer_req { #define DFS_TYPE_ROOT 0x0001 /* Referral Entry Flags */ -#define DFS_NAME_LIST_REF 0x0200 +#define DFS_NAME_LIST_REF 0x0200 /* set for domain or DC referral responses */ +#define DFS_TARGET_SET_BOUNDARY 0x0400 /* only valid with version 4 dfs req */ -typedef struct dfs_referral_level_3 { - __le16 VersionNumber; +typedef struct dfs_referral_level_3 { /* version 4 is same, + one flag bit */ + __le16 VersionNumber; /* must be 3 or 4 */ __le16 Size; __le16 ServerType; /* 0x0001 = root targets; 0x0000 = link targets */ - __le16 ReferralEntryFlags; /* 0x0200 bit set only for domain - or DC referral responce */ + __le16 ReferralEntryFlags; __le32 TimeToLive; __le16 DfsPathOffset; __le16 DfsAlternatePathOffset; __le16 NetworkAddressOffset; /* offset of the link target */ - __le16 ServiceSiteGuid; + __u8 ServiceSiteGuid[16]; /* MBZ, ignored */ } __attribute__((packed)) REFERRAL3; typedef struct smb_com_transaction_get_dfs_refer_rsp { @@ -1946,48 +1953,15 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp { __u8 Pad; __le16 PathConsumed; __le16 NumberOfReferrals; - __le16 DFSFlags; - __u16 Pad2; + __le32 DFSFlags; REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ /* followed by the strings pointed to by the referral structures */ } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_RSP; /* DFS Flags */ -#define DFSREF_REFERRAL_SERVER 0x0001 -#define DFSREF_STORAGE_SERVER 0x0002 - -/* IOCTL information */ -/* - * List of ioctl function codes that look to be of interest to remote clients - * like this one. Need to do some experimentation to make sure they all work - * remotely. Some of the following, such as the encryption/compression ones - * would be invoked from tools via a specialized hook into the VFS rather - * than via the standard vfs entry points - */ -#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000 -#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004 -#define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008 -#define FSCTL_LOCK_VOLUME 0x00090018 -#define FSCTL_UNLOCK_VOLUME 0x0009001C -#define FSCTL_GET_COMPRESSION 0x0009003C -#define FSCTL_SET_COMPRESSION 0x0009C040 -#define FSCTL_REQUEST_FILTER_OPLOCK 0x0009008C -#define FSCTL_FILESYS_GET_STATISTICS 0x00090090 -#define FSCTL_SET_REPARSE_POINT 0x000900A4 -#define FSCTL_GET_REPARSE_POINT 0x000900A8 -#define FSCTL_DELETE_REPARSE_POINT 0x000900AC -#define FSCTL_SET_SPARSE 0x000900C4 -#define FSCTL_SET_ZERO_DATA 0x000900C8 -#define FSCTL_SET_ENCRYPTION 0x000900D7 -#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB -#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF -#define FSCTL_READ_RAW_ENCRYPTED 0x000900E3 -#define FSCTL_SIS_COPYFILE 0x00090100 -#define FSCTL_SIS_LINK_FILES 0x0009C104 - -#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 -#define IO_REPARSE_TAG_HSM 0xC0000004 -#define IO_REPARSE_TAG_SIS 0x80000007 +#define DFSREF_REFERRAL_SERVER 0x00000001 /* all targets are DFS roots */ +#define DFSREF_STORAGE_SERVER 0x00000002 /* no further ref requests needed */ +#define DFSREF_TARGET_FAILBACK 0x00000004 /* only for DFS referral version 4 */ /* ************************************************************************ @@ -2508,8 +2482,6 @@ struct data_blob { 6) Use nanosecond timestamps throughout all time fields if corresponding attribute flag is set 7) sendfile - handle based copy - 8) Direct i/o - 9) Misc fcntls? what about fixing 64 bit alignment @@ -2628,7 +2600,5 @@ typedef struct file_chattr_info { __le64 mode; /* list of actual attribute bits on this inode */ } __attribute__((packed)) FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */ - -#endif - +#endif /* POSIX */ #endif /* _CIFSPDU_H */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 083dfc57c7a..4167716d32f 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -44,6 +44,9 @@ extern void _FreeXid(unsigned int); extern char *build_path_from_dentry(struct dentry *); extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb); extern char *build_wildcard_path_from_dentry(struct dentry *direntry); +extern char *cifs_compose_mount_options(const char *sb_mountdata, + const char *fullpath, const struct dfs_info3_param *ref, + char **devname); /* extern void renew_parental_timestamps(struct dentry *direntry);*/ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, struct smb_hdr * /* input */ , @@ -92,6 +95,9 @@ extern u64 cifs_UnixTimeToNT(struct timespec); extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time); extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time); +extern int cifs_posix_open(char *full_path, struct inode **pinode, + struct super_block *sb, int mode, int oflags, + int *poplock, __u16 *pnetfid, int xid); extern void posix_fill_in_inode(struct inode *tmp_inode, FILE_UNIX_BASIC_INFO *pData, int isNewInode); extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum); @@ -281,6 +287,9 @@ extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, const int smb_file_id); +extern int CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, + const int smb_file_id); + extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, unsigned int count, const __u64 lseek, unsigned int *nbytes, char **buf, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 939e2f76b95..bc09c998631 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1934,6 +1934,27 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) } int +CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id) +{ + int rc = 0; + FLUSH_REQ *pSMB = NULL; + cFYI(1, ("In CIFSSMBFlush")); + + rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB); + if (rc) + return rc; + + pSMB->FileID = (__u16) smb_file_id; + pSMB->ByteCount = 0; + rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); + cifs_stats_inc(&tcon->num_flushes); + if (rc) + cERROR(1, ("Send error in Flush = %d", rc)); + + return rc; +} + +int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, const struct nls_table *nls_codepage, int remap) @@ -2356,8 +2377,10 @@ winCreateHardLinkRetry: PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; - pSMB->OldFileName[name_len] = 0; /* pad */ - pSMB->OldFileName[name_len + 1] = 0x04; + + /* protocol specifies ASCII buffer format (0x04) for unicode */ + pSMB->OldFileName[name_len] = 0x04; + pSMB->OldFileName[name_len + 1] = 0x00; /* pad */ name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], toName, PATH_MAX, nls_codepage, remap); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index da0f4ffa061..0de3b5615a2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -95,6 +95,7 @@ struct smb_vol { bool local_lease:1; /* check leases only on local system, not remote */ bool noblocksnd:1; bool noautotune:1; + bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ unsigned int rsize; unsigned int wsize; unsigned int sockopt; @@ -1274,6 +1275,10 @@ cifs_parse_mount_options(char *options, const char *devname, vol->intr = 0; } else if (strnicmp(data, "intr", 4) == 0) { vol->intr = 1; + } else if (strnicmp(data, "nostrictsync", 12) == 0) { + vol->nostrictsync = 1; + } else if (strnicmp(data, "strictsync", 10) == 0) { + vol->nostrictsync = 0; } else if (strnicmp(data, "serverino", 7) == 0) { vol->server_ino = 1; } else if (strnicmp(data, "noserverino", 9) == 0) { @@ -2160,6 +2165,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; if (pvolume_info->nobrl) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; + if (pvolume_info->nostrictsync) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC; if (pvolume_info->mand_lock) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL; if (pvolume_info->cifs_acl) @@ -3667,7 +3674,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, BCC(smb_buffer_response)) { kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = - kzalloc(length + 2, GFP_KERNEL); + kzalloc(2*(length + 1), GFP_KERNEL); if (tcon->nativeFileSystem) cifs_strfromUCS_le( tcon->nativeFileSystem, diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 89fb7283265..2f35cccfcd8 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -129,7 +129,7 @@ cifs_bp_rename_retry: return full_path; } -static int cifs_posix_open(char *full_path, struct inode **pinode, +int cifs_posix_open(char *full_path, struct inode **pinode, struct super_block *sb, int mode, int oflags, int *poplock, __u16 *pnetfid, int xid) { @@ -187,7 +187,9 @@ static int cifs_posix_open(char *full_path, struct inode **pinode, if (!pinode) goto posix_open_ret; /* caller does not need info */ - *pinode = cifs_new_inode(sb, &presp_data->UniqueId); + if (*pinode == NULL) + *pinode = cifs_new_inode(sb, &presp_data->UniqueId); + /* else an inode was passed in. Update its info, don't create one */ /* We do not need to close the file if new_inode fails since the caller will retry qpathinfo as long as inode is null */ @@ -699,7 +701,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) return rc; } */ -struct dentry_operations cifs_dentry_ops = { +const struct dentry_operations cifs_dentry_ops = { .d_revalidate = cifs_d_revalidate, /* d_delete: cifs_d_delete, */ /* not needed except for debugging */ }; @@ -737,7 +739,7 @@ static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, return 1; } -struct dentry_operations cifs_ci_dentry_ops = { +const struct dentry_operations cifs_ci_dentry_ops = { .d_revalidate = cifs_d_revalidate, .d_hash = cifs_ci_hash, .d_compare = cifs_ci_compare, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 12bb656fbe7..81747acca4c 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -78,8 +78,36 @@ static inline int cifs_convert_flags(unsigned int flags) return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_READ_DATA); +} +static inline fmode_t cifs_posix_convert_flags(unsigned int flags) +{ + fmode_t posix_flags = 0; + if ((flags & O_ACCMODE) == O_RDONLY) + posix_flags = FMODE_READ; + else if ((flags & O_ACCMODE) == O_WRONLY) + posix_flags = FMODE_WRITE; + else if ((flags & O_ACCMODE) == O_RDWR) { + /* GENERIC_ALL is too much permission to request + can cause unnecessary access denied on create */ + /* return GENERIC_ALL; */ + posix_flags = FMODE_READ | FMODE_WRITE; + } + /* can not map O_CREAT or O_EXCL or O_TRUNC flags when + reopening a file. They had their effect on the original open */ + if (flags & O_APPEND) + posix_flags |= (fmode_t)O_APPEND; + if (flags & O_SYNC) + posix_flags |= (fmode_t)O_SYNC; + if (flags & O_DIRECTORY) + posix_flags |= (fmode_t)O_DIRECTORY; + if (flags & O_NOFOLLOW) + posix_flags |= (fmode_t)O_NOFOLLOW; + if (flags & O_DIRECT) + posix_flags |= (fmode_t)O_DIRECT; + + return posix_flags; } static inline int cifs_get_disposition(unsigned int flags) @@ -97,6 +125,80 @@ static inline int cifs_get_disposition(unsigned int flags) } /* all arguments to this function must be checked for validity in caller */ +static inline int cifs_posix_open_inode_helper(struct inode *inode, + struct file *file, struct cifsInodeInfo *pCifsInode, + struct cifsFileInfo *pCifsFile, int oplock, u16 netfid) +{ + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); +/* struct timespec temp; */ /* BB REMOVEME BB */ + + file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); + if (file->private_data == NULL) + return -ENOMEM; + pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); + write_lock(&GlobalSMBSeslock); + list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); + + pCifsInode = CIFS_I(file->f_path.dentry->d_inode); + if (pCifsInode == NULL) { + write_unlock(&GlobalSMBSeslock); + return -EINVAL; + } + + /* want handles we can use to read with first + in the list so we do not have to walk the + list to search for one in write_begin */ + if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + list_add_tail(&pCifsFile->flist, + &pCifsInode->openFileList); + } else { + list_add(&pCifsFile->flist, + &pCifsInode->openFileList); + } + + if (pCifsInode->clientCanCacheRead) { + /* we have the inode open somewhere else + no need to discard cache data */ + goto psx_client_can_cache; + } + + /* BB FIXME need to fix this check to move it earlier into posix_open + BB fIX following section BB FIXME */ + + /* if not oplocked, invalidate inode pages if mtime or file + size changed */ +/* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime)); + if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) && + (file->f_path.dentry->d_inode->i_size == + (loff_t)le64_to_cpu(buf->EndOfFile))) { + cFYI(1, ("inode unchanged on server")); + } else { + if (file->f_path.dentry->d_inode->i_mapping) { + rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping); + if (rc != 0) + CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc; + } + cFYI(1, ("invalidating remote inode since open detected it " + "changed")); + invalidate_remote_inode(file->f_path.dentry->d_inode); + } */ + +psx_client_can_cache: + if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { + pCifsInode->clientCanCacheAll = true; + pCifsInode->clientCanCacheRead = true; + cFYI(1, ("Exclusive Oplock granted on inode %p", + file->f_path.dentry->d_inode)); + } else if ((oplock & 0xF) == OPLOCK_READ) + pCifsInode->clientCanCacheRead = true; + + /* will have to change the unlock if we reenable the + filemap_fdatawrite (which does not seem necessary */ + write_unlock(&GlobalSMBSeslock); + return 0; +} + +/* all arguments to this function must be checked for validity in caller */ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile, struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf, @@ -167,7 +269,7 @@ int cifs_open(struct inode *inode, struct file *file) int rc = -EACCES; int xid, oplock; struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; + struct cifsTconInfo *tcon; struct cifsFileInfo *pCifsFile; struct cifsInodeInfo *pCifsInode; struct list_head *tmp; @@ -180,7 +282,7 @@ int cifs_open(struct inode *inode, struct file *file) xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; + tcon = cifs_sb->tcon; if (file->f_flags & O_CREAT) { /* search inode for this file and fill in file->private_data */ @@ -220,6 +322,45 @@ int cifs_open(struct inode *inode, struct file *file) cFYI(1, ("inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags, full_path)); + + if (oplockEnabled) + oplock = REQ_OPLOCK; + else + oplock = 0; + + if (!tcon->broken_posix_open && tcon->unix_ext && + (tcon->ses->capabilities & CAP_UNIX) && + (CIFS_UNIX_POSIX_PATH_OPS_CAP & + le64_to_cpu(tcon->fsUnixInfo.Capability))) { + int oflags = (int) cifs_posix_convert_flags(file->f_flags); + /* can not refresh inode info since size could be stale */ + rc = cifs_posix_open(full_path, &inode, inode->i_sb, + cifs_sb->mnt_file_mode /* ignored */, + oflags, &oplock, &netfid, xid); + if (rc == 0) { + cFYI(1, ("posix open succeeded")); + /* no need for special case handling of setting mode + on read only files needed here */ + + cifs_posix_open_inode_helper(inode, file, pCifsInode, + pCifsFile, oplock, netfid); + goto out; + } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { + if (tcon->ses->serverNOS) + cERROR(1, ("server %s of type %s returned" + " unexpected error on SMB posix open" + ", disabling posix open support." + " Check if server update available.", + tcon->ses->serverName, + tcon->ses->serverNOS)); + tcon->broken_posix_open = true; + } else if ((rc != -EIO) && (rc != -EREMOTE) && + (rc != -EOPNOTSUPP)) /* path not found or net err */ + goto out; + /* else fallthrough to retry open the old way on network i/o + or DFS errors */ + } + desiredAccess = cifs_convert_flags(file->f_flags); /********************************************************************* @@ -248,11 +389,6 @@ int cifs_open(struct inode *inode, struct file *file) disposition = cifs_get_disposition(file->f_flags); - if (oplockEnabled) - oplock = REQ_OPLOCK; - else - oplock = 0; - /* BB pass O_SYNC flag through on file attributes .. BB */ /* Also refresh inode by passing in file_info buf returned by SMBOpen @@ -269,7 +405,7 @@ int cifs_open(struct inode *inode, struct file *file) } if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) - rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, + rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -278,7 +414,7 @@ int cifs_open(struct inode *inode, struct file *file) if (rc == -EIO) { /* Old server, try legacy style OpenX */ - rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, + rc = SMBLegacyOpen(xid, tcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -295,12 +431,12 @@ int cifs_open(struct inode *inode, struct file *file) } pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); write_lock(&GlobalSMBSeslock); - list_add(&pCifsFile->tlist, &pTcon->openFileList); + list_add(&pCifsFile->tlist, &tcon->openFileList); pCifsInode = CIFS_I(file->f_path.dentry->d_inode); if (pCifsInode) { rc = cifs_open_inode_helper(inode, file, pCifsInode, - pCifsFile, pTcon, + pCifsFile, tcon, &oplock, buf, full_path, xid); } else { write_unlock(&GlobalSMBSeslock); @@ -309,7 +445,7 @@ int cifs_open(struct inode *inode, struct file *file) if (oplock & CIFS_CREATE_ACTION) { /* time to set mode which we can not set earlier due to problems creating new read-only files */ - if (pTcon->unix_ext) { + if (tcon->unix_ext) { struct cifs_unix_set_info_args args = { .mode = inode->i_mode, .uid = NO_CHANGE_64, @@ -319,7 +455,7 @@ int cifs_open(struct inode *inode, struct file *file) .mtime = NO_CHANGE_64, .device = 0, }; - CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args, + CIFSSMBUnixSetInfo(xid, tcon, full_path, &args, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -349,7 +485,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush) int rc = -EACCES; int xid, oplock; struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; + struct cifsTconInfo *tcon; struct cifsFileInfo *pCifsFile; struct cifsInodeInfo *pCifsInode; struct inode *inode; @@ -387,7 +523,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush) } cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; + tcon = cifs_sb->tcon; /* can not grab rename sem here because various ops, including those that already have the rename sem can end up causing writepage @@ -404,20 +540,37 @@ reopen_error_exit: cFYI(1, ("inode = 0x%p file flags 0x%x for %s", inode, file->f_flags, full_path)); - desiredAccess = cifs_convert_flags(file->f_flags); if (oplockEnabled) oplock = REQ_OPLOCK; else oplock = 0; + if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && + (CIFS_UNIX_POSIX_PATH_OPS_CAP & + le64_to_cpu(tcon->fsUnixInfo.Capability))) { + int oflags = (int) cifs_posix_convert_flags(file->f_flags); + /* can not refresh inode info since size could be stale */ + rc = cifs_posix_open(full_path, NULL, inode->i_sb, + cifs_sb->mnt_file_mode /* ignored */, + oflags, &oplock, &netfid, xid); + if (rc == 0) { + cFYI(1, ("posix reopen succeeded")); + goto reopen_success; + } + /* fallthrough to retry open the old way on errors, especially + in the reconnect path it is important to retry hard */ + } + + desiredAccess = cifs_convert_flags(file->f_flags); + /* Can not refresh inode by passing in file_info buf to be returned by SMBOpen and then calling get_inode_info with returned buf since file might have write behind data that needs to be flushed and server version of file size can be stale. If we knew for sure that inode was not dirty locally we could do this */ - rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, + rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -426,6 +579,7 @@ reopen_error_exit: cFYI(1, ("cifs_open returned 0x%x", rc)); cFYI(1, ("oplock: %d", oplock)); } else { +reopen_success: pCifsFile->netfid = netfid; pCifsFile->invalidHandle = false; up(&pCifsFile->fh_sem); @@ -439,7 +593,7 @@ reopen_error_exit: go to server to get inode info */ pCifsInode->clientCanCacheAll = false; pCifsInode->clientCanCacheRead = false; - if (pTcon->unix_ext) + if (tcon->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, xid); else @@ -467,7 +621,6 @@ reopen_error_exit: cifs_relock_file(pCifsFile); } } - kfree(full_path); FreeXid(xid); return rc; @@ -1523,6 +1676,9 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) { int xid; int rc = 0; + struct cifsTconInfo *tcon; + struct cifsFileInfo *smbfile = + (struct cifsFileInfo *)file->private_data; struct inode *inode = file->f_path.dentry->d_inode; xid = GetXid(); @@ -1534,7 +1690,12 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) if (rc == 0) { rc = CIFS_I(inode)->write_behind_rc; CIFS_I(inode)->write_behind_rc = 0; + tcon = CIFS_SB(inode->i_sb)->tcon; + if (!rc && tcon && smbfile && + !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) + rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); } + FreeXid(xid); return rc; } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 4690a360c85..a8797cc6080 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -763,6 +763,9 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, struct cifsTconInfo *pTcon = cifs_sb->tcon; FILE_BASIC_INFO info_buf; + if (attrs == NULL) + return -EINVAL; + if (attrs->ia_valid & ATTR_ATIME) { set_time = true; info_buf.LastAccessTime = diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h new file mode 100644 index 00000000000..7056b891e08 --- /dev/null +++ b/fs/cifs/smbfsctl.h @@ -0,0 +1,84 @@ +/* + * fs/cifs/smbfsctl.h: SMB, CIFS, SMB2 FSCTL definitions + * + * Copyright (c) International Business Machines Corp., 2002,2009 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* IOCTL information */ +/* + * List of ioctl/fsctl function codes that are or could be useful in the + * future to remote clients like cifs or SMB2 client. There is probably + * a slightly larger set of fsctls that NTFS local filesystem could handle, + * including the seven below that we do not have struct definitions for. + * Even with protocol definitions for most of these now available, we still + * need to do some experimentation to identify which are practical to do + * remotely. Some of the following, such as the encryption/compression ones + * could be invoked from tools via a specialized hook into the VFS rather + * than via the standard vfs entry points + */ +#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000 +#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004 +#define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008 +#define FSCTL_LOCK_VOLUME 0x00090018 +#define FSCTL_UNLOCK_VOLUME 0x0009001C +#define FSCTL_IS_PATHNAME_VALID 0x0009002C /* BB add struct */ +#define FSCTL_GET_COMPRESSION 0x0009003C /* BB add struct */ +#define FSCTL_SET_COMPRESSION 0x0009C040 /* BB add struct */ +#define FSCTL_QUERY_FAT_BPB 0x00090058 /* BB add struct */ +/* Verify the next FSCTL number, we had it as 0x00090090 before */ +#define FSCTL_FILESYSTEM_GET_STATS 0x00090060 /* BB add struct */ +#define FSCTL_GET_NTFS_VOLUME_DATA 0x00090064 /* BB add struct */ +#define FSCTL_GET_RETRIEVAL_POINTERS 0x00090073 /* BB add struct */ +#define FSCTL_IS_VOLUME_DIRTY 0x00090078 /* BB add struct */ +#define FSCTL_ALLOW_EXTENDED_DASD_IO 0x00090083 /* BB add struct */ +#define FSCTL_REQUEST_FILTER_OPLOCK 0x0009008C +#define FSCTL_FIND_FILES_BY_SID 0x0009008F /* BB add struct */ +#define FSCTL_SET_OBJECT_ID 0x00090098 /* BB add struct */ +#define FSCTL_GET_OBJECT_ID 0x0009009C /* BB add struct */ +#define FSCTL_DELETE_OBJECT_ID 0x000900A0 /* BB add struct */ +#define FSCTL_SET_REPARSE_POINT 0x000900A4 /* BB add struct */ +#define FSCTL_GET_REPARSE_POINT 0x000900A8 /* BB add struct */ +#define FSCTL_DELETE_REPARSE_POINT 0x000900AC /* BB add struct */ +#define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */ +#define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */ +#define FSCTL_SET_SPARSE 0x000900C4 /* BB add struct */ +#define FSCTL_SET_ZERO_DATA 0x000900C8 /* BB add struct */ +#define FSCTL_SET_ENCRYPTION 0x000900D7 /* BB add struct */ +#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB /* BB add struct */ +#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF /* BB add struct */ +#define FSCTL_READ_RAW_ENCRYPTED 0x000900E3 /* BB add struct */ +#define FSCTL_READ_FILE_USN_DATA 0x000900EB /* BB add struct */ +#define FSCTL_WRITE_USN_CLOSE_RECORD 0x000900EF /* BB add struct */ +#define FSCTL_SIS_COPYFILE 0x00090100 /* BB add struct */ +#define FSCTL_RECALL_FILE 0x00090117 /* BB add struct */ +#define FSCTL_QUERY_SPARING_INFO 0x00090138 /* BB add struct */ +#define FSCTL_SET_ZERO_ON_DEALLOC 0x00090194 /* BB add struct */ +#define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */ +#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF /* BB add struct */ +#define FSCTL_SET_DEFECT_MANAGEMENT 0x00098134 /* BB add struct */ +#define FSCTL_SIS_LINK_FILES 0x0009C104 +#define FSCTL_PIPE_PEEK 0x0011400C /* BB add struct */ +#define FSCTL_PIPE_TRANSCEIVE 0x0011C017 /* BB add struct */ +/* strange that the number for this op is not sequential with previous op */ +#define FSCTL_PIPE_WAIT 0x00110018 /* BB add struct */ +#define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */ +#define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */ + +#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 +#define IO_REPARSE_TAG_HSM 0xC0000004 +#define IO_REPARSE_TAG_SIS 0x80000007 diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 75b1fa90b2c..4bb9d0a5dec 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -59,7 +59,7 @@ static int coda_return_EIO(void) } #define CODA_EIO_ERROR ((void *) (coda_return_EIO)) -static struct dentry_operations coda_dentry_operations = +static const struct dentry_operations coda_dentry_operations = { .d_revalidate = coda_dentry_revalidate, .d_delete = coda_dentry_delete, diff --git a/fs/compat.c b/fs/compat.c index d0145ca2757..55efdfebdf5 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -378,6 +378,34 @@ out: return error; } +/* + * This is a copy of sys_ustat, just dealing with a structure layout. + * Given how simple this syscall is that apporach is more maintainable + * than the various conversion hacks. + */ +asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u) +{ + struct super_block *sb; + struct compat_ustat tmp; + struct kstatfs sbuf; + int err; + + sb = user_get_super(new_decode_dev(dev)); + if (!sb) + return -EINVAL; + err = vfs_statfs(sb->s_root, &sbuf); + drop_super(sb); + if (err) + return err; + + memset(&tmp, 0, sizeof(struct compat_ustat)); + tmp.f_tfree = sbuf.f_bfree; + tmp.f_tinode = sbuf.f_ffree; + if (copy_to_user(u, &tmp, sizeof(struct compat_ustat))) + return -EFAULT; + return 0; +} + static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) { if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || @@ -1392,22 +1420,28 @@ int compat_do_execve(char * filename, { struct linux_binprm *bprm; struct file *file; + struct files_struct *displaced; int retval; + retval = unshare_files(&displaced); + if (retval) + goto out_ret; + retval = -ENOMEM; bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); if (!bprm) - goto out_ret; + goto out_files; retval = mutex_lock_interruptible(¤t->cred_exec_mutex); if (retval < 0) goto out_free; + current->in_execve = 1; retval = -ENOMEM; bprm->cred = prepare_exec_creds(); if (!bprm->cred) goto out_unlock; - check_unsafe_exec(bprm, current->files); + check_unsafe_exec(bprm); file = open_exec(filename); retval = PTR_ERR(file); @@ -1454,9 +1488,12 @@ int compat_do_execve(char * filename, goto out; /* execve succeeded */ + current->in_execve = 0; mutex_unlock(¤t->cred_exec_mutex); acct_update_integrals(current); free_bprm(bprm); + if (displaced) + put_files_struct(displaced); return retval; out: @@ -1470,11 +1507,15 @@ out_file: } out_unlock: + current->in_execve = 0; mutex_unlock(¤t->cred_exec_mutex); out_free: free_bprm(bprm); +out_files: + if (displaced) + reset_files_struct(displaced); out_ret: return retval; } diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 45e59d3c7f1..ff786687e93 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -522,6 +522,11 @@ static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) if (err) return -EFAULT; break; + case SIOCSHWTSTAMP: + if (copy_from_user(&ifr, uifr32, sizeof(*uifr32))) + return -EFAULT; + ifr.ifr_data = compat_ptr(uifr32->ifr_ifru.ifru_data); + break; default: if (copy_from_user(&ifr, uifr32, sizeof(*uifr32))) return -EFAULT; @@ -1993,6 +1998,8 @@ COMPATIBLE_IOCTL(TUNSETGROUP) COMPATIBLE_IOCTL(TUNGETFEATURES) COMPATIBLE_IOCTL(TUNSETOFFLOAD) COMPATIBLE_IOCTL(TUNSETTXFILTER) +COMPATIBLE_IOCTL(TUNGETSNDBUF) +COMPATIBLE_IOCTL(TUNSETSNDBUF) /* Big V */ COMPATIBLE_IOCTL(VT_SETMODE) COMPATIBLE_IOCTL(VT_GETMODE) @@ -2566,6 +2573,7 @@ HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc) HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc) HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc) HANDLE_IOCTL(SIOCSIFHWBROADCAST, dev_ifsioc) +HANDLE_IOCTL(SIOCSHWTSTAMP, dev_ifsioc) /* ioctls used by appletalk ddp.c */ HANDLE_IOCTL(SIOCATALKDIFADDR, dev_ifsioc) diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 8e93341f3e8..05373db21a4 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -72,7 +72,7 @@ static int configfs_d_delete(struct dentry *dentry) return 1; } -static struct dentry_operations configfs_dentry_ops = { +static const struct dentry_operations configfs_dentry_ops = { .d_iput = configfs_d_iput, /* simple_delete_dentry() isn't exported */ .d_delete = configfs_d_delete, diff --git a/fs/dcache.c b/fs/dcache.c index 07e2d4a44bd..90bbd7e1b11 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1247,15 +1247,18 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, struct dentry *found; struct dentry *new; - /* Does a dentry matching the name exist already? */ + /* + * First check if a dentry matching the name already exists, + * if not go ahead and create it now. + */ found = d_hash_and_lookup(dentry->d_parent, name); - /* If not, create it now and return */ if (!found) { new = d_alloc(dentry->d_parent, name); if (!new) { error = -ENOMEM; goto err_out; } + found = d_splice_alias(inode, new); if (found) { dput(new); @@ -1263,61 +1266,46 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, } return new; } - /* Matching dentry exists, check if it is negative. */ + + /* + * If a matching dentry exists, and it's not negative use it. + * + * Decrement the reference count to balance the iget() done + * earlier on. + */ if (found->d_inode) { if (unlikely(found->d_inode != inode)) { /* This can't happen because bad inodes are unhashed. */ BUG_ON(!is_bad_inode(inode)); BUG_ON(!is_bad_inode(found->d_inode)); } - /* - * Already have the inode and the dentry attached, decrement - * the reference count to balance the iget() done - * earlier on. We found the dentry using d_lookup() so it - * cannot be disconnected and thus we do not need to worry - * about any NFS/disconnectedness issues here. - */ iput(inode); return found; } + /* * Negative dentry: instantiate it unless the inode is a directory and - * has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED), - * in which case d_move() that in place of the found dentry. + * already has a dentry. */ - if (!S_ISDIR(inode->i_mode)) { - /* Not a directory; everything is easy. */ - d_instantiate(found, inode); - return found; - } spin_lock(&dcache_lock); - if (list_empty(&inode->i_dentry)) { - /* - * Directory without a 'disconnected' dentry; we need to do - * d_instantiate() by hand because it takes dcache_lock which - * we already hold. - */ + if (!S_ISDIR(inode->i_mode) || list_empty(&inode->i_dentry)) { __d_instantiate(found, inode); spin_unlock(&dcache_lock); security_d_instantiate(found, inode); return found; } + /* - * Directory with a 'disconnected' dentry; get a reference to the - * 'disconnected' dentry. + * In case a directory already has a (disconnected) entry grab a + * reference to it, move it in place and use it. */ new = list_entry(inode->i_dentry.next, struct dentry, d_alias); dget_locked(new); spin_unlock(&dcache_lock); - /* Do security vodoo. */ security_d_instantiate(found, inode); - /* Move new in place of found. */ d_move(new, found); - /* Balance the iget() we did above. */ iput(inode); - /* Throw away found. */ dput(found); - /* Use new as the actual dentry. */ return new; err_out: diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index bff4052b05e..63a4a59e414 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -322,177 +322,81 @@ static int compare_init_pts_sb(struct super_block *s, void *p) } /* - * Safely parse the mount options in @data and update @opts. + * devpts_get_sb() * - * devpts ends up parsing options two times during mount, due to the - * two modes of operation it supports. The first parse occurs in - * devpts_get_sb() when determining the mode (single-instance or - * multi-instance mode). The second parse happens in devpts_remount() - * or new_pts_mount() depending on the mode. + * If the '-o newinstance' mount option was specified, mount a new + * (private) instance of devpts. PTYs created in this instance are + * independent of the PTYs in other devpts instances. * - * Parsing of options modifies the @data making subsequent parsing - * incorrect. So make a local copy of @data and parse it. + * If the '-o newinstance' option was not specified, mount/remount the + * initial kernel mount of devpts. This type of mount gives the + * legacy, single-instance semantics. * - * Return: 0 On success, -errno on error - */ -static int safe_parse_mount_options(void *data, struct pts_mount_opts *opts) -{ - int rc; - void *datacp; - - if (!data) - return 0; - - /* Use kstrdup() ? */ - datacp = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!datacp) - return -ENOMEM; - - memcpy(datacp, data, PAGE_SIZE); - rc = parse_mount_options((char *)datacp, PARSE_MOUNT, opts); - kfree(datacp); - - return rc; -} - -/* - * Mount a new (private) instance of devpts. PTYs created in this - * instance are independent of the PTYs in other devpts instances. - */ -static int new_pts_mount(struct file_system_type *fs_type, int flags, - void *data, struct vfsmount *mnt) -{ - int err; - struct pts_fs_info *fsi; - struct pts_mount_opts *opts; - - err = get_sb_nodev(fs_type, flags, data, devpts_fill_super, mnt); - if (err) - return err; - - fsi = DEVPTS_SB(mnt->mnt_sb); - opts = &fsi->mount_opts; - - err = parse_mount_options(data, PARSE_MOUNT, opts); - if (err) - goto fail; - - err = mknod_ptmx(mnt->mnt_sb); - if (err) - goto fail; - - return 0; - -fail: - dput(mnt->mnt_sb->s_root); - deactivate_super(mnt->mnt_sb); - return err; -} - -/* - * Check if 'newinstance' mount option was specified in @data. + * The 'newinstance' option is needed to support multiple namespace + * semantics in devpts while preserving backward compatibility of the + * current 'single-namespace' semantics. i.e all mounts of devpts + * without the 'newinstance' mount option should bind to the initial + * kernel mount, like get_sb_single(). * - * Return: -errno on error (eg: invalid mount options specified) - * : 1 if 'newinstance' mount option was specified - * : 0 if 'newinstance' mount option was NOT specified - */ -static int is_new_instance_mount(void *data) -{ - int rc; - struct pts_mount_opts opts; - - if (!data) - return 0; - - rc = safe_parse_mount_options(data, &opts); - if (!rc) - rc = opts.newinstance; - - return rc; -} - -/* - * get_init_pts_sb() - * - * This interface is needed to support multiple namespace semantics in - * devpts while preserving backward compatibility of the current 'single- - * namespace' semantics. i.e all mounts of devpts without the 'newinstance' - * mount option should bind to the initial kernel mount, like - * get_sb_single(). + * Mounts with 'newinstance' option create a new, private namespace. * - * Mounts with 'newinstance' option create a new private namespace. + * NOTE: * - * But for single-mount semantics, devpts cannot use get_sb_single(), + * For single-mount semantics, devpts cannot use get_sb_single(), * because get_sb_single()/sget() find and use the super-block from * the most recent mount of devpts. But that recent mount may be a * 'newinstance' mount and get_sb_single() would pick the newinstance * super-block instead of the initial super-block. - * - * This interface is identical to get_sb_single() except that it - * consistently selects the 'single-namespace' superblock even in the - * presence of the private namespace (i.e 'newinstance') super-blocks. */ -static int get_init_pts_sb(struct file_system_type *fs_type, int flags, - void *data, struct vfsmount *mnt) +static int devpts_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - struct super_block *s; int error; + struct pts_mount_opts opts; + struct super_block *s; + + memset(&opts, 0, sizeof(opts)); + if (data) { + error = parse_mount_options(data, PARSE_MOUNT, &opts); + if (error) + return error; + } + + if (opts.newinstance) + s = sget(fs_type, NULL, set_anon_super, NULL); + else + s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL); - s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL); if (IS_ERR(s)) return PTR_ERR(s); if (!s->s_root) { s->s_flags = flags; error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0); - if (error) { - up_write(&s->s_umount); - deactivate_super(s); - return error; - } + if (error) + goto out_undo_sget; s->s_flags |= MS_ACTIVE; } - do_remount_sb(s, flags, data, 0); - return simple_set_mnt(mnt, s); -} -/* - * Mount or remount the initial kernel mount of devpts. This type of - * mount maintains the legacy, single-instance semantics, while the - * kernel still allows multiple-instances. - */ -static int init_pts_mount(struct file_system_type *fs_type, int flags, - void *data, struct vfsmount *mnt) -{ - int err; + simple_set_mnt(mnt, s); - err = get_init_pts_sb(fs_type, flags, data, mnt); - if (err) - return err; + memcpy(&(DEVPTS_SB(s))->mount_opts, &opts, sizeof(opts)); - err = mknod_ptmx(mnt->mnt_sb); - if (err) { - dput(mnt->mnt_sb->s_root); - deactivate_super(mnt->mnt_sb); - } + error = mknod_ptmx(s); + if (error) + goto out_dput; - return err; -} - -static int devpts_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) -{ - int new; - - new = is_new_instance_mount(data); - if (new < 0) - return new; + return 0; - if (new) - return new_pts_mount(fs_type, flags, data, mnt); +out_dput: + dput(s->s_root); - return init_pts_mount(fs_type, flags, data, mnt); +out_undo_sget: + up_write(&s->s_umount); + deactivate_super(s); + return error; } + #else /* * This supports only the legacy single-instance semantics (no diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c index 92969f879a1..858fba14aaa 100644 --- a/fs/dlm/dir.c +++ b/fs/dlm/dir.c @@ -156,7 +156,7 @@ void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen bucket = dir_hash(ls, name, namelen); - write_lock(&ls->ls_dirtbl[bucket].lock); + spin_lock(&ls->ls_dirtbl[bucket].lock); de = search_bucket(ls, name, namelen, bucket); @@ -173,7 +173,7 @@ void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen list_del(&de->list); kfree(de); out: - write_unlock(&ls->ls_dirtbl[bucket].lock); + spin_unlock(&ls->ls_dirtbl[bucket].lock); } void dlm_dir_clear(struct dlm_ls *ls) @@ -185,14 +185,14 @@ void dlm_dir_clear(struct dlm_ls *ls) DLM_ASSERT(list_empty(&ls->ls_recover_list), ); for (i = 0; i < ls->ls_dirtbl_size; i++) { - write_lock(&ls->ls_dirtbl[i].lock); + spin_lock(&ls->ls_dirtbl[i].lock); head = &ls->ls_dirtbl[i].list; while (!list_empty(head)) { de = list_entry(head->next, struct dlm_direntry, list); list_del(&de->list); put_free_de(ls, de); } - write_unlock(&ls->ls_dirtbl[i].lock); + spin_unlock(&ls->ls_dirtbl[i].lock); } } @@ -307,17 +307,17 @@ static int get_entry(struct dlm_ls *ls, int nodeid, char *name, bucket = dir_hash(ls, name, namelen); - write_lock(&ls->ls_dirtbl[bucket].lock); + spin_lock(&ls->ls_dirtbl[bucket].lock); de = search_bucket(ls, name, namelen, bucket); if (de) { *r_nodeid = de->master_nodeid; - write_unlock(&ls->ls_dirtbl[bucket].lock); + spin_unlock(&ls->ls_dirtbl[bucket].lock); if (*r_nodeid == nodeid) return -EEXIST; return 0; } - write_unlock(&ls->ls_dirtbl[bucket].lock); + spin_unlock(&ls->ls_dirtbl[bucket].lock); if (namelen > DLM_RESNAME_MAXLEN) return -EINVAL; @@ -330,7 +330,7 @@ static int get_entry(struct dlm_ls *ls, int nodeid, char *name, de->length = namelen; memcpy(de->name, name, namelen); - write_lock(&ls->ls_dirtbl[bucket].lock); + spin_lock(&ls->ls_dirtbl[bucket].lock); tmp = search_bucket(ls, name, namelen, bucket); if (tmp) { kfree(de); @@ -339,7 +339,7 @@ static int get_entry(struct dlm_ls *ls, int nodeid, char *name, list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list); } *r_nodeid = de->master_nodeid; - write_unlock(&ls->ls_dirtbl[bucket].lock); + spin_unlock(&ls->ls_dirtbl[bucket].lock); return 0; } diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 076e86f38bc..d01ca0a711d 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -99,7 +99,7 @@ struct dlm_direntry { struct dlm_dirtable { struct list_head list; - rwlock_t lock; + spinlock_t lock; }; struct dlm_rsbtable { diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 01e7d39c5fb..205ec95b347 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -835,7 +835,7 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype) lkb->lkb_wait_count++; hold_lkb(lkb); - log_debug(ls, "add overlap %x cur %d new %d count %d flags %x", + log_debug(ls, "addwait %x cur %d overlap %d count %d f %x", lkb->lkb_id, lkb->lkb_wait_type, mstype, lkb->lkb_wait_count, lkb->lkb_flags); goto out; @@ -851,7 +851,7 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype) list_add(&lkb->lkb_wait_reply, &ls->ls_waiters); out: if (error) - log_error(ls, "add_to_waiters %x error %d flags %x %d %d %s", + log_error(ls, "addwait error %x %d flags %x %d %d %s", lkb->lkb_id, error, lkb->lkb_flags, mstype, lkb->lkb_wait_type, lkb->lkb_resource->res_name); mutex_unlock(&ls->ls_waiters_mutex); @@ -863,23 +863,55 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype) request reply on the requestqueue) between dlm_recover_waiters_pre() which set RESEND and dlm_recover_waiters_post() */ -static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype) +static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype, + struct dlm_message *ms) { struct dlm_ls *ls = lkb->lkb_resource->res_ls; int overlap_done = 0; if (is_overlap_unlock(lkb) && (mstype == DLM_MSG_UNLOCK_REPLY)) { + log_debug(ls, "remwait %x unlock_reply overlap", lkb->lkb_id); lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK; overlap_done = 1; goto out_del; } if (is_overlap_cancel(lkb) && (mstype == DLM_MSG_CANCEL_REPLY)) { + log_debug(ls, "remwait %x cancel_reply overlap", lkb->lkb_id); lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL; overlap_done = 1; goto out_del; } + /* Cancel state was preemptively cleared by a successful convert, + see next comment, nothing to do. */ + + if ((mstype == DLM_MSG_CANCEL_REPLY) && + (lkb->lkb_wait_type != DLM_MSG_CANCEL)) { + log_debug(ls, "remwait %x cancel_reply wait_type %d", + lkb->lkb_id, lkb->lkb_wait_type); + return -1; + } + + /* Remove for the convert reply, and premptively remove for the + cancel reply. A convert has been granted while there's still + an outstanding cancel on it (the cancel is moot and the result + in the cancel reply should be 0). We preempt the cancel reply + because the app gets the convert result and then can follow up + with another op, like convert. This subsequent op would see the + lingering state of the cancel and fail with -EBUSY. */ + + if ((mstype == DLM_MSG_CONVERT_REPLY) && + (lkb->lkb_wait_type == DLM_MSG_CONVERT) && + is_overlap_cancel(lkb) && ms && !ms->m_result) { + log_debug(ls, "remwait %x convert_reply zap overlap_cancel", + lkb->lkb_id); + lkb->lkb_wait_type = 0; + lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL; + lkb->lkb_wait_count--; + goto out_del; + } + /* N.B. type of reply may not always correspond to type of original msg due to lookup->request optimization, verify others? */ @@ -888,8 +920,8 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype) goto out_del; } - log_error(ls, "remove_from_waiters lkid %x flags %x types %d %d", - lkb->lkb_id, lkb->lkb_flags, mstype, lkb->lkb_wait_type); + log_error(ls, "remwait error %x reply %d flags %x no wait_type", + lkb->lkb_id, mstype, lkb->lkb_flags); return -1; out_del: @@ -899,7 +931,7 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype) this would happen */ if (overlap_done && lkb->lkb_wait_type) { - log_error(ls, "remove_from_waiters %x reply %d give up on %d", + log_error(ls, "remwait error %x reply %d wait_type %d overlap", lkb->lkb_id, mstype, lkb->lkb_wait_type); lkb->lkb_wait_count--; lkb->lkb_wait_type = 0; @@ -921,7 +953,7 @@ static int remove_from_waiters(struct dlm_lkb *lkb, int mstype) int error; mutex_lock(&ls->ls_waiters_mutex); - error = _remove_from_waiters(lkb, mstype); + error = _remove_from_waiters(lkb, mstype, NULL); mutex_unlock(&ls->ls_waiters_mutex); return error; } @@ -936,7 +968,7 @@ static int remove_from_waiters_ms(struct dlm_lkb *lkb, struct dlm_message *ms) if (ms != &ls->ls_stub_ms) mutex_lock(&ls->ls_waiters_mutex); - error = _remove_from_waiters(lkb, ms->m_type); + error = _remove_from_waiters(lkb, ms->m_type, ms); if (ms != &ls->ls_stub_ms) mutex_unlock(&ls->ls_waiters_mutex); return error; @@ -2083,6 +2115,11 @@ static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, lkb->lkb_timeout_cs = args->timeout; rv = 0; out: + if (rv) + log_debug(ls, "validate_lock_args %d %x %x %x %d %d %s", + rv, lkb->lkb_id, lkb->lkb_flags, args->flags, + lkb->lkb_status, lkb->lkb_wait_type, + lkb->lkb_resource->res_name); return rv; } @@ -2149,6 +2186,13 @@ static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args) goto out; } + /* there's nothing to cancel */ + if (lkb->lkb_status == DLM_LKSTS_GRANTED && + !lkb->lkb_wait_type) { + rv = -EBUSY; + goto out; + } + switch (lkb->lkb_wait_type) { case DLM_MSG_LOOKUP: case DLM_MSG_REQUEST: diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index aa32e5f0249..cd8e2df3c29 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -487,7 +487,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, goto out_lkbfree; for (i = 0; i < size; i++) { INIT_LIST_HEAD(&ls->ls_dirtbl[i].list); - rwlock_init(&ls->ls_dirtbl[i].lock); + spin_lock_init(&ls->ls_dirtbl[i].lock); } INIT_LIST_HEAD(&ls->ls_waiters); diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 103a5ebd137..609108a8326 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. +** Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -21,7 +21,7 @@ * * Cluster nodes are referred to by their nodeids. nodeids are * simply 32 bit numbers to the locking module - if they need to - * be expanded for the cluster infrastructure then that is it's + * be expanded for the cluster infrastructure then that is its * responsibility. It is this layer's * responsibility to resolve these into IP address or * whatever it needs for inter-node communication. @@ -36,9 +36,9 @@ * of high load. Also, this way, the sending thread can collect together * messages bound for one node and send them in one block. * - * lowcomms will choose to use wither TCP or SCTP as its transport layer + * lowcomms will choose to use either TCP or SCTP as its transport layer * depending on the configuration variable 'protocol'. This should be set - * to 0 (default) for TCP or 1 for SCTP. It shouldbe configured using a + * to 0 (default) for TCP or 1 for SCTP. It should be configured using a * cluster-wide mechanism as it must be the same on all nodes of the cluster * for the DLM to function. * @@ -48,11 +48,11 @@ #include <net/sock.h> #include <net/tcp.h> #include <linux/pagemap.h> -#include <linux/idr.h> #include <linux/file.h> #include <linux/mutex.h> #include <linux/sctp.h> #include <net/sctp/user.h> +#include <net/ipv6.h> #include "dlm_internal.h" #include "lowcomms.h" @@ -60,6 +60,7 @@ #include "config.h" #define NEEDED_RMEM (4*1024*1024) +#define CONN_HASH_SIZE 32 struct cbuf { unsigned int base; @@ -114,6 +115,7 @@ struct connection { int retries; #define MAX_CONNECT_RETRIES 3 int sctp_assoc; + struct hlist_node list; struct connection *othercon; struct work_struct rwork; /* Receive workqueue */ struct work_struct swork; /* Send workqueue */ @@ -138,14 +140,37 @@ static int dlm_local_count; static struct workqueue_struct *recv_workqueue; static struct workqueue_struct *send_workqueue; -static DEFINE_IDR(connections_idr); +static struct hlist_head connection_hash[CONN_HASH_SIZE]; static DEFINE_MUTEX(connections_lock); -static int max_nodeid; static struct kmem_cache *con_cache; static void process_recv_sockets(struct work_struct *work); static void process_send_sockets(struct work_struct *work); + +/* This is deliberately very simple because most clusters have simple + sequential nodeids, so we should be able to go straight to a connection + struct in the array */ +static inline int nodeid_hash(int nodeid) +{ + return nodeid & (CONN_HASH_SIZE-1); +} + +static struct connection *__find_con(int nodeid) +{ + int r; + struct hlist_node *h; + struct connection *con; + + r = nodeid_hash(nodeid); + + hlist_for_each_entry(con, h, &connection_hash[r], list) { + if (con->nodeid == nodeid) + return con; + } + return NULL; +} + /* * If 'allocation' is zero then we don't attempt to create a new * connection structure for this node. @@ -154,31 +179,17 @@ static struct connection *__nodeid2con(int nodeid, gfp_t alloc) { struct connection *con = NULL; int r; - int n; - con = idr_find(&connections_idr, nodeid); + con = __find_con(nodeid); if (con || !alloc) return con; - r = idr_pre_get(&connections_idr, alloc); - if (!r) - return NULL; - con = kmem_cache_zalloc(con_cache, alloc); if (!con) return NULL; - r = idr_get_new_above(&connections_idr, con, nodeid, &n); - if (r) { - kmem_cache_free(con_cache, con); - return NULL; - } - - if (n != nodeid) { - idr_remove(&connections_idr, n); - kmem_cache_free(con_cache, con); - return NULL; - } + r = nodeid_hash(nodeid); + hlist_add_head(&con->list, &connection_hash[r]); con->nodeid = nodeid; mutex_init(&con->sock_mutex); @@ -189,19 +200,30 @@ static struct connection *__nodeid2con(int nodeid, gfp_t alloc) /* Setup action pointers for child sockets */ if (con->nodeid) { - struct connection *zerocon = idr_find(&connections_idr, 0); + struct connection *zerocon = __find_con(0); con->connect_action = zerocon->connect_action; if (!con->rx_action) con->rx_action = zerocon->rx_action; } - if (nodeid > max_nodeid) - max_nodeid = nodeid; - return con; } +/* Loop round all connections */ +static void foreach_conn(void (*conn_func)(struct connection *c)) +{ + int i; + struct hlist_node *h, *n; + struct connection *con; + + for (i = 0; i < CONN_HASH_SIZE; i++) { + hlist_for_each_entry_safe(con, h, n, &connection_hash[i], list){ + conn_func(con); + } + } +} + static struct connection *nodeid2con(int nodeid, gfp_t allocation) { struct connection *con; @@ -217,14 +239,17 @@ static struct connection *nodeid2con(int nodeid, gfp_t allocation) static struct connection *assoc2con(int assoc_id) { int i; + struct hlist_node *h; struct connection *con; mutex_lock(&connections_lock); - for (i=0; i<=max_nodeid; i++) { - con = __nodeid2con(i, 0); - if (con && con->sctp_assoc == assoc_id) { - mutex_unlock(&connections_lock); - return con; + + for (i = 0 ; i < CONN_HASH_SIZE; i++) { + hlist_for_each_entry(con, h, &connection_hash[i], list) { + if (con && con->sctp_assoc == assoc_id) { + mutex_unlock(&connections_lock); + return con; + } } } mutex_unlock(&connections_lock); @@ -250,8 +275,7 @@ static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr) } else { struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &addr; struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr; - memcpy(&ret6->sin6_addr, &in6->sin6_addr, - sizeof(in6->sin6_addr)); + ipv6_addr_copy(&ret6->sin6_addr, &in6->sin6_addr); } return 0; @@ -376,25 +400,23 @@ static void sctp_send_shutdown(sctp_assoc_t associd) log_print("send EOF to node failed: %d", ret); } +static void sctp_init_failed_foreach(struct connection *con) +{ + con->sctp_assoc = 0; + if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) { + if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) + queue_work(send_workqueue, &con->swork); + } +} + /* INIT failed but we don't know which node... restart INIT on all pending nodes */ static void sctp_init_failed(void) { - int i; - struct connection *con; - mutex_lock(&connections_lock); - for (i=1; i<=max_nodeid; i++) { - con = __nodeid2con(i, 0); - if (!con) - continue; - con->sctp_assoc = 0; - if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) { - if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) { - queue_work(send_workqueue, &con->swork); - } - } - } + + foreach_conn(sctp_init_failed_foreach); + mutex_unlock(&connections_lock); } @@ -1313,13 +1335,10 @@ out_connect: static void clean_one_writequeue(struct connection *con) { - struct list_head *list; - struct list_head *temp; + struct writequeue_entry *e, *safe; spin_lock(&con->writequeue_lock); - list_for_each_safe(list, temp, &con->writequeue) { - struct writequeue_entry *e = - list_entry(list, struct writequeue_entry, list); + list_for_each_entry_safe(e, safe, &con->writequeue, list) { list_del(&e->list); free_entry(e); } @@ -1369,14 +1388,7 @@ static void process_send_sockets(struct work_struct *work) /* Discard all entries on the write queues */ static void clean_writequeues(void) { - int nodeid; - - for (nodeid = 1; nodeid <= max_nodeid; nodeid++) { - struct connection *con = __nodeid2con(nodeid, 0); - - if (con) - clean_one_writequeue(con); - } + foreach_conn(clean_one_writequeue); } static void work_stop(void) @@ -1406,23 +1418,29 @@ static int work_start(void) return 0; } -void dlm_lowcomms_stop(void) +static void stop_conn(struct connection *con) { - int i; - struct connection *con; + con->flags |= 0x0F; + if (con->sock) + con->sock->sk->sk_user_data = NULL; +} +static void free_conn(struct connection *con) +{ + close_connection(con, true); + if (con->othercon) + kmem_cache_free(con_cache, con->othercon); + hlist_del(&con->list); + kmem_cache_free(con_cache, con); +} + +void dlm_lowcomms_stop(void) +{ /* Set all the flags to prevent any socket activity. */ mutex_lock(&connections_lock); - for (i = 0; i <= max_nodeid; i++) { - con = __nodeid2con(i, 0); - if (con) { - con->flags |= 0x0F; - if (con->sock) - con->sock->sk->sk_user_data = NULL; - } - } + foreach_conn(stop_conn); mutex_unlock(&connections_lock); work_stop(); @@ -1430,25 +1448,20 @@ void dlm_lowcomms_stop(void) mutex_lock(&connections_lock); clean_writequeues(); - for (i = 0; i <= max_nodeid; i++) { - con = __nodeid2con(i, 0); - if (con) { - close_connection(con, true); - if (con->othercon) - kmem_cache_free(con_cache, con->othercon); - kmem_cache_free(con_cache, con); - } - } - max_nodeid = 0; + foreach_conn(free_conn); + mutex_unlock(&connections_lock); kmem_cache_destroy(con_cache); - idr_init(&connections_idr); } int dlm_lowcomms_start(void) { int error = -EINVAL; struct connection *con; + int i; + + for (i = 0; i < CONN_HASH_SIZE; i++) + INIT_HLIST_HEAD(&connection_hash[i]); init_local(); if (!dlm_local_count) { diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 065149e84f4..ebce994ab0b 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. + * Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -84,7 +84,7 @@ struct dlm_lock_result32 { static void compat_input(struct dlm_write_request *kb, struct dlm_write_request32 *kb32, - size_t count) + int namelen) { kb->version[0] = kb32->version[0]; kb->version[1] = kb32->version[1]; @@ -96,8 +96,7 @@ static void compat_input(struct dlm_write_request *kb, kb->cmd == DLM_USER_REMOVE_LOCKSPACE) { kb->i.lspace.flags = kb32->i.lspace.flags; kb->i.lspace.minor = kb32->i.lspace.minor; - memcpy(kb->i.lspace.name, kb32->i.lspace.name, count - - offsetof(struct dlm_write_request32, i.lspace.name)); + memcpy(kb->i.lspace.name, kb32->i.lspace.name, namelen); } else if (kb->cmd == DLM_USER_PURGE) { kb->i.purge.nodeid = kb32->i.purge.nodeid; kb->i.purge.pid = kb32->i.purge.pid; @@ -115,8 +114,7 @@ static void compat_input(struct dlm_write_request *kb, kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr; kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb; memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN); - memcpy(kb->i.lock.name, kb32->i.lock.name, count - - offsetof(struct dlm_write_request32, i.lock.name)); + memcpy(kb->i.lock.name, kb32->i.lock.name, namelen); } } @@ -539,9 +537,16 @@ static ssize_t device_write(struct file *file, const char __user *buf, #ifdef CONFIG_COMPAT if (!kbuf->is64bit) { struct dlm_write_request32 *k32buf; + int namelen = 0; + + if (count > sizeof(struct dlm_write_request32)) + namelen = count - sizeof(struct dlm_write_request32); + k32buf = (struct dlm_write_request32 *)kbuf; - kbuf = kmalloc(count + 1 + (sizeof(struct dlm_write_request) - - sizeof(struct dlm_write_request32)), GFP_KERNEL); + + /* add 1 after namelen so that the name string is terminated */ + kbuf = kzalloc(sizeof(struct dlm_write_request) + namelen + 1, + GFP_KERNEL); if (!kbuf) { kfree(k32buf); return -ENOMEM; @@ -549,7 +554,8 @@ static ssize_t device_write(struct file *file, const char __user *buf, if (proc) set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags); - compat_input(kbuf, k32buf, count + 1); + + compat_input(kbuf, k32buf, namelen); kfree(k32buf); } #endif diff --git a/fs/drop_caches.c b/fs/drop_caches.c index 3e5637fc377..44d725f612c 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c @@ -18,7 +18,7 @@ static void drop_pagecache_sb(struct super_block *sb) spin_lock(&inode_lock); list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { - if (inode->i_state & (I_FREEING|I_WILL_FREE)) + if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) continue; if (inode->i_mapping->nrpages == 0) continue; diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index f6caeb1d110..8b65f289ee0 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -946,6 +946,8 @@ static int ecryptfs_copy_mount_wide_sigs_to_inode_sigs( list_for_each_entry(global_auth_tok, &mount_crypt_stat->global_auth_tok_list, mount_crypt_stat_list) { + if (global_auth_tok->flags & ECRYPTFS_AUTH_TOK_FNEK) + continue; rc = ecryptfs_add_keysig(crypt_stat, global_auth_tok->sig); if (rc) { printk(KERN_ERR "Error adding keysig; rc = [%d]\n", rc); @@ -1322,14 +1324,13 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t max, } static int -ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat, - struct dentry *ecryptfs_dentry, - char *virt) +ecryptfs_write_metadata_to_contents(struct dentry *ecryptfs_dentry, + char *virt, size_t virt_len) { int rc; rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt, - 0, crypt_stat->num_header_bytes_at_front); + 0, virt_len); if (rc) printk(KERN_ERR "%s: Error attempting to write header " "information to lower file; rc = [%d]\n", __func__, @@ -1339,7 +1340,6 @@ ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat, static int ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, - struct ecryptfs_crypt_stat *crypt_stat, char *page_virt, size_t size) { int rc; @@ -1349,6 +1349,17 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, return rc; } +static unsigned long ecryptfs_get_zeroed_pages(gfp_t gfp_mask, + unsigned int order) +{ + struct page *page; + + page = alloc_pages(gfp_mask | __GFP_ZERO, order); + if (page) + return (unsigned long) page_address(page); + return 0; +} + /** * ecryptfs_write_metadata * @ecryptfs_dentry: The eCryptfs dentry @@ -1365,7 +1376,9 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; + unsigned int order; char *virt; + size_t virt_len; size_t size = 0; int rc = 0; @@ -1381,33 +1394,35 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) rc = -EINVAL; goto out; } + virt_len = crypt_stat->num_header_bytes_at_front; + order = get_order(virt_len); /* Released in this function */ - virt = (char *)get_zeroed_page(GFP_KERNEL); + virt = (char *)ecryptfs_get_zeroed_pages(GFP_KERNEL, order); if (!virt) { printk(KERN_ERR "%s: Out of memory\n", __func__); rc = -ENOMEM; goto out; } - rc = ecryptfs_write_headers_virt(virt, PAGE_CACHE_SIZE, &size, - crypt_stat, ecryptfs_dentry); + rc = ecryptfs_write_headers_virt(virt, virt_len, &size, crypt_stat, + ecryptfs_dentry); if (unlikely(rc)) { printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n", __func__, rc); goto out_free; } if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) - rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, - crypt_stat, virt, size); + rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, virt, + size); else - rc = ecryptfs_write_metadata_to_contents(crypt_stat, - ecryptfs_dentry, virt); + rc = ecryptfs_write_metadata_to_contents(ecryptfs_dentry, virt, + virt_len); if (rc) { printk(KERN_ERR "%s: Error writing metadata out to lower file; " "rc = [%d]\n", __func__, rc); goto out_free; } out_free: - free_page((unsigned long)virt); + free_pages((unsigned long)virt, order); out: return rc; } @@ -2206,17 +2221,19 @@ int ecryptfs_decode_and_decrypt_filename(char **plaintext_name, struct dentry *ecryptfs_dir_dentry, const char *name, size_t name_size) { + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private( + ecryptfs_dir_dentry->d_sb)->mount_crypt_stat; char *decoded_name; size_t decoded_name_size; size_t packet_size; int rc = 0; - if ((name_size > ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) + if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) + && !(mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) + && (name_size > ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) && (strncmp(name, ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX, ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) == 0)) { - struct ecryptfs_mount_crypt_stat *mount_crypt_stat = - &ecryptfs_superblock_to_private( - ecryptfs_dir_dentry->d_sb)->mount_crypt_stat; const char *orig_name = name; size_t orig_name_size = name_size; diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c index 5e596583946..2dda5ade75b 100644 --- a/fs/ecryptfs/dentry.c +++ b/fs/ecryptfs/dentry.c @@ -89,7 +89,7 @@ static void ecryptfs_d_release(struct dentry *dentry) return; } -struct dentry_operations ecryptfs_dops = { +const struct dentry_operations ecryptfs_dops = { .d_revalidate = ecryptfs_d_revalidate, .d_release = ecryptfs_d_release, }; diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index c11fc95714a..064c5820e4e 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -328,6 +328,7 @@ struct ecryptfs_dentry_info { */ struct ecryptfs_global_auth_tok { #define ECRYPTFS_AUTH_TOK_INVALID 0x00000001 +#define ECRYPTFS_AUTH_TOK_FNEK 0x00000002 u32 flags; struct list_head mount_crypt_stat_list; struct key *global_auth_tok_key; @@ -579,7 +580,7 @@ extern const struct inode_operations ecryptfs_main_iops; extern const struct inode_operations ecryptfs_dir_iops; extern const struct inode_operations ecryptfs_symlink_iops; extern const struct super_operations ecryptfs_sops; -extern struct dentry_operations ecryptfs_dops; +extern const struct dentry_operations ecryptfs_dops; extern struct address_space_operations ecryptfs_aops; extern int ecryptfs_verbosity; extern unsigned int ecryptfs_message_buf_len; @@ -619,7 +620,6 @@ int ecryptfs_interpose(struct dentry *hidden_dentry, u32 flags); int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, struct dentry *lower_dentry, - struct ecryptfs_crypt_stat *crypt_stat, struct inode *ecryptfs_dir_inode, struct nameidata *ecryptfs_nd); int ecryptfs_decode_and_decrypt_filename(char **decrypted_name, @@ -696,7 +696,7 @@ ecryptfs_write_header_metadata(char *virt, int ecryptfs_add_keysig(struct ecryptfs_crypt_stat *crypt_stat, char *sig); int ecryptfs_add_global_auth_tok(struct ecryptfs_mount_crypt_stat *mount_crypt_stat, - char *sig); + char *sig, u32 global_auth_tok_flags); int ecryptfs_get_global_auth_tok_for_sig( struct ecryptfs_global_auth_tok **global_auth_tok, struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig); diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 5697899a168..55b3145b807 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -246,7 +246,6 @@ out: */ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, struct dentry *lower_dentry, - struct ecryptfs_crypt_stat *crypt_stat, struct inode *ecryptfs_dir_inode, struct nameidata *ecryptfs_nd) { @@ -254,6 +253,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, struct vfsmount *lower_mnt; struct inode *lower_inode; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; + struct ecryptfs_crypt_stat *crypt_stat; char *page_virt = NULL; u64 file_size; int rc = 0; @@ -314,6 +314,11 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, goto out_free_kmem; } } + crypt_stat = &ecryptfs_inode_to_private( + ecryptfs_dentry->d_inode)->crypt_stat; + /* TODO: lock for crypt_stat comparison */ + if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) + ecryptfs_set_default_sizes(crypt_stat); rc = ecryptfs_read_and_validate_header_region(page_virt, ecryptfs_dentry->d_inode); if (rc) { @@ -362,9 +367,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, { char *encrypted_and_encoded_name = NULL; size_t encrypted_and_encoded_name_size; - struct ecryptfs_crypt_stat *crypt_stat = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; - struct ecryptfs_inode_info *inode_info; struct dentry *lower_dir_dentry, *lower_dentry; int rc = 0; @@ -388,26 +391,15 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, } if (lower_dentry->d_inode) goto lookup_and_interpose; - inode_info = ecryptfs_inode_to_private(ecryptfs_dentry->d_inode); - if (inode_info) { - crypt_stat = &inode_info->crypt_stat; - /* TODO: lock for crypt_stat comparison */ - if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) - ecryptfs_set_default_sizes(crypt_stat); - } - if (crypt_stat) - mount_crypt_stat = crypt_stat->mount_crypt_stat; - else - mount_crypt_stat = &ecryptfs_superblock_to_private( - ecryptfs_dentry->d_sb)->mount_crypt_stat; - if (!(crypt_stat && (crypt_stat->flags & ECRYPTFS_ENCRYPT_FILENAMES)) - && !(mount_crypt_stat && (mount_crypt_stat->flags - & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES))) + mount_crypt_stat = &ecryptfs_superblock_to_private( + ecryptfs_dentry->d_sb)->mount_crypt_stat; + if (!(mount_crypt_stat + && (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES))) goto lookup_and_interpose; dput(lower_dentry); rc = ecryptfs_encrypt_and_encode_filename( &encrypted_and_encoded_name, &encrypted_and_encoded_name_size, - crypt_stat, mount_crypt_stat, ecryptfs_dentry->d_name.name, + NULL, mount_crypt_stat, ecryptfs_dentry->d_name.name, ecryptfs_dentry->d_name.len); if (rc) { printk(KERN_ERR "%s: Error attempting to encrypt and encode " @@ -426,7 +418,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, } lookup_and_interpose: rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry, - crypt_stat, ecryptfs_dir_inode, + ecryptfs_dir_inode, ecryptfs_nd); goto out; out_d_drop: diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index ff539420cc6..af737bb56cb 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -740,8 +740,7 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, out_release_free_unlock: crypto_free_hash(s->hash_desc.tfm); out_free_unlock: - memset(s->block_aligned_filename, 0, s->block_aligned_filename_size); - kfree(s->block_aligned_filename); + kzfree(s->block_aligned_filename); out_unlock: mutex_unlock(s->tfm_mutex); out: @@ -2375,7 +2374,7 @@ struct kmem_cache *ecryptfs_global_auth_tok_cache; int ecryptfs_add_global_auth_tok(struct ecryptfs_mount_crypt_stat *mount_crypt_stat, - char *sig) + char *sig, u32 global_auth_tok_flags) { struct ecryptfs_global_auth_tok *new_auth_tok; int rc = 0; @@ -2389,6 +2388,7 @@ ecryptfs_add_global_auth_tok(struct ecryptfs_mount_crypt_stat *mount_crypt_stat, goto out; } memcpy(new_auth_tok->sig, sig, ECRYPTFS_SIG_SIZE_HEX); + new_auth_tok->flags = global_auth_tok_flags; new_auth_tok->sig[ECRYPTFS_SIG_SIZE_HEX] = '\0'; mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); list_add(&new_auth_tok->mount_crypt_stat_list, diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 789cf2e1be1..aed56c25539 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -319,7 +319,7 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) case ecryptfs_opt_ecryptfs_sig: sig_src = args[0].from; rc = ecryptfs_add_global_auth_tok(mount_crypt_stat, - sig_src); + sig_src, 0); if (rc) { printk(KERN_ERR "Error attempting to register " "global sig; rc = [%d]\n", rc); @@ -370,7 +370,8 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) ECRYPTFS_SIG_SIZE_HEX] = '\0'; rc = ecryptfs_add_global_auth_tok( mount_crypt_stat, - mount_crypt_stat->global_default_fnek_sig); + mount_crypt_stat->global_default_fnek_sig, + ECRYPTFS_AUTH_TOK_FNEK); if (rc) { printk(KERN_ERR "Error attempting to register " "global fnek sig [%s]; rc = [%d]\n", diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index 96ef51489e0..295e7fa5675 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c @@ -291,8 +291,7 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon) if (daemon->user_ns) put_user_ns(daemon->user_ns); mutex_unlock(&daemon->mux); - memset(daemon, 0, sizeof(*daemon)); - kfree(daemon); + kzfree(daemon); out: return rc; } diff --git a/fs/eventfd.c b/fs/eventfd.c index 5de2c2db3aa..2a701d593d3 100644 --- a/fs/eventfd.c +++ b/fs/eventfd.c @@ -28,6 +28,7 @@ struct eventfd_ctx { * issue a wakeup. */ __u64 count; + unsigned int flags; }; /* @@ -50,7 +51,7 @@ int eventfd_signal(struct file *file, int n) n = (int) (ULLONG_MAX - ctx->count); ctx->count += n; if (waitqueue_active(&ctx->wqh)) - wake_up_locked(&ctx->wqh); + wake_up_locked_poll(&ctx->wqh, POLLIN); spin_unlock_irqrestore(&ctx->wqh.lock, flags); return n; @@ -87,22 +88,20 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count, { struct eventfd_ctx *ctx = file->private_data; ssize_t res; - __u64 ucnt; + __u64 ucnt = 0; DECLARE_WAITQUEUE(wait, current); if (count < sizeof(ucnt)) return -EINVAL; spin_lock_irq(&ctx->wqh.lock); res = -EAGAIN; - ucnt = ctx->count; - if (ucnt > 0) + if (ctx->count > 0) res = sizeof(ucnt); else if (!(file->f_flags & O_NONBLOCK)) { __add_wait_queue(&ctx->wqh, &wait); for (res = 0;;) { set_current_state(TASK_INTERRUPTIBLE); if (ctx->count > 0) { - ucnt = ctx->count; res = sizeof(ucnt); break; } @@ -117,10 +116,11 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count, __remove_wait_queue(&ctx->wqh, &wait); __set_current_state(TASK_RUNNING); } - if (res > 0) { - ctx->count = 0; + if (likely(res > 0)) { + ucnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count; + ctx->count -= ucnt; if (waitqueue_active(&ctx->wqh)) - wake_up_locked(&ctx->wqh); + wake_up_locked_poll(&ctx->wqh, POLLOUT); } spin_unlock_irq(&ctx->wqh.lock); if (res > 0 && put_user(ucnt, (__u64 __user *) buf)) @@ -166,10 +166,10 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c __remove_wait_queue(&ctx->wqh, &wait); __set_current_state(TASK_RUNNING); } - if (res > 0) { + if (likely(res > 0)) { ctx->count += ucnt; if (waitqueue_active(&ctx->wqh)) - wake_up_locked(&ctx->wqh); + wake_up_locked_poll(&ctx->wqh, POLLIN); } spin_unlock_irq(&ctx->wqh.lock); @@ -207,7 +207,7 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC); BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK); - if (flags & ~(EFD_CLOEXEC | EFD_NONBLOCK)) + if (flags & ~EFD_FLAGS_SET) return -EINVAL; ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); @@ -216,13 +216,14 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) init_waitqueue_head(&ctx->wqh); ctx->count = count; + ctx->flags = flags; /* * When we call this, the initialization must be complete, since * anon_inode_getfd() will install the fd. */ fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx, - flags & (O_CLOEXEC | O_NONBLOCK)); + flags & EFD_SHARED_FCNTL_FLAGS); if (fd < 0) kfree(ctx); return fd; @@ -232,3 +233,4 @@ SYSCALL_DEFINE1(eventfd, unsigned int, count) { return sys_eventfd2(count, 0); } + diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 011b9b8c90c..a89f370fadb 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1,6 +1,6 @@ /* - * fs/eventpoll.c (Efficent event polling implementation) - * Copyright (C) 2001,...,2007 Davide Libenzi + * fs/eventpoll.c (Efficient event retrieval implementation) + * Copyright (C) 2001,...,2009 Davide Libenzi * * 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 @@ -71,29 +71,11 @@ * a better scalability. */ -#define DEBUG_EPOLL 0 - -#if DEBUG_EPOLL > 0 -#define DPRINTK(x) printk x -#define DNPRINTK(n, x) do { if ((n) <= DEBUG_EPOLL) printk x; } while (0) -#else /* #if DEBUG_EPOLL > 0 */ -#define DPRINTK(x) (void) 0 -#define DNPRINTK(n, x) (void) 0 -#endif /* #if DEBUG_EPOLL > 0 */ - -#define DEBUG_EPI 0 - -#if DEBUG_EPI != 0 -#define EPI_SLAB_DEBUG (SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */) -#else /* #if DEBUG_EPI != 0 */ -#define EPI_SLAB_DEBUG 0 -#endif /* #if DEBUG_EPI != 0 */ - /* Epoll private bits inside the event mask */ #define EP_PRIVATE_BITS (EPOLLONESHOT | EPOLLET) -/* Maximum number of poll wake up nests we are allowing */ -#define EP_MAX_POLLWAKE_NESTS 4 +/* Maximum number of nesting allowed inside epoll sets */ +#define EP_MAX_NESTS 4 /* Maximum msec timeout value storeable in a long int */ #define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ) @@ -110,24 +92,21 @@ struct epoll_filefd { }; /* - * Node that is linked into the "wake_task_list" member of the "struct poll_safewake". - * It is used to keep track on all tasks that are currently inside the wake_up() code - * to 1) short-circuit the one coming from the same task and same wait queue head - * (loop) 2) allow a maximum number of epoll descriptors inclusion nesting - * 3) let go the ones coming from other tasks. + * Structure used to track possible nested calls, for too deep recursions + * and loop cycles. */ -struct wake_task_node { +struct nested_call_node { struct list_head llink; - struct task_struct *task; - wait_queue_head_t *wq; + void *cookie; + int cpu; }; /* - * This is used to implement the safe poll wake up avoiding to reenter - * the poll callback from inside wake_up(). + * This structure is used as collector for nested calls, to check for + * maximum recursion dept and loop cycles. */ -struct poll_safewake { - struct list_head wake_task_list; +struct nested_calls { + struct list_head tasks_call_list; spinlock_t lock; }; @@ -213,7 +192,7 @@ struct eppoll_entry { struct list_head llink; /* The "base" pointer is set to the container "struct epitem" */ - void *base; + struct epitem *base; /* * Wait queue item that will be linked to the target file wait @@ -231,6 +210,12 @@ struct ep_pqueue { struct epitem *epi; }; +/* Used by the ep_send_events() function as callback private data */ +struct ep_send_events_data { + int maxevents; + struct epoll_event __user *events; +}; + /* * Configuration options available inside /proc/sys/fs/epoll/ */ @@ -242,8 +227,11 @@ static int max_user_watches __read_mostly; */ static DEFINE_MUTEX(epmutex); -/* Safe wake up implementation */ -static struct poll_safewake psw; +/* Used for safe wake up implementation */ +static struct nested_calls poll_safewake_ncalls; + +/* Used to call file's f_op->poll() under the nested calls boundaries */ +static struct nested_calls poll_readywalk_ncalls; /* Slab cache used to allocate "struct epitem" */ static struct kmem_cache *epi_cache __read_mostly; @@ -312,89 +300,230 @@ static inline int ep_op_has_event(int op) } /* Initialize the poll safe wake up structure */ -static void ep_poll_safewake_init(struct poll_safewake *psw) +static void ep_nested_calls_init(struct nested_calls *ncalls) { - - INIT_LIST_HEAD(&psw->wake_task_list); - spin_lock_init(&psw->lock); + INIT_LIST_HEAD(&ncalls->tasks_call_list); + spin_lock_init(&ncalls->lock); } -/* - * Perform a safe wake up of the poll wait list. The problem is that - * with the new callback'd wake up system, it is possible that the - * poll callback is reentered from inside the call to wake_up() done - * on the poll wait queue head. The rule is that we cannot reenter the - * wake up code from the same task more than EP_MAX_POLLWAKE_NESTS times, - * and we cannot reenter the same wait queue head at all. This will - * enable to have a hierarchy of epoll file descriptor of no more than - * EP_MAX_POLLWAKE_NESTS deep. We need the irq version of the spin lock - * because this one gets called by the poll callback, that in turn is called - * from inside a wake_up(), that might be called from irq context. +/** + * ep_call_nested - Perform a bound (possibly) nested call, by checking + * that the recursion limit is not exceeded, and that + * the same nested call (by the meaning of same cookie) is + * no re-entered. + * + * @ncalls: Pointer to the nested_calls structure to be used for this call. + * @max_nests: Maximum number of allowed nesting calls. + * @nproc: Nested call core function pointer. + * @priv: Opaque data to be passed to the @nproc callback. + * @cookie: Cookie to be used to identify this nested call. + * + * Returns: Returns the code returned by the @nproc callback, or -1 if + * the maximum recursion limit has been exceeded. */ -static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq) +static int ep_call_nested(struct nested_calls *ncalls, int max_nests, + int (*nproc)(void *, void *, int), void *priv, + void *cookie) { - int wake_nests = 0; + int error, call_nests = 0; unsigned long flags; - struct task_struct *this_task = current; - struct list_head *lsthead = &psw->wake_task_list; - struct wake_task_node *tncur; - struct wake_task_node tnode; + int this_cpu = get_cpu(); + struct list_head *lsthead = &ncalls->tasks_call_list; + struct nested_call_node *tncur; + struct nested_call_node tnode; - spin_lock_irqsave(&psw->lock, flags); + spin_lock_irqsave(&ncalls->lock, flags); - /* Try to see if the current task is already inside this wakeup call */ + /* + * Try to see if the current task is already inside this wakeup call. + * We use a list here, since the population inside this set is always + * very much limited. + */ list_for_each_entry(tncur, lsthead, llink) { - - if (tncur->wq == wq || - (tncur->task == this_task && ++wake_nests > EP_MAX_POLLWAKE_NESTS)) { + if (tncur->cpu == this_cpu && + (tncur->cookie == cookie || ++call_nests > max_nests)) { /* * Ops ... loop detected or maximum nest level reached. * We abort this wake by breaking the cycle itself. */ - spin_unlock_irqrestore(&psw->lock, flags); - return; + error = -1; + goto out_unlock; } } - /* Add the current task to the list */ - tnode.task = this_task; - tnode.wq = wq; + /* Add the current task and cookie to the list */ + tnode.cpu = this_cpu; + tnode.cookie = cookie; list_add(&tnode.llink, lsthead); - spin_unlock_irqrestore(&psw->lock, flags); + spin_unlock_irqrestore(&ncalls->lock, flags); - /* Do really wake up now */ - wake_up_nested(wq, 1 + wake_nests); + /* Call the nested function */ + error = (*nproc)(priv, cookie, call_nests); /* Remove the current task from the list */ - spin_lock_irqsave(&psw->lock, flags); + spin_lock_irqsave(&ncalls->lock, flags); list_del(&tnode.llink); - spin_unlock_irqrestore(&psw->lock, flags); + out_unlock: + spin_unlock_irqrestore(&ncalls->lock, flags); + + put_cpu(); + return error; +} + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +static inline void ep_wake_up_nested(wait_queue_head_t *wqueue, + unsigned long events, int subclass) +{ + unsigned long flags; + + spin_lock_irqsave_nested(&wqueue->lock, flags, subclass); + wake_up_locked_poll(wqueue, events); + spin_unlock_irqrestore(&wqueue->lock, flags); +} +#else +static inline void ep_wake_up_nested(wait_queue_head_t *wqueue, + unsigned long events, int subclass) +{ + wake_up_poll(wqueue, events); +} +#endif + +static int ep_poll_wakeup_proc(void *priv, void *cookie, int call_nests) +{ + ep_wake_up_nested((wait_queue_head_t *) cookie, POLLIN, + 1 + call_nests); + return 0; +} + +/* + * Perform a safe wake up of the poll wait list. The problem is that + * with the new callback'd wake up system, it is possible that the + * poll callback is reentered from inside the call to wake_up() done + * on the poll wait queue head. The rule is that we cannot reenter the + * wake up code from the same task more than EP_MAX_NESTS times, + * and we cannot reenter the same wait queue head at all. This will + * enable to have a hierarchy of epoll file descriptor of no more than + * EP_MAX_NESTS deep. + */ +static void ep_poll_safewake(wait_queue_head_t *wq) +{ + ep_call_nested(&poll_safewake_ncalls, EP_MAX_NESTS, + ep_poll_wakeup_proc, NULL, wq); } /* - * This function unregister poll callbacks from the associated file descriptor. - * Since this must be called without holding "ep->lock" the atomic exchange trick - * will protect us from multiple unregister. + * This function unregisters poll callbacks from the associated file + * descriptor. Must be called with "mtx" held (or "epmutex" if called from + * ep_free). */ static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi) { - int nwait; struct list_head *lsthead = &epi->pwqlist; struct eppoll_entry *pwq; - /* This is called without locks, so we need the atomic exchange */ - nwait = xchg(&epi->nwait, 0); + while (!list_empty(lsthead)) { + pwq = list_first_entry(lsthead, struct eppoll_entry, llink); - if (nwait) { - while (!list_empty(lsthead)) { - pwq = list_first_entry(lsthead, struct eppoll_entry, llink); + list_del(&pwq->llink); + remove_wait_queue(pwq->whead, &pwq->wait); + kmem_cache_free(pwq_cache, pwq); + } +} - list_del_init(&pwq->llink); - remove_wait_queue(pwq->whead, &pwq->wait); - kmem_cache_free(pwq_cache, pwq); - } +/** + * ep_scan_ready_list - Scans the ready list in a way that makes possible for + * the scan code, to call f_op->poll(). Also allows for + * O(NumReady) performance. + * + * @ep: Pointer to the epoll private data structure. + * @sproc: Pointer to the scan callback. + * @priv: Private opaque data passed to the @sproc callback. + * + * Returns: The same integer error code returned by the @sproc callback. + */ +static int ep_scan_ready_list(struct eventpoll *ep, + int (*sproc)(struct eventpoll *, + struct list_head *, void *), + void *priv) +{ + int error, pwake = 0; + unsigned long flags; + struct epitem *epi, *nepi; + LIST_HEAD(txlist); + + /* + * We need to lock this because we could be hit by + * eventpoll_release_file() and epoll_ctl(). + */ + mutex_lock(&ep->mtx); + + /* + * Steal the ready list, and re-init the original one to the + * empty list. Also, set ep->ovflist to NULL so that events + * happening while looping w/out locks, are not lost. We cannot + * have the poll callback to queue directly on ep->rdllist, + * because we want the "sproc" callback to be able to do it + * in a lockless way. + */ + spin_lock_irqsave(&ep->lock, flags); + list_splice_init(&ep->rdllist, &txlist); + ep->ovflist = NULL; + spin_unlock_irqrestore(&ep->lock, flags); + + /* + * Now call the callback function. + */ + error = (*sproc)(ep, &txlist, priv); + + spin_lock_irqsave(&ep->lock, flags); + /* + * During the time we spent inside the "sproc" callback, some + * other events might have been queued by the poll callback. + * We re-insert them inside the main ready-list here. + */ + for (nepi = ep->ovflist; (epi = nepi) != NULL; + nepi = epi->next, epi->next = EP_UNACTIVE_PTR) { + /* + * We need to check if the item is already in the list. + * During the "sproc" callback execution time, items are + * queued into ->ovflist but the "txlist" might already + * contain them, and the list_splice() below takes care of them. + */ + if (!ep_is_linked(&epi->rdllink)) + list_add_tail(&epi->rdllink, &ep->rdllist); + } + /* + * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after + * releasing the lock, events will be queued in the normal way inside + * ep->rdllist. + */ + ep->ovflist = EP_UNACTIVE_PTR; + + /* + * Quickly re-inject items left on "txlist". + */ + list_splice(&txlist, &ep->rdllist); + + if (!list_empty(&ep->rdllist)) { + /* + * Wake up (if active) both the eventpoll wait list and + * the ->poll() wait list (delayed after we release the lock). + */ + if (waitqueue_active(&ep->wq)) + wake_up_locked(&ep->wq); + if (waitqueue_active(&ep->poll_wait)) + pwake++; } + spin_unlock_irqrestore(&ep->lock, flags); + + mutex_unlock(&ep->mtx); + + /* We have to call this outside the lock */ + if (pwake) + ep_poll_safewake(&ep->poll_wait); + + return error; } /* @@ -417,10 +546,10 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) ep_unregister_pollwait(ep, epi); /* Remove the current item from the list of epoll hooks */ - spin_lock(&file->f_ep_lock); + spin_lock(&file->f_lock); if (ep_is_linked(&epi->fllink)) list_del_init(&epi->fllink); - spin_unlock(&file->f_ep_lock); + spin_unlock(&file->f_lock); rb_erase(&epi->rbn, &ep->rbr); @@ -434,9 +563,6 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) atomic_dec(&ep->user->epoll_watches); - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p)\n", - current, ep, file)); - return 0; } @@ -447,7 +573,7 @@ static void ep_free(struct eventpoll *ep) /* We need to release all tasks waiting for these file */ if (waitqueue_active(&ep->poll_wait)) - ep_poll_safewake(&psw, &ep->poll_wait); + ep_poll_safewake(&ep->poll_wait); /* * We need to lock this because we could be hit by @@ -492,26 +618,54 @@ static int ep_eventpoll_release(struct inode *inode, struct file *file) if (ep) ep_free(ep); - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep)); return 0; } +static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head, + void *priv) +{ + struct epitem *epi, *tmp; + + list_for_each_entry_safe(epi, tmp, head, rdllink) { + if (epi->ffd.file->f_op->poll(epi->ffd.file, NULL) & + epi->event.events) + return POLLIN | POLLRDNORM; + else { + /* + * Item has been dropped into the ready list by the poll + * callback, but it's not actually ready, as far as + * caller requested events goes. We can remove it here. + */ + list_del_init(&epi->rdllink); + } + } + + return 0; +} + +static int ep_poll_readyevents_proc(void *priv, void *cookie, int call_nests) +{ + return ep_scan_ready_list(priv, ep_read_events_proc, NULL); +} + static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait) { - unsigned int pollflags = 0; - unsigned long flags; + int pollflags; struct eventpoll *ep = file->private_data; /* Insert inside our poll wait queue */ poll_wait(file, &ep->poll_wait, wait); - /* Check our condition */ - spin_lock_irqsave(&ep->lock, flags); - if (!list_empty(&ep->rdllist)) - pollflags = POLLIN | POLLRDNORM; - spin_unlock_irqrestore(&ep->lock, flags); + /* + * Proceed to find out if wanted events are really available inside + * the ready list. This need to be done under ep_call_nested() + * supervision, since the call to f_op->poll() done on listed files + * could re-enter here. + */ + pollflags = ep_call_nested(&poll_readywalk_ncalls, EP_MAX_NESTS, + ep_poll_readyevents_proc, ep, ep); - return pollflags; + return pollflags != -1 ? pollflags : 0; } /* File callbacks that implement the eventpoll file behaviour */ @@ -538,15 +692,17 @@ void eventpoll_release_file(struct file *file) struct epitem *epi; /* - * We don't want to get "file->f_ep_lock" because it is not + * We don't want to get "file->f_lock" because it is not * necessary. It is not necessary because we're in the "struct file" * cleanup path, and this means that noone is using this file anymore. - * So, for example, epoll_ctl() cannot hit here sicne if we reach this + * So, for example, epoll_ctl() cannot hit here since if we reach this * point, the file counter already went to zero and fget() would fail. * The only hit might come from ep_free() but by holding the mutex * will correctly serialize the operation. We do need to acquire * "ep->mtx" after "epmutex" because ep_remove() requires it when called * from anywhere but ep_free(). + * + * Besides, ep_remove() acquires the lock, so we can't hold it here. */ mutex_lock(&epmutex); @@ -586,8 +742,6 @@ static int ep_alloc(struct eventpoll **pep) *pep = ep; - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n", - current, ep)); return 0; free_uid: @@ -621,9 +775,6 @@ static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd) } } - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_find(%p) -> %p\n", - current, file, epir)); - return epir; } @@ -639,9 +790,6 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k struct epitem *epi = ep_item_from_wait(wait); struct eventpoll *ep = epi->ep; - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n", - current, epi->ffd.file, epi, ep)); - spin_lock_irqsave(&ep->lock, flags); /* @@ -654,6 +802,15 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k goto out_unlock; /* + * Check the events coming with the callback. At this stage, not + * every device reports the events in the "key" parameter of the + * callback. We need to be able to handle both cases here, hence the + * test for "key" != NULL before the event match test. + */ + if (key && !((unsigned long) key & epi->event.events)) + goto out_unlock; + + /* * If we are trasfering events to userspace, we can hold no locks * (because we're accessing user memory, and because of linux f_op->poll() * semantics). All the events that happens during that period of time are @@ -668,12 +825,9 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k } /* If this file is already in the ready list we exit soon */ - if (ep_is_linked(&epi->rdllink)) - goto is_linked; - - list_add_tail(&epi->rdllink, &ep->rdllist); + if (!ep_is_linked(&epi->rdllink)) + list_add_tail(&epi->rdllink, &ep->rdllist); -is_linked: /* * Wake up ( if active ) both the eventpoll wait list and the ->poll() * wait list. @@ -688,7 +842,7 @@ out_unlock: /* We have to call this outside the lock */ if (pwake) - ep_poll_safewake(&psw, &ep->poll_wait); + ep_poll_safewake(&ep->poll_wait); return 1; } @@ -785,9 +939,9 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, goto error_unregister; /* Add the current item to the list of active epoll hook for this file */ - spin_lock(&tfile->f_ep_lock); + spin_lock(&tfile->f_lock); list_add_tail(&epi->fllink, &tfile->f_ep_links); - spin_unlock(&tfile->f_ep_lock); + spin_unlock(&tfile->f_lock); /* * Add the current item to the RB tree. All RB tree operations are @@ -815,10 +969,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, /* We have to call this outside the lock */ if (pwake) - ep_poll_safewake(&psw, &ep->poll_wait); - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_insert(%p, %p, %d)\n", - current, ep, tfile, fd)); + ep_poll_safewake(&ep->poll_wait); return 0; @@ -849,15 +1000,14 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even { int pwake = 0; unsigned int revents; - unsigned long flags; /* - * Set the new event interest mask before calling f_op->poll(), otherwise - * a potential race might occur. In fact if we do this operation inside - * the lock, an event might happen between the f_op->poll() call and the - * new event set registering. + * Set the new event interest mask before calling f_op->poll(); + * otherwise we might miss an event that happens between the + * f_op->poll() call and the new event set registering. */ epi->event.events = event->events; + epi->event.data = event->data; /* protected by mtx */ /* * Get current event bits. We can safely use the file* here because @@ -865,16 +1015,12 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even */ revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL); - spin_lock_irqsave(&ep->lock, flags); - - /* Copy the data member from inside the lock */ - epi->event.data = event->data; - /* * If the item is "hot" and it is not registered inside the ready * list, push it inside. */ if (revents & event->events) { + spin_lock_irq(&ep->lock); if (!ep_is_linked(&epi->rdllink)) { list_add_tail(&epi->rdllink, &ep->rdllist); @@ -884,142 +1030,84 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even if (waitqueue_active(&ep->poll_wait)) pwake++; } + spin_unlock_irq(&ep->lock); } - spin_unlock_irqrestore(&ep->lock, flags); /* We have to call this outside the lock */ if (pwake) - ep_poll_safewake(&psw, &ep->poll_wait); + ep_poll_safewake(&ep->poll_wait); return 0; } -static int ep_send_events(struct eventpoll *ep, struct epoll_event __user *events, - int maxevents) +static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head, + void *priv) { - int eventcnt, error = -EFAULT, pwake = 0; + struct ep_send_events_data *esed = priv; + int eventcnt; unsigned int revents; - unsigned long flags; - struct epitem *epi, *nepi; - struct list_head txlist; - - INIT_LIST_HEAD(&txlist); - - /* - * We need to lock this because we could be hit by - * eventpoll_release_file() and epoll_ctl(EPOLL_CTL_DEL). - */ - mutex_lock(&ep->mtx); - - /* - * Steal the ready list, and re-init the original one to the - * empty list. Also, set ep->ovflist to NULL so that events - * happening while looping w/out locks, are not lost. We cannot - * have the poll callback to queue directly on ep->rdllist, - * because we are doing it in the loop below, in a lockless way. - */ - spin_lock_irqsave(&ep->lock, flags); - list_splice(&ep->rdllist, &txlist); - INIT_LIST_HEAD(&ep->rdllist); - ep->ovflist = NULL; - spin_unlock_irqrestore(&ep->lock, flags); + struct epitem *epi; + struct epoll_event __user *uevent; /* - * We can loop without lock because this is a task private list. - * We just splice'd out the ep->rdllist in ep_collect_ready_items(). - * Items cannot vanish during the loop because we are holding "mtx". + * We can loop without lock because we are passed a task private list. + * Items cannot vanish during the loop because ep_scan_ready_list() is + * holding "mtx" during this call. */ - for (eventcnt = 0; !list_empty(&txlist) && eventcnt < maxevents;) { - epi = list_first_entry(&txlist, struct epitem, rdllink); + for (eventcnt = 0, uevent = esed->events; + !list_empty(head) && eventcnt < esed->maxevents;) { + epi = list_first_entry(head, struct epitem, rdllink); list_del_init(&epi->rdllink); - /* - * Get the ready file event set. We can safely use the file - * because we are holding the "mtx" and this will guarantee - * that both the file and the item will not vanish. - */ - revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL); - revents &= epi->event.events; + revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL) & + epi->event.events; /* - * Is the event mask intersect the caller-requested one, - * deliver the event to userspace. Again, we are holding - * "mtx", so no operations coming from userspace can change - * the item. + * If the event mask intersect the caller-requested one, + * deliver the event to userspace. Again, ep_scan_ready_list() + * is holding "mtx", so no operations coming from userspace + * can change the item. */ if (revents) { - if (__put_user(revents, - &events[eventcnt].events) || - __put_user(epi->event.data, - &events[eventcnt].data)) - goto errxit; + if (__put_user(revents, &uevent->events) || + __put_user(epi->event.data, &uevent->data)) { + list_add(&epi->rdllink, head); + return eventcnt ? eventcnt : -EFAULT; + } + eventcnt++; + uevent++; if (epi->event.events & EPOLLONESHOT) epi->event.events &= EP_PRIVATE_BITS; - eventcnt++; + else if (!(epi->event.events & EPOLLET)) { + /* + * If this file has been added with Level + * Trigger mode, we need to insert back inside + * the ready list, so that the next call to + * epoll_wait() will check again the events + * availability. At this point, noone can insert + * into ep->rdllist besides us. The epoll_ctl() + * callers are locked out by + * ep_scan_ready_list() holding "mtx" and the + * poll callback will queue them in ep->ovflist. + */ + list_add_tail(&epi->rdllink, &ep->rdllist); + } } - /* - * At this point, noone can insert into ep->rdllist besides - * us. The epoll_ctl() callers are locked out by us holding - * "mtx" and the poll callback will queue them in ep->ovflist. - */ - if (!(epi->event.events & EPOLLET) && - (revents & epi->event.events)) - list_add_tail(&epi->rdllink, &ep->rdllist); - } - error = 0; - -errxit: - - spin_lock_irqsave(&ep->lock, flags); - /* - * During the time we spent in the loop above, some other events - * might have been queued by the poll callback. We re-insert them - * inside the main ready-list here. - */ - for (nepi = ep->ovflist; (epi = nepi) != NULL; - nepi = epi->next, epi->next = EP_UNACTIVE_PTR) { - /* - * If the above loop quit with errors, the epoll item might still - * be linked to "txlist", and the list_splice() done below will - * take care of those cases. - */ - if (!ep_is_linked(&epi->rdllink)) - list_add_tail(&epi->rdllink, &ep->rdllist); } - /* - * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after - * releasing the lock, events will be queued in the normal way inside - * ep->rdllist. - */ - ep->ovflist = EP_UNACTIVE_PTR; - /* - * In case of error in the event-send loop, or in case the number of - * ready events exceeds the userspace limit, we need to splice the - * "txlist" back inside ep->rdllist. - */ - list_splice(&txlist, &ep->rdllist); - - if (!list_empty(&ep->rdllist)) { - /* - * Wake up (if active) both the eventpoll wait list and the ->poll() - * wait list (delayed after we release the lock). - */ - if (waitqueue_active(&ep->wq)) - wake_up_locked(&ep->wq); - if (waitqueue_active(&ep->poll_wait)) - pwake++; - } - spin_unlock_irqrestore(&ep->lock, flags); + return eventcnt; +} - mutex_unlock(&ep->mtx); +static int ep_send_events(struct eventpoll *ep, + struct epoll_event __user *events, int maxevents) +{ + struct ep_send_events_data esed; - /* We have to call this outside the lock */ - if (pwake) - ep_poll_safewake(&psw, &ep->poll_wait); + esed.maxevents = maxevents; + esed.events = events; - return eventcnt == 0 ? error: eventcnt; + return ep_scan_ready_list(ep, ep_send_events_proc, &esed); } static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, @@ -1031,7 +1119,7 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, wait_queue_t wait; /* - * Calculate the timeout by checking for the "infinite" value ( -1 ) + * Calculate the timeout by checking for the "infinite" value (-1) * and the overflow condition. The passed timeout is in milliseconds, * that why (t * HZ) / 1000. */ @@ -1074,9 +1162,8 @@ retry: set_current_state(TASK_RUNNING); } - /* Is it worth to try to dig for events ? */ - eavail = !list_empty(&ep->rdllist); + eavail = !list_empty(&ep->rdllist) || ep->ovflist != EP_UNACTIVE_PTR; spin_unlock_irqrestore(&ep->lock, flags); @@ -1097,41 +1184,30 @@ retry: */ SYSCALL_DEFINE1(epoll_create1, int, flags) { - int error, fd = -1; - struct eventpoll *ep; + int error; + struct eventpoll *ep = NULL; /* Check the EPOLL_* constant for consistency. */ BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC); if (flags & ~EPOLL_CLOEXEC) return -EINVAL; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", - current, flags)); - /* - * Create the internal data structure ( "struct eventpoll" ). + * Create the internal data structure ("struct eventpoll"). */ error = ep_alloc(&ep); - if (error < 0) { - fd = error; - goto error_return; - } - + if (error < 0) + return error; /* * Creates all the items needed to setup an eventpoll file. That is, * a file structure and a free file descriptor. */ - fd = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep, - flags & O_CLOEXEC); - if (fd < 0) + error = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep, + flags & O_CLOEXEC); + if (error < 0) ep_free(ep); -error_return: - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", - current, flags, fd)); - - return fd; + return error; } SYSCALL_DEFINE1(epoll_create, int, size) @@ -1156,9 +1232,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, struct epitem *epi; struct epoll_event epds; - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n", - current, epfd, op, fd, event)); - error = -EFAULT; if (ep_op_has_event(op) && copy_from_user(&epds, event, sizeof(struct epoll_event))) @@ -1209,7 +1282,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, case EPOLL_CTL_ADD: if (!epi) { epds.events |= POLLERR | POLLHUP; - error = ep_insert(ep, &epds, tfile, fd); } else error = -EEXIST; @@ -1235,8 +1307,6 @@ error_tgt_fput: error_fput: fput(file); error_return: - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p) = %d\n", - current, epfd, op, fd, event, error)); return error; } @@ -1252,9 +1322,6 @@ SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events, struct file *file; struct eventpoll *ep; - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n", - current, epfd, events, maxevents, timeout)); - /* The maximum number of event must be greater than zero */ if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) return -EINVAL; @@ -1291,8 +1358,6 @@ SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events, error_fput: fput(file); error_return: - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n", - current, epfd, events, maxevents, timeout, error)); return error; } @@ -1357,17 +1422,18 @@ static int __init eventpoll_init(void) EP_ITEM_COST; /* Initialize the structure used to perform safe poll wait head wake ups */ - ep_poll_safewake_init(&psw); + ep_nested_calls_init(&poll_safewake_ncalls); + + /* Initialize the structure used to perform file's f_op->poll() calls */ + ep_nested_calls_init(&poll_readywalk_ncalls); /* Allocates slab cache used to allocate "struct epitem" items */ epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem), - 0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC, - NULL); + 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); /* Allocates slab cache used to allocate "struct eppoll_entry" */ pwq_cache = kmem_cache_create("eventpoll_pwq", - sizeof(struct eppoll_entry), 0, - EPI_SLAB_DEBUG|SLAB_PANIC, NULL); + sizeof(struct eppoll_entry), 0, SLAB_PANIC, NULL); return 0; } diff --git a/fs/exec.c b/fs/exec.c index 929b58004b7..c5128fbc916 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -45,6 +45,7 @@ #include <linux/proc_fs.h> #include <linux/mount.h> #include <linux/security.h> +#include <linux/ima.h> #include <linux/syscalls.h> #include <linux/tsacct_kern.h> #include <linux/cn_proc.h> @@ -127,6 +128,9 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) MAY_READ | MAY_EXEC | MAY_OPEN); if (error) goto exit; + error = ima_path_check(&nd.path, MAY_READ | MAY_EXEC | MAY_OPEN); + if (error) + goto exit; file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); error = PTR_ERR(file); @@ -674,6 +678,9 @@ struct file *open_exec(const char *name) err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN); if (err) goto out_path_put; + err = ima_path_check(&nd.path, MAY_EXEC | MAY_OPEN); + if (err) + goto out_path_put; file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); if (IS_ERR(file)) @@ -1049,28 +1056,24 @@ EXPORT_SYMBOL(install_exec_creds); * - the caller must hold current->cred_exec_mutex to protect against * PTRACE_ATTACH */ -void check_unsafe_exec(struct linux_binprm *bprm, struct files_struct *files) +void check_unsafe_exec(struct linux_binprm *bprm) { struct task_struct *p = current, *t; unsigned long flags; - unsigned n_fs, n_files, n_sighand; + unsigned n_fs, n_sighand; bprm->unsafe = tracehook_unsafe_exec(p); n_fs = 1; - n_files = 1; n_sighand = 1; lock_task_sighand(p, &flags); for (t = next_thread(p); t != p; t = next_thread(t)) { if (t->fs == p->fs) n_fs++; - if (t->files == files) - n_files++; n_sighand++; } if (atomic_read(&p->fs->count) > n_fs || - atomic_read(&p->files->count) > n_files || atomic_read(&p->sighand->count) > n_sighand) bprm->unsafe |= LSM_UNSAFE_SHARE; @@ -1184,6 +1187,9 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) retval = security_bprm_check(bprm); if (retval) return retval; + retval = ima_bprm_check(bprm); + if (retval) + return retval; /* kernel module loader fixup */ /* so we don't try to load run modprobe in kernel space. */ @@ -1284,12 +1290,13 @@ int do_execve(char * filename, retval = mutex_lock_interruptible(¤t->cred_exec_mutex); if (retval < 0) goto out_free; + current->in_execve = 1; retval = -ENOMEM; bprm->cred = prepare_exec_creds(); if (!bprm->cred) goto out_unlock; - check_unsafe_exec(bprm, displaced); + check_unsafe_exec(bprm); file = open_exec(filename); retval = PTR_ERR(file); @@ -1337,6 +1344,7 @@ int do_execve(char * filename, goto out; /* execve succeeded */ + current->in_execve = 0; mutex_unlock(¤t->cred_exec_mutex); acct_update_integrals(current); free_bprm(bprm); @@ -1355,6 +1363,7 @@ out_file: } out_unlock: + current->in_execve = 0; mutex_unlock(¤t->cred_exec_mutex); out_free: diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 4a29d637608..7f8d2e5a7ea 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -570,7 +570,7 @@ do_more: error_return: brelse(bitmap_bh); release_blocks(sb, freed); - DQUOT_FREE_BLOCK(inode, freed); + vfs_dq_free_block(inode, freed); } /** @@ -1247,7 +1247,7 @@ ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal, /* * Check quota for allocation of this block. */ - if (DQUOT_ALLOC_BLOCK(inode, num)) { + if (vfs_dq_alloc_block(inode, num)) { *errp = -EDQUOT; return 0; } @@ -1409,7 +1409,7 @@ allocated: *errp = 0; brelse(bitmap_bh); - DQUOT_FREE_BLOCK(inode, *count-num); + vfs_dq_free_block(inode, *count-num); *count = num; return ret_block; @@ -1420,7 +1420,7 @@ out: * Undo the block allocation */ if (!performed_allocation) - DQUOT_FREE_BLOCK(inode, *count); + vfs_dq_free_block(inode, *count); brelse(bitmap_bh); return 0; } diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 66321a877e7..15387c9c17d 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -121,8 +121,8 @@ void ext2_free_inode (struct inode * inode) if (!is_bad_inode(inode)) { /* Quota is already initialized in iput() */ ext2_xattr_delete_inode(inode); - DQUOT_FREE_INODE(inode); - DQUOT_DROP(inode); + vfs_dq_free_inode(inode); + vfs_dq_drop(inode); } es = EXT2_SB(sb)->s_es; @@ -586,7 +586,7 @@ got: goto fail_drop; } - if (DQUOT_ALLOC_INODE(inode)) { + if (vfs_dq_alloc_inode(inode)) { err = -EDQUOT; goto fail_drop; } @@ -605,10 +605,10 @@ got: return inode; fail_free_drop: - DQUOT_FREE_INODE(inode); + vfs_dq_free_inode(inode); fail_drop: - DQUOT_DROP(inode); + vfs_dq_drop(inode); inode->i_flags |= S_NOQUOTA; inode->i_nlink = 0; unlock_new_inode(inode); diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 23fff2f8778..b43b9556366 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1444,7 +1444,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) return error; if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { - error = DQUOT_TRANSFER(inode, iattr) ? -EDQUOT : 0; + error = vfs_dq_transfer(inode, iattr) ? -EDQUOT : 0; if (error) return error; } diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 7c6e3606f0e..f983225266d 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1331,6 +1331,7 @@ static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, sb->s_blocksize - offset : toread; tmp_bh.b_state = 0; + tmp_bh.b_size = sb->s_blocksize; err = ext2_get_block(inode, blk, &tmp_bh, 0); if (err < 0) return err; diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 987a5261cc2..7913531ec6d 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -642,7 +642,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, ea_bdebug(new_bh, "reusing block"); error = -EDQUOT; - if (DQUOT_ALLOC_BLOCK(inode, 1)) { + if (vfs_dq_alloc_block(inode, 1)) { unlock_buffer(new_bh); goto cleanup; } @@ -699,7 +699,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, * as if nothing happened and cleanup the unused block */ if (error && error != -ENOSPC) { if (new_bh && new_bh != old_bh) - DQUOT_FREE_BLOCK(inode, 1); + vfs_dq_free_block(inode, 1); goto cleanup; } } else @@ -731,7 +731,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, le32_add_cpu(&HDR(old_bh)->h_refcount, -1); if (ce) mb_cache_entry_release(ce); - DQUOT_FREE_BLOCK(inode, 1); + vfs_dq_free_block(inode, 1); mark_buffer_dirty(old_bh); ea_bdebug(old_bh, "refcount now=%d", le32_to_cpu(HDR(old_bh)->h_refcount)); @@ -794,7 +794,7 @@ ext2_xattr_delete_inode(struct inode *inode) mark_buffer_dirty(bh); if (IS_SYNC(inode)) sync_dirty_buffer(bh); - DQUOT_FREE_BLOCK(inode, 1); + vfs_dq_free_block(inode, 1); } EXT2_I(inode)->i_file_acl = 0; diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 0dbf1c04847..225202db897 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -676,7 +676,7 @@ void ext3_free_blocks(handle_t *handle, struct inode *inode, } ext3_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks); if (dquot_freed_blocks) - DQUOT_FREE_BLOCK(inode, dquot_freed_blocks); + vfs_dq_free_block(inode, dquot_freed_blocks); return; } @@ -1502,7 +1502,7 @@ ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode, /* * Check quota for allocation of this block. */ - if (DQUOT_ALLOC_BLOCK(inode, num)) { + if (vfs_dq_alloc_block(inode, num)) { *errp = -EDQUOT; return 0; } @@ -1714,7 +1714,7 @@ allocated: *errp = 0; brelse(bitmap_bh); - DQUOT_FREE_BLOCK(inode, *count-num); + vfs_dq_free_block(inode, *count-num); *count = num; return ret_block; @@ -1729,7 +1729,7 @@ out: * Undo the block allocation */ if (!performed_allocation) - DQUOT_FREE_BLOCK(inode, *count); + vfs_dq_free_block(inode, *count); brelse(bitmap_bh); return 0; } diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 8de6c720e51..dd13d60d524 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -123,10 +123,10 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) * Note: we must free any quota before locking the superblock, * as writing the quota to disk may need the lock as well. */ - DQUOT_INIT(inode); + vfs_dq_init(inode); ext3_xattr_delete_inode(handle, inode); - DQUOT_FREE_INODE(inode); - DQUOT_DROP(inode); + vfs_dq_free_inode(inode); + vfs_dq_drop(inode); is_directory = S_ISDIR(inode->i_mode); @@ -589,7 +589,7 @@ got: sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE : 0; ret = inode; - if(DQUOT_ALLOC_INODE(inode)) { + if (vfs_dq_alloc_inode(inode)) { err = -EDQUOT; goto fail_drop; } @@ -620,10 +620,10 @@ really_out: return ret; fail_free_drop: - DQUOT_FREE_INODE(inode); + vfs_dq_free_inode(inode); fail_drop: - DQUOT_DROP(inode); + vfs_dq_drop(inode); inode->i_flags |= S_NOQUOTA; inode->i_nlink = 0; unlock_new_inode(inode); diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 5fa453b49a6..4a09ff16987 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1435,6 +1435,10 @@ static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) return 0; } +static int buffer_unmapped(handle_t *handle, struct buffer_head *bh) +{ + return !buffer_mapped(bh); +} /* * Note that we always start a transaction even if we're not journalling * data. This is to preserve ordering: any hole instantiation within @@ -1505,6 +1509,15 @@ static int ext3_ordered_writepage(struct page *page, if (ext3_journal_current_handle()) goto out_fail; + if (!page_has_buffers(page)) { + create_empty_buffers(page, inode->i_sb->s_blocksize, + (1 << BH_Dirty)|(1 << BH_Uptodate)); + } else if (!walk_page_buffers(NULL, page_buffers(page), 0, PAGE_CACHE_SIZE, NULL, buffer_unmapped)) { + /* Provide NULL instead of get_block so that we catch bugs if buffers weren't really mapped */ + return block_write_full_page(page, NULL, wbc); + } + page_bufs = page_buffers(page); + handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); if (IS_ERR(handle)) { @@ -1512,11 +1525,6 @@ static int ext3_ordered_writepage(struct page *page, goto out_fail; } - if (!page_has_buffers(page)) { - create_empty_buffers(page, inode->i_sb->s_blocksize, - (1 << BH_Dirty)|(1 << BH_Uptodate)); - } - page_bufs = page_buffers(page); walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, NULL, bget_one); @@ -3055,7 +3063,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) error = PTR_ERR(handle); goto err_out; } - error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; + error = vfs_dq_transfer(inode, attr) ? -EDQUOT : 0; if (error) { ext3_journal_stop(handle); return error; @@ -3146,7 +3154,7 @@ static int ext3_writepage_trans_blocks(struct inode *inode) ret = 2 * (bpp + indirects) + 2; #ifdef CONFIG_QUOTA - /* We know that structure was already allocated during DQUOT_INIT so + /* We know that structure was already allocated during vfs_dq_init so * we will be updating only the data blocks + inodes */ ret += 2*EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb); #endif @@ -3237,7 +3245,7 @@ int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode) * i_size has been changed by generic_commit_write() and we thus need * to include the updated inode in the current transaction. * - * Also, DQUOT_ALLOC_SPACE() will always dirty the inode when blocks + * Also, vfs_dq_alloc_space() will always dirty the inode when blocks * are allocated to the file. * * If the inode is marked synchronous, we don't honour that here - doing diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 4db4ffa1eda..e2fc63cbba8 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -2049,7 +2049,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) /* Initialize quotas before so that eventual writes go in * separate transaction */ - DQUOT_INIT(dentry->d_inode); + vfs_dq_init(dentry->d_inode); handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); @@ -2108,7 +2108,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) /* Initialize quotas before so that eventual writes go * in separate transaction */ - DQUOT_INIT(dentry->d_inode); + vfs_dq_init(dentry->d_inode); handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); @@ -2272,7 +2272,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, /* Initialize quotas before so that eventual writes go * in separate transaction */ if (new_dentry->d_inode) - DQUOT_INIT(new_dentry->d_inode); + vfs_dq_init(new_dentry->d_inode); handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 4a970411a45..9e5b8e387e1 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -707,8 +707,6 @@ static int bdev_try_to_free_page(struct super_block *sb, struct page *page, #define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group") #define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA)) -static int ext3_dquot_initialize(struct inode *inode, int type); -static int ext3_dquot_drop(struct inode *inode); static int ext3_write_dquot(struct dquot *dquot); static int ext3_acquire_dquot(struct dquot *dquot); static int ext3_release_dquot(struct dquot *dquot); @@ -723,8 +721,8 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off); static struct dquot_operations ext3_quota_operations = { - .initialize = ext3_dquot_initialize, - .drop = ext3_dquot_drop, + .initialize = dquot_initialize, + .drop = dquot_drop, .alloc_space = dquot_alloc_space, .alloc_inode = dquot_alloc_inode, .free_space = dquot_free_space, @@ -1438,7 +1436,7 @@ static void ext3_orphan_cleanup (struct super_block * sb, } list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan); - DQUOT_INIT(inode); + vfs_dq_init(inode); if (inode->i_nlink) { printk(KERN_DEBUG "%s: truncating inode %lu to %Ld bytes\n", @@ -2702,7 +2700,7 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) * Process 1 Process 2 * ext3_create() quota_sync() * journal_start() write_dquot() - * DQUOT_INIT() down(dqio_mutex) + * vfs_dq_init() down(dqio_mutex) * down(dqio_mutex) journal_start() * */ @@ -2714,44 +2712,6 @@ static inline struct inode *dquot_to_inode(struct dquot *dquot) return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; } -static int ext3_dquot_initialize(struct inode *inode, int type) -{ - handle_t *handle; - int ret, err; - - /* We may create quota structure so we need to reserve enough blocks */ - handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - ret = dquot_initialize(inode, type); - err = ext3_journal_stop(handle); - if (!ret) - ret = err; - return ret; -} - -static int ext3_dquot_drop(struct inode *inode) -{ - handle_t *handle; - int ret, err; - - /* We may delete quota structure so we need to reserve enough blocks */ - handle = ext3_journal_start(inode, 2*EXT3_QUOTA_DEL_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) { - /* - * We call dquot_drop() anyway to at least release references - * to quota structures so that umount does not hang. - */ - dquot_drop(inode); - return PTR_ERR(handle); - } - ret = dquot_drop(inode); - err = ext3_journal_stop(handle); - if (!ret) - ret = err; - return ret; -} - static int ext3_write_dquot(struct dquot *dquot) { int ret, err; diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 175414ac221..83b7be849bd 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -498,7 +498,7 @@ ext3_xattr_release_block(handle_t *handle, struct inode *inode, error = ext3_journal_dirty_metadata(handle, bh); if (IS_SYNC(inode)) handle->h_sync = 1; - DQUOT_FREE_BLOCK(inode, 1); + vfs_dq_free_block(inode, 1); ea_bdebug(bh, "refcount now=%d; releasing", le32_to_cpu(BHDR(bh)->h_refcount)); if (ce) @@ -774,7 +774,7 @@ inserted: /* The old block is released after updating the inode. */ error = -EDQUOT; - if (DQUOT_ALLOC_BLOCK(inode, 1)) + if (vfs_dq_alloc_block(inode, 1)) goto cleanup; error = ext3_journal_get_write_access(handle, new_bh); @@ -848,7 +848,7 @@ cleanup: return error; cleanup_dquot: - DQUOT_FREE_BLOCK(inode, 1); + vfs_dq_free_block(inode, 1); goto cleanup; bad_block: diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index de9459b4cb9..38f40d55899 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -536,7 +536,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, ext4_mb_free_blocks(handle, inode, block, count, metadata, &dquot_freed_blocks); if (dquot_freed_blocks) - DQUOT_FREE_BLOCK(inode, dquot_freed_blocks); + vfs_dq_free_block(inode, dquot_freed_blocks); return; } diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index b0c87dce66a..990c9400092 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -20,6 +20,7 @@ #include <linux/blkdev.h> #include <linux/magic.h> #include <linux/jbd2.h> +#include <linux/quota.h> #include "ext4_i.h" /* @@ -1097,7 +1098,8 @@ extern int ext4_meta_trans_blocks(struct inode *, int nrblocks, int idxblocks); extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); extern int ext4_block_truncate_page(handle_t *handle, struct address_space *mapping, loff_t from); -extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page); +extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); +extern qsize_t ext4_get_reserved_space(struct inode *inode); /* ioctl.c */ extern long ext4_ioctl(struct file *, unsigned int, unsigned long); diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e2eab196875..e0aa4fe4f59 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -1122,7 +1122,8 @@ ext4_ext_search_right(struct inode *inode, struct ext4_ext_path *path, struct ext4_extent_idx *ix; struct ext4_extent *ex; ext4_fsblk_t block; - int depth, ee_len; + int depth; /* Note, NOT eh_depth; depth from top of tree */ + int ee_len; BUG_ON(path == NULL); depth = path->p_depth; @@ -1179,7 +1180,8 @@ got_index: if (bh == NULL) return -EIO; eh = ext_block_hdr(bh); - if (ext4_ext_check_header(inode, eh, depth)) { + /* subtract from p_depth to get proper eh_depth */ + if (ext4_ext_check_header(inode, eh, path->p_depth - depth)) { put_bh(bh); return -EIO; } diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 627f8c3337a..fb51b40e3e8 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -220,10 +220,10 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) * Note: we must free any quota before locking the superblock, * as writing the quota to disk may need the lock as well. */ - DQUOT_INIT(inode); + vfs_dq_init(inode); ext4_xattr_delete_inode(handle, inode); - DQUOT_FREE_INODE(inode); - DQUOT_DROP(inode); + vfs_dq_free_inode(inode); + vfs_dq_drop(inode); is_directory = S_ISDIR(inode->i_mode); @@ -698,6 +698,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) struct inode *ret; ext4_group_t i; int free = 0; + static int once = 1; ext4_group_t flex_group; /* Cannot create files in a deleted directory */ @@ -719,7 +720,8 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) ret2 = find_group_flex(sb, dir, &group); if (ret2 == -1) { ret2 = find_group_other(sb, dir, &group); - if (ret2 == 0 && printk_ratelimit()) + if (ret2 == 0 && once) + once = 0; printk(KERN_NOTICE "ext4: find_group_flex " "failed, fallback succeeded dir %lu\n", dir->i_ino); @@ -913,7 +915,7 @@ got: ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize; ret = inode; - if (DQUOT_ALLOC_INODE(inode)) { + if (vfs_dq_alloc_inode(inode)) { err = -EDQUOT; goto fail_drop; } @@ -954,10 +956,10 @@ really_out: return ret; fail_free_drop: - DQUOT_FREE_INODE(inode); + vfs_dq_free_inode(inode); fail_drop: - DQUOT_DROP(inode); + vfs_dq_drop(inode); inode->i_flags |= S_NOQUOTA; inode->i_nlink = 0; unlock_new_inode(inode); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c7fed5b1874..dd82ff39006 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -975,6 +975,17 @@ out: return err; } +qsize_t ext4_get_reserved_space(struct inode *inode) +{ + unsigned long long total; + + spin_lock(&EXT4_I(inode)->i_block_reservation_lock); + total = EXT4_I(inode)->i_reserved_data_blocks + + EXT4_I(inode)->i_reserved_meta_blocks; + spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); + + return total; +} /* * Calculate the number of metadata blocks need to reserve * to allocate @blocks for non extent file based file @@ -1036,8 +1047,14 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used) /* update per-inode reservations */ BUG_ON(used > EXT4_I(inode)->i_reserved_data_blocks); EXT4_I(inode)->i_reserved_data_blocks -= used; - spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); + + /* + * free those over-booking quota for metadata blocks + */ + + if (mdb_free) + vfs_dq_release_reservation_block(inode, mdb_free); } /* @@ -1553,8 +1570,8 @@ static int ext4_journalled_write_end(struct file *file, static int ext4_da_reserve_space(struct inode *inode, int nrblocks) { int retries = 0; - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - unsigned long md_needed, mdblocks, total = 0; + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + unsigned long md_needed, mdblocks, total = 0; /* * recalculate the amount of metadata blocks to reserve @@ -1570,12 +1587,23 @@ repeat: md_needed = mdblocks - EXT4_I(inode)->i_reserved_meta_blocks; total = md_needed + nrblocks; + /* + * Make quota reservation here to prevent quota overflow + * later. Real quota accounting is done at pages writeout + * time. + */ + if (vfs_dq_reserve_block(inode, total)) { + spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); + return -EDQUOT; + } + if (ext4_claim_free_blocks(sbi, total)) { spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); if (ext4_should_retry_alloc(inode->i_sb, &retries)) { yield(); goto repeat; } + vfs_dq_release_reservation_block(inode, total); return -ENOSPC; } EXT4_I(inode)->i_reserved_data_blocks += nrblocks; @@ -1629,6 +1657,8 @@ static void ext4_da_release_space(struct inode *inode, int to_free) BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); EXT4_I(inode)->i_reserved_meta_blocks = mdb; spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); + + vfs_dq_release_reservation_block(inode, release); } static void ext4_da_page_release_reservation(struct page *page, @@ -4612,7 +4642,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) error = PTR_ERR(handle); goto err_out; } - error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; + error = vfs_dq_transfer(inode, attr) ? -EDQUOT : 0; if (error) { ext4_journal_stop(handle); return error; @@ -4991,7 +5021,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) * i_size has been changed by generic_commit_write() and we thus need * to include the updated inode in the current transaction. * - * Also, DQUOT_ALLOC_SPACE() will always dirty the inode when blocks + * Also, vfs_dq_alloc_block() will always dirty the inode when blocks * are allocated to the file. * * If the inode is marked synchronous, we don't honour that here - doing @@ -5116,8 +5146,9 @@ static int ext4_bh_unmapped(handle_t *handle, struct buffer_head *bh) return !buffer_mapped(bh); } -int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page) +int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { + struct page *page = vmf->page; loff_t size; unsigned long len; int ret = -EINVAL; @@ -5169,6 +5200,8 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page) goto out_unlock; ret = 0; out_unlock: + if (ret) + ret = VM_FAULT_SIGBUS; up_read(&inode->i_alloc_sem); return ret; } diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 4415beeb0b6..b038188bd03 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -1447,7 +1447,7 @@ static void ext4_mb_measure_extent(struct ext4_allocation_context *ac, struct ext4_free_extent *gex = &ac->ac_g_ex; BUG_ON(ex->fe_len <= 0); - BUG_ON(ex->fe_len >= EXT4_BLOCKS_PER_GROUP(ac->ac_sb)); + BUG_ON(ex->fe_len > EXT4_BLOCKS_PER_GROUP(ac->ac_sb)); BUG_ON(ex->fe_start >= EXT4_BLOCKS_PER_GROUP(ac->ac_sb)); BUG_ON(ac->ac_status != AC_STATUS_CONTINUE); @@ -3086,9 +3086,12 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED)) /* release all the reserved blocks if non delalloc */ percpu_counter_sub(&sbi->s_dirtyblocks_counter, reserv_blks); - else + else { percpu_counter_sub(&sbi->s_dirtyblocks_counter, ac->ac_b_ex.fe_len); + /* convert reserved quota blocks to real quota blocks */ + vfs_dq_claim_block(ac->ac_inode, ac->ac_b_ex.fe_len); + } if (sbi->s_log_groups_per_flex) { ext4_group_t flex_group = ext4_flex_group(sbi, @@ -3292,7 +3295,7 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, } BUG_ON(start + size <= ac->ac_o_ex.fe_logical && start > ac->ac_o_ex.fe_logical); - BUG_ON(size <= 0 || size >= EXT4_BLOCKS_PER_GROUP(ac->ac_sb)); + BUG_ON(size <= 0 || size > EXT4_BLOCKS_PER_GROUP(ac->ac_sb)); /* now prepare goal request */ @@ -3589,6 +3592,7 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac, struct super_block *sb, struct ext4_prealloc_space *pa) { ext4_group_t grp; + ext4_fsblk_t grp_blk; if (!atomic_dec_and_test(&pa->pa_count) || pa->pa_free != 0) return; @@ -3603,8 +3607,12 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac, pa->pa_deleted = 1; spin_unlock(&pa->pa_lock); - /* -1 is to protect from crossing allocation group */ - ext4_get_group_no_and_offset(sb, pa->pa_pstart - 1, &grp, NULL); + grp_blk = pa->pa_pstart; + /* If linear, pa_pstart may be in the next group when pa is used up */ + if (pa->pa_linear) + grp_blk--; + + ext4_get_group_no_and_offset(sb, grp_blk, &grp, NULL); /* * possible race: @@ -4539,7 +4547,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, struct ext4_sb_info *sbi; struct super_block *sb; ext4_fsblk_t block = 0; - unsigned int inquota; + unsigned int inquota = 0; unsigned int reserv_blks = 0; sb = ar->inode->i_sb; @@ -4557,9 +4565,17 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, (unsigned long long) ar->pleft, (unsigned long long) ar->pright); - if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag) { - /* - * With delalloc we already reserved the blocks + /* + * For delayed allocation, we could skip the ENOSPC and + * EDQUOT check, as blocks and quotas have been already + * reserved when data being copied into pagecache. + */ + if (EXT4_I(ar->inode)->i_delalloc_reserved_flag) + ar->flags |= EXT4_MB_DELALLOC_RESERVED; + else { + /* Without delayed allocation we need to verify + * there is enough free blocks to do block allocation + * and verify allocation doesn't exceed the quota limits. */ while (ar->len && ext4_claim_free_blocks(sbi, ar->len)) { /* let others to free the space */ @@ -4571,19 +4587,16 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, return 0; } reserv_blks = ar->len; + while (ar->len && vfs_dq_alloc_block(ar->inode, ar->len)) { + ar->flags |= EXT4_MB_HINT_NOPREALLOC; + ar->len--; + } + inquota = ar->len; + if (ar->len == 0) { + *errp = -EDQUOT; + goto out3; + } } - while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) { - ar->flags |= EXT4_MB_HINT_NOPREALLOC; - ar->len--; - } - if (ar->len == 0) { - *errp = -EDQUOT; - goto out3; - } - inquota = ar->len; - - if (EXT4_I(ar->inode)->i_delalloc_reserved_flag) - ar->flags |= EXT4_MB_DELALLOC_RESERVED; ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); if (!ac) { @@ -4649,8 +4662,8 @@ repeat: out2: kmem_cache_free(ext4_ac_cachep, ac); out1: - if (ar->len < inquota) - DQUOT_FREE_BLOCK(ar->inode, inquota - ar->len); + if (inquota && ar->len < inquota) + vfs_dq_free_block(ar->inode, inquota - ar->len); out3: if (!ar->len) { if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index ba702bd7910..83410244d3e 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2092,7 +2092,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry) /* Initialize quotas before so that eventual writes go in * separate transaction */ - DQUOT_INIT(dentry->d_inode); + vfs_dq_init(dentry->d_inode); handle = ext4_journal_start(dir, EXT4_DELETE_TRANS_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); @@ -2151,7 +2151,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) /* Initialize quotas before so that eventual writes go * in separate transaction */ - DQUOT_INIT(dentry->d_inode); + vfs_dq_init(dentry->d_inode); handle = ext4_journal_start(dir, EXT4_DELETE_TRANS_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); @@ -2318,7 +2318,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, /* Initialize quotas before so that eventual writes go * in separate transaction */ if (new_dentry->d_inode) - DQUOT_INIT(new_dentry->d_inode); + vfs_dq_init(new_dentry->d_inode); handle = ext4_journal_start(old_dir, 2 * EXT4_DATA_TRANS_BLOCKS(old_dir->i_sb) + EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 39d1993cfa1..f7371a6a923 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -926,8 +926,6 @@ static int bdev_try_to_free_page(struct super_block *sb, struct page *page, gfp_ #define QTYPE2NAME(t) ((t) == USRQUOTA ? "user" : "group") #define QTYPE2MOPT(on, t) ((t) == USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA)) -static int ext4_dquot_initialize(struct inode *inode, int type); -static int ext4_dquot_drop(struct inode *inode); static int ext4_write_dquot(struct dquot *dquot); static int ext4_acquire_dquot(struct dquot *dquot); static int ext4_release_dquot(struct dquot *dquot); @@ -942,9 +940,13 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off); static struct dquot_operations ext4_quota_operations = { - .initialize = ext4_dquot_initialize, - .drop = ext4_dquot_drop, + .initialize = dquot_initialize, + .drop = dquot_drop, .alloc_space = dquot_alloc_space, + .reserve_space = dquot_reserve_space, + .claim_space = dquot_claim_space, + .release_rsv = dquot_release_reserved_space, + .get_reserved_space = ext4_get_reserved_space, .alloc_inode = dquot_alloc_inode, .free_space = dquot_free_space, .free_inode = dquot_free_inode, @@ -1802,7 +1804,7 @@ static void ext4_orphan_cleanup(struct super_block *sb, } list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan); - DQUOT_INIT(inode); + vfs_dq_init(inode); if (inode->i_nlink) { printk(KERN_DEBUG "%s: truncating inode %lu to %lld bytes\n", @@ -3367,8 +3369,8 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) * is locked for write. Otherwise the are possible deadlocks: * Process 1 Process 2 * ext4_create() quota_sync() - * jbd2_journal_start() write_dquot() - * DQUOT_INIT() down(dqio_mutex) + * jbd2_journal_start() write_dquot() + * vfs_dq_init() down(dqio_mutex) * down(dqio_mutex) jbd2_journal_start() * */ @@ -3380,44 +3382,6 @@ static inline struct inode *dquot_to_inode(struct dquot *dquot) return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; } -static int ext4_dquot_initialize(struct inode *inode, int type) -{ - handle_t *handle; - int ret, err; - - /* We may create quota structure so we need to reserve enough blocks */ - handle = ext4_journal_start(inode, 2*EXT4_QUOTA_INIT_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - ret = dquot_initialize(inode, type); - err = ext4_journal_stop(handle); - if (!ret) - ret = err; - return ret; -} - -static int ext4_dquot_drop(struct inode *inode) -{ - handle_t *handle; - int ret, err; - - /* We may delete quota structure so we need to reserve enough blocks */ - handle = ext4_journal_start(inode, 2*EXT4_QUOTA_DEL_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) { - /* - * We call dquot_drop() anyway to at least release references - * to quota structures so that umount does not hang. - */ - dquot_drop(inode); - return PTR_ERR(handle); - } - ret = dquot_drop(inode); - err = ext4_journal_stop(handle); - if (!ret) - ret = err; - return ret; -} - static int ext4_write_dquot(struct dquot *dquot) { int ret, err; diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 157ce6589c5..62b31c24699 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -490,7 +490,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, error = ext4_handle_dirty_metadata(handle, inode, bh); if (IS_SYNC(inode)) ext4_handle_sync(handle); - DQUOT_FREE_BLOCK(inode, 1); + vfs_dq_free_block(inode, 1); ea_bdebug(bh, "refcount now=%d; releasing", le32_to_cpu(BHDR(bh)->h_refcount)); if (ce) @@ -784,7 +784,7 @@ inserted: /* The old block is released after updating the inode. */ error = -EDQUOT; - if (DQUOT_ALLOC_BLOCK(inode, 1)) + if (vfs_dq_alloc_block(inode, 1)) goto cleanup; error = ext4_journal_get_write_access(handle, new_bh); @@ -860,7 +860,7 @@ cleanup: return error; cleanup_dquot: - DQUOT_FREE_BLOCK(inode, 1); + vfs_dq_free_block(inode, 1); goto cleanup; bad_block: diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 6b74d09adbe..de0004fe6e0 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -202,9 +202,9 @@ static sector_t _fat_bmap(struct address_space *mapping, sector_t block) sector_t blocknr; /* fat_get_cluster() assumes the requested blocknr isn't truncated. */ - mutex_lock(&mapping->host->i_mutex); + down_read(&mapping->host->i_alloc_sem); blocknr = generic_block_bmap(mapping, block, fat_get_block); - mutex_unlock(&mapping->host->i_mutex); + up_read(&mapping->host->i_alloc_sem); return blocknr; } diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index 7ba03a4acbe..da3f361a37d 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -188,7 +188,7 @@ old_compare: goto out; } -static struct dentry_operations msdos_dentry_operations = { +static const struct dentry_operations msdos_dentry_operations = { .d_hash = msdos_hash, .d_compare = msdos_cmp, }; diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 8ae32e37673..a0e00e3a46e 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -166,13 +166,13 @@ static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) return 1; } -static struct dentry_operations vfat_ci_dentry_ops = { +static const struct dentry_operations vfat_ci_dentry_ops = { .d_revalidate = vfat_revalidate_ci, .d_hash = vfat_hashi, .d_compare = vfat_cmpi, }; -static struct dentry_operations vfat_dentry_ops = { +static const struct dentry_operations vfat_dentry_ops = { .d_revalidate = vfat_revalidate, .d_hash = vfat_hash, .d_compare = vfat_cmp, diff --git a/fs/fcntl.c b/fs/fcntl.c index bd215cc791d..cc8e4de2fee 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -141,7 +141,7 @@ SYSCALL_DEFINE1(dup, unsigned int, fildes) return ret; } -#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC | O_DIRECT | O_NOATIME) +#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) static int setfl(int fd, struct file * filp, unsigned long arg) { @@ -177,21 +177,21 @@ static int setfl(int fd, struct file * filp, unsigned long arg) return error; /* - * We still need a lock here for now to keep multiple FASYNC calls - * from racing with each other. + * ->fasync() is responsible for setting the FASYNC bit. */ - lock_kernel(); - if ((arg ^ filp->f_flags) & FASYNC) { - if (filp->f_op && filp->f_op->fasync) { - error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); - if (error < 0) - goto out; - } + if (((arg ^ filp->f_flags) & FASYNC) && filp->f_op && + filp->f_op->fasync) { + error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); + if (error < 0) + goto out; + if (error > 0) + error = 0; } - + spin_lock(&filp->f_lock); filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK); + spin_unlock(&filp->f_lock); + out: - unlock_kernel(); return error; } @@ -516,7 +516,7 @@ static DEFINE_RWLOCK(fasync_lock); static struct kmem_cache *fasync_cache __read_mostly; /* - * fasync_helper() is used by some character device drivers (mainly mice) + * fasync_helper() is used by almost all character device drivers * to set up the fasync queue. It returns negative on error, 0 if it did * no changes and positive if it added/deleted the entry. */ @@ -531,6 +531,12 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap if (!new) return -ENOMEM; } + + /* + * We need to take f_lock first since it's not an IRQ-safe + * lock. + */ + spin_lock(&filp->f_lock); write_lock_irq(&fasync_lock); for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { if (fa->fa_file == filp) { @@ -555,7 +561,12 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap result = 1; } out: + if (on) + filp->f_flags |= FASYNC; + else + filp->f_flags &= ~FASYNC; write_unlock_irq(&fasync_lock); + spin_unlock(&filp->f_lock); return result; } diff --git a/fs/file_table.c b/fs/file_table.c index bbeeac6efa1..b74a8e1da91 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/fs.h> #include <linux/security.h> +#include <linux/ima.h> #include <linux/eventpoll.h> #include <linux/rcupdate.h> #include <linux/mount.h> @@ -127,6 +128,7 @@ struct file *get_empty_filp(void) atomic_long_set(&f->f_count, 1); rwlock_init(&f->f_owner.lock); f->f_cred = get_cred(cred); + spin_lock_init(&f->f_lock); eventpoll_init_file(f); /* f->f_version: 0 */ return f; @@ -279,6 +281,7 @@ void __fput(struct file *file) if (file->f_op && file->f_op->release) file->f_op->release(inode, file); security_file_free(file); + ima_file_free(file); if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) cdev_put(inode->i_cdev); fops_put(file->f_op); diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index e5eaa62fd17..e3fe9918faa 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -274,6 +274,7 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) int ret; BUG_ON(inode->i_state & I_SYNC); + WARN_ON(inode->i_state & I_NEW); /* Set I_SYNC, reset I_DIRTY */ dirty = inode->i_state & I_DIRTY; @@ -298,6 +299,7 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) } spin_lock(&inode_lock); + WARN_ON(inode->i_state & I_NEW); inode->i_state &= ~I_SYNC; if (!(inode->i_state & I_FREEING)) { if (!(inode->i_state & I_DIRTY) && @@ -470,6 +472,11 @@ void generic_sync_sb_inodes(struct super_block *sb, break; } + if (inode->i_state & I_NEW) { + requeue_io(inode); + continue; + } + if (wbc->nonblocking && bdi_write_congested(bdi)) { wbc->encountered_congestion = 1; if (!sb_is_blkdev_sb(sb)) @@ -531,7 +538,7 @@ void generic_sync_sb_inodes(struct super_block *sb, list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { struct address_space *mapping; - if (inode->i_state & (I_FREEING|I_WILL_FREE)) + if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) continue; mapping = inode->i_mapping; if (mapping->nrpages == 0) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index fdff346e96f..06da05261e0 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -224,7 +224,7 @@ static int invalid_nodeid(u64 nodeid) return !nodeid || nodeid == FUSE_ROOT_ID; } -struct dentry_operations fuse_dentry_operations = { +const struct dentry_operations fuse_dentry_operations = { .d_revalidate = fuse_dentry_revalidate, }; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index d9fdb7cec53..4e340fedf76 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1234,8 +1234,9 @@ static void fuse_vma_close(struct vm_area_struct *vma) * - sync(2) * - try_to_free_pages() with order > PAGE_ALLOC_COSTLY_ORDER */ -static int fuse_page_mkwrite(struct vm_area_struct *vma, struct page *page) +static int fuse_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { + struct page *page = vmf->page; /* * Don't use page->mapping as it may become NULL from a * concurrent truncate. @@ -1465,7 +1466,7 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin) case SEEK_END: retval = fuse_update_attributes(inode, NULL, file, NULL); if (retval) - return retval; + goto exit; offset += i_size_read(inode); break; case SEEK_CUR: @@ -1479,6 +1480,7 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin) } retval = offset; } +exit: mutex_unlock(&inode->i_mutex); return retval; } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 5e64b815a5a..6fc5aedaa0d 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -493,7 +493,7 @@ static inline u64 get_node_id(struct inode *inode) /** Device operations */ extern const struct file_operations fuse_dev_operations; -extern struct dentry_operations fuse_dentry_operations; +extern const struct dentry_operations fuse_dentry_operations; /** * Get a filled in inode diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index e563a644981..3a981b7f64c 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig @@ -1,6 +1,10 @@ config GFS2_FS tristate "GFS2 file system support" depends on EXPERIMENTAL && (64BIT || LBD) + select DLM if GFS2_FS_LOCKING_DLM + select CONFIGFS_FS if GFS2_FS_LOCKING_DLM + select SYSFS if GFS2_FS_LOCKING_DLM + select IP_SCTP if DLM_SCTP select FS_POSIX_ACL select CRC32 help @@ -18,17 +22,16 @@ config GFS2_FS the locking module below. Documentation and utilities for GFS2 can be found here: http://sources.redhat.com/cluster - The "nolock" lock module is now built in to GFS2 by default. + The "nolock" lock module is now built in to GFS2 by default. If + you want to use the DLM, be sure to enable HOTPLUG and IPv4/6 + networking. config GFS2_FS_LOCKING_DLM - tristate "GFS2 DLM locking module" - depends on GFS2_FS && SYSFS && NET && INET && (IPV6 || IPV6=n) - select IP_SCTP if DLM_SCTP - select CONFIGFS_FS - select DLM + bool "GFS2 DLM locking" + depends on (GFS2_FS!=n) && NET && INET && (IPV6 || IPV6=n) && HOTPLUG help Multiple node locking module for GFS2 - Most users of GFS2 will require this module. It provides the locking + Most users of GFS2 will require this. It provides the locking interface between GFS2 and the DLM, which is required to use GFS2 in a cluster environment. diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index c1b4ec6a965..a851ea4bdf7 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -1,9 +1,9 @@ obj-$(CONFIG_GFS2_FS) += gfs2.o gfs2-y := acl.o bmap.o dir.o eaops.o eattr.o glock.o \ - glops.o inode.o log.o lops.o locking.o main.o meta_io.o \ + glops.o inode.o log.o lops.o main.o meta_io.o \ mount.o ops_address.o ops_dentry.o ops_export.o ops_file.o \ ops_fstype.o ops_inode.o ops_super.o quota.o \ recovery.o rgrp.o super.o sys.o trans.o util.o -obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += locking/dlm/ +gfs2-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index e335dceb6a4..43764f4fa76 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -15,7 +15,6 @@ #include <linux/posix_acl.h> #include <linux/posix_acl_xattr.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include "gfs2.h" #include "incore.h" diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 11ffc56f1f8..3a5d3f883e1 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -13,7 +13,6 @@ #include <linux/buffer_head.h> #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> -#include <linux/lm_interface.h> #include "gfs2.h" #include "incore.h" diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index b7c8e5c7079..aef4d0c0674 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -60,7 +60,6 @@ #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> #include <linux/vmalloc.h> -#include <linux/lm_interface.h> #include "gfs2.h" #include "incore.h" diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c index f114ba2b355..dee9b03e5b3 100644 --- a/fs/gfs2/eaops.c +++ b/fs/gfs2/eaops.c @@ -14,7 +14,6 @@ #include <linux/capability.h> #include <linux/xattr.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include <asm/uaccess.h> #include "gfs2.h" diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 0d1c76d906a..899763aed21 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -13,7 +13,6 @@ #include <linux/buffer_head.h> #include <linux/xattr.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include <asm/uaccess.h> #include "gfs2.h" diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 6b983aef785..3984e47d1d3 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -10,7 +10,6 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/completion.h> #include <linux/buffer_head.h> #include <linux/delay.h> #include <linux/sort.h> @@ -18,7 +17,6 @@ #include <linux/kallsyms.h> #include <linux/gfs2_ondisk.h> #include <linux/list.h> -#include <linux/lm_interface.h> #include <linux/wait.h> #include <linux/module.h> #include <linux/rwsem.h> @@ -155,13 +153,10 @@ static void glock_free(struct gfs2_glock *gl) struct gfs2_sbd *sdp = gl->gl_sbd; struct inode *aspace = gl->gl_aspace; - if (sdp->sd_lockstruct.ls_ops->lm_put_lock) - sdp->sd_lockstruct.ls_ops->lm_put_lock(gl->gl_lock); - if (aspace) gfs2_aspace_put(aspace); - kmem_cache_free(gfs2_glock_cachep, gl); + sdp->sd_lockstruct.ls_ops->lm_put_lock(gfs2_glock_cachep, gl); } /** @@ -172,6 +167,7 @@ static void glock_free(struct gfs2_glock *gl) static void gfs2_glock_hold(struct gfs2_glock *gl) { + GLOCK_BUG_ON(gl, atomic_read(&gl->gl_ref) == 0); atomic_inc(&gl->gl_ref); } @@ -211,17 +207,15 @@ int gfs2_glock_put(struct gfs2_glock *gl) atomic_dec(&lru_count); } spin_unlock(&lru_lock); - GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_UNLOCKED); - GLOCK_BUG_ON(gl, !list_empty(&gl->gl_lru)); GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); glock_free(gl); rv = 1; goto out; } - write_unlock(gl_lock_addr(gl->gl_hash)); /* 1 for being hashed, 1 for having state != LM_ST_UNLOCKED */ if (atomic_read(&gl->gl_ref) == 2) gfs2_glock_schedule_for_reclaim(gl); + write_unlock(gl_lock_addr(gl->gl_hash)); out: return rv; } @@ -256,27 +250,6 @@ static struct gfs2_glock *search_bucket(unsigned int hash, } /** - * gfs2_glock_find() - Find glock by lock number - * @sdp: The GFS2 superblock - * @name: The lock name - * - * Returns: NULL, or the struct gfs2_glock with the requested number - */ - -static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp, - const struct lm_lockname *name) -{ - unsigned int hash = gl_hash(sdp, name); - struct gfs2_glock *gl; - - read_lock(gl_lock_addr(hash)); - gl = search_bucket(hash, sdp, name); - read_unlock(gl_lock_addr(hash)); - - return gl; -} - -/** * may_grant - check if its ok to grant a new lock * @gl: The glock * @gh: The lock request which we wish to grant @@ -523,7 +496,7 @@ out_locked: } static unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock, - unsigned int cur_state, unsigned int req_state, + unsigned int req_state, unsigned int flags) { int ret = LM_OUT_ERROR; @@ -532,7 +505,7 @@ static unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock, return req_state == LM_ST_UNLOCKED ? 0 : req_state; if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, cur_state, + ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, req_state, flags); return ret; } @@ -575,7 +548,7 @@ __acquires(&gl->gl_spin) gl->gl_state == LM_ST_DEFERRED) && !(lck_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))) lck_flags |= LM_FLAG_TRY_1CB; - ret = gfs2_lm_lock(sdp, gl->gl_lock, gl->gl_state, target, lck_flags); + ret = gfs2_lm_lock(sdp, gl, target, lck_flags); if (!(ret & LM_OUT_ASYNC)) { finish_xmote(gl, ret); @@ -624,10 +597,11 @@ __acquires(&gl->gl_spin) GLOCK_BUG_ON(gl, test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags)); + down_read(&gfs2_umount_flush_sem); if (test_bit(GLF_DEMOTE, &gl->gl_flags) && gl->gl_demote_state != gl->gl_state) { if (find_first_holder(gl)) - goto out; + goto out_unlock; if (nonblock) goto out_sched; set_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags); @@ -638,23 +612,26 @@ __acquires(&gl->gl_spin) gfs2_demote_wake(gl); ret = do_promote(gl); if (ret == 0) - goto out; + goto out_unlock; if (ret == 2) - return; + goto out_sem; gh = find_first_waiter(gl); gl->gl_target = gh->gh_state; if (!(gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))) do_error(gl, 0); /* Fail queued try locks */ } do_xmote(gl, gh, gl->gl_target); +out_sem: + up_read(&gfs2_umount_flush_sem); return; out_sched: gfs2_glock_hold(gl); if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) gfs2_glock_put(gl); -out: +out_unlock: clear_bit(GLF_LOCK, &gl->gl_flags); + goto out_sem; } static void glock_work_func(struct work_struct *work) @@ -681,18 +658,6 @@ static void glock_work_func(struct work_struct *work) gfs2_glock_put(gl); } -static int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name, - void **lockp) -{ - int error = -EIO; - if (!sdp->sd_lockstruct.ls_ops->lm_get_lock) - return 0; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = sdp->sd_lockstruct.ls_ops->lm_get_lock( - sdp->sd_lockstruct.ls_lockspace, name, lockp); - return error; -} - /** * gfs2_glock_get() - Get a glock, or create one if one doesn't exist * @sdp: The GFS2 superblock @@ -719,10 +684,11 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl = search_bucket(hash, sdp, &name); read_unlock(gl_lock_addr(hash)); - if (gl || !create) { - *glp = gl; + *glp = gl; + if (gl) return 0; - } + if (!create) + return -ENOENT; gl = kmem_cache_alloc(gfs2_glock_cachep, GFP_KERNEL); if (!gl) @@ -736,7 +702,9 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_demote_state = LM_ST_EXCLUSIVE; gl->gl_hash = hash; gl->gl_ops = glops; - gl->gl_stamp = jiffies; + snprintf(gl->gl_strname, GDLM_STRNAME_BYTES, "%8x%16llx", name.ln_type, (unsigned long long)number); + memset(&gl->gl_lksb, 0, sizeof(struct dlm_lksb)); + gl->gl_lksb.sb_lvbptr = gl->gl_lvb; gl->gl_tchange = jiffies; gl->gl_object = NULL; gl->gl_sbd = sdp; @@ -753,10 +721,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, } } - error = gfs2_lm_get_lock(sdp, &name, &gl->gl_lock); - if (error) - goto fail_aspace; - write_lock(gl_lock_addr(hash)); tmp = search_bucket(hash, sdp, &name); if (tmp) { @@ -772,9 +736,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, return 0; -fail_aspace: - if (gl->gl_aspace) - gfs2_aspace_put(gl->gl_aspace); fail: kmem_cache_free(gfs2_glock_cachep, gl); return error; @@ -966,7 +927,7 @@ do_cancel: if (!(gh->gh_flags & LM_FLAG_PRIORITY)) { spin_unlock(&gl->gl_spin); if (sdp->sd_lockstruct.ls_ops->lm_cancel) - sdp->sd_lockstruct.ls_ops->lm_cancel(gl->gl_lock); + sdp->sd_lockstruct.ls_ops->lm_cancel(gl); spin_lock(&gl->gl_spin); } return; @@ -1051,7 +1012,6 @@ void gfs2_glock_dq(struct gfs2_holder *gh) spin_lock(&gl->gl_spin); clear_bit(GLF_LOCK, &gl->gl_flags); } - gl->gl_stamp = jiffies; if (list_empty(&gl->gl_holders) && !test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) && !test_bit(GLF_DEMOTE, &gl->gl_flags)) @@ -1240,70 +1200,13 @@ void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs) gfs2_glock_dq_uninit(&ghs[x]); } -static int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp) -{ - int error = -EIO; - if (!sdp->sd_lockstruct.ls_ops->lm_hold_lvb) - return 0; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp); - return error; -} - -/** - * gfs2_lvb_hold - attach a LVB from a glock - * @gl: The glock in question - * - */ - -int gfs2_lvb_hold(struct gfs2_glock *gl) -{ - int error; - - if (!atomic_read(&gl->gl_lvb_count)) { - error = gfs2_lm_hold_lvb(gl->gl_sbd, gl->gl_lock, &gl->gl_lvb); - if (error) - return error; - gfs2_glock_hold(gl); - } - atomic_inc(&gl->gl_lvb_count); - - return 0; -} - -/** - * gfs2_lvb_unhold - detach a LVB from a glock - * @gl: The glock in question - * - */ - -void gfs2_lvb_unhold(struct gfs2_glock *gl) -{ - struct gfs2_sbd *sdp = gl->gl_sbd; - - gfs2_glock_hold(gl); - gfs2_assert(gl->gl_sbd, atomic_read(&gl->gl_lvb_count) > 0); - if (atomic_dec_and_test(&gl->gl_lvb_count)) { - if (sdp->sd_lockstruct.ls_ops->lm_unhold_lvb) - sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(gl->gl_lock, gl->gl_lvb); - gl->gl_lvb = NULL; - gfs2_glock_put(gl); - } - gfs2_glock_put(gl); -} - -static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name, - unsigned int state) +void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state) { - struct gfs2_glock *gl; unsigned long delay = 0; unsigned long holdtime; unsigned long now = jiffies; - gl = gfs2_glock_find(sdp, name); - if (!gl) - return; - + gfs2_glock_hold(gl); holdtime = gl->gl_tchange + gl->gl_ops->go_min_hold_time; if (time_before(now, holdtime)) delay = holdtime - now; @@ -1317,74 +1220,33 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name, gfs2_glock_put(gl); } -static void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid) -{ - struct gfs2_jdesc *jd; - - spin_lock(&sdp->sd_jindex_spin); - list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { - if (jd->jd_jid != jid) - continue; - jd->jd_dirty = 1; - break; - } - spin_unlock(&sdp->sd_jindex_spin); -} - /** - * gfs2_glock_cb - Callback used by locking module - * @sdp: Pointer to the superblock - * @type: Type of callback - * @data: Type dependent data pointer + * gfs2_glock_complete - Callback used by locking + * @gl: Pointer to the glock + * @ret: The return value from the dlm * - * Called by the locking module when it wants to tell us something. - * Either we need to drop a lock, one of our ASYNC requests completed, or - * a journal from another client needs to be recovered. */ -void gfs2_glock_cb(void *cb_data, unsigned int type, void *data) +void gfs2_glock_complete(struct gfs2_glock *gl, int ret) { - struct gfs2_sbd *sdp = cb_data; - - switch (type) { - case LM_CB_NEED_E: - blocking_cb(sdp, data, LM_ST_UNLOCKED); - return; - - case LM_CB_NEED_D: - blocking_cb(sdp, data, LM_ST_DEFERRED); - return; - - case LM_CB_NEED_S: - blocking_cb(sdp, data, LM_ST_SHARED); - return; - - case LM_CB_ASYNC: { - struct lm_async_cb *async = data; - struct gfs2_glock *gl; - - down_read(&gfs2_umount_flush_sem); - gl = gfs2_glock_find(sdp, &async->lc_name); - if (gfs2_assert_warn(sdp, gl)) + struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; + gl->gl_reply = ret; + if (unlikely(test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags))) { + struct gfs2_holder *gh; + spin_lock(&gl->gl_spin); + gh = find_first_waiter(gl); + if ((!(gh && (gh->gh_flags & LM_FLAG_NOEXP)) && + (gl->gl_target != LM_ST_UNLOCKED)) || + ((ret & ~LM_OUT_ST_MASK) != 0)) + set_bit(GLF_FROZEN, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + if (test_bit(GLF_FROZEN, &gl->gl_flags)) return; - gl->gl_reply = async->lc_ret; - set_bit(GLF_REPLY_PENDING, &gl->gl_flags); - if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) - gfs2_glock_put(gl); - up_read(&gfs2_umount_flush_sem); - return; - } - - case LM_CB_NEED_RECOVERY: - gfs2_jdesc_make_dirty(sdp, *(unsigned int *)data); - if (sdp->sd_recoverd_process) - wake_up_process(sdp->sd_recoverd_process); - return; - - default: - gfs2_assert_warn(sdp, 0); - return; } + set_bit(GLF_REPLY_PENDING, &gl->gl_flags); + gfs2_glock_hold(gl); + if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) + gfs2_glock_put(gl); } /** @@ -1515,6 +1377,25 @@ out: return has_entries; } + +/** + * thaw_glock - thaw out a glock which has an unprocessed reply waiting + * @gl: The glock to thaw + * + * N.B. When we freeze a glock, we leave a ref to the glock outstanding, + * so this has to result in the ref count being dropped by one. + */ + +static void thaw_glock(struct gfs2_glock *gl) +{ + if (!test_and_clear_bit(GLF_FROZEN, &gl->gl_flags)) + return; + set_bit(GLF_REPLY_PENDING, &gl->gl_flags); + gfs2_glock_hold(gl); + if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) + gfs2_glock_put(gl); +} + /** * clear_glock - look at a glock and see if we can free it from glock cache * @gl: the glock to look at @@ -1540,6 +1421,20 @@ static void clear_glock(struct gfs2_glock *gl) } /** + * gfs2_glock_thaw - Thaw any frozen glocks + * @sdp: The super block + * + */ + +void gfs2_glock_thaw(struct gfs2_sbd *sdp) +{ + unsigned x; + + for (x = 0; x < GFS2_GL_HASH_SIZE; x++) + examine_bucket(thaw_glock, sdp, x); +} + +/** * gfs2_gl_hash_clear - Empty out the glock hash table * @sdp: the filesystem * @wait: wait until it's all gone @@ -1619,7 +1514,7 @@ static const char *hflags2str(char *buf, unsigned flags, unsigned long iflags) if (flags & LM_FLAG_NOEXP) *p++ = 'e'; if (flags & LM_FLAG_ANY) - *p++ = 'a'; + *p++ = 'A'; if (flags & LM_FLAG_PRIORITY) *p++ = 'p'; if (flags & GL_ASYNC) @@ -1683,6 +1578,10 @@ static const char *gflags2str(char *buf, const unsigned long *gflags) *p++ = 'i'; if (test_bit(GLF_REPLY_PENDING, gflags)) *p++ = 'r'; + if (test_bit(GLF_INITIAL, gflags)) + *p++ = 'I'; + if (test_bit(GLF_FROZEN, gflags)) + *p++ = 'F'; *p = 0; return buf; } @@ -1717,14 +1616,13 @@ static int __dump_glock(struct seq_file *seq, const struct gfs2_glock *gl) dtime *= 1000000/HZ; /* demote time in uSec */ if (!test_bit(GLF_DEMOTE, &gl->gl_flags)) dtime = 0; - gfs2_print_dbg(seq, "G: s:%s n:%u/%llu f:%s t:%s d:%s/%llu l:%d a:%d r:%d\n", + gfs2_print_dbg(seq, "G: s:%s n:%u/%llu f:%s t:%s d:%s/%llu a:%d r:%d\n", state2str(gl->gl_state), gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number, gflags2str(gflags_buf, &gl->gl_flags), state2str(gl->gl_target), state2str(gl->gl_demote_state), dtime, - atomic_read(&gl->gl_lvb_count), atomic_read(&gl->gl_ail_count), atomic_read(&gl->gl_ref)); diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 543ec7ecfbd..a602a28f6f0 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -11,15 +11,130 @@ #define __GLOCK_DOT_H__ #include <linux/sched.h> +#include <linux/parser.h> #include "incore.h" -/* Flags for lock requests; used in gfs2_holder gh_flag field. - From lm_interface.h: +/* Options for hostdata parser */ + +enum { + Opt_jid, + Opt_id, + Opt_first, + Opt_nodir, + Opt_err, +}; + +/* + * lm_lockname types + */ + +#define LM_TYPE_RESERVED 0x00 +#define LM_TYPE_NONDISK 0x01 +#define LM_TYPE_INODE 0x02 +#define LM_TYPE_RGRP 0x03 +#define LM_TYPE_META 0x04 +#define LM_TYPE_IOPEN 0x05 +#define LM_TYPE_FLOCK 0x06 +#define LM_TYPE_PLOCK 0x07 +#define LM_TYPE_QUOTA 0x08 +#define LM_TYPE_JOURNAL 0x09 + +/* + * lm_lock() states + * + * SHARED is compatible with SHARED, not with DEFERRED or EX. + * DEFERRED is compatible with DEFERRED, not with SHARED or EX. + */ + +#define LM_ST_UNLOCKED 0 +#define LM_ST_EXCLUSIVE 1 +#define LM_ST_DEFERRED 2 +#define LM_ST_SHARED 3 + +/* + * lm_lock() flags + * + * LM_FLAG_TRY + * Don't wait to acquire the lock if it can't be granted immediately. + * + * LM_FLAG_TRY_1CB + * Send one blocking callback if TRY is set and the lock is not granted. + * + * LM_FLAG_NOEXP + * GFS sets this flag on lock requests it makes while doing journal recovery. + * These special requests should not be blocked due to the recovery like + * ordinary locks would be. + * + * LM_FLAG_ANY + * A SHARED request may also be granted in DEFERRED, or a DEFERRED request may + * also be granted in SHARED. The preferred state is whichever is compatible + * with other granted locks, or the specified state if no other locks exist. + * + * LM_FLAG_PRIORITY + * Override fairness considerations. Suppose a lock is held in a shared state + * and there is a pending request for the deferred state. A shared lock + * request with the priority flag would be allowed to bypass the deferred + * request and directly join the other shared lock. A shared lock request + * without the priority flag might be forced to wait until the deferred + * requested had acquired and released the lock. + */ + #define LM_FLAG_TRY 0x00000001 #define LM_FLAG_TRY_1CB 0x00000002 #define LM_FLAG_NOEXP 0x00000004 #define LM_FLAG_ANY 0x00000008 -#define LM_FLAG_PRIORITY 0x00000010 */ +#define LM_FLAG_PRIORITY 0x00000010 +#define GL_ASYNC 0x00000040 +#define GL_EXACT 0x00000080 +#define GL_SKIP 0x00000100 +#define GL_ATIME 0x00000200 +#define GL_NOCACHE 0x00000400 + +/* + * lm_lock() and lm_async_cb return flags + * + * LM_OUT_ST_MASK + * Masks the lower two bits of lock state in the returned value. + * + * LM_OUT_CANCELED + * The lock request was canceled. + * + * LM_OUT_ASYNC + * The result of the request will be returned in an LM_CB_ASYNC callback. + * + */ + +#define LM_OUT_ST_MASK 0x00000003 +#define LM_OUT_CANCELED 0x00000008 +#define LM_OUT_ASYNC 0x00000080 +#define LM_OUT_ERROR 0x00000100 + +/* + * lm_recovery_done() messages + */ + +#define LM_RD_GAVEUP 308 +#define LM_RD_SUCCESS 309 + +#define GLR_TRYFAILED 13 + +struct lm_lockops { + const char *lm_proto_name; + int (*lm_mount) (struct gfs2_sbd *sdp, const char *fsname); + void (*lm_unmount) (struct gfs2_sbd *sdp); + void (*lm_withdraw) (struct gfs2_sbd *sdp); + void (*lm_put_lock) (struct kmem_cache *cachep, void *gl); + unsigned int (*lm_lock) (struct gfs2_glock *gl, + unsigned int req_state, unsigned int flags); + void (*lm_cancel) (struct gfs2_glock *gl); + const match_table_t *lm_tokens; +}; + +#define LM_FLAG_TRY 0x00000001 +#define LM_FLAG_TRY_1CB 0x00000002 +#define LM_FLAG_NOEXP 0x00000004 +#define LM_FLAG_ANY 0x00000008 +#define LM_FLAG_PRIORITY 0x00000010 #define GL_ASYNC 0x00000040 #define GL_EXACT 0x00000080 @@ -128,10 +243,12 @@ static inline int gfs2_glock_nq_init(struct gfs2_glock *gl, int gfs2_lvb_hold(struct gfs2_glock *gl); void gfs2_lvb_unhold(struct gfs2_glock *gl); -void gfs2_glock_cb(void *cb_data, unsigned int type, void *data); +void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state); +void gfs2_glock_complete(struct gfs2_glock *gl, int ret); void gfs2_reclaim_glock(struct gfs2_sbd *sdp); void gfs2_gl_hash_clear(struct gfs2_sbd *sdp); void gfs2_glock_finish_truncate(struct gfs2_inode *ip); +void gfs2_glock_thaw(struct gfs2_sbd *sdp); int __init gfs2_glock_init(void); void gfs2_glock_exit(void); @@ -141,4 +258,6 @@ void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp); int gfs2_register_debugfs(void); void gfs2_unregister_debugfs(void); +extern const struct lm_lockops gfs2_dlm_ops; + #endif /* __GLOCK_DOT_H__ */ diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 8522d3aa64f..bf23a62aa92 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -12,7 +12,6 @@ #include <linux/completion.h> #include <linux/buffer_head.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include <linux/bio.h> #include "gfs2.h" @@ -38,20 +37,25 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) { struct gfs2_sbd *sdp = gl->gl_sbd; - unsigned int blocks; struct list_head *head = &gl->gl_ail_list; struct gfs2_bufdata *bd; struct buffer_head *bh; - int error; + struct gfs2_trans tr; - blocks = atomic_read(&gl->gl_ail_count); - if (!blocks) - return; + memset(&tr, 0, sizeof(tr)); + tr.tr_revokes = atomic_read(&gl->gl_ail_count); - error = gfs2_trans_begin(sdp, 0, blocks); - if (gfs2_assert_withdraw(sdp, !error)) + if (!tr.tr_revokes) return; + /* A shortened, inline version of gfs2_trans_begin() */ + tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64)); + tr.tr_ip = (unsigned long)__builtin_return_address(0); + INIT_LIST_HEAD(&tr.tr_list_buf); + gfs2_log_reserve(sdp, tr.tr_reserved); + BUG_ON(current->journal_info); + current->journal_info = &tr; + gfs2_log_lock(sdp); while (!list_empty(head)) { bd = list_entry(head->next, struct gfs2_bufdata, @@ -72,29 +76,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) } /** - * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock - * @gl: the glock - * - */ - -static void gfs2_pte_inval(struct gfs2_glock *gl) -{ - struct gfs2_inode *ip; - struct inode *inode; - - ip = gl->gl_object; - inode = &ip->i_inode; - if (!ip || !S_ISREG(inode->i_mode)) - return; - - unmap_shared_mapping_range(inode->i_mapping, 0, 0); - if (test_bit(GIF_SW_PAGED, &ip->i_flags)) - set_bit(GLF_DIRTY, &gl->gl_flags); - -} - -/** - * meta_go_sync - sync out the metadata for this glock + * rgrp_go_sync - sync out the metadata for this glock * @gl: the glock * * Called when demoting or unlocking an EX glock. We must flush @@ -102,36 +84,42 @@ static void gfs2_pte_inval(struct gfs2_glock *gl) * not return to caller to demote/unlock the glock until I/O is complete. */ -static void meta_go_sync(struct gfs2_glock *gl) +static void rgrp_go_sync(struct gfs2_glock *gl) { - if (gl->gl_state != LM_ST_EXCLUSIVE) + struct address_space *metamapping = gl->gl_aspace->i_mapping; + int error; + + if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) return; + BUG_ON(gl->gl_state != LM_ST_EXCLUSIVE); - if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) { - gfs2_log_flush(gl->gl_sbd, gl); - gfs2_meta_sync(gl); - gfs2_ail_empty_gl(gl); - } + gfs2_log_flush(gl->gl_sbd, gl); + filemap_fdatawrite(metamapping); + error = filemap_fdatawait(metamapping); + mapping_set_error(metamapping, error); + gfs2_ail_empty_gl(gl); } /** - * meta_go_inval - invalidate the metadata for this glock + * rgrp_go_inval - invalidate the metadata for this glock * @gl: the glock * @flags: * + * We never used LM_ST_DEFERRED with resource groups, so that we + * should always see the metadata flag set here. + * */ -static void meta_go_inval(struct gfs2_glock *gl, int flags) +static void rgrp_go_inval(struct gfs2_glock *gl, int flags) { - if (!(flags & DIO_METADATA)) - return; + struct address_space *mapping = gl->gl_aspace->i_mapping; - gfs2_meta_inval(gl); - if (gl->gl_object == GFS2_I(gl->gl_sbd->sd_rindex)) - gl->gl_sbd->sd_rindex_uptodate = 0; - else if (gl->gl_ops == &gfs2_rgrp_glops && gl->gl_object) { - struct gfs2_rgrpd *rgd = (struct gfs2_rgrpd *)gl->gl_object; + BUG_ON(!(flags & DIO_METADATA)); + gfs2_assert_withdraw(gl->gl_sbd, !atomic_read(&gl->gl_ail_count)); + truncate_inode_pages(mapping, 0); + if (gl->gl_object) { + struct gfs2_rgrpd *rgd = (struct gfs2_rgrpd *)gl->gl_object; rgd->rd_flags &= ~GFS2_RDF_UPTODATE; } } @@ -148,48 +136,54 @@ static void inode_go_sync(struct gfs2_glock *gl) struct address_space *metamapping = gl->gl_aspace->i_mapping; int error; - if (gl->gl_state != LM_ST_UNLOCKED) - gfs2_pte_inval(gl); - if (gl->gl_state != LM_ST_EXCLUSIVE) - return; - if (ip && !S_ISREG(ip->i_inode.i_mode)) ip = NULL; + if (ip && test_and_clear_bit(GIF_SW_PAGED, &ip->i_flags)) + unmap_shared_mapping_range(ip->i_inode.i_mapping, 0, 0); + if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) + return; - if (test_bit(GLF_DIRTY, &gl->gl_flags)) { - gfs2_log_flush(gl->gl_sbd, gl); - filemap_fdatawrite(metamapping); - if (ip) { - struct address_space *mapping = ip->i_inode.i_mapping; - filemap_fdatawrite(mapping); - error = filemap_fdatawait(mapping); - mapping_set_error(mapping, error); - } - error = filemap_fdatawait(metamapping); - mapping_set_error(metamapping, error); - clear_bit(GLF_DIRTY, &gl->gl_flags); - gfs2_ail_empty_gl(gl); + BUG_ON(gl->gl_state != LM_ST_EXCLUSIVE); + + gfs2_log_flush(gl->gl_sbd, gl); + filemap_fdatawrite(metamapping); + if (ip) { + struct address_space *mapping = ip->i_inode.i_mapping; + filemap_fdatawrite(mapping); + error = filemap_fdatawait(mapping); + mapping_set_error(mapping, error); } + error = filemap_fdatawait(metamapping); + mapping_set_error(metamapping, error); + gfs2_ail_empty_gl(gl); } /** * inode_go_inval - prepare a inode glock to be released * @gl: the glock * @flags: + * + * Normally we invlidate everything, but if we are moving into + * LM_ST_DEFERRED from LM_ST_SHARED or LM_ST_EXCLUSIVE then we + * can keep hold of the metadata, since it won't have changed. * */ static void inode_go_inval(struct gfs2_glock *gl, int flags) { struct gfs2_inode *ip = gl->gl_object; - int meta = (flags & DIO_METADATA); - if (meta) { - gfs2_meta_inval(gl); + gfs2_assert_withdraw(gl->gl_sbd, !atomic_read(&gl->gl_ail_count)); + + if (flags & DIO_METADATA) { + struct address_space *mapping = gl->gl_aspace->i_mapping; + truncate_inode_pages(mapping, 0); if (ip) set_bit(GIF_INVALID, &ip->i_flags); } + if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) + gl->gl_sbd->sd_rindex_uptodate = 0; if (ip && S_ISREG(ip->i_inode.i_mode)) truncate_inode_pages(ip->i_inode.i_mapping, 0); } @@ -390,20 +384,7 @@ static int trans_go_demote_ok(const struct gfs2_glock *gl) return 0; } -/** - * quota_go_demote_ok - Check to see if it's ok to unlock a quota glock - * @gl: the glock - * - * Returns: 1 if it's ok - */ - -static int quota_go_demote_ok(const struct gfs2_glock *gl) -{ - return !atomic_read(&gl->gl_lvb_count); -} - const struct gfs2_glock_operations gfs2_meta_glops = { - .go_xmote_th = meta_go_sync, .go_type = LM_TYPE_META, }; @@ -418,8 +399,8 @@ const struct gfs2_glock_operations gfs2_inode_glops = { }; const struct gfs2_glock_operations gfs2_rgrp_glops = { - .go_xmote_th = meta_go_sync, - .go_inval = meta_go_inval, + .go_xmote_th = rgrp_go_sync, + .go_inval = rgrp_go_inval, .go_demote_ok = rgrp_go_demote_ok, .go_lock = rgrp_go_lock, .go_unlock = rgrp_go_unlock, @@ -448,7 +429,6 @@ const struct gfs2_glock_operations gfs2_nondisk_glops = { }; const struct gfs2_glock_operations gfs2_quota_glops = { - .go_demote_ok = quota_go_demote_ok, .go_type = LM_TYPE_QUOTA, }; @@ -456,3 +436,15 @@ const struct gfs2_glock_operations gfs2_journal_glops = { .go_type = LM_TYPE_JOURNAL, }; +const struct gfs2_glock_operations *gfs2_glops_list[] = { + [LM_TYPE_META] = &gfs2_meta_glops, + [LM_TYPE_INODE] = &gfs2_inode_glops, + [LM_TYPE_RGRP] = &gfs2_rgrp_glops, + [LM_TYPE_NONDISK] = &gfs2_trans_glops, + [LM_TYPE_IOPEN] = &gfs2_iopen_glops, + [LM_TYPE_FLOCK] = &gfs2_flock_glops, + [LM_TYPE_NONDISK] = &gfs2_nondisk_glops, + [LM_TYPE_QUOTA] = &gfs2_quota_glops, + [LM_TYPE_JOURNAL] = &gfs2_journal_glops, +}; + diff --git a/fs/gfs2/glops.h b/fs/gfs2/glops.h index a1d9b5b024e..b3aa2e3210f 100644 --- a/fs/gfs2/glops.h +++ b/fs/gfs2/glops.h @@ -21,5 +21,6 @@ extern const struct gfs2_glock_operations gfs2_flock_glops; extern const struct gfs2_glock_operations gfs2_nondisk_glops; extern const struct gfs2_glock_operations gfs2_quota_glops; extern const struct gfs2_glock_operations gfs2_journal_glops; +extern const struct gfs2_glock_operations *gfs2_glops_list[]; #endif /* __GLOPS_DOT_H__ */ diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 608849d0002..399d1b97804 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -12,6 +12,8 @@ #include <linux/fs.h> #include <linux/workqueue.h> +#include <linux/dlm.h> +#include <linux/buffer_head.h> #define DIO_WAIT 0x00000010 #define DIO_METADATA 0x00000020 @@ -26,6 +28,7 @@ struct gfs2_trans; struct gfs2_ail; struct gfs2_jdesc; struct gfs2_sbd; +struct lm_lockops; typedef void (*gfs2_glop_bh_t) (struct gfs2_glock *gl, unsigned int ret); @@ -121,6 +124,28 @@ struct gfs2_bufdata { struct list_head bd_ail_gl_list; }; +/* + * Internally, we prefix things with gdlm_ and GDLM_ (for gfs-dlm) since a + * prefix of lock_dlm_ gets awkward. + */ + +#define GDLM_STRNAME_BYTES 25 +#define GDLM_LVB_SIZE 32 + +enum { + DFL_BLOCK_LOCKS = 0, +}; + +struct lm_lockname { + u64 ln_number; + unsigned int ln_type; +}; + +#define lm_name_equal(name1, name2) \ + (((name1)->ln_number == (name2)->ln_number) && \ + ((name1)->ln_type == (name2)->ln_type)) + + struct gfs2_glock_operations { void (*go_xmote_th) (struct gfs2_glock *gl); int (*go_xmote_bh) (struct gfs2_glock *gl, struct gfs2_holder *gh); @@ -162,6 +187,8 @@ enum { GLF_LFLUSH = 7, GLF_INVALIDATE_IN_PROGRESS = 8, GLF_REPLY_PENDING = 9, + GLF_INITIAL = 10, + GLF_FROZEN = 11, }; struct gfs2_glock { @@ -176,16 +203,15 @@ struct gfs2_glock { unsigned int gl_target; unsigned int gl_reply; unsigned int gl_hash; + unsigned int gl_req; unsigned int gl_demote_state; /* state requested by remote node */ unsigned long gl_demote_time; /* time of first demote request */ struct list_head gl_holders; const struct gfs2_glock_operations *gl_ops; - void *gl_lock; - char *gl_lvb; - atomic_t gl_lvb_count; - - unsigned long gl_stamp; + char gl_strname[GDLM_STRNAME_BYTES]; + struct dlm_lksb gl_lksb; + char gl_lvb[32]; unsigned long gl_tchange; void *gl_object; @@ -283,7 +309,9 @@ enum { struct gfs2_quota_data { struct list_head qd_list; - unsigned int qd_count; + struct list_head qd_reclaim; + + atomic_t qd_count; u32 qd_id; unsigned long qd_flags; /* QDF_... */ @@ -303,7 +331,6 @@ struct gfs2_quota_data { u64 qd_sync_gen; unsigned long qd_last_warn; - unsigned long qd_last_touched; }; struct gfs2_trans { @@ -390,7 +417,7 @@ struct gfs2_args { unsigned int ar_suiddir:1; /* suiddir support */ unsigned int ar_data:2; /* ordered/writeback */ unsigned int ar_meta:1; /* mount metafs */ - unsigned int ar_num_glockd; /* Number of glockd threads */ + unsigned int ar_discard:1; /* discard requests */ }; struct gfs2_tune { @@ -406,7 +433,6 @@ struct gfs2_tune { unsigned int gt_quota_warn_period; /* Secs between quota warn msgs */ unsigned int gt_quota_scale_num; /* Numerator */ unsigned int gt_quota_scale_den; /* Denominator */ - unsigned int gt_quota_cache_secs; unsigned int gt_quota_quantum; /* Secs between syncs to quota file */ unsigned int gt_new_files_jdata; unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */ @@ -445,6 +471,31 @@ struct gfs2_sb_host { char sb_lockproto[GFS2_LOCKNAME_LEN]; char sb_locktable[GFS2_LOCKNAME_LEN]; + u8 sb_uuid[16]; +}; + +/* + * lm_mount() return values + * + * ls_jid - the journal ID this node should use + * ls_first - this node is the first to mount the file system + * ls_lockspace - lock module's context for this file system + * ls_ops - lock module's functions + */ + +struct lm_lockstruct { + u32 ls_id; + unsigned int ls_jid; + unsigned int ls_first; + unsigned int ls_first_done; + unsigned int ls_nodir; + const struct lm_lockops *ls_ops; + unsigned long ls_flags; + dlm_lockspace_t *ls_dlm; + + int ls_recover_jid; + int ls_recover_jid_done; + int ls_recover_jid_status; }; struct gfs2_sbd { @@ -520,7 +571,6 @@ struct gfs2_sbd { spinlock_t sd_jindex_spin; struct mutex sd_jindex_mutex; unsigned int sd_journals; - unsigned long sd_jindex_refresh_time; struct gfs2_jdesc *sd_jdesc; struct gfs2_holder sd_journal_gh; @@ -540,7 +590,6 @@ struct gfs2_sbd { struct list_head sd_quota_list; atomic_t sd_quota_count; - spinlock_t sd_quota_spin; struct mutex sd_quota_mutex; wait_queue_head_t sd_quota_wait; struct list_head sd_trunc_list; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 3b87c188da4..7b277d44915 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -16,7 +16,6 @@ #include <linux/sort.h> #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> -#include <linux/lm_interface.h> #include <linux/security.h> #include <linux/time.h> @@ -137,16 +136,16 @@ void gfs2_set_iop(struct inode *inode) if (S_ISREG(mode)) { inode->i_op = &gfs2_file_iops; - if (sdp->sd_args.ar_localflocks) - inode->i_fop = &gfs2_file_fops_nolock; + if (gfs2_localflocks(sdp)) + inode->i_fop = gfs2_file_fops_nolock; else - inode->i_fop = &gfs2_file_fops; + inode->i_fop = gfs2_file_fops; } else if (S_ISDIR(mode)) { inode->i_op = &gfs2_dir_iops; - if (sdp->sd_args.ar_localflocks) - inode->i_fop = &gfs2_dir_fops_nolock; + if (gfs2_localflocks(sdp)) + inode->i_fop = gfs2_dir_fops_nolock; else - inode->i_fop = &gfs2_dir_fops; + inode->i_fop = gfs2_dir_fops; } else if (S_ISLNK(mode)) { inode->i_op = &gfs2_symlink_iops; } else { diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index d5329364cdf..dca4fee3078 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -101,12 +101,26 @@ void gfs2_dinode_print(const struct gfs2_inode *ip); extern const struct inode_operations gfs2_file_iops; extern const struct inode_operations gfs2_dir_iops; extern const struct inode_operations gfs2_symlink_iops; -extern const struct file_operations gfs2_file_fops; -extern const struct file_operations gfs2_dir_fops; -extern const struct file_operations gfs2_file_fops_nolock; -extern const struct file_operations gfs2_dir_fops_nolock; +extern const struct file_operations *gfs2_file_fops_nolock; +extern const struct file_operations *gfs2_dir_fops_nolock; extern void gfs2_set_inode_flags(struct inode *inode); + +#ifdef CONFIG_GFS2_FS_LOCKING_DLM +extern const struct file_operations *gfs2_file_fops; +extern const struct file_operations *gfs2_dir_fops; +static inline int gfs2_localflocks(const struct gfs2_sbd *sdp) +{ + return sdp->sd_args.ar_localflocks; +} +#else /* Single node only */ +#define gfs2_file_fops NULL +#define gfs2_dir_fops NULL +static inline int gfs2_localflocks(const struct gfs2_sbd *sdp) +{ + return 1; +} +#endif /* CONFIG_GFS2_FS_LOCKING_DLM */ #endif /* __INODE_DOT_H__ */ diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c new file mode 100644 index 00000000000..46df988323b --- /dev/null +++ b/fs/gfs2/lock_dlm.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License version 2. + */ + +#include <linux/fs.h> +#include <linux/dlm.h> +#include <linux/types.h> +#include <linux/gfs2_ondisk.h> + +#include "incore.h" +#include "glock.h" +#include "util.h" + + +static void gdlm_ast(void *arg) +{ + struct gfs2_glock *gl = arg; + unsigned ret = gl->gl_state; + + BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED); + + if (gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID) + memset(gl->gl_lvb, 0, GDLM_LVB_SIZE); + + switch (gl->gl_lksb.sb_status) { + case -DLM_EUNLOCK: /* Unlocked, so glock can be freed */ + kmem_cache_free(gfs2_glock_cachep, gl); + return; + case -DLM_ECANCEL: /* Cancel while getting lock */ + ret |= LM_OUT_CANCELED; + goto out; + case -EAGAIN: /* Try lock fails */ + goto out; + case -EINVAL: /* Invalid */ + case -ENOMEM: /* Out of memory */ + ret |= LM_OUT_ERROR; + goto out; + case 0: /* Success */ + break; + default: /* Something unexpected */ + BUG(); + } + + ret = gl->gl_req; + if (gl->gl_lksb.sb_flags & DLM_SBF_ALTMODE) { + if (gl->gl_req == LM_ST_SHARED) + ret = LM_ST_DEFERRED; + else if (gl->gl_req == LM_ST_DEFERRED) + ret = LM_ST_SHARED; + else + BUG(); + } + + set_bit(GLF_INITIAL, &gl->gl_flags); + gfs2_glock_complete(gl, ret); + return; +out: + if (!test_bit(GLF_INITIAL, &gl->gl_flags)) + gl->gl_lksb.sb_lkid = 0; + gfs2_glock_complete(gl, ret); +} + +static void gdlm_bast(void *arg, int mode) +{ + struct gfs2_glock *gl = arg; + + switch (mode) { + case DLM_LOCK_EX: + gfs2_glock_cb(gl, LM_ST_UNLOCKED); + break; + case DLM_LOCK_CW: + gfs2_glock_cb(gl, LM_ST_DEFERRED); + break; + case DLM_LOCK_PR: + gfs2_glock_cb(gl, LM_ST_SHARED); + break; + default: + printk(KERN_ERR "unknown bast mode %d", mode); + BUG(); + } +} + +/* convert gfs lock-state to dlm lock-mode */ + +static int make_mode(const unsigned int lmstate) +{ + switch (lmstate) { + case LM_ST_UNLOCKED: + return DLM_LOCK_NL; + case LM_ST_EXCLUSIVE: + return DLM_LOCK_EX; + case LM_ST_DEFERRED: + return DLM_LOCK_CW; + case LM_ST_SHARED: + return DLM_LOCK_PR; + } + printk(KERN_ERR "unknown LM state %d", lmstate); + BUG(); + return -1; +} + +static u32 make_flags(const u32 lkid, const unsigned int gfs_flags, + const int req) +{ + u32 lkf = 0; + + if (gfs_flags & LM_FLAG_TRY) + lkf |= DLM_LKF_NOQUEUE; + + if (gfs_flags & LM_FLAG_TRY_1CB) { + lkf |= DLM_LKF_NOQUEUE; + lkf |= DLM_LKF_NOQUEUEBAST; + } + + if (gfs_flags & LM_FLAG_PRIORITY) { + lkf |= DLM_LKF_NOORDER; + lkf |= DLM_LKF_HEADQUE; + } + + if (gfs_flags & LM_FLAG_ANY) { + if (req == DLM_LOCK_PR) + lkf |= DLM_LKF_ALTCW; + else if (req == DLM_LOCK_CW) + lkf |= DLM_LKF_ALTPR; + else + BUG(); + } + + if (lkid != 0) + lkf |= DLM_LKF_CONVERT; + + lkf |= DLM_LKF_VALBLK; + + return lkf; +} + +static unsigned int gdlm_lock(struct gfs2_glock *gl, + unsigned int req_state, unsigned int flags) +{ + struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; + int error; + int req; + u32 lkf; + + gl->gl_req = req_state; + req = make_mode(req_state); + lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req); + + /* + * Submit the actual lock request. + */ + + error = dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname, + GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast); + if (error == -EAGAIN) + return 0; + if (error) + return LM_OUT_ERROR; + return LM_OUT_ASYNC; +} + +static void gdlm_put_lock(struct kmem_cache *cachep, void *ptr) +{ + struct gfs2_glock *gl = ptr; + struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; + int error; + + if (gl->gl_lksb.sb_lkid == 0) { + kmem_cache_free(cachep, gl); + return; + } + + error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK, + NULL, gl); + if (error) { + printk(KERN_ERR "gdlm_unlock %x,%llx err=%d\n", + gl->gl_name.ln_type, + (unsigned long long)gl->gl_name.ln_number, error); + return; + } +} + +static void gdlm_cancel(struct gfs2_glock *gl) +{ + struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; + dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_CANCEL, NULL, gl); +} + +static int gdlm_mount(struct gfs2_sbd *sdp, const char *fsname) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + int error; + + if (fsname == NULL) { + fs_info(sdp, "no fsname found\n"); + return -EINVAL; + } + + error = dlm_new_lockspace(fsname, strlen(fsname), &ls->ls_dlm, + DLM_LSFL_FS | DLM_LSFL_NEWEXCL | + (ls->ls_nodir ? DLM_LSFL_NODIR : 0), + GDLM_LVB_SIZE); + if (error) + printk(KERN_ERR "dlm_new_lockspace error %d", error); + + return error; +} + +static void gdlm_unmount(struct gfs2_sbd *sdp) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + + if (ls->ls_dlm) { + dlm_release_lockspace(ls->ls_dlm, 2); + ls->ls_dlm = NULL; + } +} + +static const match_table_t dlm_tokens = { + { Opt_jid, "jid=%d"}, + { Opt_id, "id=%d"}, + { Opt_first, "first=%d"}, + { Opt_nodir, "nodir=%d"}, + { Opt_err, NULL }, +}; + +const struct lm_lockops gfs2_dlm_ops = { + .lm_proto_name = "lock_dlm", + .lm_mount = gdlm_mount, + .lm_unmount = gdlm_unmount, + .lm_put_lock = gdlm_put_lock, + .lm_lock = gdlm_lock, + .lm_cancel = gdlm_cancel, + .lm_tokens = &dlm_tokens, +}; + diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c deleted file mode 100644 index 523243a13a2..00000000000 --- a/fs/gfs2/locking.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/wait.h> -#include <linux/sched.h> -#include <linux/kmod.h> -#include <linux/fs.h> -#include <linux/delay.h> -#include <linux/lm_interface.h> - -struct lmh_wrapper { - struct list_head lw_list; - const struct lm_lockops *lw_ops; -}; - -static int nolock_mount(char *table_name, char *host_data, - lm_callback_t cb, void *cb_data, - unsigned int min_lvb_size, int flags, - struct lm_lockstruct *lockstruct, - struct kobject *fskobj); - -/* List of registered low-level locking protocols. A file system selects one - of them by name at mount time, e.g. lock_nolock, lock_dlm. */ - -static const struct lm_lockops nolock_ops = { - .lm_proto_name = "lock_nolock", - .lm_mount = nolock_mount, -}; - -static struct lmh_wrapper nolock_proto = { - .lw_list = LIST_HEAD_INIT(nolock_proto.lw_list), - .lw_ops = &nolock_ops, -}; - -static LIST_HEAD(lmh_list); -static DEFINE_MUTEX(lmh_lock); - -static int nolock_mount(char *table_name, char *host_data, - lm_callback_t cb, void *cb_data, - unsigned int min_lvb_size, int flags, - struct lm_lockstruct *lockstruct, - struct kobject *fskobj) -{ - char *c; - unsigned int jid; - - c = strstr(host_data, "jid="); - if (!c) - jid = 0; - else { - c += 4; - sscanf(c, "%u", &jid); - } - - lockstruct->ls_jid = jid; - lockstruct->ls_first = 1; - lockstruct->ls_lvb_size = min_lvb_size; - lockstruct->ls_ops = &nolock_ops; - lockstruct->ls_flags = LM_LSFLAG_LOCAL; - - return 0; -} - -/** - * gfs2_register_lockproto - Register a low-level locking protocol - * @proto: the protocol definition - * - * Returns: 0 on success, -EXXX on failure - */ - -int gfs2_register_lockproto(const struct lm_lockops *proto) -{ - struct lmh_wrapper *lw; - - mutex_lock(&lmh_lock); - - list_for_each_entry(lw, &lmh_list, lw_list) { - if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) { - mutex_unlock(&lmh_lock); - printk(KERN_INFO "GFS2: protocol %s already exists\n", - proto->lm_proto_name); - return -EEXIST; - } - } - - lw = kzalloc(sizeof(struct lmh_wrapper), GFP_KERNEL); - if (!lw) { - mutex_unlock(&lmh_lock); - return -ENOMEM; - } - - lw->lw_ops = proto; - list_add(&lw->lw_list, &lmh_list); - - mutex_unlock(&lmh_lock); - - return 0; -} - -/** - * gfs2_unregister_lockproto - Unregister a low-level locking protocol - * @proto: the protocol definition - * - */ - -void gfs2_unregister_lockproto(const struct lm_lockops *proto) -{ - struct lmh_wrapper *lw; - - mutex_lock(&lmh_lock); - - list_for_each_entry(lw, &lmh_list, lw_list) { - if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) { - list_del(&lw->lw_list); - mutex_unlock(&lmh_lock); - kfree(lw); - return; - } - } - - mutex_unlock(&lmh_lock); - - printk(KERN_WARNING "GFS2: can't unregister lock protocol %s\n", - proto->lm_proto_name); -} - -/** - * gfs2_mount_lockproto - Mount a lock protocol - * @proto_name - the name of the protocol - * @table_name - the name of the lock space - * @host_data - data specific to this host - * @cb - the callback to the code using the lock module - * @sdp - The GFS2 superblock - * @min_lvb_size - the mininum LVB size that the caller can deal with - * @flags - LM_MFLAG_* - * @lockstruct - a structure returned describing the mount - * - * Returns: 0 on success, -EXXX on failure - */ - -int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data, - lm_callback_t cb, void *cb_data, - unsigned int min_lvb_size, int flags, - struct lm_lockstruct *lockstruct, - struct kobject *fskobj) -{ - struct lmh_wrapper *lw = NULL; - int try = 0; - int error, found; - - -retry: - mutex_lock(&lmh_lock); - - if (list_empty(&nolock_proto.lw_list)) - list_add(&nolock_proto.lw_list, &lmh_list); - - found = 0; - list_for_each_entry(lw, &lmh_list, lw_list) { - if (!strcmp(lw->lw_ops->lm_proto_name, proto_name)) { - found = 1; - break; - } - } - - if (!found) { - if (!try && capable(CAP_SYS_MODULE)) { - try = 1; - mutex_unlock(&lmh_lock); - request_module(proto_name); - goto retry; - } - printk(KERN_INFO "GFS2: can't find protocol %s\n", proto_name); - error = -ENOENT; - goto out; - } - - if (lw->lw_ops->lm_owner && - !try_module_get(lw->lw_ops->lm_owner)) { - try = 0; - mutex_unlock(&lmh_lock); - msleep(1000); - goto retry; - } - - error = lw->lw_ops->lm_mount(table_name, host_data, cb, cb_data, - min_lvb_size, flags, lockstruct, fskobj); - if (error) - module_put(lw->lw_ops->lm_owner); -out: - mutex_unlock(&lmh_lock); - return error; -} - -void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct) -{ - mutex_lock(&lmh_lock); - if (lockstruct->ls_ops->lm_unmount) - lockstruct->ls_ops->lm_unmount(lockstruct->ls_lockspace); - if (lockstruct->ls_ops->lm_owner) - module_put(lockstruct->ls_ops->lm_owner); - mutex_unlock(&lmh_lock); -} - -/** - * gfs2_withdraw_lockproto - abnormally unmount a lock module - * @lockstruct: the lockstruct passed into mount - * - */ - -void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct) -{ - mutex_lock(&lmh_lock); - lockstruct->ls_ops->lm_withdraw(lockstruct->ls_lockspace); - if (lockstruct->ls_ops->lm_owner) - module_put(lockstruct->ls_ops->lm_owner); - mutex_unlock(&lmh_lock); -} - -EXPORT_SYMBOL_GPL(gfs2_register_lockproto); -EXPORT_SYMBOL_GPL(gfs2_unregister_lockproto); - diff --git a/fs/gfs2/locking/dlm/Makefile b/fs/gfs2/locking/dlm/Makefile deleted file mode 100644 index 2609bb6cd01..00000000000 --- a/fs/gfs2/locking/dlm/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o -lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o - diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c deleted file mode 100644 index 2482c904750..00000000000 --- a/fs/gfs2/locking/dlm/lock.c +++ /dev/null @@ -1,708 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#include "lock_dlm.h" - -static char junk_lvb[GDLM_LVB_SIZE]; - - -/* convert dlm lock-mode to gfs lock-state */ - -static s16 gdlm_make_lmstate(s16 dlmmode) -{ - switch (dlmmode) { - case DLM_LOCK_IV: - case DLM_LOCK_NL: - return LM_ST_UNLOCKED; - case DLM_LOCK_EX: - return LM_ST_EXCLUSIVE; - case DLM_LOCK_CW: - return LM_ST_DEFERRED; - case DLM_LOCK_PR: - return LM_ST_SHARED; - } - gdlm_assert(0, "unknown DLM mode %d", dlmmode); - return -1; -} - -/* A lock placed on this queue is re-submitted to DLM as soon as the lock_dlm - thread gets to it. */ - -static void queue_submit(struct gdlm_lock *lp) -{ - struct gdlm_ls *ls = lp->ls; - - spin_lock(&ls->async_lock); - list_add_tail(&lp->delay_list, &ls->submit); - spin_unlock(&ls->async_lock); - wake_up(&ls->thread_wait); -} - -static void wake_up_ast(struct gdlm_lock *lp) -{ - clear_bit(LFL_AST_WAIT, &lp->flags); - smp_mb__after_clear_bit(); - wake_up_bit(&lp->flags, LFL_AST_WAIT); -} - -static void gdlm_delete_lp(struct gdlm_lock *lp) -{ - struct gdlm_ls *ls = lp->ls; - - spin_lock(&ls->async_lock); - if (!list_empty(&lp->delay_list)) - list_del_init(&lp->delay_list); - ls->all_locks_count--; - spin_unlock(&ls->async_lock); - - kfree(lp); -} - -static void gdlm_queue_delayed(struct gdlm_lock *lp) -{ - struct gdlm_ls *ls = lp->ls; - - spin_lock(&ls->async_lock); - list_add_tail(&lp->delay_list, &ls->delayed); - spin_unlock(&ls->async_lock); -} - -static void process_complete(struct gdlm_lock *lp) -{ - struct gdlm_ls *ls = lp->ls; - struct lm_async_cb acb; - - memset(&acb, 0, sizeof(acb)); - - if (lp->lksb.sb_status == -DLM_ECANCEL) { - log_info("complete dlm cancel %x,%llx flags %lx", - lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number, - lp->flags); - - lp->req = lp->cur; - acb.lc_ret |= LM_OUT_CANCELED; - if (lp->cur == DLM_LOCK_IV) - lp->lksb.sb_lkid = 0; - goto out; - } - - if (test_and_clear_bit(LFL_DLM_UNLOCK, &lp->flags)) { - if (lp->lksb.sb_status != -DLM_EUNLOCK) { - log_info("unlock sb_status %d %x,%llx flags %lx", - lp->lksb.sb_status, lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number, - lp->flags); - return; - } - - lp->cur = DLM_LOCK_IV; - lp->req = DLM_LOCK_IV; - lp->lksb.sb_lkid = 0; - - if (test_and_clear_bit(LFL_UNLOCK_DELETE, &lp->flags)) { - gdlm_delete_lp(lp); - return; - } - goto out; - } - - if (lp->lksb.sb_flags & DLM_SBF_VALNOTVALID) - memset(lp->lksb.sb_lvbptr, 0, GDLM_LVB_SIZE); - - if (lp->lksb.sb_flags & DLM_SBF_ALTMODE) { - if (lp->req == DLM_LOCK_PR) - lp->req = DLM_LOCK_CW; - else if (lp->req == DLM_LOCK_CW) - lp->req = DLM_LOCK_PR; - } - - /* - * A canceled lock request. The lock was just taken off the delayed - * list and was never even submitted to dlm. - */ - - if (test_and_clear_bit(LFL_CANCEL, &lp->flags)) { - log_info("complete internal cancel %x,%llx", - lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number); - lp->req = lp->cur; - acb.lc_ret |= LM_OUT_CANCELED; - goto out; - } - - /* - * An error occured. - */ - - if (lp->lksb.sb_status) { - /* a "normal" error */ - if ((lp->lksb.sb_status == -EAGAIN) && - (lp->lkf & DLM_LKF_NOQUEUE)) { - lp->req = lp->cur; - if (lp->cur == DLM_LOCK_IV) - lp->lksb.sb_lkid = 0; - goto out; - } - - /* this could only happen with cancels I think */ - log_info("ast sb_status %d %x,%llx flags %lx", - lp->lksb.sb_status, lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number, - lp->flags); - return; - } - - /* - * This is an AST for an EX->EX conversion for sync_lvb from GFS. - */ - - if (test_and_clear_bit(LFL_SYNC_LVB, &lp->flags)) { - wake_up_ast(lp); - return; - } - - /* - * A lock has been demoted to NL because it initially completed during - * BLOCK_LOCKS. Now it must be requested in the originally requested - * mode. - */ - - if (test_and_clear_bit(LFL_REREQUEST, &lp->flags)) { - gdlm_assert(lp->req == DLM_LOCK_NL, "%x,%llx", - lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number); - gdlm_assert(lp->prev_req > DLM_LOCK_NL, "%x,%llx", - lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number); - - lp->cur = DLM_LOCK_NL; - lp->req = lp->prev_req; - lp->prev_req = DLM_LOCK_IV; - lp->lkf &= ~DLM_LKF_CONVDEADLK; - - set_bit(LFL_NOCACHE, &lp->flags); - - if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) && - !test_bit(LFL_NOBLOCK, &lp->flags)) - gdlm_queue_delayed(lp); - else - queue_submit(lp); - return; - } - - /* - * A request is granted during dlm recovery. It may be granted - * because the locks of a failed node were cleared. In that case, - * there may be inconsistent data beneath this lock and we must wait - * for recovery to complete to use it. When gfs recovery is done this - * granted lock will be converted to NL and then reacquired in this - * granted state. - */ - - if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) && - !test_bit(LFL_NOBLOCK, &lp->flags) && - lp->req != DLM_LOCK_NL) { - - lp->cur = lp->req; - lp->prev_req = lp->req; - lp->req = DLM_LOCK_NL; - lp->lkf |= DLM_LKF_CONVERT; - lp->lkf &= ~DLM_LKF_CONVDEADLK; - - log_debug("rereq %x,%llx id %x %d,%d", - lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number, - lp->lksb.sb_lkid, lp->cur, lp->req); - - set_bit(LFL_REREQUEST, &lp->flags); - queue_submit(lp); - return; - } - - /* - * DLM demoted the lock to NL before it was granted so GFS must be - * told it cannot cache data for this lock. - */ - - if (lp->lksb.sb_flags & DLM_SBF_DEMOTED) - set_bit(LFL_NOCACHE, &lp->flags); - -out: - /* - * This is an internal lock_dlm lock - */ - - if (test_bit(LFL_INLOCK, &lp->flags)) { - clear_bit(LFL_NOBLOCK, &lp->flags); - lp->cur = lp->req; - wake_up_ast(lp); - return; - } - - /* - * Normal completion of a lock request. Tell GFS it now has the lock. - */ - - clear_bit(LFL_NOBLOCK, &lp->flags); - lp->cur = lp->req; - - acb.lc_name = lp->lockname; - acb.lc_ret |= gdlm_make_lmstate(lp->cur); - - ls->fscb(ls->sdp, LM_CB_ASYNC, &acb); -} - -static void gdlm_ast(void *astarg) -{ - struct gdlm_lock *lp = astarg; - clear_bit(LFL_ACTIVE, &lp->flags); - process_complete(lp); -} - -static void process_blocking(struct gdlm_lock *lp, int bast_mode) -{ - struct gdlm_ls *ls = lp->ls; - unsigned int cb = 0; - - switch (gdlm_make_lmstate(bast_mode)) { - case LM_ST_EXCLUSIVE: - cb = LM_CB_NEED_E; - break; - case LM_ST_DEFERRED: - cb = LM_CB_NEED_D; - break; - case LM_ST_SHARED: - cb = LM_CB_NEED_S; - break; - default: - gdlm_assert(0, "unknown bast mode %u", bast_mode); - } - - ls->fscb(ls->sdp, cb, &lp->lockname); -} - - -static void gdlm_bast(void *astarg, int mode) -{ - struct gdlm_lock *lp = astarg; - - if (!mode) { - printk(KERN_INFO "lock_dlm: bast mode zero %x,%llx\n", - lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number); - return; - } - - process_blocking(lp, mode); -} - -/* convert gfs lock-state to dlm lock-mode */ - -static s16 make_mode(s16 lmstate) -{ - switch (lmstate) { - case LM_ST_UNLOCKED: - return DLM_LOCK_NL; - case LM_ST_EXCLUSIVE: - return DLM_LOCK_EX; - case LM_ST_DEFERRED: - return DLM_LOCK_CW; - case LM_ST_SHARED: - return DLM_LOCK_PR; - } - gdlm_assert(0, "unknown LM state %d", lmstate); - return -1; -} - - -/* verify agreement with GFS on the current lock state, NB: DLM_LOCK_NL and - DLM_LOCK_IV are both considered LM_ST_UNLOCKED by GFS. */ - -static void check_cur_state(struct gdlm_lock *lp, unsigned int cur_state) -{ - s16 cur = make_mode(cur_state); - if (lp->cur != DLM_LOCK_IV) - gdlm_assert(lp->cur == cur, "%d, %d", lp->cur, cur); -} - -static inline unsigned int make_flags(struct gdlm_lock *lp, - unsigned int gfs_flags, - s16 cur, s16 req) -{ - unsigned int lkf = 0; - - if (gfs_flags & LM_FLAG_TRY) - lkf |= DLM_LKF_NOQUEUE; - - if (gfs_flags & LM_FLAG_TRY_1CB) { - lkf |= DLM_LKF_NOQUEUE; - lkf |= DLM_LKF_NOQUEUEBAST; - } - - if (gfs_flags & LM_FLAG_PRIORITY) { - lkf |= DLM_LKF_NOORDER; - lkf |= DLM_LKF_HEADQUE; - } - - if (gfs_flags & LM_FLAG_ANY) { - if (req == DLM_LOCK_PR) - lkf |= DLM_LKF_ALTCW; - else if (req == DLM_LOCK_CW) - lkf |= DLM_LKF_ALTPR; - } - - if (lp->lksb.sb_lkid != 0) { - lkf |= DLM_LKF_CONVERT; - } - - if (lp->lvb) - lkf |= DLM_LKF_VALBLK; - - return lkf; -} - -/* make_strname - convert GFS lock numbers to a string */ - -static inline void make_strname(const struct lm_lockname *lockname, - struct gdlm_strname *str) -{ - sprintf(str->name, "%8x%16llx", lockname->ln_type, - (unsigned long long)lockname->ln_number); - str->namelen = GDLM_STRNAME_BYTES; -} - -static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name, - struct gdlm_lock **lpp) -{ - struct gdlm_lock *lp; - - lp = kzalloc(sizeof(struct gdlm_lock), GFP_NOFS); - if (!lp) - return -ENOMEM; - - lp->lockname = *name; - make_strname(name, &lp->strname); - lp->ls = ls; - lp->cur = DLM_LOCK_IV; - INIT_LIST_HEAD(&lp->delay_list); - - spin_lock(&ls->async_lock); - ls->all_locks_count++; - spin_unlock(&ls->async_lock); - - *lpp = lp; - return 0; -} - -int gdlm_get_lock(void *lockspace, struct lm_lockname *name, - void **lockp) -{ - struct gdlm_lock *lp; - int error; - - error = gdlm_create_lp(lockspace, name, &lp); - - *lockp = lp; - return error; -} - -void gdlm_put_lock(void *lock) -{ - gdlm_delete_lp(lock); -} - -unsigned int gdlm_do_lock(struct gdlm_lock *lp) -{ - struct gdlm_ls *ls = lp->ls; - int error, bast = 1; - - /* - * When recovery is in progress, delay lock requests for submission - * once recovery is done. Requests for recovery (NOEXP) and unlocks - * can pass. - */ - - if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) && - !test_bit(LFL_NOBLOCK, &lp->flags) && lp->req != DLM_LOCK_NL) { - gdlm_queue_delayed(lp); - return LM_OUT_ASYNC; - } - - /* - * Submit the actual lock request. - */ - - if (test_bit(LFL_NOBAST, &lp->flags)) - bast = 0; - - set_bit(LFL_ACTIVE, &lp->flags); - - log_debug("lk %x,%llx id %x %d,%d %x", lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number, lp->lksb.sb_lkid, - lp->cur, lp->req, lp->lkf); - - error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf, - lp->strname.name, lp->strname.namelen, 0, gdlm_ast, - lp, bast ? gdlm_bast : NULL); - - if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) { - lp->lksb.sb_status = -EAGAIN; - gdlm_ast(lp); - error = 0; - } - - if (error) { - log_error("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x " - "flags=%lx", ls->fsname, lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number, error, - lp->cur, lp->req, lp->lkf, lp->flags); - return LM_OUT_ERROR; - } - return LM_OUT_ASYNC; -} - -static unsigned int gdlm_do_unlock(struct gdlm_lock *lp) -{ - struct gdlm_ls *ls = lp->ls; - unsigned int lkf = 0; - int error; - - set_bit(LFL_DLM_UNLOCK, &lp->flags); - set_bit(LFL_ACTIVE, &lp->flags); - - if (lp->lvb) - lkf = DLM_LKF_VALBLK; - - log_debug("un %x,%llx %x %d %x", lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number, - lp->lksb.sb_lkid, lp->cur, lkf); - - error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, lkf, NULL, lp); - - if (error) { - log_error("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x " - "flags=%lx", ls->fsname, lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number, error, - lp->cur, lp->req, lp->lkf, lp->flags); - return LM_OUT_ERROR; - } - return LM_OUT_ASYNC; -} - -unsigned int gdlm_lock(void *lock, unsigned int cur_state, - unsigned int req_state, unsigned int flags) -{ - struct gdlm_lock *lp = lock; - - if (req_state == LM_ST_UNLOCKED) - return gdlm_unlock(lock, cur_state); - - if (req_state == LM_ST_UNLOCKED) - return gdlm_unlock(lock, cur_state); - - clear_bit(LFL_DLM_CANCEL, &lp->flags); - if (flags & LM_FLAG_NOEXP) - set_bit(LFL_NOBLOCK, &lp->flags); - - check_cur_state(lp, cur_state); - lp->req = make_mode(req_state); - lp->lkf = make_flags(lp, flags, lp->cur, lp->req); - - return gdlm_do_lock(lp); -} - -unsigned int gdlm_unlock(void *lock, unsigned int cur_state) -{ - struct gdlm_lock *lp = lock; - - clear_bit(LFL_DLM_CANCEL, &lp->flags); - if (lp->cur == DLM_LOCK_IV) - return 0; - return gdlm_do_unlock(lp); -} - -void gdlm_cancel(void *lock) -{ - struct gdlm_lock *lp = lock; - struct gdlm_ls *ls = lp->ls; - int error, delay_list = 0; - - if (test_bit(LFL_DLM_CANCEL, &lp->flags)) - return; - - log_info("gdlm_cancel %x,%llx flags %lx", lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number, lp->flags); - - spin_lock(&ls->async_lock); - if (!list_empty(&lp->delay_list)) { - list_del_init(&lp->delay_list); - delay_list = 1; - } - spin_unlock(&ls->async_lock); - - if (delay_list) { - set_bit(LFL_CANCEL, &lp->flags); - set_bit(LFL_ACTIVE, &lp->flags); - gdlm_ast(lp); - return; - } - - if (!test_bit(LFL_ACTIVE, &lp->flags) || - test_bit(LFL_DLM_UNLOCK, &lp->flags)) { - log_info("gdlm_cancel skip %x,%llx flags %lx", - lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number, lp->flags); - return; - } - - /* the lock is blocked in the dlm */ - - set_bit(LFL_DLM_CANCEL, &lp->flags); - set_bit(LFL_ACTIVE, &lp->flags); - - error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, DLM_LKF_CANCEL, - NULL, lp); - - log_info("gdlm_cancel rv %d %x,%llx flags %lx", error, - lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number, lp->flags); - - if (error == -EBUSY) - clear_bit(LFL_DLM_CANCEL, &lp->flags); -} - -static int gdlm_add_lvb(struct gdlm_lock *lp) -{ - char *lvb; - - lvb = kzalloc(GDLM_LVB_SIZE, GFP_NOFS); - if (!lvb) - return -ENOMEM; - - lp->lksb.sb_lvbptr = lvb; - lp->lvb = lvb; - return 0; -} - -static void gdlm_del_lvb(struct gdlm_lock *lp) -{ - kfree(lp->lvb); - lp->lvb = NULL; - lp->lksb.sb_lvbptr = NULL; -} - -static int gdlm_ast_wait(void *word) -{ - schedule(); - return 0; -} - -/* This can do a synchronous dlm request (requiring a lock_dlm thread to get - the completion) because gfs won't call hold_lvb() during a callback (from - the context of a lock_dlm thread). */ - -static int hold_null_lock(struct gdlm_lock *lp) -{ - struct gdlm_lock *lpn = NULL; - int error; - - if (lp->hold_null) { - printk(KERN_INFO "lock_dlm: lvb already held\n"); - return 0; - } - - error = gdlm_create_lp(lp->ls, &lp->lockname, &lpn); - if (error) - goto out; - - lpn->lksb.sb_lvbptr = junk_lvb; - lpn->lvb = junk_lvb; - - lpn->req = DLM_LOCK_NL; - lpn->lkf = DLM_LKF_VALBLK | DLM_LKF_EXPEDITE; - set_bit(LFL_NOBAST, &lpn->flags); - set_bit(LFL_INLOCK, &lpn->flags); - set_bit(LFL_AST_WAIT, &lpn->flags); - - gdlm_do_lock(lpn); - wait_on_bit(&lpn->flags, LFL_AST_WAIT, gdlm_ast_wait, TASK_UNINTERRUPTIBLE); - error = lpn->lksb.sb_status; - if (error) { - printk(KERN_INFO "lock_dlm: hold_null_lock dlm error %d\n", - error); - gdlm_delete_lp(lpn); - lpn = NULL; - } -out: - lp->hold_null = lpn; - return error; -} - -/* This cannot do a synchronous dlm request (requiring a lock_dlm thread to get - the completion) because gfs may call unhold_lvb() during a callback (from - the context of a lock_dlm thread) which could cause a deadlock since the - other lock_dlm thread could be engaged in recovery. */ - -static void unhold_null_lock(struct gdlm_lock *lp) -{ - struct gdlm_lock *lpn = lp->hold_null; - - gdlm_assert(lpn, "%x,%llx", lp->lockname.ln_type, - (unsigned long long)lp->lockname.ln_number); - lpn->lksb.sb_lvbptr = NULL; - lpn->lvb = NULL; - set_bit(LFL_UNLOCK_DELETE, &lpn->flags); - gdlm_do_unlock(lpn); - lp->hold_null = NULL; -} - -/* Acquire a NL lock because gfs requires the value block to remain - intact on the resource while the lvb is "held" even if it's holding no locks - on the resource. */ - -int gdlm_hold_lvb(void *lock, char **lvbp) -{ - struct gdlm_lock *lp = lock; - int error; - - error = gdlm_add_lvb(lp); - if (error) - return error; - - *lvbp = lp->lvb; - - error = hold_null_lock(lp); - if (error) - gdlm_del_lvb(lp); - - return error; -} - -void gdlm_unhold_lvb(void *lock, char *lvb) -{ - struct gdlm_lock *lp = lock; - - unhold_null_lock(lp); - gdlm_del_lvb(lp); -} - -void gdlm_submit_delayed(struct gdlm_ls *ls) -{ - struct gdlm_lock *lp, *safe; - - spin_lock(&ls->async_lock); - list_for_each_entry_safe(lp, safe, &ls->delayed, delay_list) { - list_del_init(&lp->delay_list); - list_add_tail(&lp->delay_list, &ls->submit); - } - spin_unlock(&ls->async_lock); - wake_up(&ls->thread_wait); -} - diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h deleted file mode 100644 index 3c98e7c6f93..00000000000 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#ifndef LOCK_DLM_DOT_H -#define LOCK_DLM_DOT_H - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/list.h> -#include <linux/socket.h> -#include <linux/delay.h> -#include <linux/kthread.h> -#include <linux/kobject.h> -#include <linux/fcntl.h> -#include <linux/wait.h> -#include <net/sock.h> - -#include <linux/dlm.h> -#include <linux/dlm_plock.h> -#include <linux/lm_interface.h> - -/* - * Internally, we prefix things with gdlm_ and GDLM_ (for gfs-dlm) since a - * prefix of lock_dlm_ gets awkward. Externally, GFS refers to this module - * as "lock_dlm". - */ - -#define GDLM_STRNAME_BYTES 24 -#define GDLM_LVB_SIZE 32 -#define GDLM_DROP_COUNT 0 -#define GDLM_DROP_PERIOD 60 -#define GDLM_NAME_LEN 128 - -/* GFS uses 12 bytes to identify a resource (32 bit type + 64 bit number). - We sprintf these numbers into a 24 byte string of hex values to make them - human-readable (to make debugging simpler.) */ - -struct gdlm_strname { - unsigned char name[GDLM_STRNAME_BYTES]; - unsigned short namelen; -}; - -enum { - DFL_BLOCK_LOCKS = 0, - DFL_SPECTATOR = 1, - DFL_WITHDRAW = 2, -}; - -struct gdlm_ls { - u32 id; - int jid; - int first; - int first_done; - unsigned long flags; - struct kobject kobj; - char clustername[GDLM_NAME_LEN]; - char fsname[GDLM_NAME_LEN]; - int fsflags; - dlm_lockspace_t *dlm_lockspace; - lm_callback_t fscb; - struct gfs2_sbd *sdp; - int recover_jid; - int recover_jid_done; - int recover_jid_status; - spinlock_t async_lock; - struct list_head delayed; - struct list_head submit; - u32 all_locks_count; - wait_queue_head_t wait_control; - struct task_struct *thread; - wait_queue_head_t thread_wait; -}; - -enum { - LFL_NOBLOCK = 0, - LFL_NOCACHE = 1, - LFL_DLM_UNLOCK = 2, - LFL_DLM_CANCEL = 3, - LFL_SYNC_LVB = 4, - LFL_FORCE_PROMOTE = 5, - LFL_REREQUEST = 6, - LFL_ACTIVE = 7, - LFL_INLOCK = 8, - LFL_CANCEL = 9, - LFL_NOBAST = 10, - LFL_HEADQUE = 11, - LFL_UNLOCK_DELETE = 12, - LFL_AST_WAIT = 13, -}; - -struct gdlm_lock { - struct gdlm_ls *ls; - struct lm_lockname lockname; - struct gdlm_strname strname; - char *lvb; - struct dlm_lksb lksb; - - s16 cur; - s16 req; - s16 prev_req; - u32 lkf; /* dlm flags DLM_LKF_ */ - unsigned long flags; /* lock_dlm flags LFL_ */ - - struct list_head delay_list; /* delayed */ - struct gdlm_lock *hold_null; /* NL lock for hold_lvb */ -}; - -#define gdlm_assert(assertion, fmt, args...) \ -do { \ - if (unlikely(!(assertion))) { \ - printk(KERN_EMERG "lock_dlm: fatal assertion failed \"%s\"\n" \ - "lock_dlm: " fmt "\n", \ - #assertion, ##args); \ - BUG(); \ - } \ -} while (0) - -#define log_print(lev, fmt, arg...) printk(lev "lock_dlm: " fmt "\n" , ## arg) -#define log_info(fmt, arg...) log_print(KERN_INFO , fmt , ## arg) -#define log_error(fmt, arg...) log_print(KERN_ERR , fmt , ## arg) -#ifdef LOCK_DLM_LOG_DEBUG -#define log_debug(fmt, arg...) log_print(KERN_DEBUG , fmt , ## arg) -#else -#define log_debug(fmt, arg...) -#endif - -/* sysfs.c */ - -int gdlm_sysfs_init(void); -void gdlm_sysfs_exit(void); -int gdlm_kobject_setup(struct gdlm_ls *, struct kobject *); -void gdlm_kobject_release(struct gdlm_ls *); - -/* thread.c */ - -int gdlm_init_threads(struct gdlm_ls *); -void gdlm_release_threads(struct gdlm_ls *); - -/* lock.c */ - -void gdlm_submit_delayed(struct gdlm_ls *); -unsigned int gdlm_do_lock(struct gdlm_lock *); - -int gdlm_get_lock(void *, struct lm_lockname *, void **); -void gdlm_put_lock(void *); -unsigned int gdlm_lock(void *, unsigned int, unsigned int, unsigned int); -unsigned int gdlm_unlock(void *, unsigned int); -void gdlm_cancel(void *); -int gdlm_hold_lvb(void *, char **); -void gdlm_unhold_lvb(void *, char *); - -/* mount.c */ - -extern const struct lm_lockops gdlm_ops; - -#endif - diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c deleted file mode 100644 index b9a03a7ff80..00000000000 --- a/fs/gfs2/locking/dlm/main.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#include <linux/init.h> - -#include "lock_dlm.h" - -static int __init init_lock_dlm(void) -{ - int error; - - error = gfs2_register_lockproto(&gdlm_ops); - if (error) { - printk(KERN_WARNING "lock_dlm: can't register protocol: %d\n", - error); - return error; - } - - error = gdlm_sysfs_init(); - if (error) { - gfs2_unregister_lockproto(&gdlm_ops); - return error; - } - - printk(KERN_INFO - "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__); - return 0; -} - -static void __exit exit_lock_dlm(void) -{ - gdlm_sysfs_exit(); - gfs2_unregister_lockproto(&gdlm_ops); -} - -module_init(init_lock_dlm); -module_exit(exit_lock_dlm); - -MODULE_DESCRIPTION("GFS DLM Locking Module"); -MODULE_AUTHOR("Red Hat, Inc."); -MODULE_LICENSE("GPL"); - diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c deleted file mode 100644 index 1aa7eb6a022..00000000000 --- a/fs/gfs2/locking/dlm/mount.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#include "lock_dlm.h" - -const struct lm_lockops gdlm_ops; - - -static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp, - int flags, char *table_name) -{ - struct gdlm_ls *ls; - char buf[256], *p; - - ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL); - if (!ls) - return NULL; - - ls->fscb = cb; - ls->sdp = sdp; - ls->fsflags = flags; - spin_lock_init(&ls->async_lock); - INIT_LIST_HEAD(&ls->delayed); - INIT_LIST_HEAD(&ls->submit); - init_waitqueue_head(&ls->thread_wait); - init_waitqueue_head(&ls->wait_control); - ls->jid = -1; - - strncpy(buf, table_name, 256); - buf[255] = '\0'; - - p = strchr(buf, ':'); - if (!p) { - log_info("invalid table_name \"%s\"", table_name); - kfree(ls); - return NULL; - } - *p = '\0'; - p++; - - strncpy(ls->clustername, buf, GDLM_NAME_LEN); - strncpy(ls->fsname, p, GDLM_NAME_LEN); - - return ls; -} - -static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir) -{ - char data[256]; - char *options, *x, *y; - int error = 0; - - memset(data, 0, 256); - strncpy(data, data_arg, 255); - - if (!strlen(data)) { - log_error("no mount options, (u)mount helpers not installed"); - return -EINVAL; - } - - for (options = data; (x = strsep(&options, ":")); ) { - if (!*x) - continue; - - y = strchr(x, '='); - if (y) - *y++ = 0; - - if (!strcmp(x, "jid")) { - if (!y) { - log_error("need argument to jid"); - error = -EINVAL; - break; - } - sscanf(y, "%u", &ls->jid); - - } else if (!strcmp(x, "first")) { - if (!y) { - log_error("need argument to first"); - error = -EINVAL; - break; - } - sscanf(y, "%u", &ls->first); - - } else if (!strcmp(x, "id")) { - if (!y) { - log_error("need argument to id"); - error = -EINVAL; - break; - } - sscanf(y, "%u", &ls->id); - - } else if (!strcmp(x, "nodir")) { - if (!y) { - log_error("need argument to nodir"); - error = -EINVAL; - break; - } - sscanf(y, "%u", nodir); - - } else { - log_error("unkonwn option: %s", x); - error = -EINVAL; - break; - } - } - - return error; -} - -static int gdlm_mount(char *table_name, char *host_data, - lm_callback_t cb, void *cb_data, - unsigned int min_lvb_size, int flags, - struct lm_lockstruct *lockstruct, - struct kobject *fskobj) -{ - struct gdlm_ls *ls; - int error = -ENOMEM, nodir = 0; - - if (min_lvb_size > GDLM_LVB_SIZE) - goto out; - - ls = init_gdlm(cb, cb_data, flags, table_name); - if (!ls) - goto out; - - error = make_args(ls, host_data, &nodir); - if (error) - goto out; - - error = gdlm_init_threads(ls); - if (error) - goto out_free; - - error = gdlm_kobject_setup(ls, fskobj); - if (error) - goto out_thread; - - error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname), - &ls->dlm_lockspace, - DLM_LSFL_FS | DLM_LSFL_NEWEXCL | - (nodir ? DLM_LSFL_NODIR : 0), - GDLM_LVB_SIZE); - if (error) { - log_error("dlm_new_lockspace error %d", error); - goto out_kobj; - } - - lockstruct->ls_jid = ls->jid; - lockstruct->ls_first = ls->first; - lockstruct->ls_lockspace = ls; - lockstruct->ls_ops = &gdlm_ops; - lockstruct->ls_flags = 0; - lockstruct->ls_lvb_size = GDLM_LVB_SIZE; - return 0; - -out_kobj: - gdlm_kobject_release(ls); -out_thread: - gdlm_release_threads(ls); -out_free: - kfree(ls); -out: - return error; -} - -static void gdlm_unmount(void *lockspace) -{ - struct gdlm_ls *ls = lockspace; - - log_debug("unmount flags %lx", ls->flags); - - /* FIXME: serialize unmount and withdraw in case they - happen at once. Also, if unmount follows withdraw, - wait for withdraw to finish. */ - - if (test_bit(DFL_WITHDRAW, &ls->flags)) - goto out; - - gdlm_kobject_release(ls); - dlm_release_lockspace(ls->dlm_lockspace, 2); - gdlm_release_threads(ls); - BUG_ON(ls->all_locks_count); -out: - kfree(ls); -} - -static void gdlm_recovery_done(void *lockspace, unsigned int jid, - unsigned int message) -{ - char env_jid[20]; - char env_status[20]; - char *envp[] = { env_jid, env_status, NULL }; - struct gdlm_ls *ls = lockspace; - ls->recover_jid_done = jid; - ls->recover_jid_status = message; - sprintf(env_jid, "JID=%d", jid); - sprintf(env_status, "RECOVERY=%s", - message == LM_RD_SUCCESS ? "Done" : "Failed"); - kobject_uevent_env(&ls->kobj, KOBJ_CHANGE, envp); -} - -static void gdlm_others_may_mount(void *lockspace) -{ - char *message = "FIRSTMOUNT=Done"; - char *envp[] = { message, NULL }; - struct gdlm_ls *ls = lockspace; - ls->first_done = 1; - kobject_uevent_env(&ls->kobj, KOBJ_CHANGE, envp); -} - -/* Userspace gets the offline uevent, blocks new gfs locks on - other mounters, and lets us know (sets WITHDRAW flag). Then, - userspace leaves the mount group while we leave the lockspace. */ - -static void gdlm_withdraw(void *lockspace) -{ - struct gdlm_ls *ls = lockspace; - - kobject_uevent(&ls->kobj, KOBJ_OFFLINE); - - wait_event_interruptible(ls->wait_control, - test_bit(DFL_WITHDRAW, &ls->flags)); - - dlm_release_lockspace(ls->dlm_lockspace, 2); - gdlm_release_threads(ls); - gdlm_kobject_release(ls); -} - -static int gdlm_plock(void *lockspace, struct lm_lockname *name, - struct file *file, int cmd, struct file_lock *fl) -{ - struct gdlm_ls *ls = lockspace; - return dlm_posix_lock(ls->dlm_lockspace, name->ln_number, file, cmd, fl); -} - -static int gdlm_punlock(void *lockspace, struct lm_lockname *name, - struct file *file, struct file_lock *fl) -{ - struct gdlm_ls *ls = lockspace; - return dlm_posix_unlock(ls->dlm_lockspace, name->ln_number, file, fl); -} - -static int gdlm_plock_get(void *lockspace, struct lm_lockname *name, - struct file *file, struct file_lock *fl) -{ - struct gdlm_ls *ls = lockspace; - return dlm_posix_get(ls->dlm_lockspace, name->ln_number, file, fl); -} - -const struct lm_lockops gdlm_ops = { - .lm_proto_name = "lock_dlm", - .lm_mount = gdlm_mount, - .lm_others_may_mount = gdlm_others_may_mount, - .lm_unmount = gdlm_unmount, - .lm_withdraw = gdlm_withdraw, - .lm_get_lock = gdlm_get_lock, - .lm_put_lock = gdlm_put_lock, - .lm_lock = gdlm_lock, - .lm_unlock = gdlm_unlock, - .lm_plock = gdlm_plock, - .lm_punlock = gdlm_punlock, - .lm_plock_get = gdlm_plock_get, - .lm_cancel = gdlm_cancel, - .lm_hold_lvb = gdlm_hold_lvb, - .lm_unhold_lvb = gdlm_unhold_lvb, - .lm_recovery_done = gdlm_recovery_done, - .lm_owner = THIS_MODULE, -}; - diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c deleted file mode 100644 index 9b7edcf7bd4..00000000000 --- a/fs/gfs2/locking/dlm/sysfs.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#include <linux/ctype.h> -#include <linux/stat.h> - -#include "lock_dlm.h" - -static ssize_t proto_name_show(struct gdlm_ls *ls, char *buf) -{ - return sprintf(buf, "%s\n", gdlm_ops.lm_proto_name); -} - -static ssize_t block_show(struct gdlm_ls *ls, char *buf) -{ - ssize_t ret; - int val = 0; - - if (test_bit(DFL_BLOCK_LOCKS, &ls->flags)) - val = 1; - ret = sprintf(buf, "%d\n", val); - return ret; -} - -static ssize_t block_store(struct gdlm_ls *ls, const char *buf, size_t len) -{ - ssize_t ret = len; - int val; - - val = simple_strtol(buf, NULL, 0); - - if (val == 1) - set_bit(DFL_BLOCK_LOCKS, &ls->flags); - else if (val == 0) { - clear_bit(DFL_BLOCK_LOCKS, &ls->flags); - gdlm_submit_delayed(ls); - } else { - ret = -EINVAL; - } - return ret; -} - -static ssize_t withdraw_show(struct gdlm_ls *ls, char *buf) -{ - ssize_t ret; - int val = 0; - - if (test_bit(DFL_WITHDRAW, &ls->flags)) - val = 1; - ret = sprintf(buf, "%d\n", val); - return ret; -} - -static ssize_t withdraw_store(struct gdlm_ls *ls, const char *buf, size_t len) -{ - ssize_t ret = len; - int val; - - val = simple_strtol(buf, NULL, 0); - - if (val == 1) - set_bit(DFL_WITHDRAW, &ls->flags); - else - ret = -EINVAL; - wake_up(&ls->wait_control); - return ret; -} - -static ssize_t id_show(struct gdlm_ls *ls, char *buf) -{ - return sprintf(buf, "%u\n", ls->id); -} - -static ssize_t jid_show(struct gdlm_ls *ls, char *buf) -{ - return sprintf(buf, "%d\n", ls->jid); -} - -static ssize_t first_show(struct gdlm_ls *ls, char *buf) -{ - return sprintf(buf, "%d\n", ls->first); -} - -static ssize_t first_done_show(struct gdlm_ls *ls, char *buf) -{ - return sprintf(buf, "%d\n", ls->first_done); -} - -static ssize_t recover_show(struct gdlm_ls *ls, char *buf) -{ - return sprintf(buf, "%d\n", ls->recover_jid); -} - -static ssize_t recover_store(struct gdlm_ls *ls, const char *buf, size_t len) -{ - ls->recover_jid = simple_strtol(buf, NULL, 0); - ls->fscb(ls->sdp, LM_CB_NEED_RECOVERY, &ls->recover_jid); - return len; -} - -static ssize_t recover_done_show(struct gdlm_ls *ls, char *buf) -{ - return sprintf(buf, "%d\n", ls->recover_jid_done); -} - -static ssize_t recover_status_show(struct gdlm_ls *ls, char *buf) -{ - return sprintf(buf, "%d\n", ls->recover_jid_status); -} - -struct gdlm_attr { - struct attribute attr; - ssize_t (*show)(struct gdlm_ls *, char *); - ssize_t (*store)(struct gdlm_ls *, const char *, size_t); -}; - -#define GDLM_ATTR(_name,_mode,_show,_store) \ -static struct gdlm_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) - -GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); -GDLM_ATTR(block, 0644, block_show, block_store); -GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); -GDLM_ATTR(id, 0444, id_show, NULL); -GDLM_ATTR(jid, 0444, jid_show, NULL); -GDLM_ATTR(first, 0444, first_show, NULL); -GDLM_ATTR(first_done, 0444, first_done_show, NULL); -GDLM_ATTR(recover, 0644, recover_show, recover_store); -GDLM_ATTR(recover_done, 0444, recover_done_show, NULL); -GDLM_ATTR(recover_status, 0444, recover_status_show, NULL); - -static struct attribute *gdlm_attrs[] = { - &gdlm_attr_proto_name.attr, - &gdlm_attr_block.attr, - &gdlm_attr_withdraw.attr, - &gdlm_attr_id.attr, - &gdlm_attr_jid.attr, - &gdlm_attr_first.attr, - &gdlm_attr_first_done.attr, - &gdlm_attr_recover.attr, - &gdlm_attr_recover_done.attr, - &gdlm_attr_recover_status.attr, - NULL, -}; - -static ssize_t gdlm_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj); - struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr); - return a->show ? a->show(ls, buf) : 0; -} - -static ssize_t gdlm_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t len) -{ - struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj); - struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr); - return a->store ? a->store(ls, buf, len) : len; -} - -static struct sysfs_ops gdlm_attr_ops = { - .show = gdlm_attr_show, - .store = gdlm_attr_store, -}; - -static struct kobj_type gdlm_ktype = { - .default_attrs = gdlm_attrs, - .sysfs_ops = &gdlm_attr_ops, -}; - -static struct kset *gdlm_kset; - -int gdlm_kobject_setup(struct gdlm_ls *ls, struct kobject *fskobj) -{ - int error; - - ls->kobj.kset = gdlm_kset; - error = kobject_init_and_add(&ls->kobj, &gdlm_ktype, fskobj, - "lock_module"); - if (error) - log_error("can't register kobj %d", error); - kobject_uevent(&ls->kobj, KOBJ_ADD); - - return error; -} - -void gdlm_kobject_release(struct gdlm_ls *ls) -{ - kobject_put(&ls->kobj); -} - -static int gdlm_uevent(struct kset *kset, struct kobject *kobj, - struct kobj_uevent_env *env) -{ - struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj); - add_uevent_var(env, "LOCKTABLE=%s:%s", ls->clustername, ls->fsname); - add_uevent_var(env, "LOCKPROTO=lock_dlm"); - return 0; -} - -static struct kset_uevent_ops gdlm_uevent_ops = { - .uevent = gdlm_uevent, -}; - - -int gdlm_sysfs_init(void) -{ - gdlm_kset = kset_create_and_add("lock_dlm", &gdlm_uevent_ops, kernel_kobj); - if (!gdlm_kset) { - printk(KERN_WARNING "%s: can not create kset\n", __func__); - return -ENOMEM; - } - return 0; -} - -void gdlm_sysfs_exit(void) -{ - kset_unregister(gdlm_kset); -} - diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c deleted file mode 100644 index 38823efd698..00000000000 --- a/fs/gfs2/locking/dlm/thread.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#include "lock_dlm.h" - -static inline int no_work(struct gdlm_ls *ls) -{ - int ret; - - spin_lock(&ls->async_lock); - ret = list_empty(&ls->submit); - spin_unlock(&ls->async_lock); - - return ret; -} - -static int gdlm_thread(void *data) -{ - struct gdlm_ls *ls = (struct gdlm_ls *) data; - struct gdlm_lock *lp = NULL; - - while (!kthread_should_stop()) { - wait_event_interruptible(ls->thread_wait, - !no_work(ls) || kthread_should_stop()); - - spin_lock(&ls->async_lock); - - if (!list_empty(&ls->submit)) { - lp = list_entry(ls->submit.next, struct gdlm_lock, - delay_list); - list_del_init(&lp->delay_list); - spin_unlock(&ls->async_lock); - gdlm_do_lock(lp); - spin_lock(&ls->async_lock); - } - spin_unlock(&ls->async_lock); - } - - return 0; -} - -int gdlm_init_threads(struct gdlm_ls *ls) -{ - struct task_struct *p; - int error; - - p = kthread_run(gdlm_thread, ls, "lock_dlm"); - error = IS_ERR(p); - if (error) { - log_error("can't start lock_dlm thread %d", error); - return error; - } - ls->thread = p; - - return 0; -} - -void gdlm_release_threads(struct gdlm_ls *ls) -{ - kthread_stop(ls->thread); -} - diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index ad305854bdc..98918a75641 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -14,7 +14,6 @@ #include <linux/buffer_head.h> #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> -#include <linux/lm_interface.h> #include <linux/delay.h> #include <linux/kthread.h> #include <linux/freezer.h> diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 4390f6f4047..80e4f5f898b 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -13,7 +13,6 @@ #include <linux/completion.h> #include <linux/buffer_head.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include "gfs2.h" #include "incore.h" diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 7cacfde3219..a6892ed0840 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -14,7 +14,6 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include <asm/atomic.h> #include "gfs2.h" @@ -23,6 +22,12 @@ #include "sys.h" #include "util.h" #include "glock.h" +#include "quota.h" + +static struct shrinker qd_shrinker = { + .shrink = gfs2_shrink_qd_memory, + .seeks = DEFAULT_SEEKS, +}; static void gfs2_init_inode_once(void *foo) { @@ -41,8 +46,6 @@ static void gfs2_init_glock_once(void *foo) INIT_HLIST_NODE(&gl->gl_list); spin_lock_init(&gl->gl_spin); INIT_LIST_HEAD(&gl->gl_holders); - gl->gl_lvb = NULL; - atomic_set(&gl->gl_lvb_count, 0); INIT_LIST_HEAD(&gl->gl_lru); INIT_LIST_HEAD(&gl->gl_ail_list); atomic_set(&gl->gl_ail_count, 0); @@ -100,6 +103,8 @@ static int __init init_gfs2_fs(void) if (!gfs2_quotad_cachep) goto fail; + register_shrinker(&qd_shrinker); + error = register_filesystem(&gfs2_fs_type); if (error) goto fail; @@ -117,6 +122,7 @@ static int __init init_gfs2_fs(void) fail_unregister: unregister_filesystem(&gfs2_fs_type); fail: + unregister_shrinker(&qd_shrinker); gfs2_glock_exit(); if (gfs2_quotad_cachep) @@ -145,6 +151,7 @@ fail: static void __exit exit_gfs2_fs(void) { + unregister_shrinker(&qd_shrinker); gfs2_glock_exit(); gfs2_unregister_debugfs(); unregister_filesystem(&gfs2_fs_type); diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 09853620c95..8d6f13256b2 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -19,7 +19,6 @@ #include <linux/delay.h> #include <linux/bio.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include "gfs2.h" #include "incore.h" @@ -90,27 +89,6 @@ void gfs2_aspace_put(struct inode *aspace) } /** - * gfs2_meta_inval - Invalidate all buffers associated with a glock - * @gl: the glock - * - */ - -void gfs2_meta_inval(struct gfs2_glock *gl) -{ - struct gfs2_sbd *sdp = gl->gl_sbd; - struct inode *aspace = gl->gl_aspace; - struct address_space *mapping = gl->gl_aspace->i_mapping; - - gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); - - atomic_inc(&aspace->i_writecount); - truncate_inode_pages(mapping, 0); - atomic_dec(&aspace->i_writecount); - - gfs2_assert_withdraw(sdp, !mapping->nrpages); -} - -/** * gfs2_meta_sync - Sync all buffers associated with a glock * @gl: The glock * diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index b1a5f3674d4..de270c2f9b6 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -40,7 +40,6 @@ static inline void gfs2_buffer_copy_tail(struct buffer_head *to_bh, struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp); void gfs2_aspace_put(struct inode *aspace); -void gfs2_meta_inval(struct gfs2_glock *gl); void gfs2_meta_sync(struct gfs2_glock *gl); struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno); diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c index 3cb0a44ba02..f7e8527a21e 100644 --- a/fs/gfs2/mount.c +++ b/fs/gfs2/mount.c @@ -12,12 +12,11 @@ #include <linux/completion.h> #include <linux/buffer_head.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include <linux/parser.h> #include "gfs2.h" #include "incore.h" -#include "mount.h" +#include "super.h" #include "sys.h" #include "util.h" @@ -37,11 +36,15 @@ enum { Opt_quota_off, Opt_quota_account, Opt_quota_on, + Opt_quota, + Opt_noquota, Opt_suiddir, Opt_nosuiddir, Opt_data_writeback, Opt_data_ordered, Opt_meta, + Opt_discard, + Opt_nodiscard, Opt_err, }; @@ -61,11 +64,15 @@ static const match_table_t tokens = { {Opt_quota_off, "quota=off"}, {Opt_quota_account, "quota=account"}, {Opt_quota_on, "quota=on"}, + {Opt_quota, "quota"}, + {Opt_noquota, "noquota"}, {Opt_suiddir, "suiddir"}, {Opt_nosuiddir, "nosuiddir"}, {Opt_data_writeback, "data=writeback"}, {Opt_data_ordered, "data=ordered"}, {Opt_meta, "meta"}, + {Opt_discard, "discard"}, + {Opt_nodiscard, "nodiscard"}, {Opt_err, NULL} }; @@ -77,101 +84,46 @@ static const match_table_t tokens = { * Return: errno */ -int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount) +int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) { - struct gfs2_args *args = &sdp->sd_args; - char *data = data_arg; - char *options, *o, *v; - int error = 0; - - if (!remount) { - /* Set some defaults */ - args->ar_quota = GFS2_QUOTA_DEFAULT; - args->ar_data = GFS2_DATA_DEFAULT; - } + char *o; + int token; + substring_t tmp[MAX_OPT_ARGS]; /* Split the options into tokens with the "," character and process them */ - for (options = data; (o = strsep(&options, ",")); ) { - int token; - substring_t tmp[MAX_OPT_ARGS]; - - if (!*o) + while (1) { + o = strsep(&options, ","); + if (o == NULL) + break; + if (*o == '\0') continue; token = match_token(o, tokens, tmp); switch (token) { case Opt_lockproto: - v = match_strdup(&tmp[0]); - if (!v) { - fs_info(sdp, "no memory for lockproto\n"); - error = -ENOMEM; - goto out_error; - } - - if (remount && strcmp(v, args->ar_lockproto)) { - kfree(v); - goto cant_remount; - } - - strncpy(args->ar_lockproto, v, GFS2_LOCKNAME_LEN); - args->ar_lockproto[GFS2_LOCKNAME_LEN - 1] = 0; - kfree(v); + match_strlcpy(args->ar_lockproto, &tmp[0], + GFS2_LOCKNAME_LEN); break; case Opt_locktable: - v = match_strdup(&tmp[0]); - if (!v) { - fs_info(sdp, "no memory for locktable\n"); - error = -ENOMEM; - goto out_error; - } - - if (remount && strcmp(v, args->ar_locktable)) { - kfree(v); - goto cant_remount; - } - - strncpy(args->ar_locktable, v, GFS2_LOCKNAME_LEN); - args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0; - kfree(v); + match_strlcpy(args->ar_locktable, &tmp[0], + GFS2_LOCKNAME_LEN); break; case Opt_hostdata: - v = match_strdup(&tmp[0]); - if (!v) { - fs_info(sdp, "no memory for hostdata\n"); - error = -ENOMEM; - goto out_error; - } - - if (remount && strcmp(v, args->ar_hostdata)) { - kfree(v); - goto cant_remount; - } - - strncpy(args->ar_hostdata, v, GFS2_LOCKNAME_LEN); - args->ar_hostdata[GFS2_LOCKNAME_LEN - 1] = 0; - kfree(v); + match_strlcpy(args->ar_hostdata, &tmp[0], + GFS2_LOCKNAME_LEN); break; case Opt_spectator: - if (remount && !args->ar_spectator) - goto cant_remount; args->ar_spectator = 1; - sdp->sd_vfs->s_flags |= MS_RDONLY; break; case Opt_ignore_local_fs: - if (remount && !args->ar_ignore_local_fs) - goto cant_remount; args->ar_ignore_local_fs = 1; break; case Opt_localflocks: - if (remount && !args->ar_localflocks) - goto cant_remount; args->ar_localflocks = 1; break; case Opt_localcaching: - if (remount && !args->ar_localcaching) - goto cant_remount; args->ar_localcaching = 1; break; case Opt_debug: @@ -181,25 +133,23 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount) args->ar_debug = 0; break; case Opt_upgrade: - if (remount && !args->ar_upgrade) - goto cant_remount; args->ar_upgrade = 1; break; case Opt_acl: args->ar_posix_acl = 1; - sdp->sd_vfs->s_flags |= MS_POSIXACL; break; case Opt_noacl: args->ar_posix_acl = 0; - sdp->sd_vfs->s_flags &= ~MS_POSIXACL; break; case Opt_quota_off: + case Opt_noquota: args->ar_quota = GFS2_QUOTA_OFF; break; case Opt_quota_account: args->ar_quota = GFS2_QUOTA_ACCOUNT; break; case Opt_quota_on: + case Opt_quota: args->ar_quota = GFS2_QUOTA_ON; break; case Opt_suiddir: @@ -215,29 +165,21 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount) args->ar_data = GFS2_DATA_ORDERED; break; case Opt_meta: - if (remount && args->ar_meta != 1) - goto cant_remount; args->ar_meta = 1; break; + case Opt_discard: + args->ar_discard = 1; + break; + case Opt_nodiscard: + args->ar_discard = 0; + break; case Opt_err: default: - fs_info(sdp, "unknown option: %s\n", o); - error = -EINVAL; - goto out_error; + fs_info(sdp, "invalid mount option: %s\n", o); + return -EINVAL; } } -out_error: - if (error) - fs_info(sdp, "invalid mount option(s)\n"); - - if (data != data_arg) - kfree(data); - - return error; - -cant_remount: - fs_info(sdp, "can't remount with option %s\n", o); - return -EINVAL; + return 0; } diff --git a/fs/gfs2/mount.h b/fs/gfs2/mount.h deleted file mode 100644 index 401288acfdf..00000000000 --- a/fs/gfs2/mount.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#ifndef __MOUNT_DOT_H__ -#define __MOUNT_DOT_H__ - -struct gfs2_sbd; - -int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount); - -#endif /* __MOUNT_DOT_H__ */ diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 4ddab67867e..a6dde1751e1 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -19,7 +19,6 @@ #include <linux/writeback.h> #include <linux/swap.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include <linux/backing-dev.h> #include "gfs2.h" @@ -442,6 +441,7 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) */ if (unlikely(page->index)) { zero_user(page, 0, PAGE_CACHE_SIZE); + SetPageUptodate(page); return 0; } @@ -1096,6 +1096,7 @@ static const struct address_space_operations gfs2_writeback_aops = { .releasepage = gfs2_releasepage, .direct_IO = gfs2_direct_IO, .migratepage = buffer_migrate_page, + .is_partially_uptodate = block_is_partially_uptodate, }; static const struct address_space_operations gfs2_ordered_aops = { @@ -1111,6 +1112,7 @@ static const struct address_space_operations gfs2_ordered_aops = { .releasepage = gfs2_releasepage, .direct_IO = gfs2_direct_IO, .migratepage = buffer_migrate_page, + .is_partially_uptodate = block_is_partially_uptodate, }; static const struct address_space_operations gfs2_jdata_aops = { @@ -1125,6 +1127,7 @@ static const struct address_space_operations gfs2_jdata_aops = { .bmap = gfs2_bmap, .invalidatepage = gfs2_invalidatepage, .releasepage = gfs2_releasepage, + .is_partially_uptodate = block_is_partially_uptodate, }; void gfs2_set_aops(struct inode *inode) diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index c2ad36330ca..022c66cd560 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -13,7 +13,6 @@ #include <linux/buffer_head.h> #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> -#include <linux/lm_interface.h> #include "gfs2.h" #include "incore.h" @@ -108,7 +107,7 @@ static int gfs2_dhash(struct dentry *dentry, struct qstr *str) return 0; } -struct dentry_operations gfs2_dops = { +const struct dentry_operations gfs2_dops = { .d_revalidate = gfs2_drevalidate, .d_hash = gfs2_dhash, }; diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 7fdeb14ddd1..9200ef22171 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -14,7 +14,6 @@ #include <linux/exportfs.h> #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> -#include <linux/lm_interface.h> #include "gfs2.h" #include "incore.h" diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 93fe41b67f9..70b9b854894 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -20,9 +20,10 @@ #include <linux/gfs2_ondisk.h> #include <linux/ext2_fs.h> #include <linux/crc32.h> -#include <linux/lm_interface.h> #include <linux/writeback.h> #include <asm/uaccess.h> +#include <linux/dlm.h> +#include <linux/dlm_plock.h> #include "gfs2.h" #include "incore.h" @@ -336,8 +337,9 @@ static int gfs2_allocate_page_backing(struct page *page) * blocks allocated on disk to back that page. */ -static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page) +static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { + struct page *page = vmf->page; struct inode *inode = vma->vm_file->f_path.dentry->d_inode; struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); @@ -354,7 +356,9 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page) if (ret) goto out; + set_bit(GLF_DIRTY, &ip->i_gl->gl_flags); set_bit(GIF_SW_PAGED, &ip->i_flags); + ret = gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE, &alloc_required); if (ret || !alloc_required) goto out_unlock; @@ -409,6 +413,8 @@ out_unlock: gfs2_glock_dq(&gh); out: gfs2_holder_uninit(&gh); + if (ret) + ret = VM_FAULT_SIGBUS; return ret; } @@ -560,57 +566,24 @@ static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync) return ret; } +#ifdef CONFIG_GFS2_FS_LOCKING_DLM + /** * gfs2_setlease - acquire/release a file lease * @file: the file pointer * @arg: lease type * @fl: file lock * + * We don't currently have a way to enforce a lease across the whole + * cluster; until we do, disable leases (by just returning -EINVAL), + * unless the administrator has requested purely local locking. + * * Returns: errno */ static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl) { - struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host); - - /* - * We don't currently have a way to enforce a lease across the whole - * cluster; until we do, disable leases (by just returning -EINVAL), - * unless the administrator has requested purely local locking. - */ - if (!sdp->sd_args.ar_localflocks) - return -EINVAL; - return generic_setlease(file, arg, fl); -} - -static int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name, - struct file *file, struct file_lock *fl) -{ - int error = -EIO; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = sdp->sd_lockstruct.ls_ops->lm_plock_get( - sdp->sd_lockstruct.ls_lockspace, name, file, fl); - return error; -} - -static int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name, - struct file *file, int cmd, struct file_lock *fl) -{ - int error = -EIO; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = sdp->sd_lockstruct.ls_ops->lm_plock( - sdp->sd_lockstruct.ls_lockspace, name, file, cmd, fl); - return error; -} - -static int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name, - struct file *file, struct file_lock *fl) -{ - int error = -EIO; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - error = sdp->sd_lockstruct.ls_ops->lm_punlock( - sdp->sd_lockstruct.ls_lockspace, name, file, fl); - return error; + return -EINVAL; } /** @@ -626,9 +599,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) { struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host); - struct lm_lockname name = - { .ln_number = ip->i_no_addr, - .ln_type = LM_TYPE_PLOCK }; + struct lm_lockstruct *ls = &sdp->sd_lockstruct; if (!(fl->fl_flags & FL_POSIX)) return -ENOLCK; @@ -640,12 +611,14 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) cmd = F_SETLK; fl->fl_type = F_UNLCK; } + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + return -EIO; if (IS_GETLK(cmd)) - return gfs2_lm_plock_get(sdp, &name, file, fl); + return dlm_posix_get(ls->ls_dlm, ip->i_no_addr, file, fl); else if (fl->fl_type == F_UNLCK) - return gfs2_lm_punlock(sdp, &name, file, fl); + return dlm_posix_unlock(ls->ls_dlm, ip->i_no_addr, file, fl); else - return gfs2_lm_plock(sdp, &name, file, cmd, fl); + return dlm_posix_lock(ls->ls_dlm, ip->i_no_addr, file, cmd, fl); } static int do_flock(struct file *file, int cmd, struct file_lock *fl) @@ -732,7 +705,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) } } -const struct file_operations gfs2_file_fops = { +const struct file_operations *gfs2_file_fops = &(const struct file_operations){ .llseek = gfs2_llseek, .read = do_sync_read, .aio_read = generic_file_aio_read, @@ -750,7 +723,7 @@ const struct file_operations gfs2_file_fops = { .setlease = gfs2_setlease, }; -const struct file_operations gfs2_dir_fops = { +const struct file_operations *gfs2_dir_fops = &(const struct file_operations){ .readdir = gfs2_readdir, .unlocked_ioctl = gfs2_ioctl, .open = gfs2_open, @@ -760,7 +733,9 @@ const struct file_operations gfs2_dir_fops = { .flock = gfs2_flock, }; -const struct file_operations gfs2_file_fops_nolock = { +#endif /* CONFIG_GFS2_FS_LOCKING_DLM */ + +const struct file_operations *gfs2_file_fops_nolock = &(const struct file_operations){ .llseek = gfs2_llseek, .read = do_sync_read, .aio_read = generic_file_aio_read, @@ -773,10 +748,10 @@ const struct file_operations gfs2_file_fops_nolock = { .fsync = gfs2_fsync, .splice_read = generic_file_splice_read, .splice_write = generic_file_splice_write, - .setlease = gfs2_setlease, + .setlease = generic_setlease, }; -const struct file_operations gfs2_dir_fops_nolock = { +const struct file_operations *gfs2_dir_fops_nolock = &(const struct file_operations){ .readdir = gfs2_readdir, .unlocked_ioctl = gfs2_ioctl, .open = gfs2_open, diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index f91eebdde58..51883b3ad89 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -17,7 +17,6 @@ #include <linux/namei.h> #include <linux/mount.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include "gfs2.h" #include "incore.h" @@ -25,7 +24,6 @@ #include "glock.h" #include "glops.h" #include "inode.h" -#include "mount.h" #include "recovery.h" #include "rgrp.h" #include "super.h" @@ -64,7 +62,6 @@ static void gfs2_tune_init(struct gfs2_tune *gt) gt->gt_quota_warn_period = 10; gt->gt_quota_scale_num = 1; gt->gt_quota_scale_den = 1; - gt->gt_quota_cache_secs = 300; gt->gt_quota_quantum = 60; gt->gt_new_files_jdata = 0; gt->gt_max_readahead = 1 << 18; @@ -100,7 +97,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) mutex_init(&sdp->sd_jindex_mutex); INIT_LIST_HEAD(&sdp->sd_quota_list); - spin_lock_init(&sdp->sd_quota_spin); mutex_init(&sdp->sd_quota_mutex); init_waitqueue_head(&sdp->sd_quota_wait); INIT_LIST_HEAD(&sdp->sd_trunc_list); @@ -238,6 +234,7 @@ static void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf) memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN); memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN); + memcpy(sb->sb_uuid, str->sb_uuid, 16); } /** @@ -299,15 +296,15 @@ static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector) __free_page(page); return 0; } + /** * gfs2_read_sb - Read super block * @sdp: The GFS2 superblock - * @gl: the glock for the superblock (assumed to be held) * @silent: Don't print message if mount fails * */ -static int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) +static int gfs2_read_sb(struct gfs2_sbd *sdp, int silent) { u32 hash_blocks, ind_blocks, leaf_blocks; u32 tmp_blocks; @@ -527,7 +524,7 @@ static int init_sb(struct gfs2_sbd *sdp, int silent) return ret; } - ret = gfs2_read_sb(sdp, sb_gh.gh_gl, silent); + ret = gfs2_read_sb(sdp, silent); if (ret) { fs_err(sdp, "can't read superblock: %d\n", ret); goto out; @@ -630,13 +627,13 @@ static int map_journal_extents(struct gfs2_sbd *sdp) return rc; } -static void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp) +static void gfs2_others_may_mount(struct gfs2_sbd *sdp) { - if (!sdp->sd_lockstruct.ls_ops->lm_others_may_mount) - return; - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - sdp->sd_lockstruct.ls_ops->lm_others_may_mount( - sdp->sd_lockstruct.ls_lockspace); + char *message = "FIRSTMOUNT=Done"; + char *envp[] = { message, NULL }; + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + ls->ls_first_done = 1; + kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp); } /** @@ -796,7 +793,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) } } - gfs2_lm_others_may_mount(sdp); + gfs2_others_may_mount(sdp); } else if (!sdp->sd_args.ar_spectator) { error = gfs2_recover_journal(sdp->sd_jdesc); if (error) { @@ -1005,7 +1002,6 @@ static int init_threads(struct gfs2_sbd *sdp, int undo) goto fail_quotad; sdp->sd_log_flush_time = jiffies; - sdp->sd_jindex_refresh_time = jiffies; p = kthread_run(gfs2_logd, sdp, "gfs2_logd"); error = IS_ERR(p); @@ -1033,6 +1029,17 @@ fail: return error; } +static const match_table_t nolock_tokens = { + { Opt_jid, "jid=%d\n", }, + { Opt_err, NULL }, +}; + +static const struct lm_lockops nolock_ops = { + .lm_proto_name = "lock_nolock", + .lm_put_lock = kmem_cache_free, + .lm_tokens = &nolock_tokens, +}; + /** * gfs2_lm_mount - mount a locking protocol * @sdp: the filesystem @@ -1044,31 +1051,73 @@ fail: static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) { - char *proto = sdp->sd_proto_name; - char *table = sdp->sd_table_name; - int flags = LM_MFLAG_CONV_NODROP; - int error; + const struct lm_lockops *lm; + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + struct gfs2_args *args = &sdp->sd_args; + const char *proto = sdp->sd_proto_name; + const char *table = sdp->sd_table_name; + const char *fsname; + char *o, *options; + int ret; - if (sdp->sd_args.ar_spectator) - flags |= LM_MFLAG_SPECTATOR; + if (!strcmp("lock_nolock", proto)) { + lm = &nolock_ops; + sdp->sd_args.ar_localflocks = 1; + sdp->sd_args.ar_localcaching = 1; +#ifdef CONFIG_GFS2_FS_LOCKING_DLM + } else if (!strcmp("lock_dlm", proto)) { + lm = &gfs2_dlm_ops; +#endif + } else { + printk(KERN_INFO "GFS2: can't find protocol %s\n", proto); + return -ENOENT; + } fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table); - error = gfs2_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata, - gfs2_glock_cb, sdp, - GFS2_MIN_LVB_SIZE, flags, - &sdp->sd_lockstruct, &sdp->sd_kobj); - if (error) { - fs_info(sdp, "can't mount proto=%s, table=%s, hostdata=%s\n", - proto, table, sdp->sd_args.ar_hostdata); - goto out; - } + ls->ls_ops = lm; + ls->ls_first = 1; + ls->ls_id = 0; - if (gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) || - gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >= - GFS2_MIN_LVB_SIZE)) { - gfs2_unmount_lockproto(&sdp->sd_lockstruct); - goto out; + for (options = args->ar_hostdata; (o = strsep(&options, ":")); ) { + substring_t tmp[MAX_OPT_ARGS]; + int token, option; + + if (!o || !*o) + continue; + + token = match_token(o, *lm->lm_tokens, tmp); + switch (token) { + case Opt_jid: + ret = match_int(&tmp[0], &option); + if (ret || option < 0) + goto hostdata_error; + ls->ls_jid = option; + break; + case Opt_id: + ret = match_int(&tmp[0], &option); + if (ret) + goto hostdata_error; + ls->ls_id = option; + break; + case Opt_first: + ret = match_int(&tmp[0], &option); + if (ret || (option != 0 && option != 1)) + goto hostdata_error; + ls->ls_first = option; + break; + case Opt_nodir: + ret = match_int(&tmp[0], &option); + if (ret || (option != 0 && option != 1)) + goto hostdata_error; + ls->ls_nodir = option; + break; + case Opt_err: + default: +hostdata_error: + fs_info(sdp, "unknown hostdata (%s)\n", o); + return -EINVAL; + } } if (sdp->sd_args.ar_spectator) @@ -1077,22 +1126,25 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table, sdp->sd_lockstruct.ls_jid); - fs_info(sdp, "Joined cluster. Now mounting FS...\n"); - - if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) && - !sdp->sd_args.ar_ignore_local_fs) { - sdp->sd_args.ar_localflocks = 1; - sdp->sd_args.ar_localcaching = 1; + fsname = strchr(table, ':'); + if (fsname) + fsname++; + if (lm->lm_mount == NULL) { + fs_info(sdp, "Now mounting FS...\n"); + return 0; } - -out: - return error; + ret = lm->lm_mount(sdp, fsname); + if (ret == 0) + fs_info(sdp, "Joined cluster. Now mounting FS...\n"); + return ret; } void gfs2_lm_unmount(struct gfs2_sbd *sdp) { - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - gfs2_unmount_lockproto(&sdp->sd_lockstruct); + const struct lm_lockops *lm = sdp->sd_lockstruct.ls_ops; + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) && + lm->lm_unmount) + lm->lm_unmount(sdp); } /** @@ -1116,12 +1168,20 @@ static int fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; } - error = gfs2_mount_args(sdp, (char *)data, 0); + sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT; + sdp->sd_args.ar_data = GFS2_DATA_DEFAULT; + + error = gfs2_mount_args(sdp, &sdp->sd_args, data); if (error) { printk(KERN_WARNING "GFS2: can't parse mount arguments\n"); goto fail; } + if (sdp->sd_args.ar_spectator) + sb->s_flags |= MS_RDONLY; + if (sdp->sd_args.ar_posix_acl) + sb->s_flags |= MS_POSIXACL; + sb->s_magic = GFS2_MAGIC; sb->s_op = &gfs2_super_ops; sb->s_export_op = &gfs2_export_ops; @@ -1199,6 +1259,8 @@ fail_sb: dput(sdp->sd_root_dir); if (sdp->sd_master_dir) dput(sdp->sd_master_dir); + if (sb->s_root) + dput(sb->s_root); sb->s_root = NULL; fail_locking: init_locking(sdp, &mount_gh, UNDO); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 49877546beb..abd5429ae28 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -18,7 +18,6 @@ #include <linux/posix_acl.h> #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> -#include <linux/lm_interface.h> #include <linux/fiemap.h> #include <asm/uaccess.h> diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 320323d0347..458019569dc 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -19,7 +19,6 @@ #include <linux/delay.h> #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> -#include <linux/lm_interface.h> #include <linux/time.h> #include "gfs2.h" @@ -27,7 +26,6 @@ #include "glock.h" #include "inode.h" #include "log.h" -#include "mount.h" #include "quota.h" #include "recovery.h" #include "rgrp.h" @@ -40,6 +38,8 @@ #include "bmap.h" #include "meta_io.h" +#define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x) + /** * gfs2_write_inode - Make sure the inode is stable on the disk * @inode: The inode @@ -435,25 +435,45 @@ static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf) static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) { struct gfs2_sbd *sdp = sb->s_fs_info; + struct gfs2_args args = sdp->sd_args; /* Default to current settings */ int error; - error = gfs2_mount_args(sdp, data, 1); + error = gfs2_mount_args(sdp, &args, data); if (error) return error; + /* Not allowed to change locking details */ + if (strcmp(args.ar_lockproto, sdp->sd_args.ar_lockproto) || + strcmp(args.ar_locktable, sdp->sd_args.ar_locktable) || + strcmp(args.ar_hostdata, sdp->sd_args.ar_hostdata)) + return -EINVAL; + + /* Some flags must not be changed */ + if (args_neq(&args, &sdp->sd_args, spectator) || + args_neq(&args, &sdp->sd_args, ignore_local_fs) || + args_neq(&args, &sdp->sd_args, localflocks) || + args_neq(&args, &sdp->sd_args, localcaching) || + args_neq(&args, &sdp->sd_args, meta)) + return -EINVAL; + if (sdp->sd_args.ar_spectator) *flags |= MS_RDONLY; - else { - if (*flags & MS_RDONLY) { - if (!(sb->s_flags & MS_RDONLY)) - error = gfs2_make_fs_ro(sdp); - } else if (!(*flags & MS_RDONLY) && - (sb->s_flags & MS_RDONLY)) { + + if ((sb->s_flags ^ *flags) & MS_RDONLY) { + if (*flags & MS_RDONLY) + error = gfs2_make_fs_ro(sdp); + else error = gfs2_make_fs_rw(sdp); - } + if (error) + return error; } - return error; + sdp->sd_args = args; + if (sdp->sd_args.ar_posix_acl) + sb->s_flags |= MS_POSIXACL; + else + sb->s_flags &= ~MS_POSIXACL; + return 0; } /** @@ -588,6 +608,8 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) } seq_printf(s, ",data=%s", state); } + if (args->ar_discard) + seq_printf(s, ",discard"); return 0; } diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index b08d09696b3..8d53f66b5bc 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -45,7 +45,6 @@ #include <linux/fs.h> #include <linux/bio.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include <linux/kthread.h> #include <linux/freezer.h> @@ -80,6 +79,51 @@ struct gfs2_quota_change_host { u32 qc_id; }; +static LIST_HEAD(qd_lru_list); +static atomic_t qd_lru_count = ATOMIC_INIT(0); +static spinlock_t qd_lru_lock = SPIN_LOCK_UNLOCKED; + +int gfs2_shrink_qd_memory(int nr, gfp_t gfp_mask) +{ + struct gfs2_quota_data *qd; + struct gfs2_sbd *sdp; + + if (nr == 0) + goto out; + + if (!(gfp_mask & __GFP_FS)) + return -1; + + spin_lock(&qd_lru_lock); + while (nr && !list_empty(&qd_lru_list)) { + qd = list_entry(qd_lru_list.next, + struct gfs2_quota_data, qd_reclaim); + sdp = qd->qd_gl->gl_sbd; + + /* Free from the filesystem-specific list */ + list_del(&qd->qd_list); + + gfs2_assert_warn(sdp, !qd->qd_change); + gfs2_assert_warn(sdp, !qd->qd_slot_count); + gfs2_assert_warn(sdp, !qd->qd_bh_count); + + gfs2_glock_put(qd->qd_gl); + atomic_dec(&sdp->sd_quota_count); + + /* Delete it from the common reclaim list */ + list_del_init(&qd->qd_reclaim); + atomic_dec(&qd_lru_count); + spin_unlock(&qd_lru_lock); + kmem_cache_free(gfs2_quotad_cachep, qd); + spin_lock(&qd_lru_lock); + nr--; + } + spin_unlock(&qd_lru_lock); + +out: + return (atomic_read(&qd_lru_count) * sysctl_vfs_cache_pressure) / 100; +} + static u64 qd2offset(struct gfs2_quota_data *qd) { u64 offset; @@ -100,22 +144,18 @@ static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id, if (!qd) return -ENOMEM; - qd->qd_count = 1; + atomic_set(&qd->qd_count, 1); qd->qd_id = id; if (user) set_bit(QDF_USER, &qd->qd_flags); qd->qd_slot = -1; + INIT_LIST_HEAD(&qd->qd_reclaim); error = gfs2_glock_get(sdp, 2 * (u64)id + !user, &gfs2_quota_glops, CREATE, &qd->qd_gl); if (error) goto fail; - error = gfs2_lvb_hold(qd->qd_gl); - gfs2_glock_put(qd->qd_gl); - if (error) - goto fail; - *qdp = qd; return 0; @@ -135,11 +175,17 @@ static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create, for (;;) { found = 0; - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) { if (qd->qd_id == id && !test_bit(QDF_USER, &qd->qd_flags) == !user) { - qd->qd_count++; + if (!atomic_read(&qd->qd_count) && + !list_empty(&qd->qd_reclaim)) { + /* Remove it from reclaim list */ + list_del_init(&qd->qd_reclaim); + atomic_dec(&qd_lru_count); + } + atomic_inc(&qd->qd_count); found = 1; break; } @@ -155,11 +201,11 @@ static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create, new_qd = NULL; } - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); if (qd || !create) { if (new_qd) { - gfs2_lvb_unhold(new_qd->qd_gl); + gfs2_glock_put(new_qd->qd_gl); kmem_cache_free(gfs2_quotad_cachep, new_qd); } *qdp = qd; @@ -175,21 +221,18 @@ static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create, static void qd_hold(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - - spin_lock(&sdp->sd_quota_spin); - gfs2_assert(sdp, qd->qd_count); - qd->qd_count++; - spin_unlock(&sdp->sd_quota_spin); + gfs2_assert(sdp, atomic_read(&qd->qd_count)); + atomic_inc(&qd->qd_count); } static void qd_put(struct gfs2_quota_data *qd) { - struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - spin_lock(&sdp->sd_quota_spin); - gfs2_assert(sdp, qd->qd_count); - if (!--qd->qd_count) - qd->qd_last_touched = jiffies; - spin_unlock(&sdp->sd_quota_spin); + if (atomic_dec_and_lock(&qd->qd_count, &qd_lru_lock)) { + /* Add to the reclaim list */ + list_add_tail(&qd->qd_reclaim, &qd_lru_list); + atomic_inc(&qd_lru_count); + spin_unlock(&qd_lru_lock); + } } static int slot_get(struct gfs2_quota_data *qd) @@ -198,10 +241,10 @@ static int slot_get(struct gfs2_quota_data *qd) unsigned int c, o = 0, b; unsigned char byte = 0; - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); if (qd->qd_slot_count++) { - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); return 0; } @@ -225,13 +268,13 @@ found: sdp->sd_quota_bitmap[c][o] |= 1 << b; - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); return 0; fail: qd->qd_slot_count--; - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); return -ENOSPC; } @@ -239,23 +282,23 @@ static void slot_hold(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); gfs2_assert(sdp, qd->qd_slot_count); qd->qd_slot_count++; - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); } static void slot_put(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); gfs2_assert(sdp, qd->qd_slot_count); if (!--qd->qd_slot_count) { gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, qd->qd_slot, 0); qd->qd_slot = -1; } - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); } static int bh_get(struct gfs2_quota_data *qd) @@ -330,7 +373,7 @@ static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp) if (sdp->sd_vfs->s_flags & MS_RDONLY) return 0; - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) { if (test_bit(QDF_LOCKED, &qd->qd_flags) || @@ -341,8 +384,8 @@ static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp) list_move_tail(&qd->qd_list, &sdp->sd_quota_list); set_bit(QDF_LOCKED, &qd->qd_flags); - gfs2_assert_warn(sdp, qd->qd_count); - qd->qd_count++; + gfs2_assert_warn(sdp, atomic_read(&qd->qd_count)); + atomic_inc(&qd->qd_count); qd->qd_change_sync = qd->qd_change; gfs2_assert_warn(sdp, qd->qd_slot_count); qd->qd_slot_count++; @@ -354,7 +397,7 @@ static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp) if (!found) qd = NULL; - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); if (qd) { gfs2_assert_warn(sdp, qd->qd_change_sync); @@ -379,24 +422,24 @@ static int qd_trylock(struct gfs2_quota_data *qd) if (sdp->sd_vfs->s_flags & MS_RDONLY) return 0; - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); if (test_bit(QDF_LOCKED, &qd->qd_flags) || !test_bit(QDF_CHANGE, &qd->qd_flags)) { - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); return 0; } list_move_tail(&qd->qd_list, &sdp->sd_quota_list); set_bit(QDF_LOCKED, &qd->qd_flags); - gfs2_assert_warn(sdp, qd->qd_count); - qd->qd_count++; + gfs2_assert_warn(sdp, atomic_read(&qd->qd_count)); + atomic_inc(&qd->qd_count); qd->qd_change_sync = qd->qd_change; gfs2_assert_warn(sdp, qd->qd_slot_count); qd->qd_slot_count++; - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); gfs2_assert_warn(sdp, qd->qd_change_sync); if (bh_get(qd)) { @@ -556,9 +599,9 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change) x = be64_to_cpu(qc->qc_change) + change; qc->qc_change = cpu_to_be64(x); - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); qd->qd_change = x; - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); if (!x) { gfs2_assert_warn(sdp, test_bit(QDF_CHANGE, &qd->qd_flags)); @@ -802,8 +845,8 @@ restart: loff_t pos; gfs2_glock_dq_uninit(q_gh); error = gfs2_glock_nq_init(qd->qd_gl, - LM_ST_EXCLUSIVE, GL_NOCACHE, - q_gh); + LM_ST_EXCLUSIVE, GL_NOCACHE, + q_gh); if (error) return error; @@ -820,7 +863,6 @@ restart: gfs2_glock_dq_uninit(&i_gh); - gfs2_quota_in(&q, buf); qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC); @@ -890,9 +932,9 @@ static int need_sync(struct gfs2_quota_data *qd) if (!qd->qd_qb.qb_limit) return 0; - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); value = qd->qd_change; - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); spin_lock(>->gt_spin); num = gt->gt_quota_scale_num; @@ -985,9 +1027,9 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid) continue; value = (s64)be64_to_cpu(qd->qd_qb.qb_value); - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); value += qd->qd_change; - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) { print_message(qd, "exceeded"); @@ -1171,13 +1213,12 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) qd->qd_change = qc.qc_change; qd->qd_slot = slot; qd->qd_slot_count = 1; - qd->qd_last_touched = jiffies; - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, slot, 1); list_add(&qd->qd_list, &sdp->sd_quota_list); atomic_inc(&sdp->sd_quota_count); - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); found++; } @@ -1197,73 +1238,48 @@ fail: return error; } -static void gfs2_quota_scan(struct gfs2_sbd *sdp) -{ - struct gfs2_quota_data *qd, *safe; - LIST_HEAD(dead); - - spin_lock(&sdp->sd_quota_spin); - list_for_each_entry_safe(qd, safe, &sdp->sd_quota_list, qd_list) { - if (!qd->qd_count && - time_after_eq(jiffies, qd->qd_last_touched + - gfs2_tune_get(sdp, gt_quota_cache_secs) * HZ)) { - list_move(&qd->qd_list, &dead); - gfs2_assert_warn(sdp, - atomic_read(&sdp->sd_quota_count) > 0); - atomic_dec(&sdp->sd_quota_count); - } - } - spin_unlock(&sdp->sd_quota_spin); - - while (!list_empty(&dead)) { - qd = list_entry(dead.next, struct gfs2_quota_data, qd_list); - list_del(&qd->qd_list); - - gfs2_assert_warn(sdp, !qd->qd_change); - gfs2_assert_warn(sdp, !qd->qd_slot_count); - gfs2_assert_warn(sdp, !qd->qd_bh_count); - - gfs2_lvb_unhold(qd->qd_gl); - kmem_cache_free(gfs2_quotad_cachep, qd); - } -} - void gfs2_quota_cleanup(struct gfs2_sbd *sdp) { struct list_head *head = &sdp->sd_quota_list; struct gfs2_quota_data *qd; unsigned int x; - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); while (!list_empty(head)) { qd = list_entry(head->prev, struct gfs2_quota_data, qd_list); - if (qd->qd_count > 1 || - (qd->qd_count && !test_bit(QDF_CHANGE, &qd->qd_flags))) { + if (atomic_read(&qd->qd_count) > 1 || + (atomic_read(&qd->qd_count) && + !test_bit(QDF_CHANGE, &qd->qd_flags))) { list_move(&qd->qd_list, head); - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); schedule(); - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); continue; } list_del(&qd->qd_list); + /* Also remove if this qd exists in the reclaim list */ + if (!list_empty(&qd->qd_reclaim)) { + list_del_init(&qd->qd_reclaim); + atomic_dec(&qd_lru_count); + } atomic_dec(&sdp->sd_quota_count); - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); - if (!qd->qd_count) { + if (!atomic_read(&qd->qd_count)) { gfs2_assert_warn(sdp, !qd->qd_change); gfs2_assert_warn(sdp, !qd->qd_slot_count); } else gfs2_assert_warn(sdp, qd->qd_slot_count == 1); gfs2_assert_warn(sdp, !qd->qd_bh_count); - gfs2_lvb_unhold(qd->qd_gl); + gfs2_glock_put(qd->qd_gl); kmem_cache_free(gfs2_quotad_cachep, qd); - spin_lock(&sdp->sd_quota_spin); + spin_lock(&qd_lru_lock); } - spin_unlock(&sdp->sd_quota_spin); + spin_unlock(&qd_lru_lock); gfs2_assert_warn(sdp, !atomic_read(&sdp->sd_quota_count)); @@ -1341,9 +1357,6 @@ int gfs2_quotad(void *data) quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t, "ad_timeo, &tune->gt_quota_quantum); - /* FIXME: This should be turned into a shrinker */ - gfs2_quota_scan(sdp); - /* Check for & recover partially truncated inodes */ quotad_check_trunc_list(sdp); diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index cec9032be97..0fa5fa63d0e 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -49,4 +49,6 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip) return ret; } +extern int gfs2_shrink_qd_memory(int nr, gfp_t gfp_mask); + #endif /* __QUOTA_DOT_H__ */ diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index efd09c3d2b2..247e8f7d6b3 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -13,7 +13,6 @@ #include <linux/buffer_head.h> #include <linux/gfs2_ondisk.h> #include <linux/crc32.h> -#include <linux/lm_interface.h> #include <linux/kthread.h> #include <linux/freezer.h> @@ -427,20 +426,23 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *hea } -static void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, - unsigned int message) +static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, + unsigned int message) { - if (!sdp->sd_lockstruct.ls_ops->lm_recovery_done) - return; - - if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) - sdp->sd_lockstruct.ls_ops->lm_recovery_done( - sdp->sd_lockstruct.ls_lockspace, jid, message); + char env_jid[20]; + char env_status[20]; + char *envp[] = { env_jid, env_status, NULL }; + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + ls->ls_recover_jid_done = jid; + ls->ls_recover_jid_status = message; + sprintf(env_jid, "JID=%d", jid); + sprintf(env_status, "RECOVERY=%s", + message == LM_RD_SUCCESS ? "Done" : "Failed"); + kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp); } - /** - * gfs2_recover_journal - recovery a given journal + * gfs2_recover_journal - recover a given journal * @jd: the struct gfs2_jdesc describing the journal * * Acquire the journal's lock, check to see if the journal is clean, and @@ -561,7 +563,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd) if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) gfs2_glock_dq_uninit(&ji_gh); - gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_SUCCESS); + gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_SUCCESS); if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) gfs2_glock_dq_uninit(&j_gh); @@ -581,7 +583,7 @@ fail_gunlock_j: fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done"); fail: - gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); + gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); return error; } diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 8b01c635d92..f03d024038e 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -13,8 +13,8 @@ #include <linux/buffer_head.h> #include <linux/fs.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include <linux/prefetch.h> +#include <linux/blkdev.h> #include "gfs2.h" #include "incore.h" @@ -132,81 +132,90 @@ static inline unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, } /** + * gfs2_bit_search + * @ptr: Pointer to bitmap data + * @mask: Mask to use (normally 0x55555.... but adjusted for search start) + * @state: The state we are searching for + * + * We xor the bitmap data with a patter which is the bitwise opposite + * of what we are looking for, this gives rise to a pattern of ones + * wherever there is a match. Since we have two bits per entry, we + * take this pattern, shift it down by one place and then and it with + * the original. All the even bit positions (0,2,4, etc) then represent + * successful matches, so we mask with 0x55555..... to remove the unwanted + * odd bit positions. + * + * This allows searching of a whole u64 at once (32 blocks) with a + * single test (on 64 bit arches). + */ + +static inline u64 gfs2_bit_search(const __le64 *ptr, u64 mask, u8 state) +{ + u64 tmp; + static const u64 search[] = { + [0] = 0xffffffffffffffffULL, + [1] = 0xaaaaaaaaaaaaaaaaULL, + [2] = 0x5555555555555555ULL, + [3] = 0x0000000000000000ULL, + }; + tmp = le64_to_cpu(*ptr) ^ search[state]; + tmp &= (tmp >> 1); + tmp &= mask; + return tmp; +} + +/** * gfs2_bitfit - Search an rgrp's bitmap buffer to find a bit-pair representing * a block in a given allocation state. * @buffer: the buffer that holds the bitmaps - * @buflen: the length (in bytes) of the buffer + * @len: the length (in bytes) of the buffer * @goal: start search at this block's bit-pair (within @buffer) - * @old_state: GFS2_BLKST_XXX the state of the block we're looking for. + * @state: GFS2_BLKST_XXX the state of the block we're looking for. * * Scope of @goal and returned block number is only within this bitmap buffer, * not entire rgrp or filesystem. @buffer will be offset from the actual - * beginning of a bitmap block buffer, skipping any header structures. + * beginning of a bitmap block buffer, skipping any header structures, but + * headers are always a multiple of 64 bits long so that the buffer is + * always aligned to a 64 bit boundary. + * + * The size of the buffer is in bytes, but is it assumed that it is + * always ok to to read a complete multiple of 64 bits at the end + * of the block in case the end is no aligned to a natural boundary. * * Return: the block number (bitmap buffer scope) that was found */ -static u32 gfs2_bitfit(const u8 *buffer, unsigned int buflen, u32 goal, - u8 old_state) +static u32 gfs2_bitfit(const u8 *buf, const unsigned int len, + u32 goal, u8 state) { - const u8 *byte, *start, *end; - int bit, startbit; - u32 g1, g2, misaligned; - unsigned long *plong; - unsigned long lskipval; - - lskipval = (old_state & GFS2_BLKST_USED) ? LBITSKIP00 : LBITSKIP55; - g1 = (goal / GFS2_NBBY); - start = buffer + g1; - byte = start; - end = buffer + buflen; - g2 = ALIGN(g1, sizeof(unsigned long)); - plong = (unsigned long *)(buffer + g2); - startbit = bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE; - misaligned = g2 - g1; - if (!misaligned) - goto ulong_aligned; -/* parse the bitmap a byte at a time */ -misaligned: - while (byte < end) { - if (((*byte >> bit) & GFS2_BIT_MASK) == old_state) { - return goal + - (((byte - start) * GFS2_NBBY) + - ((bit - startbit) >> 1)); - } - bit += GFS2_BIT_SIZE; - if (bit >= GFS2_NBBY * GFS2_BIT_SIZE) { - bit = 0; - byte++; - misaligned--; - if (!misaligned) { - plong = (unsigned long *)byte; - goto ulong_aligned; - } - } - } - return BFITNOENT; - -/* parse the bitmap a unsigned long at a time */ -ulong_aligned: - /* Stop at "end - 1" or else prefetch can go past the end and segfault. - We could "if" it but we'd lose some of the performance gained. - This way will only slow down searching the very last 4/8 bytes - depending on architecture. I've experimented with several ways - of writing this section such as using an else before the goto - but this one seems to be the fastest. */ - while ((unsigned char *)plong < end - sizeof(unsigned long)) { - prefetch(plong + 1); - if (((*plong) & LBITMASK) != lskipval) - break; - plong++; - } - if ((unsigned char *)plong < end) { - byte = (const u8 *)plong; - misaligned += sizeof(unsigned long) - 1; - goto misaligned; + u32 spoint = (goal << 1) & ((8*sizeof(u64)) - 1); + const __le64 *ptr = ((__le64 *)buf) + (goal >> 5); + const __le64 *end = (__le64 *)(buf + ALIGN(len, sizeof(u64))); + u64 tmp; + u64 mask = 0x5555555555555555ULL; + u32 bit; + + BUG_ON(state > 3); + + /* Mask off bits we don't care about at the start of the search */ + mask <<= spoint; + tmp = gfs2_bit_search(ptr, mask, state); + ptr++; + while(tmp == 0 && ptr < end) { + tmp = gfs2_bit_search(ptr, 0x5555555555555555ULL, state); + ptr++; } - return BFITNOENT; + /* Mask off any bits which are more than len bytes from the start */ + if (ptr == end && (len & (sizeof(u64) - 1))) + tmp &= (((u64)~0) >> (64 - 8*(len & (sizeof(u64) - 1)))); + /* Didn't find anything, so return */ + if (tmp == 0) + return BFITNOENT; + ptr--; + bit = fls64(tmp); + bit--; /* fls64 always adds one to the bit count */ + bit /= 2; /* two bits per entry in the bitmap */ + return (((const unsigned char *)ptr - buf) * GFS2_NBBY) + bit; } /** @@ -831,6 +840,58 @@ void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd) spin_unlock(&sdp->sd_rindex_spin); } +static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, + const struct gfs2_bitmap *bi) +{ + struct super_block *sb = sdp->sd_vfs; + struct block_device *bdev = sb->s_bdev; + const unsigned int sects_per_blk = sdp->sd_sb.sb_bsize / + bdev_hardsect_size(sb->s_bdev); + u64 blk; + sector_t start = 0; + sector_t nr_sects = 0; + int rv; + unsigned int x; + + for (x = 0; x < bi->bi_len; x++) { + const u8 *orig = bi->bi_bh->b_data + bi->bi_offset + x; + const u8 *clone = bi->bi_clone + bi->bi_offset + x; + u8 diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1)); + diff &= 0x55; + if (diff == 0) + continue; + blk = offset + ((bi->bi_start + x) * GFS2_NBBY); + blk *= sects_per_blk; /* convert to sectors */ + while(diff) { + if (diff & 1) { + if (nr_sects == 0) + goto start_new_extent; + if ((start + nr_sects) != blk) { + rv = blkdev_issue_discard(bdev, start, + nr_sects, GFP_NOFS); + if (rv) + goto fail; + nr_sects = 0; +start_new_extent: + start = blk; + } + nr_sects += sects_per_blk; + } + diff >>= 2; + blk += sects_per_blk; + } + } + if (nr_sects) { + rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS); + if (rv) + goto fail; + } + return; +fail: + fs_warn(sdp, "error %d on discard request, turning discards off for this filesystem", rv); + sdp->sd_args.ar_discard = 0; +} + void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd) { struct gfs2_sbd *sdp = rgd->rd_sbd; @@ -841,6 +902,8 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd) struct gfs2_bitmap *bi = rgd->rd_bits + x; if (!bi->bi_clone) continue; + if (sdp->sd_args.ar_discard) + gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bi); memcpy(bi->bi_clone + bi->bi_offset, bi->bi_bh->b_data + bi->bi_offset, bi->bi_len); } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 141b781f2fc..601913e0a48 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -15,7 +15,6 @@ #include <linux/crc32.h> #include <linux/gfs2_ondisk.h> #include <linux/bio.h> -#include <linux/lm_interface.h> #include "gfs2.h" #include "incore.h" @@ -339,7 +338,6 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp, struct gfs2_holder *t_gh) { struct gfs2_inode *ip; - struct gfs2_holder ji_gh; struct gfs2_jdesc *jd; struct lfcc *lfcc; LIST_HEAD(list); @@ -387,7 +385,6 @@ out: gfs2_glock_dq_uninit(&lfcc->gh); kfree(lfcc); } - gfs2_glock_dq_uninit(&ji_gh); return error; } diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index f6b8b00ad88..b56413e3e40 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -14,7 +14,7 @@ #include <linux/dcache.h> #include "incore.h" -void gfs2_lm_unmount(struct gfs2_sbd *sdp); +extern void gfs2_lm_unmount(struct gfs2_sbd *sdp); static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) { @@ -27,27 +27,29 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) void gfs2_jindex_free(struct gfs2_sbd *sdp); -struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); -int gfs2_jdesc_check(struct gfs2_jdesc *jd); +extern int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *data); -int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename, - struct gfs2_inode **ipp); +extern struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); +extern int gfs2_jdesc_check(struct gfs2_jdesc *jd); -int gfs2_make_fs_rw(struct gfs2_sbd *sdp); +extern int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename, + struct gfs2_inode **ipp); -int gfs2_statfs_init(struct gfs2_sbd *sdp); -void gfs2_statfs_change(struct gfs2_sbd *sdp, - s64 total, s64 free, s64 dinodes); -int gfs2_statfs_sync(struct gfs2_sbd *sdp); +extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp); -int gfs2_freeze_fs(struct gfs2_sbd *sdp); -void gfs2_unfreeze_fs(struct gfs2_sbd *sdp); +extern int gfs2_statfs_init(struct gfs2_sbd *sdp); +extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, + s64 dinodes); +extern int gfs2_statfs_sync(struct gfs2_sbd *sdp); + +extern int gfs2_freeze_fs(struct gfs2_sbd *sdp); +extern void gfs2_unfreeze_fs(struct gfs2_sbd *sdp); extern struct file_system_type gfs2_fs_type; extern struct file_system_type gfs2meta_fs_type; extern const struct export_operations gfs2_export_ops; extern const struct super_operations gfs2_super_ops; -extern struct dentry_operations gfs2_dops; +extern const struct dentry_operations gfs2_dops; #endif /* __SUPER_DOT_H__ */ diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 26c1fa777a9..7655f5025fe 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -14,9 +14,8 @@ #include <linux/buffer_head.h> #include <linux/module.h> #include <linux/kobject.h> -#include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include <asm/uaccess.h> +#include <linux/gfs2_ondisk.h> #include "gfs2.h" #include "incore.h" @@ -25,6 +24,7 @@ #include "glock.h" #include "quota.h" #include "util.h" +#include "glops.h" static ssize_t id_show(struct gfs2_sbd *sdp, char *buf) { @@ -37,6 +37,30 @@ static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf) return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_fsname); } +static int gfs2_uuid_valid(const u8 *uuid) +{ + int i; + + for (i = 0; i < 16; i++) { + if (uuid[i]) + return 1; + } + return 0; +} + +static ssize_t uuid_show(struct gfs2_sbd *sdp, char *buf) +{ + const u8 *uuid = sdp->sd_sb.sb_uuid; + buf[0] = '\0'; + if (!gfs2_uuid_valid(uuid)) + return 0; + return snprintf(buf, PAGE_SIZE, "%02X%02X%02X%02X-%02X%02X-" + "%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n", + uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], + uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); +} + static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf) { unsigned int count; @@ -148,6 +172,46 @@ static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf, return len; } +static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len) +{ + struct gfs2_glock *gl; + const struct gfs2_glock_operations *glops; + unsigned int glmode; + unsigned int gltype; + unsigned long long glnum; + char mode[16]; + int rv; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + rv = sscanf(buf, "%u:%llu %15s", &gltype, &glnum, + mode); + if (rv != 3) + return -EINVAL; + + if (strcmp(mode, "EX") == 0) + glmode = LM_ST_UNLOCKED; + else if ((strcmp(mode, "CW") == 0) || (strcmp(mode, "DF") == 0)) + glmode = LM_ST_DEFERRED; + else if ((strcmp(mode, "PR") == 0) || (strcmp(mode, "SH") == 0)) + glmode = LM_ST_SHARED; + else + return -EINVAL; + + if (gltype > LM_TYPE_JOURNAL) + return -EINVAL; + glops = gfs2_glops_list[gltype]; + if (glops == NULL) + return -EINVAL; + rv = gfs2_glock_get(sdp, glnum, glops, 0, &gl); + if (rv) + return rv; + gfs2_glock_cb(gl, glmode); + gfs2_glock_put(gl); + return len; +} + struct gfs2_attr { struct attribute attr; ssize_t (*show)(struct gfs2_sbd *, char *); @@ -159,22 +223,26 @@ static struct gfs2_attr gfs2_attr_##name = __ATTR(name, mode, show, store) GFS2_ATTR(id, 0444, id_show, NULL); GFS2_ATTR(fsname, 0444, fsname_show, NULL); +GFS2_ATTR(uuid, 0444, uuid_show, NULL); GFS2_ATTR(freeze, 0644, freeze_show, freeze_store); GFS2_ATTR(withdraw, 0644, withdraw_show, withdraw_store); GFS2_ATTR(statfs_sync, 0200, NULL, statfs_sync_store); GFS2_ATTR(quota_sync, 0200, NULL, quota_sync_store); GFS2_ATTR(quota_refresh_user, 0200, NULL, quota_refresh_user_store); GFS2_ATTR(quota_refresh_group, 0200, NULL, quota_refresh_group_store); +GFS2_ATTR(demote_rq, 0200, NULL, demote_rq_store); static struct attribute *gfs2_attrs[] = { &gfs2_attr_id.attr, &gfs2_attr_fsname.attr, + &gfs2_attr_uuid.attr, &gfs2_attr_freeze.attr, &gfs2_attr_withdraw.attr, &gfs2_attr_statfs_sync.attr, &gfs2_attr_quota_sync.attr, &gfs2_attr_quota_refresh_user.attr, &gfs2_attr_quota_refresh_group.attr, + &gfs2_attr_demote_rq.attr, NULL, }; @@ -224,14 +292,145 @@ static struct lockstruct_attr lockstruct_attr_##name = __ATTR_RO(name) LOCKSTRUCT_ATTR(jid, "%u\n"); LOCKSTRUCT_ATTR(first, "%u\n"); -LOCKSTRUCT_ATTR(lvb_size, "%u\n"); -LOCKSTRUCT_ATTR(flags, "%d\n"); static struct attribute *lockstruct_attrs[] = { &lockstruct_attr_jid.attr, &lockstruct_attr_first.attr, - &lockstruct_attr_lvb_size.attr, - &lockstruct_attr_flags.attr, + NULL, +}; + +/* + * lock_module. Originally from lock_dlm + */ + +static ssize_t proto_name_show(struct gfs2_sbd *sdp, char *buf) +{ + const struct lm_lockops *ops = sdp->sd_lockstruct.ls_ops; + return sprintf(buf, "%s\n", ops->lm_proto_name); +} + +static ssize_t block_show(struct gfs2_sbd *sdp, char *buf) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + ssize_t ret; + int val = 0; + + if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags)) + val = 1; + ret = sprintf(buf, "%d\n", val); + return ret; +} + +static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + ssize_t ret = len; + int val; + + val = simple_strtol(buf, NULL, 0); + + if (val == 1) + set_bit(DFL_BLOCK_LOCKS, &ls->ls_flags); + else if (val == 0) { + clear_bit(DFL_BLOCK_LOCKS, &ls->ls_flags); + smp_mb__after_clear_bit(); + gfs2_glock_thaw(sdp); + } else { + ret = -EINVAL; + } + return ret; +} + +static ssize_t lkid_show(struct gfs2_sbd *sdp, char *buf) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + return sprintf(buf, "%u\n", ls->ls_id); +} + +static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + return sprintf(buf, "%d\n", ls->ls_first); +} + +static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + return sprintf(buf, "%d\n", ls->ls_first_done); +} + +static ssize_t recover_show(struct gfs2_sbd *sdp, char *buf) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + return sprintf(buf, "%d\n", ls->ls_recover_jid); +} + +static void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid) +{ + struct gfs2_jdesc *jd; + + spin_lock(&sdp->sd_jindex_spin); + list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) { + if (jd->jd_jid != jid) + continue; + jd->jd_dirty = 1; + break; + } + spin_unlock(&sdp->sd_jindex_spin); +} + +static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + ls->ls_recover_jid = simple_strtol(buf, NULL, 0); + gfs2_jdesc_make_dirty(sdp, ls->ls_recover_jid); + if (sdp->sd_recoverd_process) + wake_up_process(sdp->sd_recoverd_process); + return len; +} + +static ssize_t recover_done_show(struct gfs2_sbd *sdp, char *buf) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + return sprintf(buf, "%d\n", ls->ls_recover_jid_done); +} + +static ssize_t recover_status_show(struct gfs2_sbd *sdp, char *buf) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + return sprintf(buf, "%d\n", ls->ls_recover_jid_status); +} + +struct gdlm_attr { + struct attribute attr; + ssize_t (*show)(struct gfs2_sbd *sdp, char *); + ssize_t (*store)(struct gfs2_sbd *sdp, const char *, size_t); +}; + +#define GDLM_ATTR(_name,_mode,_show,_store) \ +static struct gdlm_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) + +GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); +GDLM_ATTR(block, 0644, block_show, block_store); +GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); +GDLM_ATTR(id, 0444, lkid_show, NULL); +GDLM_ATTR(first, 0444, lkfirst_show, NULL); +GDLM_ATTR(first_done, 0444, first_done_show, NULL); +GDLM_ATTR(recover, 0644, recover_show, recover_store); +GDLM_ATTR(recover_done, 0444, recover_done_show, NULL); +GDLM_ATTR(recover_status, 0444, recover_status_show, NULL); + +static struct attribute *lock_module_attrs[] = { + &gdlm_attr_proto_name.attr, + &gdlm_attr_block.attr, + &gdlm_attr_withdraw.attr, + &gdlm_attr_id.attr, + &lockstruct_attr_jid.attr, + &gdlm_attr_first.attr, + &gdlm_attr_first_done.attr, + &gdlm_attr_recover.attr, + &gdlm_attr_recover_done.attr, + &gdlm_attr_recover_status.attr, NULL, }; @@ -373,7 +572,6 @@ TUNE_ATTR(complain_secs, 0); TUNE_ATTR(statfs_slow, 0); TUNE_ATTR(new_files_jdata, 0); TUNE_ATTR(quota_simul_sync, 1); -TUNE_ATTR(quota_cache_secs, 1); TUNE_ATTR(stall_secs, 1); TUNE_ATTR(statfs_quantum, 1); TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process); @@ -389,7 +587,6 @@ static struct attribute *tune_attrs[] = { &tune_attr_complain_secs.attr, &tune_attr_statfs_slow.attr, &tune_attr_quota_simul_sync.attr, - &tune_attr_quota_cache_secs.attr, &tune_attr_stall_secs.attr, &tune_attr_statfs_quantum.attr, &tune_attr_recoverd_secs.attr, @@ -414,6 +611,11 @@ static struct attribute_group tune_group = { .attrs = tune_attrs, }; +static struct attribute_group lock_module_group = { + .name = "lock_module", + .attrs = lock_module_attrs, +}; + int gfs2_sys_fs_add(struct gfs2_sbd *sdp) { int error; @@ -436,9 +638,15 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp) if (error) goto fail_args; + error = sysfs_create_group(&sdp->sd_kobj, &lock_module_group); + if (error) + goto fail_tune; + kobject_uevent(&sdp->sd_kobj, KOBJ_ADD); return 0; +fail_tune: + sysfs_remove_group(&sdp->sd_kobj, &tune_group); fail_args: sysfs_remove_group(&sdp->sd_kobj, &args_group); fail_lockstruct: @@ -455,15 +663,27 @@ void gfs2_sys_fs_del(struct gfs2_sbd *sdp) sysfs_remove_group(&sdp->sd_kobj, &tune_group); sysfs_remove_group(&sdp->sd_kobj, &args_group); sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group); + sysfs_remove_group(&sdp->sd_kobj, &lock_module_group); kobject_put(&sdp->sd_kobj); } + static int gfs2_uevent(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env) { struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); + const u8 *uuid = sdp->sd_sb.sb_uuid; + add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name); add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name); + if (gfs2_uuid_valid(uuid)) { + add_uevent_var(env, "UUID=%02X%02X%02X%02X-%02X%02X-%02X%02X-" + "%02X%02X-%02X%02X%02X%02X%02X%02X", + uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], + uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], + uuid[10], uuid[11], uuid[12], uuid[13], + uuid[14], uuid[15]); + } return 0; } diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index f677b8a83f0..053752d4b27 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -12,9 +12,8 @@ #include <linux/spinlock.h> #include <linux/completion.h> #include <linux/buffer_head.h> -#include <linux/gfs2_ondisk.h> #include <linux/kallsyms.h> -#include <linux/lm_interface.h> +#include <linux/gfs2_ondisk.h> #include "gfs2.h" #include "incore.h" @@ -88,9 +87,11 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) if (!tr->tr_touched) { gfs2_log_release(sdp, tr->tr_reserved); - gfs2_glock_dq(&tr->tr_t_gh); - gfs2_holder_uninit(&tr->tr_t_gh); - kfree(tr); + if (tr->tr_t_gh.gh_gl) { + gfs2_glock_dq(&tr->tr_t_gh); + gfs2_holder_uninit(&tr->tr_t_gh); + kfree(tr); + } return; } @@ -106,9 +107,11 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) } gfs2_log_commit(sdp, tr); - gfs2_glock_dq(&tr->tr_t_gh); - gfs2_holder_uninit(&tr->tr_t_gh); - kfree(tr); + if (tr->tr_t_gh.gh_gl) { + gfs2_glock_dq(&tr->tr_t_gh); + gfs2_holder_uninit(&tr->tr_t_gh); + kfree(tr); + } if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS) gfs2_log_flush(sdp, NULL); diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 374f50e9549..9d12b1118ba 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -13,7 +13,6 @@ #include <linux/buffer_head.h> #include <linux/crc32.h> #include <linux/gfs2_ondisk.h> -#include <linux/lm_interface.h> #include <asm/uaccess.h> #include "gfs2.h" @@ -35,6 +34,8 @@ void gfs2_assert_i(struct gfs2_sbd *sdp) int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) { + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + const struct lm_lockops *lm = ls->ls_ops; va_list args; if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) @@ -47,8 +48,12 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) fs_err(sdp, "about to withdraw this file system\n"); BUG_ON(sdp->sd_args.ar_debug); - fs_err(sdp, "telling LM to withdraw\n"); - gfs2_withdraw_lockproto(&sdp->sd_lockstruct); + kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE); + + if (lm->lm_unmount) { + fs_err(sdp, "telling LM to unmount\n"); + lm->lm_unmount(sdp); + } fs_err(sdp, "withdrawn\n"); dump_stack(); diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h index 9955232fdf8..052387e1167 100644 --- a/fs/hfs/hfs_fs.h +++ b/fs/hfs/hfs_fs.h @@ -213,7 +213,7 @@ extern void hfs_mdb_put(struct super_block *); extern int hfs_part_find(struct super_block *, sector_t *, sector_t *); /* string.c */ -extern struct dentry_operations hfs_dentry_operations; +extern const struct dentry_operations hfs_dentry_operations; extern int hfs_hash_dentry(struct dentry *, struct qstr *); extern int hfs_strcmp(const unsigned char *, unsigned int, diff --git a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c index 5bf89ec01cd..7478f5c219a 100644 --- a/fs/hfs/sysdep.c +++ b/fs/hfs/sysdep.c @@ -31,7 +31,7 @@ static int hfs_revalidate_dentry(struct dentry *dentry, struct nameidata *nd) return 1; } -struct dentry_operations hfs_dentry_operations = +const struct dentry_operations hfs_dentry_operations = { .d_revalidate = hfs_revalidate_dentry, .d_hash = hfs_hash_dentry, diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index f027a905225..5c10d803d9d 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -327,7 +327,7 @@ void hfsplus_file_truncate(struct inode *); /* inode.c */ extern const struct address_space_operations hfsplus_aops; extern const struct address_space_operations hfsplus_btree_aops; -extern struct dentry_operations hfsplus_dentry_operations; +extern const struct dentry_operations hfsplus_dentry_operations; void hfsplus_inode_read_fork(struct inode *, struct hfsplus_fork_raw *); void hfsplus_inode_write_fork(struct inode *, struct hfsplus_fork_raw *); diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index f105ee9e1cc..1bcf597c056 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -137,7 +137,7 @@ const struct address_space_operations hfsplus_aops = { .writepages = hfsplus_writepages, }; -struct dentry_operations hfsplus_dentry_operations = { +const struct dentry_operations hfsplus_dentry_operations = { .d_hash = hfsplus_hash_dentry, .d_compare = hfsplus_compare_dentry, }; diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 5c538e0ec14..fe02ad4740e 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -31,12 +31,12 @@ static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode) #define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode) -int hostfs_d_delete(struct dentry *dentry) +static int hostfs_d_delete(struct dentry *dentry) { return 1; } -struct dentry_operations hostfs_dentry_ops = { +static const struct dentry_operations hostfs_dentry_ops = { .d_delete = hostfs_d_delete, }; diff --git a/fs/hpfs/dentry.c b/fs/hpfs/dentry.c index 08319126b2a..940d6d150be 100644 --- a/fs/hpfs/dentry.c +++ b/fs/hpfs/dentry.c @@ -49,7 +49,7 @@ static int hpfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qst return 0; } -static struct dentry_operations hpfs_dentry_operations = { +static const struct dentry_operations hpfs_dentry_operations = { .d_hash = hpfs_hash_dentry, .d_compare = hpfs_compare_dentry, }; diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 9b800d97a68..23a3c76711e 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -943,14 +943,13 @@ static struct vfsmount *hugetlbfs_vfsmount; static int can_do_hugetlb_shm(void) { - return likely(capable(CAP_IPC_LOCK) || - in_group_p(sysctl_hugetlb_shm_group) || - can_do_mlock()); + return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group); } struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag) { int error = -ENOMEM; + int unlock_shm = 0; struct file *file; struct inode *inode; struct dentry *dentry, *root; @@ -960,11 +959,14 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag) if (!hugetlbfs_vfsmount) return ERR_PTR(-ENOENT); - if (!can_do_hugetlb_shm()) - return ERR_PTR(-EPERM); - - if (!user_shm_lock(size, user)) - return ERR_PTR(-ENOMEM); + if (!can_do_hugetlb_shm()) { + if (user_shm_lock(size, user)) { + unlock_shm = 1; + WARN_ONCE(1, + "Using mlock ulimits for SHM_HUGETLB deprecated\n"); + } else + return ERR_PTR(-EPERM); + } root = hugetlbfs_vfsmount->mnt_root; quick_string.name = name; @@ -1004,7 +1006,8 @@ out_inode: out_dentry: dput(dentry); out_shm_unlock: - user_shm_unlock(size, user); + if (unlock_shm) + user_shm_unlock(size, user); return ERR_PTR(error); } diff --git a/fs/inode.c b/fs/inode.c index 913ab2d9a5d..d06d6d268de 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -17,6 +17,7 @@ #include <linux/hash.h> #include <linux/swap.h> #include <linux/security.h> +#include <linux/ima.h> #include <linux/pagemap.h> #include <linux/cdev.h> #include <linux/bootmem.h> @@ -147,13 +148,13 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode) inode->i_cdev = NULL; inode->i_rdev = 0; inode->dirtied_when = 0; - if (security_inode_alloc(inode)) { - if (inode->i_sb->s_op->destroy_inode) - inode->i_sb->s_op->destroy_inode(inode); - else - kmem_cache_free(inode_cachep, (inode)); - return NULL; - } + + if (security_inode_alloc(inode)) + goto out_free_inode; + + /* allocate and initialize an i_integrity */ + if (ima_inode_alloc(inode)) + goto out_free_security; spin_lock_init(&inode->i_lock); lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key); @@ -189,6 +190,15 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode) inode->i_mapping = mapping; return inode; + +out_free_security: + security_inode_free(inode); +out_free_inode: + if (inode->i_sb->s_op->destroy_inode) + inode->i_sb->s_op->destroy_inode(inode); + else + kmem_cache_free(inode_cachep, (inode)); + return NULL; } EXPORT_SYMBOL(inode_init_always); @@ -284,7 +294,7 @@ void clear_inode(struct inode *inode) BUG_ON(!(inode->i_state & I_FREEING)); BUG_ON(inode->i_state & I_CLEAR); inode_sync_wait(inode); - DQUOT_DROP(inode); + vfs_dq_drop(inode); if (inode->i_sb->s_op->clear_inode) inode->i_sb->s_op->clear_inode(inode); if (S_ISBLK(inode->i_mode) && inode->i_bdev) @@ -356,9 +366,12 @@ static int invalidate_list(struct list_head *head, struct list_head *dispose) if (tmp == head) break; inode = list_entry(tmp, struct inode, i_sb_list); + if (inode->i_state & I_NEW) + continue; invalidate_inode_buffers(inode); if (!atomic_read(&inode->i_count)) { list_move(&inode->i_list, dispose); + WARN_ON(inode->i_state & I_NEW); inode->i_state |= I_FREEING; count++; continue; @@ -460,6 +473,7 @@ static void prune_icache(int nr_to_scan) continue; } list_move(&inode->i_list, &freeable); + WARN_ON(inode->i_state & I_NEW); inode->i_state |= I_FREEING; nr_pruned++; } @@ -656,6 +670,7 @@ void unlock_new_inode(struct inode *inode) * just created it (so there can be no old holders * that haven't tested I_LOCK). */ + WARN_ON((inode->i_state & (I_LOCK|I_NEW)) != (I_LOCK|I_NEW)); inode->i_state &= ~(I_LOCK|I_NEW); wake_up_inode(inode); } @@ -1145,6 +1160,7 @@ void generic_delete_inode(struct inode *inode) list_del_init(&inode->i_list); list_del_init(&inode->i_sb_list); + WARN_ON(inode->i_state & I_NEW); inode->i_state |= I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); @@ -1154,7 +1170,7 @@ void generic_delete_inode(struct inode *inode) if (op->delete_inode) { void (*delete)(struct inode *) = op->delete_inode; if (!is_bad_inode(inode)) - DQUOT_INIT(inode); + vfs_dq_init(inode); /* Filesystems implementing their own * s_op->delete_inode are required to call * truncate_inode_pages and clear_inode() @@ -1186,16 +1202,19 @@ static void generic_forget_inode(struct inode *inode) spin_unlock(&inode_lock); return; } + WARN_ON(inode->i_state & I_NEW); inode->i_state |= I_WILL_FREE; spin_unlock(&inode_lock); write_inode_now(inode, 1); spin_lock(&inode_lock); + WARN_ON(inode->i_state & I_NEW); inode->i_state &= ~I_WILL_FREE; inodes_stat.nr_unused--; hlist_del_init(&inode->i_hash); } list_del_init(&inode->i_list); list_del_init(&inode->i_sb_list); + WARN_ON(inode->i_state & I_NEW); inode->i_state |= I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); @@ -1283,6 +1302,40 @@ sector_t bmap(struct inode * inode, sector_t block) } EXPORT_SYMBOL(bmap); +/* + * With relative atime, only update atime if the previous atime is + * earlier than either the ctime or mtime or if at least a day has + * passed since the last atime update. + */ +static int relatime_need_update(struct vfsmount *mnt, struct inode *inode, + struct timespec now) +{ + + if (!(mnt->mnt_flags & MNT_RELATIME)) + return 1; + /* + * Is mtime younger than atime? If yes, update atime: + */ + if (timespec_compare(&inode->i_mtime, &inode->i_atime) >= 0) + return 1; + /* + * Is ctime younger than atime? If yes, update atime: + */ + if (timespec_compare(&inode->i_ctime, &inode->i_atime) >= 0) + return 1; + + /* + * Is the previous atime value older than a day? If yes, + * update atime: + */ + if ((long)(now.tv_sec - inode->i_atime.tv_sec) >= 24*60*60) + return 1; + /* + * Good, we can skip the atime update: + */ + return 0; +} + /** * touch_atime - update the access time * @mnt: mount the inode is accessed on @@ -1310,17 +1363,12 @@ void touch_atime(struct vfsmount *mnt, struct dentry *dentry) goto out; if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)) goto out; - if (mnt->mnt_flags & MNT_RELATIME) { - /* - * With relative atime, only update atime if the previous - * atime is earlier than either the ctime or mtime. - */ - if (timespec_compare(&inode->i_mtime, &inode->i_atime) < 0 && - timespec_compare(&inode->i_ctime, &inode->i_atime) < 0) - goto out; - } now = current_fs_time(inode->i_sb); + + if (!relatime_need_update(mnt, inode, now)) + goto out; + if (timespec_equal(&inode->i_atime, &now)) goto out; diff --git a/fs/internal.h b/fs/internal.h index 0d8ac497b3d..53af885f173 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -43,7 +43,7 @@ extern void __init chrdev_init(void); /* * exec.c */ -extern void check_unsafe_exec(struct linux_binprm *, struct files_struct *); +extern void check_unsafe_exec(struct linux_binprm *); /* * namespace.c diff --git a/fs/ioctl.c b/fs/ioctl.c index 240ec63984c..ac2d47e4392 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -404,10 +404,12 @@ static int ioctl_fionbio(struct file *filp, int __user *argp) if (O_NONBLOCK != O_NDELAY) flag |= O_NDELAY; #endif + spin_lock(&filp->f_lock); if (on) filp->f_flags |= flag; else filp->f_flags &= ~flag; + spin_unlock(&filp->f_lock); return error; } @@ -425,18 +427,12 @@ static int ioctl_fioasync(unsigned int fd, struct file *filp, /* Did FASYNC state change ? */ if ((flag ^ filp->f_flags) & FASYNC) { if (filp->f_op && filp->f_op->fasync) + /* fasync() adjusts filp->f_flags */ error = filp->f_op->fasync(fd, filp, on); else error = -ENOTTY; } - if (error) - return error; - - if (on) - filp->f_flags |= FASYNC; - else - filp->f_flags &= ~FASYNC; - return error; + return error < 0 ? error : 0; } static int ioctl_fsfreeze(struct file *filp) @@ -499,17 +495,11 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, break; case FIONBIO: - /* BKL needed to avoid races tweaking f_flags */ - lock_kernel(); error = ioctl_fionbio(filp, argp); - unlock_kernel(); break; case FIOASYNC: - /* BKL needed to avoid races tweaking f_flags */ - lock_kernel(); error = ioctl_fioasync(fd, filp, argp); - unlock_kernel(); break; case FIOQSIZE: diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 6147ec3643a..13d2eddd069 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -114,7 +114,7 @@ static const struct super_operations isofs_sops = { }; -static struct dentry_operations isofs_dentry_ops[] = { +static const struct dentry_operations isofs_dentry_ops[] = { { .d_hash = isofs_hash, .d_compare = isofs_dentry_cmp, diff --git a/fs/jfs/Kconfig b/fs/jfs/Kconfig index 9ff619a6f9c..57cef19951d 100644 --- a/fs/jfs/Kconfig +++ b/fs/jfs/Kconfig @@ -1,6 +1,7 @@ config JFS_FS tristate "JFS filesystem support" select NLS + select CRC32 help This is a port of IBM's Journaled Filesystem . More information is available in the file <file:Documentation/filesystems/jfs.txt>. diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index d3e5c33665d..a166c1669e8 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -233,7 +233,7 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr) if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { - if (DQUOT_TRANSFER(inode, iattr)) + if (vfs_dq_transfer(inode, iattr)) return -EDQUOT; } diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index b00ee9f05a0..b2ae190a77b 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -158,9 +158,9 @@ void jfs_delete_inode(struct inode *inode) /* * Free the inode from the quota allocation. */ - DQUOT_INIT(inode); - DQUOT_FREE_INODE(inode); - DQUOT_DROP(inode); + vfs_dq_init(inode); + vfs_dq_free_inode(inode); + vfs_dq_drop(inode); } clear_inode(inode); diff --git a/fs/jfs/jfs_debug.c b/fs/jfs/jfs_debug.c index 6a73de84bce..dd824d9b0b1 100644 --- a/fs/jfs/jfs_debug.c +++ b/fs/jfs/jfs_debug.c @@ -90,7 +90,6 @@ void jfs_proc_init(void) if (!(base = proc_mkdir("fs/jfs", NULL))) return; - base->owner = THIS_MODULE; for (i = 0; i < NPROCENT; i++) proc_create(Entries[i].name, 0, base, Entries[i].proc_fops); diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index 4dcc0581999..925871e9887 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -381,10 +381,10 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot) * It's time to move the inline table to an external * page and begin to build the xtree */ - if (DQUOT_ALLOC_BLOCK(ip, sbi->nbperpage)) + if (vfs_dq_alloc_block(ip, sbi->nbperpage)) goto clean_up; if (dbAlloc(ip, 0, sbi->nbperpage, &xaddr)) { - DQUOT_FREE_BLOCK(ip, sbi->nbperpage); + vfs_dq_free_block(ip, sbi->nbperpage); goto clean_up; } @@ -408,7 +408,7 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot) memcpy(&jfs_ip->i_dirtable, temp_table, sizeof (temp_table)); dbFree(ip, xaddr, sbi->nbperpage); - DQUOT_FREE_BLOCK(ip, sbi->nbperpage); + vfs_dq_free_block(ip, sbi->nbperpage); goto clean_up; } ip->i_size = PSIZE; @@ -1027,7 +1027,7 @@ static int dtSplitUp(tid_t tid, n = xlen; /* Allocate blocks to quota. */ - if (DQUOT_ALLOC_BLOCK(ip, n)) { + if (vfs_dq_alloc_block(ip, n)) { rc = -EDQUOT; goto extendOut; } @@ -1308,7 +1308,7 @@ static int dtSplitUp(tid_t tid, /* Rollback quota allocation */ if (rc && quota_allocation) - DQUOT_FREE_BLOCK(ip, quota_allocation); + vfs_dq_free_block(ip, quota_allocation); dtSplitUp_Exit: @@ -1369,7 +1369,7 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split, return -EIO; /* Allocate blocks to quota. */ - if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) { + if (vfs_dq_alloc_block(ip, lengthPXD(pxd))) { release_metapage(rmp); return -EDQUOT; } @@ -1916,7 +1916,7 @@ static int dtSplitRoot(tid_t tid, rp = rmp->data; /* Allocate blocks to quota. */ - if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) { + if (vfs_dq_alloc_block(ip, lengthPXD(pxd))) { release_metapage(rmp); return -EDQUOT; } @@ -2287,7 +2287,7 @@ static int dtDeleteUp(tid_t tid, struct inode *ip, xlen = lengthPXD(&fp->header.self); /* Free quota allocation. */ - DQUOT_FREE_BLOCK(ip, xlen); + vfs_dq_free_block(ip, xlen); /* free/invalidate its buffer page */ discard_metapage(fmp); @@ -2363,7 +2363,7 @@ static int dtDeleteUp(tid_t tid, struct inode *ip, xlen = lengthPXD(&p->header.self); /* Free quota allocation */ - DQUOT_FREE_BLOCK(ip, xlen); + vfs_dq_free_block(ip, xlen); /* free/invalidate its buffer page */ discard_metapage(mp); diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c index 7ae1e3281de..bbbd5f202e3 100644 --- a/fs/jfs/jfs_extent.c +++ b/fs/jfs/jfs_extent.c @@ -141,7 +141,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr) } /* Allocate blocks to quota. */ - if (DQUOT_ALLOC_BLOCK(ip, nxlen)) { + if (vfs_dq_alloc_block(ip, nxlen)) { dbFree(ip, nxaddr, (s64) nxlen); mutex_unlock(&JFS_IP(ip)->commit_mutex); return -EDQUOT; @@ -164,7 +164,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr) */ if (rc) { dbFree(ip, nxaddr, nxlen); - DQUOT_FREE_BLOCK(ip, nxlen); + vfs_dq_free_block(ip, nxlen); mutex_unlock(&JFS_IP(ip)->commit_mutex); return (rc); } @@ -256,7 +256,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, bool abnr) goto exit; /* Allocat blocks to quota. */ - if (DQUOT_ALLOC_BLOCK(ip, nxlen)) { + if (vfs_dq_alloc_block(ip, nxlen)) { dbFree(ip, nxaddr, (s64) nxlen); mutex_unlock(&JFS_IP(ip)->commit_mutex); return -EDQUOT; @@ -297,7 +297,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, bool abnr) /* extend the extent */ if ((rc = xtExtend(0, ip, xoff + xlen, (int) nextend, 0))) { dbFree(ip, xaddr + xlen, delta); - DQUOT_FREE_BLOCK(ip, nxlen); + vfs_dq_free_block(ip, nxlen); goto exit; } } else { @@ -308,7 +308,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, bool abnr) */ if ((rc = xtTailgate(0, ip, xoff, (int) ntail, nxaddr, 0))) { dbFree(ip, nxaddr, nxlen); - DQUOT_FREE_BLOCK(ip, nxlen); + vfs_dq_free_block(ip, nxlen); goto exit; } } @@ -362,11 +362,12 @@ exit: int extHint(struct inode *ip, s64 offset, xad_t * xp) { struct super_block *sb = ip->i_sb; - struct xadlist xadl; - struct lxdlist lxdl; - lxd_t lxd; + int nbperpage = JFS_SBI(sb)->nbperpage; s64 prev; - int rc, nbperpage = JFS_SBI(sb)->nbperpage; + int rc = 0; + s64 xaddr; + int xlen; + int xflag; /* init the hint as "no hint provided" */ XADaddress(xp, 0); @@ -376,46 +377,30 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp) */ prev = ((offset & ~POFFSET) >> JFS_SBI(sb)->l2bsize) - nbperpage; - /* if the offsets in the first page of the file, - * no hint provided. + /* if the offset is in the first page of the file, no hint provided. */ if (prev < 0) - return (0); - - /* prepare to lookup the previous page's extent info */ - lxdl.maxnlxd = 1; - lxdl.nlxd = 1; - lxdl.lxd = &lxd; - LXDoffset(&lxd, prev) - LXDlength(&lxd, nbperpage); - - xadl.maxnxad = 1; - xadl.nxad = 0; - xadl.xad = xp; - - /* perform the lookup */ - if ((rc = xtLookupList(ip, &lxdl, &xadl, 0))) - return (rc); - - /* check if no extent exists for the previous page. - * this is possible for sparse files. - */ - if (xadl.nxad == 0) { -// assert(ISSPARSE(ip)); - return (0); - } + goto out; - /* only preserve the abnr flag within the xad flags - * of the returned hint. - */ - xp->flag &= XAD_NOTRECORDED; + rc = xtLookup(ip, prev, nbperpage, &xflag, &xaddr, &xlen, 0); - if(xadl.nxad != 1 || lengthXAD(xp) != nbperpage) { - jfs_error(ip->i_sb, "extHint: corrupt xtree"); - return -EIO; - } + if ((rc == 0) && xlen) { + if (xlen != nbperpage) { + jfs_error(ip->i_sb, "extHint: corrupt xtree"); + rc = -EIO; + } + XADaddress(xp, xaddr); + XADlength(xp, xlen); + /* + * only preserve the abnr flag within the xad flags + * of the returned hint. + */ + xp->flag = xflag & XAD_NOTRECORDED; + } else + rc = 0; - return (0); +out: + return (rc); } diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index 0f94381ca6d..346057218ed 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -57,12 +57,6 @@ #include "jfs_debug.h" /* - * __mark_inode_dirty expects inodes to be hashed. Since we don't want - * special inodes in the fileset inode space, we make them appear hashed, - * but do not put on any lists. - */ - -/* * imap locks */ /* iag free list lock */ @@ -497,7 +491,9 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary) release_metapage(mp); /* - * that will look hashed, but won't be on any list; hlist_del() + * __mark_inode_dirty expects inodes to be hashed. Since we don't + * want special inodes in the fileset inode space, we make them + * appear hashed, but do not put on any lists. hlist_del() * will work fine and require no locking. */ ip->i_hash.pprev = &ip->i_hash.next; diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c index d4d142c2edd..dc0e02159ac 100644 --- a/fs/jfs/jfs_inode.c +++ b/fs/jfs/jfs_inode.c @@ -116,7 +116,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode) /* * Allocate inode to quota. */ - if (DQUOT_ALLOC_INODE(inode)) { + if (vfs_dq_alloc_inode(inode)) { rc = -EDQUOT; goto fail_drop; } @@ -162,7 +162,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode) return inode; fail_drop: - DQUOT_DROP(inode); + vfs_dq_drop(inode); inode->i_flags |= S_NOQUOTA; fail_unlock: inode->i_nlink = 0; diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index adb2fafcc54..1eff7db34d6 100644 --- a/fs/jfs/jfs_inode.h +++ b/fs/jfs/jfs_inode.h @@ -47,5 +47,5 @@ extern const struct file_operations jfs_dir_operations; extern const struct inode_operations jfs_file_inode_operations; extern const struct file_operations jfs_file_operations; extern const struct inode_operations jfs_symlink_inode_operations; -extern struct dentry_operations jfs_ci_dentry_operations; +extern const struct dentry_operations jfs_ci_dentry_operations; #endif /* _H_JFS_INODE */ diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index c350057087d..07b6c5dfb4b 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -369,6 +369,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) unsigned long bio_bytes = 0; unsigned long bio_offset = 0; int offset; + int bad_blocks = 0; page_start = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); @@ -394,6 +395,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) } clear_bit(META_dirty, &mp->flag); + set_bit(META_io, &mp->flag); block_offset = offset >> inode->i_blkbits; lblock = page_start + block_offset; if (bio) { @@ -402,7 +404,6 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) len = min(xlen, blocks_per_mp); xlen -= len; bio_bytes += len << inode->i_blkbits; - set_bit(META_io, &mp->flag); continue; } /* Not contiguous */ @@ -424,12 +425,14 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) xlen = (PAGE_CACHE_SIZE - offset) >> inode->i_blkbits; pblock = metapage_get_blocks(inode, lblock, &xlen); if (!pblock) { - /* Need better error handling */ printk(KERN_ERR "JFS: metapage_get_blocks failed\n"); - dec_io(page, last_write_complete); + /* + * We already called inc_io(), but can't cancel it + * with dec_io() until we're done with the page + */ + bad_blocks++; continue; } - set_bit(META_io, &mp->flag); len = min(xlen, (int)JFS_SBI(inode->i_sb)->nbperpage); bio = bio_alloc(GFP_NOFS, 1); @@ -459,6 +462,9 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) unlock_page(page); + if (bad_blocks) + goto err_out; + if (nr_underway == 0) end_page_writeback(page); @@ -474,7 +480,9 @@ skip: bio_put(bio); unlock_page(page); dec_io(page, last_write_complete); - +err_out: + while (bad_blocks--) + dec_io(page, last_write_complete); return -EIO; } diff --git a/fs/jfs/jfs_types.h b/fs/jfs/jfs_types.h index 649f9817acc..43ea3713c08 100644 --- a/fs/jfs/jfs_types.h +++ b/fs/jfs/jfs_types.h @@ -58,35 +58,6 @@ struct timestruc_t { #define ONES 0xffffffffu /* all bit on */ /* - * logical xd (lxd) - */ -typedef struct { - unsigned len:24; - unsigned off1:8; - u32 off2; -} lxd_t; - -/* lxd_t field construction */ -#define LXDlength(lxd, length32) ( (lxd)->len = length32 ) -#define LXDoffset(lxd, offset64)\ -{\ - (lxd)->off1 = ((s64)offset64) >> 32;\ - (lxd)->off2 = (offset64) & 0xffffffff;\ -} - -/* lxd_t field extraction */ -#define lengthLXD(lxd) ( (lxd)->len ) -#define offsetLXD(lxd)\ - ( ((s64)((lxd)->off1)) << 32 | (lxd)->off2 ) - -/* lxd list */ -struct lxdlist { - s16 maxnlxd; - s16 nlxd; - lxd_t *lxd; -}; - -/* * physical xd (pxd) */ typedef struct { diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c index ae3acafb447..d654a645864 100644 --- a/fs/jfs/jfs_xtree.c +++ b/fs/jfs/jfs_xtree.c @@ -164,11 +164,8 @@ int xtLookup(struct inode *ip, s64 lstart, /* is lookup offset beyond eof ? */ size = ((u64) ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >> JFS_SBI(ip->i_sb)->l2bsize; - if (lstart >= size) { - jfs_err("xtLookup: lstart (0x%lx) >= size (0x%lx)", - (ulong) lstart, (ulong) size); + if (lstart >= size) return 0; - } } /* @@ -220,264 +217,6 @@ int xtLookup(struct inode *ip, s64 lstart, return rc; } - -/* - * xtLookupList() - * - * function: map a single logical extent into a list of physical extent; - * - * parameter: - * struct inode *ip, - * struct lxdlist *lxdlist, lxd list (in) - * struct xadlist *xadlist, xad list (in/out) - * int flag) - * - * coverage of lxd by xad under assumption of - * . lxd's are ordered and disjoint. - * . xad's are ordered and disjoint. - * - * return: - * 0: success - * - * note: a page being written (even a single byte) is backed fully, - * except the last page which is only backed with blocks - * required to cover the last byte; - * the extent backing a page is fully contained within an xad; - */ -int xtLookupList(struct inode *ip, struct lxdlist * lxdlist, - struct xadlist * xadlist, int flag) -{ - int rc = 0; - struct btstack btstack; - int cmp; - s64 bn; - struct metapage *mp; - xtpage_t *p; - int index; - lxd_t *lxd; - xad_t *xad, *pxd; - s64 size, lstart, lend, xstart, xend, pstart; - s64 llen, xlen, plen; - s64 xaddr, paddr; - int nlxd, npxd, maxnpxd; - - npxd = xadlist->nxad = 0; - maxnpxd = xadlist->maxnxad; - pxd = xadlist->xad; - - nlxd = lxdlist->nlxd; - lxd = lxdlist->lxd; - - lstart = offsetLXD(lxd); - llen = lengthLXD(lxd); - lend = lstart + llen; - - size = (ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >> - JFS_SBI(ip->i_sb)->l2bsize; - - /* - * search for the xad entry covering the logical extent - */ - search: - if (lstart >= size) - return 0; - - if ((rc = xtSearch(ip, lstart, NULL, &cmp, &btstack, 0))) - return rc; - - /* - * compute the physical extent covering logical extent - * - * N.B. search may have failed (e.g., hole in sparse file), - * and returned the index of the next entry. - */ -//map: - /* retrieve search result */ - XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); - - /* is xad on the next sibling page ? */ - if (index == le16_to_cpu(p->header.nextindex)) { - if (p->header.flag & BT_ROOT) - goto mapend; - - if ((bn = le64_to_cpu(p->header.next)) == 0) - goto mapend; - - XT_PUTPAGE(mp); - - /* get next sibling page */ - XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); - if (rc) - return rc; - - index = XTENTRYSTART; - } - - xad = &p->xad[index]; - - /* - * is lxd covered by xad ? - */ - compare: - xstart = offsetXAD(xad); - xlen = lengthXAD(xad); - xend = xstart + xlen; - xaddr = addressXAD(xad); - - compare1: - if (xstart < lstart) - goto compare2; - - /* (lstart <= xstart) */ - - /* lxd is NOT covered by xad */ - if (lend <= xstart) { - /* - * get next lxd - */ - if (--nlxd == 0) - goto mapend; - lxd++; - - lstart = offsetLXD(lxd); - llen = lengthLXD(lxd); - lend = lstart + llen; - if (lstart >= size) - goto mapend; - - /* compare with the current xad */ - goto compare1; - } - /* lxd is covered by xad */ - else { /* (xstart < lend) */ - - /* initialize new pxd */ - pstart = xstart; - plen = min(lend - xstart, xlen); - paddr = xaddr; - - goto cover; - } - - /* (xstart < lstart) */ - compare2: - /* lxd is covered by xad */ - if (lstart < xend) { - /* initialize new pxd */ - pstart = lstart; - plen = min(xend - lstart, llen); - paddr = xaddr + (lstart - xstart); - - goto cover; - } - /* lxd is NOT covered by xad */ - else { /* (xend <= lstart) */ - - /* - * get next xad - * - * linear search next xad covering lxd on - * the current xad page, and then tree search - */ - if (index == le16_to_cpu(p->header.nextindex) - 1) { - if (p->header.flag & BT_ROOT) - goto mapend; - - XT_PUTPAGE(mp); - goto search; - } else { - index++; - xad++; - - /* compare with new xad */ - goto compare; - } - } - - /* - * lxd is covered by xad and a new pxd has been initialized - * (lstart <= xstart < lend) or (xstart < lstart < xend) - */ - cover: - /* finalize pxd corresponding to current xad */ - XT_PUTENTRY(pxd, xad->flag, pstart, plen, paddr); - - if (++npxd >= maxnpxd) - goto mapend; - pxd++; - - /* - * lxd is fully covered by xad - */ - if (lend <= xend) { - /* - * get next lxd - */ - if (--nlxd == 0) - goto mapend; - lxd++; - - lstart = offsetLXD(lxd); - llen = lengthLXD(lxd); - lend = lstart + llen; - if (lstart >= size) - goto mapend; - - /* - * test for old xad covering new lxd - * (old xstart < new lstart) - */ - goto compare2; - } - /* - * lxd is partially covered by xad - */ - else { /* (xend < lend) */ - - /* - * get next xad - * - * linear search next xad covering lxd on - * the current xad page, and then next xad page search - */ - if (index == le16_to_cpu(p->header.nextindex) - 1) { - if (p->header.flag & BT_ROOT) - goto mapend; - - if ((bn = le64_to_cpu(p->header.next)) == 0) - goto mapend; - - XT_PUTPAGE(mp); - - /* get next sibling page */ - XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); - if (rc) - return rc; - - index = XTENTRYSTART; - xad = &p->xad[index]; - } else { - index++; - xad++; - } - - /* - * test for new xad covering old lxd - * (old lstart < new xstart) - */ - goto compare; - } - - mapend: - xadlist->nxad = npxd; - -//out: - XT_PUTPAGE(mp); - - return rc; -} - - /* * xtSearch() * @@ -846,10 +585,10 @@ int xtInsert(tid_t tid, /* transaction id */ hint = addressXAD(xad) + lengthXAD(xad) - 1; } else hint = 0; - if ((rc = DQUOT_ALLOC_BLOCK(ip, xlen))) + if ((rc = vfs_dq_alloc_block(ip, xlen))) goto out; if ((rc = dbAlloc(ip, hint, (s64) xlen, &xaddr))) { - DQUOT_FREE_BLOCK(ip, xlen); + vfs_dq_free_block(ip, xlen); goto out; } } @@ -878,7 +617,7 @@ int xtInsert(tid_t tid, /* transaction id */ /* undo data extent allocation */ if (*xaddrp == 0) { dbFree(ip, xaddr, (s64) xlen); - DQUOT_FREE_BLOCK(ip, xlen); + vfs_dq_free_block(ip, xlen); } return rc; } @@ -1246,7 +985,7 @@ xtSplitPage(tid_t tid, struct inode *ip, rbn = addressPXD(pxd); /* Allocate blocks to quota. */ - if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) { + if (vfs_dq_alloc_block(ip, lengthPXD(pxd))) { rc = -EDQUOT; goto clean_up; } @@ -1456,7 +1195,7 @@ xtSplitPage(tid_t tid, struct inode *ip, /* Rollback quota allocation. */ if (quota_allocation) - DQUOT_FREE_BLOCK(ip, quota_allocation); + vfs_dq_free_block(ip, quota_allocation); return (rc); } @@ -1513,7 +1252,7 @@ xtSplitRoot(tid_t tid, return -EIO; /* Allocate blocks to quota. */ - if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) { + if (vfs_dq_alloc_block(ip, lengthPXD(pxd))) { release_metapage(rmp); return -EDQUOT; } @@ -3941,7 +3680,7 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag) ip->i_size = newsize; /* update quota allocation to reflect freed blocks */ - DQUOT_FREE_BLOCK(ip, nfreed); + vfs_dq_free_block(ip, nfreed); /* * free tlock of invalidated pages diff --git a/fs/jfs/jfs_xtree.h b/fs/jfs/jfs_xtree.h index 70815c8a3d6..08c0c749b98 100644 --- a/fs/jfs/jfs_xtree.h +++ b/fs/jfs/jfs_xtree.h @@ -110,8 +110,6 @@ typedef union { */ extern int xtLookup(struct inode *ip, s64 lstart, s64 llen, int *pflag, s64 * paddr, int *plen, int flag); -extern int xtLookupList(struct inode *ip, struct lxdlist * lxdlist, - struct xadlist * xadlist, int flag); extern void xtInitRoot(tid_t tid, struct inode *ip); extern int xtInsert(tid_t tid, struct inode *ip, int xflag, s64 xoff, int xlen, s64 * xaddrp, int flag); diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index b4de56b851e..514ee2edb92 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -35,7 +35,7 @@ /* * forward references */ -struct dentry_operations jfs_ci_dentry_operations; +const struct dentry_operations jfs_ci_dentry_operations; static s64 commitZeroLink(tid_t, struct inode *); @@ -356,7 +356,7 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name); /* Init inode for quota operations. */ - DQUOT_INIT(ip); + vfs_dq_init(ip); /* directory must be empty to be removed */ if (!dtEmpty(ip)) { @@ -483,7 +483,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name); /* Init inode for quota operations. */ - DQUOT_INIT(ip); + vfs_dq_init(ip); if ((rc = get_UCSname(&dname, dentry))) goto out; @@ -1136,7 +1136,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, } else if (new_ip) { IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL); /* Init inode for quota operations. */ - DQUOT_INIT(new_ip); + vfs_dq_init(new_ip); } /* @@ -1595,7 +1595,7 @@ out: return result; } -struct dentry_operations jfs_ci_dentry_operations = +const struct dentry_operations jfs_ci_dentry_operations = { .d_hash = jfs_ci_hash, .d_compare = jfs_ci_compare, diff --git a/fs/jfs/super.c b/fs/jfs/super.c index b37d1f78b85..6f21adf9479 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -29,6 +29,7 @@ #include <linux/posix_acl.h> #include <linux/buffer_head.h> #include <linux/exportfs.h> +#include <linux/crc32.h> #include <asm/uaccess.h> #include <linux/seq_file.h> @@ -168,6 +169,9 @@ static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_files = maxinodes; buf->f_ffree = maxinodes - (atomic_read(&imap->im_numinos) - atomic_read(&imap->im_numfree)); + buf->f_fsid.val[0] = (u32)crc32_le(0, sbi->uuid, sizeof(sbi->uuid)/2); + buf->f_fsid.val[1] = (u32)crc32_le(0, sbi->uuid + sizeof(sbi->uuid)/2, + sizeof(sbi->uuid)/2); buf->f_namelen = JFS_NAME_MAX; return 0; diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index 9b7f2cdaae0..61dfa8173eb 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -260,14 +260,14 @@ static int ea_write(struct inode *ip, struct jfs_ea_list *ealist, int size, nblocks = (size + (sb->s_blocksize - 1)) >> sb->s_blocksize_bits; /* Allocate new blocks to quota. */ - if (DQUOT_ALLOC_BLOCK(ip, nblocks)) { + if (vfs_dq_alloc_block(ip, nblocks)) { return -EDQUOT; } rc = dbAlloc(ip, INOHINT(ip), nblocks, &blkno); if (rc) { /*Rollback quota allocation. */ - DQUOT_FREE_BLOCK(ip, nblocks); + vfs_dq_free_block(ip, nblocks); return rc; } @@ -332,7 +332,7 @@ static int ea_write(struct inode *ip, struct jfs_ea_list *ealist, int size, failed: /* Rollback quota allocation. */ - DQUOT_FREE_BLOCK(ip, nblocks); + vfs_dq_free_block(ip, nblocks); dbFree(ip, blkno, nblocks); return rc; @@ -538,7 +538,7 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size) if (blocks_needed > current_blocks) { /* Allocate new blocks to quota. */ - if (DQUOT_ALLOC_BLOCK(inode, blocks_needed)) + if (vfs_dq_alloc_block(inode, blocks_needed)) return -EDQUOT; quota_allocation = blocks_needed; @@ -602,7 +602,7 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size) clean_up: /* Rollback quota allocation */ if (quota_allocation) - DQUOT_FREE_BLOCK(inode, quota_allocation); + vfs_dq_free_block(inode, quota_allocation); return (rc); } @@ -677,7 +677,7 @@ static int ea_put(tid_t tid, struct inode *inode, struct ea_buffer *ea_buf, /* If old blocks exist, they must be removed from quota allocation. */ if (old_blocks) - DQUOT_FREE_BLOCK(inode, old_blocks); + vfs_dq_free_block(inode, old_blocks); inode->i_ctime = CURRENT_TIME; diff --git a/fs/libfs.c b/fs/libfs.c index 49b44099dab..4910a36f516 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -44,7 +44,7 @@ static int simple_delete_dentry(struct dentry *dentry) */ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { - static struct dentry_operations simple_dentry_operations = { + static const struct dentry_operations simple_dentry_operations = { .d_delete = simple_delete_dentry, }; @@ -242,7 +242,8 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name, d_instantiate(dentry, root); s->s_root = dentry; s->s_flags |= MS_ACTIVE; - return simple_set_mnt(mnt, s); + simple_set_mnt(mnt, s); + return 0; Enomem: up_write(&s->s_umount); diff --git a/fs/minix/inode.c b/fs/minix/inode.c index d1d1eb84679..618865b3128 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -3,7 +3,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * - * Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl) + * Copyright (C) 1996 Gertjan van Wingerde * Minix V2 fs support. * * Modified for 680x0 by Andreas Schwab diff --git a/fs/namei.c b/fs/namei.c index bbc15c23755..d040ce11785 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -24,6 +24,7 @@ #include <linux/fsnotify.h> #include <linux/personality.h> #include <linux/security.h> +#include <linux/ima.h> #include <linux/syscalls.h> #include <linux/mount.h> #include <linux/audit.h> @@ -850,6 +851,8 @@ static int __link_path_walk(const char *name, struct nameidata *nd) if (err == -EAGAIN) err = inode_permission(nd->path.dentry->d_inode, MAY_EXEC); + if (!err) + err = ima_path_check(&nd->path, MAY_EXEC); if (err) break; @@ -1470,7 +1473,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode, error = security_inode_create(dir, dentry, mode); if (error) return error; - DQUOT_INIT(dir); + vfs_dq_init(dir); error = dir->i_op->create(dir, dentry, mode, nd); if (!error) fsnotify_create(dir, dentry); @@ -1486,29 +1489,32 @@ int may_open(struct path *path, int acc_mode, int flag) if (!inode) return -ENOENT; - if (S_ISLNK(inode->i_mode)) + switch (inode->i_mode & S_IFMT) { + case S_IFLNK: return -ELOOP; - - if (S_ISDIR(inode->i_mode) && (acc_mode & MAY_WRITE)) - return -EISDIR; - - /* - * FIFO's, sockets and device files are special: they don't - * actually live on the filesystem itself, and as such you - * can write to them even if the filesystem is read-only. - */ - if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { - flag &= ~O_TRUNC; - } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { + case S_IFDIR: + if (acc_mode & MAY_WRITE) + return -EISDIR; + break; + case S_IFBLK: + case S_IFCHR: if (path->mnt->mnt_flags & MNT_NODEV) return -EACCES; - + /*FALLTHRU*/ + case S_IFIFO: + case S_IFSOCK: flag &= ~O_TRUNC; + break; } error = inode_permission(inode, acc_mode); if (error) return error; + + error = ima_path_check(path, + acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC)); + if (error) + return error; /* * An append-only file must be opened in append mode for writing. */ @@ -1544,7 +1550,7 @@ int may_open(struct path *path, int acc_mode, int flag) error = security_path_truncate(path, 0, ATTR_MTIME|ATTR_CTIME|ATTR_OPEN); if (!error) { - DQUOT_INIT(inode); + vfs_dq_init(inode); error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME|ATTR_OPEN, @@ -1555,7 +1561,7 @@ int may_open(struct path *path, int acc_mode, int flag) return error; } else if (flag & FMODE_WRITE) - DQUOT_INIT(inode); + vfs_dq_init(inode); return 0; } @@ -1938,7 +1944,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) if (error) return error; - DQUOT_INIT(dir); + vfs_dq_init(dir); error = dir->i_op->mknod(dir, dentry, mode, dev); if (!error) fsnotify_create(dir, dentry); @@ -2037,7 +2043,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) if (error) return error; - DQUOT_INIT(dir); + vfs_dq_init(dir); error = dir->i_op->mkdir(dir, dentry, mode); if (!error) fsnotify_mkdir(dir, dentry); @@ -2123,7 +2129,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) if (!dir->i_op->rmdir) return -EPERM; - DQUOT_INIT(dir); + vfs_dq_init(dir); mutex_lock(&dentry->d_inode->i_mutex); dentry_unhash(dentry); @@ -2210,7 +2216,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) if (!dir->i_op->unlink) return -EPERM; - DQUOT_INIT(dir); + vfs_dq_init(dir); mutex_lock(&dentry->d_inode->i_mutex); if (d_mountpoint(dentry)) @@ -2321,7 +2327,7 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) if (error) return error; - DQUOT_INIT(dir); + vfs_dq_init(dir); error = dir->i_op->symlink(dir, dentry, oldname); if (!error) fsnotify_create(dir, dentry); @@ -2405,7 +2411,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de return error; mutex_lock(&inode->i_mutex); - DQUOT_INIT(dir); + vfs_dq_init(dir); error = dir->i_op->link(old_dentry, dir, new_dentry); mutex_unlock(&inode->i_mutex); if (!error) @@ -2604,8 +2610,8 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (!old_dir->i_op->rename) return -EPERM; - DQUOT_INIT(old_dir); - DQUOT_INIT(new_dir); + vfs_dq_init(old_dir); + vfs_dq_init(new_dir); old_name = fsnotify_oldname_init(old_dentry->d_name.name); diff --git a/fs/namespace.c b/fs/namespace.c index 06f8e63f6cb..0a42e0e9602 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -397,11 +397,10 @@ static void __mnt_unmake_readonly(struct vfsmount *mnt) spin_unlock(&vfsmount_lock); } -int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb) +void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb) { mnt->mnt_sb = sb; mnt->mnt_root = dget(sb->s_root); - return 0; } EXPORT_SYMBOL(simple_set_mnt); @@ -780,6 +779,7 @@ static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) { MNT_NOATIME, ",noatime" }, { MNT_NODIRATIME, ",nodiratime" }, { MNT_RELATIME, ",relatime" }, + { MNT_STRICTATIME, ",strictatime" }, { 0, NULL } }; const struct proc_fs_info *fs_infop; @@ -1919,6 +1919,9 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; + /* Default to relatime */ + mnt_flags |= MNT_RELATIME; + /* Separate the per-mountpoint flags */ if (flags & MS_NOSUID) mnt_flags |= MNT_NOSUID; @@ -1930,13 +1933,14 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, mnt_flags |= MNT_NOATIME; if (flags & MS_NODIRATIME) mnt_flags |= MNT_NODIRATIME; - if (flags & MS_RELATIME) - mnt_flags |= MNT_RELATIME; + if (flags & MS_STRICTATIME) + mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME); if (flags & MS_RDONLY) mnt_flags |= MNT_READONLY; flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | - MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT); + MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | + MS_STRICTATIME); /* ... and get the mountpoint */ retval = kern_path(dir_name, LOOKUP_FOLLOW, &path); diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 07e9715b865..9c590722d87 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -79,7 +79,7 @@ static int ncp_hash_dentry(struct dentry *, struct qstr *); static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); static int ncp_delete_dentry(struct dentry *); -static struct dentry_operations ncp_dentry_operations = +static const struct dentry_operations ncp_dentry_operations = { .d_revalidate = ncp_lookup_validate, .d_hash = ncp_hash_dentry, @@ -87,7 +87,7 @@ static struct dentry_operations ncp_dentry_operations = .d_delete = ncp_delete_dentry, }; -struct dentry_operations ncp_root_dentry_operations = +const struct dentry_operations ncp_root_dentry_operations = { .d_hash = ncp_hash_dentry, .d_compare = ncp_compare_dentry, diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 855daac0f24..aba38017bde 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -1594,8 +1594,6 @@ int __init nfs_fs_proc_init(void) if (!proc_fs_nfs) goto error_0; - proc_fs_nfs->owner = THIS_MODULE; - /* a file of servers with which we're dealing */ p = proc_create("servers", S_IFREG|S_IRUGO, proc_fs_nfs, &nfs_server_list_fops); diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 3b2f6973e7c..370b190a09d 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -899,7 +899,7 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) iput(inode); } -struct dentry_operations nfs_dentry_operations = { +const struct dentry_operations nfs_dentry_operations = { .d_revalidate = nfs_lookup_revalidate, .d_delete = nfs_dentry_delete, .d_iput = nfs_dentry_iput, @@ -967,7 +967,7 @@ out: #ifdef CONFIG_NFS_V4 static int nfs_open_revalidate(struct dentry *, struct nameidata *); -struct dentry_operations nfs4_dentry_operations = { +const struct dentry_operations nfs4_dentry_operations = { .d_revalidate = nfs_open_revalidate, .d_delete = nfs_dentry_delete, .d_iput = nfs_dentry_iput, diff --git a/fs/nfs/file.c b/fs/nfs/file.c index d451073c494..0abf3f331f5 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -451,8 +451,9 @@ const struct address_space_operations nfs_file_aops = { .launder_page = nfs_launder_page, }; -static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page) +static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { + struct page *page = vmf->page; struct file *filp = vma->vm_file; struct dentry *dentry = filp->f_path.dentry; unsigned pagelen; @@ -483,6 +484,8 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page) ret = pagelen; out_unlock: unlock_page(page); + if (ret) + ret = VM_FAULT_SIGBUS; return ret; } diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 4e4d3320437..84345deab26 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -179,7 +179,7 @@ struct nfs4_state_recovery_ops { int (*recover_lock)(struct nfs4_state *, struct file_lock *); }; -extern struct dentry_operations nfs4_dentry_operations; +extern const struct dentry_operations nfs4_dentry_operations; extern const struct inode_operations nfs4_dir_inode_operations; /* inode.c */ diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index f65953be39c..9250067943d 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2596,6 +2596,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop, [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop, [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open, + [OP_OPENATTR] = (nfsd4_enc)nfsd4_encode_noop, [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm, [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade, [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop, diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 6e50aaa56ca..78376b6c023 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -356,7 +356,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, put_write_access(inode); goto out_nfserr; } - DQUOT_INIT(inode); + vfs_dq_init(inode); } /* sanitize the mode change */ @@ -723,7 +723,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, else flags = O_WRONLY|O_LARGEFILE; - DQUOT_INIT(inode); + vfs_dq_init(inode); } *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), flags, cred); @@ -998,8 +998,11 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, if (!EX_ISSYNC(exp)) stable = 0; - if (stable && !EX_WGATHER(exp)) + if (stable && !EX_WGATHER(exp)) { + spin_lock(&file->f_lock); file->f_flags |= O_SYNC; + spin_unlock(&file->f_lock); + } /* Write the data. */ oldfs = get_fs(); set_fs(KERNEL_DS); diff --git a/fs/notify/inotify/inotify.c b/fs/notify/inotify/inotify.c index 331f2e88e28..220c13f0d73 100644 --- a/fs/notify/inotify/inotify.c +++ b/fs/notify/inotify/inotify.c @@ -380,6 +380,14 @@ void inotify_unmount_inodes(struct list_head *list) struct list_head *watches; /* + * We cannot __iget() an inode in state I_CLEAR, I_FREEING, + * I_WILL_FREE, or I_NEW which is fine because by that point + * the inode cannot have any associated watches. + */ + if (inode->i_state & (I_CLEAR|I_FREEING|I_WILL_FREE|I_NEW)) + continue; + + /* * If i_count is zero, the inode cannot have any watches and * doing an __iget/iput with MS_ACTIVE clear would actually * evict all inodes with zero i_count from icache which is @@ -388,14 +396,6 @@ void inotify_unmount_inodes(struct list_head *list) if (!atomic_read(&inode->i_count)) continue; - /* - * We cannot __iget() an inode in state I_CLEAR, I_FREEING, or - * I_WILL_FREE which is fine because by that point the inode - * cannot have any associated watches. - */ - if (inode->i_state & (I_CLEAR | I_FREEING | I_WILL_FREE)) - continue; - need_iput_tmp = need_iput; need_iput = NULL; /* In case inotify_remove_watch_locked() drops a reference. */ diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c index 34314b33dbd..5a9e34475e3 100644 --- a/fs/ntfs/dir.c +++ b/fs/ntfs/dir.c @@ -32,8 +32,8 @@ /** * The little endian Unicode string $I30 as a global constant. */ -ntfschar I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'), - const_cpu_to_le16('3'), const_cpu_to_le16('0'), 0 }; +ntfschar I30[5] = { cpu_to_le16('$'), cpu_to_le16('I'), + cpu_to_le16('3'), cpu_to_le16('0'), 0 }; /** * ntfs_lookup_inode_by_name - find an inode in a directory given its name diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 86bef156cf0..82c5085559c 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -1975,8 +1975,7 @@ int ntfs_read_inode_mount(struct inode *vi) goto em_put_err_out; next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + le16_to_cpu(al_entry->length)); - if (le32_to_cpu(al_entry->type) > - const_le32_to_cpu(AT_DATA)) + if (le32_to_cpu(al_entry->type) > le32_to_cpu(AT_DATA)) goto em_put_err_out; if (AT_DATA != al_entry->type) continue; diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h index 1e383328ece..50931b1ce4b 100644 --- a/fs/ntfs/layout.h +++ b/fs/ntfs/layout.h @@ -31,19 +31,8 @@ #include "types.h" -/* - * Constant endianness conversion defines. - */ -#define const_le16_to_cpu(x) __constant_le16_to_cpu(x) -#define const_le32_to_cpu(x) __constant_le32_to_cpu(x) -#define const_le64_to_cpu(x) __constant_le64_to_cpu(x) - -#define const_cpu_to_le16(x) __constant_cpu_to_le16(x) -#define const_cpu_to_le32(x) __constant_cpu_to_le32(x) -#define const_cpu_to_le64(x) __constant_cpu_to_le64(x) - /* The NTFS oem_id "NTFS " */ -#define magicNTFS const_cpu_to_le64(0x202020205346544eULL) +#define magicNTFS cpu_to_le64(0x202020205346544eULL) /* * Location of bootsector on partition: @@ -114,25 +103,25 @@ typedef struct { */ enum { /* Found in $MFT/$DATA. */ - magic_FILE = const_cpu_to_le32(0x454c4946), /* Mft entry. */ - magic_INDX = const_cpu_to_le32(0x58444e49), /* Index buffer. */ - magic_HOLE = const_cpu_to_le32(0x454c4f48), /* ? (NTFS 3.0+?) */ + magic_FILE = cpu_to_le32(0x454c4946), /* Mft entry. */ + magic_INDX = cpu_to_le32(0x58444e49), /* Index buffer. */ + magic_HOLE = cpu_to_le32(0x454c4f48), /* ? (NTFS 3.0+?) */ /* Found in $LogFile/$DATA. */ - magic_RSTR = const_cpu_to_le32(0x52545352), /* Restart page. */ - magic_RCRD = const_cpu_to_le32(0x44524352), /* Log record page. */ + magic_RSTR = cpu_to_le32(0x52545352), /* Restart page. */ + magic_RCRD = cpu_to_le32(0x44524352), /* Log record page. */ /* Found in $LogFile/$DATA. (May be found in $MFT/$DATA, also?) */ - magic_CHKD = const_cpu_to_le32(0x444b4843), /* Modified by chkdsk. */ + magic_CHKD = cpu_to_le32(0x444b4843), /* Modified by chkdsk. */ /* Found in all ntfs record containing records. */ - magic_BAAD = const_cpu_to_le32(0x44414142), /* Failed multi sector + magic_BAAD = cpu_to_le32(0x44414142), /* Failed multi sector transfer was detected. */ /* * Found in $LogFile/$DATA when a page is full of 0xff bytes and is * thus not initialized. Page must be initialized before using it. */ - magic_empty = const_cpu_to_le32(0xffffffff) /* Record is empty. */ + magic_empty = cpu_to_le32(0xffffffff) /* Record is empty. */ }; typedef le32 NTFS_RECORD_TYPE; @@ -258,8 +247,8 @@ typedef enum { * information about the mft record in which they are present. */ enum { - MFT_RECORD_IN_USE = const_cpu_to_le16(0x0001), - MFT_RECORD_IS_DIRECTORY = const_cpu_to_le16(0x0002), + MFT_RECORD_IN_USE = cpu_to_le16(0x0001), + MFT_RECORD_IS_DIRECTORY = cpu_to_le16(0x0002), } __attribute__ ((__packed__)); typedef le16 MFT_RECORD_FLAGS; @@ -309,7 +298,7 @@ typedef le16 MFT_RECORD_FLAGS; * Note: The _LE versions will return a CPU endian formatted value! */ #define MFT_REF_MASK_CPU 0x0000ffffffffffffULL -#define MFT_REF_MASK_LE const_cpu_to_le64(MFT_REF_MASK_CPU) +#define MFT_REF_MASK_LE cpu_to_le64(MFT_REF_MASK_CPU) typedef u64 MFT_REF; typedef le64 leMFT_REF; @@ -477,25 +466,25 @@ typedef struct { * a revealing choice of symbol I do not know what is... (-; */ enum { - AT_UNUSED = const_cpu_to_le32( 0), - AT_STANDARD_INFORMATION = const_cpu_to_le32( 0x10), - AT_ATTRIBUTE_LIST = const_cpu_to_le32( 0x20), - AT_FILE_NAME = const_cpu_to_le32( 0x30), - AT_OBJECT_ID = const_cpu_to_le32( 0x40), - AT_SECURITY_DESCRIPTOR = const_cpu_to_le32( 0x50), - AT_VOLUME_NAME = const_cpu_to_le32( 0x60), - AT_VOLUME_INFORMATION = const_cpu_to_le32( 0x70), - AT_DATA = const_cpu_to_le32( 0x80), - AT_INDEX_ROOT = const_cpu_to_le32( 0x90), - AT_INDEX_ALLOCATION = const_cpu_to_le32( 0xa0), - AT_BITMAP = const_cpu_to_le32( 0xb0), - AT_REPARSE_POINT = const_cpu_to_le32( 0xc0), - AT_EA_INFORMATION = const_cpu_to_le32( 0xd0), - AT_EA = const_cpu_to_le32( 0xe0), - AT_PROPERTY_SET = const_cpu_to_le32( 0xf0), - AT_LOGGED_UTILITY_STREAM = const_cpu_to_le32( 0x100), - AT_FIRST_USER_DEFINED_ATTRIBUTE = const_cpu_to_le32( 0x1000), - AT_END = const_cpu_to_le32(0xffffffff) + AT_UNUSED = cpu_to_le32( 0), + AT_STANDARD_INFORMATION = cpu_to_le32( 0x10), + AT_ATTRIBUTE_LIST = cpu_to_le32( 0x20), + AT_FILE_NAME = cpu_to_le32( 0x30), + AT_OBJECT_ID = cpu_to_le32( 0x40), + AT_SECURITY_DESCRIPTOR = cpu_to_le32( 0x50), + AT_VOLUME_NAME = cpu_to_le32( 0x60), + AT_VOLUME_INFORMATION = cpu_to_le32( 0x70), + AT_DATA = cpu_to_le32( 0x80), + AT_INDEX_ROOT = cpu_to_le32( 0x90), + AT_INDEX_ALLOCATION = cpu_to_le32( 0xa0), + AT_BITMAP = cpu_to_le32( 0xb0), + AT_REPARSE_POINT = cpu_to_le32( 0xc0), + AT_EA_INFORMATION = cpu_to_le32( 0xd0), + AT_EA = cpu_to_le32( 0xe0), + AT_PROPERTY_SET = cpu_to_le32( 0xf0), + AT_LOGGED_UTILITY_STREAM = cpu_to_le32( 0x100), + AT_FIRST_USER_DEFINED_ATTRIBUTE = cpu_to_le32( 0x1000), + AT_END = cpu_to_le32(0xffffffff) }; typedef le32 ATTR_TYPE; @@ -539,13 +528,13 @@ typedef le32 ATTR_TYPE; * equal then the second le32 values would be compared, etc. */ enum { - COLLATION_BINARY = const_cpu_to_le32(0x00), - COLLATION_FILE_NAME = const_cpu_to_le32(0x01), - COLLATION_UNICODE_STRING = const_cpu_to_le32(0x02), - COLLATION_NTOFS_ULONG = const_cpu_to_le32(0x10), - COLLATION_NTOFS_SID = const_cpu_to_le32(0x11), - COLLATION_NTOFS_SECURITY_HASH = const_cpu_to_le32(0x12), - COLLATION_NTOFS_ULONGS = const_cpu_to_le32(0x13), + COLLATION_BINARY = cpu_to_le32(0x00), + COLLATION_FILE_NAME = cpu_to_le32(0x01), + COLLATION_UNICODE_STRING = cpu_to_le32(0x02), + COLLATION_NTOFS_ULONG = cpu_to_le32(0x10), + COLLATION_NTOFS_SID = cpu_to_le32(0x11), + COLLATION_NTOFS_SECURITY_HASH = cpu_to_le32(0x12), + COLLATION_NTOFS_ULONGS = cpu_to_le32(0x13), }; typedef le32 COLLATION_RULE; @@ -559,25 +548,25 @@ typedef le32 COLLATION_RULE; * NT4. */ enum { - ATTR_DEF_INDEXABLE = const_cpu_to_le32(0x02), /* Attribute can be + ATTR_DEF_INDEXABLE = cpu_to_le32(0x02), /* Attribute can be indexed. */ - ATTR_DEF_MULTIPLE = const_cpu_to_le32(0x04), /* Attribute type + ATTR_DEF_MULTIPLE = cpu_to_le32(0x04), /* Attribute type can be present multiple times in the mft records of an inode. */ - ATTR_DEF_NOT_ZERO = const_cpu_to_le32(0x08), /* Attribute value + ATTR_DEF_NOT_ZERO = cpu_to_le32(0x08), /* Attribute value must contain at least one non-zero byte. */ - ATTR_DEF_INDEXED_UNIQUE = const_cpu_to_le32(0x10), /* Attribute must be + ATTR_DEF_INDEXED_UNIQUE = cpu_to_le32(0x10), /* Attribute must be indexed and the attribute value must be unique for the attribute type in all of the mft records of an inode. */ - ATTR_DEF_NAMED_UNIQUE = const_cpu_to_le32(0x20), /* Attribute must be + ATTR_DEF_NAMED_UNIQUE = cpu_to_le32(0x20), /* Attribute must be named and the name must be unique for the attribute type in all of the mft records of an inode. */ - ATTR_DEF_RESIDENT = const_cpu_to_le32(0x40), /* Attribute must be + ATTR_DEF_RESIDENT = cpu_to_le32(0x40), /* Attribute must be resident. */ - ATTR_DEF_ALWAYS_LOG = const_cpu_to_le32(0x80), /* Always log + ATTR_DEF_ALWAYS_LOG = cpu_to_le32(0x80), /* Always log modifications to this attribute, regardless of whether it is resident or non-resident. Without this, only log @@ -614,12 +603,12 @@ typedef struct { * Attribute flags (16-bit). */ enum { - ATTR_IS_COMPRESSED = const_cpu_to_le16(0x0001), - ATTR_COMPRESSION_MASK = const_cpu_to_le16(0x00ff), /* Compression method + ATTR_IS_COMPRESSED = cpu_to_le16(0x0001), + ATTR_COMPRESSION_MASK = cpu_to_le16(0x00ff), /* Compression method mask. Also, first illegal value. */ - ATTR_IS_ENCRYPTED = const_cpu_to_le16(0x4000), - ATTR_IS_SPARSE = const_cpu_to_le16(0x8000), + ATTR_IS_ENCRYPTED = cpu_to_le16(0x4000), + ATTR_IS_SPARSE = cpu_to_le16(0x8000), } __attribute__ ((__packed__)); typedef le16 ATTR_FLAGS; @@ -811,32 +800,32 @@ typedef ATTR_RECORD ATTR_REC; * flags appear in all of the above. */ enum { - FILE_ATTR_READONLY = const_cpu_to_le32(0x00000001), - FILE_ATTR_HIDDEN = const_cpu_to_le32(0x00000002), - FILE_ATTR_SYSTEM = const_cpu_to_le32(0x00000004), - /* Old DOS volid. Unused in NT. = const_cpu_to_le32(0x00000008), */ + FILE_ATTR_READONLY = cpu_to_le32(0x00000001), + FILE_ATTR_HIDDEN = cpu_to_le32(0x00000002), + FILE_ATTR_SYSTEM = cpu_to_le32(0x00000004), + /* Old DOS volid. Unused in NT. = cpu_to_le32(0x00000008), */ - FILE_ATTR_DIRECTORY = const_cpu_to_le32(0x00000010), + FILE_ATTR_DIRECTORY = cpu_to_le32(0x00000010), /* Note, FILE_ATTR_DIRECTORY is not considered valid in NT. It is reserved for the DOS SUBDIRECTORY flag. */ - FILE_ATTR_ARCHIVE = const_cpu_to_le32(0x00000020), - FILE_ATTR_DEVICE = const_cpu_to_le32(0x00000040), - FILE_ATTR_NORMAL = const_cpu_to_le32(0x00000080), + FILE_ATTR_ARCHIVE = cpu_to_le32(0x00000020), + FILE_ATTR_DEVICE = cpu_to_le32(0x00000040), + FILE_ATTR_NORMAL = cpu_to_le32(0x00000080), - FILE_ATTR_TEMPORARY = const_cpu_to_le32(0x00000100), - FILE_ATTR_SPARSE_FILE = const_cpu_to_le32(0x00000200), - FILE_ATTR_REPARSE_POINT = const_cpu_to_le32(0x00000400), - FILE_ATTR_COMPRESSED = const_cpu_to_le32(0x00000800), + FILE_ATTR_TEMPORARY = cpu_to_le32(0x00000100), + FILE_ATTR_SPARSE_FILE = cpu_to_le32(0x00000200), + FILE_ATTR_REPARSE_POINT = cpu_to_le32(0x00000400), + FILE_ATTR_COMPRESSED = cpu_to_le32(0x00000800), - FILE_ATTR_OFFLINE = const_cpu_to_le32(0x00001000), - FILE_ATTR_NOT_CONTENT_INDEXED = const_cpu_to_le32(0x00002000), - FILE_ATTR_ENCRYPTED = const_cpu_to_le32(0x00004000), + FILE_ATTR_OFFLINE = cpu_to_le32(0x00001000), + FILE_ATTR_NOT_CONTENT_INDEXED = cpu_to_le32(0x00002000), + FILE_ATTR_ENCRYPTED = cpu_to_le32(0x00004000), - FILE_ATTR_VALID_FLAGS = const_cpu_to_le32(0x00007fb7), + FILE_ATTR_VALID_FLAGS = cpu_to_le32(0x00007fb7), /* Note, FILE_ATTR_VALID_FLAGS masks out the old DOS VolId and the FILE_ATTR_DEVICE and preserves everything else. This mask is used to obtain all flags that are valid for reading. */ - FILE_ATTR_VALID_SET_FLAGS = const_cpu_to_le32(0x000031a7), + FILE_ATTR_VALID_SET_FLAGS = cpu_to_le32(0x000031a7), /* Note, FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT, F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask @@ -846,11 +835,11 @@ enum { * FILENAME_ATTR attributes but not in the STANDARD_INFORMATION * attribute of an mft record. */ - FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT = const_cpu_to_le32(0x10000000), + FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT = cpu_to_le32(0x10000000), /* Note, this is a copy of the corresponding bit from the mft record, telling us whether this is a directory or not, i.e. whether it has an index root attribute or not. */ - FILE_ATTR_DUP_VIEW_INDEX_PRESENT = const_cpu_to_le32(0x20000000), + FILE_ATTR_DUP_VIEW_INDEX_PRESENT = cpu_to_le32(0x20000000), /* Note, this is a copy of the corresponding bit from the mft record, telling us whether this file has a view index present (eg. object id index, quota index, one of the security indexes or the encrypting @@ -1446,42 +1435,42 @@ enum { /* Specific rights for files and directories are as follows: */ /* Right to read data from the file. (FILE) */ - FILE_READ_DATA = const_cpu_to_le32(0x00000001), + FILE_READ_DATA = cpu_to_le32(0x00000001), /* Right to list contents of a directory. (DIRECTORY) */ - FILE_LIST_DIRECTORY = const_cpu_to_le32(0x00000001), + FILE_LIST_DIRECTORY = cpu_to_le32(0x00000001), /* Right to write data to the file. (FILE) */ - FILE_WRITE_DATA = const_cpu_to_le32(0x00000002), + FILE_WRITE_DATA = cpu_to_le32(0x00000002), /* Right to create a file in the directory. (DIRECTORY) */ - FILE_ADD_FILE = const_cpu_to_le32(0x00000002), + FILE_ADD_FILE = cpu_to_le32(0x00000002), /* Right to append data to the file. (FILE) */ - FILE_APPEND_DATA = const_cpu_to_le32(0x00000004), + FILE_APPEND_DATA = cpu_to_le32(0x00000004), /* Right to create a subdirectory. (DIRECTORY) */ - FILE_ADD_SUBDIRECTORY = const_cpu_to_le32(0x00000004), + FILE_ADD_SUBDIRECTORY = cpu_to_le32(0x00000004), /* Right to read extended attributes. (FILE/DIRECTORY) */ - FILE_READ_EA = const_cpu_to_le32(0x00000008), + FILE_READ_EA = cpu_to_le32(0x00000008), /* Right to write extended attributes. (FILE/DIRECTORY) */ - FILE_WRITE_EA = const_cpu_to_le32(0x00000010), + FILE_WRITE_EA = cpu_to_le32(0x00000010), /* Right to execute a file. (FILE) */ - FILE_EXECUTE = const_cpu_to_le32(0x00000020), + FILE_EXECUTE = cpu_to_le32(0x00000020), /* Right to traverse the directory. (DIRECTORY) */ - FILE_TRAVERSE = const_cpu_to_le32(0x00000020), + FILE_TRAVERSE = cpu_to_le32(0x00000020), /* * Right to delete a directory and all the files it contains (its * children), even if the files are read-only. (DIRECTORY) */ - FILE_DELETE_CHILD = const_cpu_to_le32(0x00000040), + FILE_DELETE_CHILD = cpu_to_le32(0x00000040), /* Right to read file attributes. (FILE/DIRECTORY) */ - FILE_READ_ATTRIBUTES = const_cpu_to_le32(0x00000080), + FILE_READ_ATTRIBUTES = cpu_to_le32(0x00000080), /* Right to change file attributes. (FILE/DIRECTORY) */ - FILE_WRITE_ATTRIBUTES = const_cpu_to_le32(0x00000100), + FILE_WRITE_ATTRIBUTES = cpu_to_le32(0x00000100), /* * The standard rights (bits 16 to 23). These are independent of the @@ -1489,27 +1478,27 @@ enum { */ /* Right to delete the object. */ - DELETE = const_cpu_to_le32(0x00010000), + DELETE = cpu_to_le32(0x00010000), /* * Right to read the information in the object's security descriptor, * not including the information in the SACL, i.e. right to read the * security descriptor and owner. */ - READ_CONTROL = const_cpu_to_le32(0x00020000), + READ_CONTROL = cpu_to_le32(0x00020000), /* Right to modify the DACL in the object's security descriptor. */ - WRITE_DAC = const_cpu_to_le32(0x00040000), + WRITE_DAC = cpu_to_le32(0x00040000), /* Right to change the owner in the object's security descriptor. */ - WRITE_OWNER = const_cpu_to_le32(0x00080000), + WRITE_OWNER = cpu_to_le32(0x00080000), /* * Right to use the object for synchronization. Enables a process to * wait until the object is in the signalled state. Some object types * do not support this access right. */ - SYNCHRONIZE = const_cpu_to_le32(0x00100000), + SYNCHRONIZE = cpu_to_le32(0x00100000), /* * The following STANDARD_RIGHTS_* are combinations of the above for @@ -1517,25 +1506,25 @@ enum { */ /* These are currently defined to READ_CONTROL. */ - STANDARD_RIGHTS_READ = const_cpu_to_le32(0x00020000), - STANDARD_RIGHTS_WRITE = const_cpu_to_le32(0x00020000), - STANDARD_RIGHTS_EXECUTE = const_cpu_to_le32(0x00020000), + STANDARD_RIGHTS_READ = cpu_to_le32(0x00020000), + STANDARD_RIGHTS_WRITE = cpu_to_le32(0x00020000), + STANDARD_RIGHTS_EXECUTE = cpu_to_le32(0x00020000), /* Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access. */ - STANDARD_RIGHTS_REQUIRED = const_cpu_to_le32(0x000f0000), + STANDARD_RIGHTS_REQUIRED = cpu_to_le32(0x000f0000), /* * Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and * SYNCHRONIZE access. */ - STANDARD_RIGHTS_ALL = const_cpu_to_le32(0x001f0000), + STANDARD_RIGHTS_ALL = cpu_to_le32(0x001f0000), /* * The access system ACL and maximum allowed access types (bits 24 to * 25, bits 26 to 27 are reserved). */ - ACCESS_SYSTEM_SECURITY = const_cpu_to_le32(0x01000000), - MAXIMUM_ALLOWED = const_cpu_to_le32(0x02000000), + ACCESS_SYSTEM_SECURITY = cpu_to_le32(0x01000000), + MAXIMUM_ALLOWED = cpu_to_le32(0x02000000), /* * The generic rights (bits 28 to 31). These map onto the standard and @@ -1543,10 +1532,10 @@ enum { */ /* Read, write, and execute access. */ - GENERIC_ALL = const_cpu_to_le32(0x10000000), + GENERIC_ALL = cpu_to_le32(0x10000000), /* Execute access. */ - GENERIC_EXECUTE = const_cpu_to_le32(0x20000000), + GENERIC_EXECUTE = cpu_to_le32(0x20000000), /* * Write access. For files, this maps onto: @@ -1555,7 +1544,7 @@ enum { * For directories, the mapping has the same numerical value. See * above for the descriptions of the rights granted. */ - GENERIC_WRITE = const_cpu_to_le32(0x40000000), + GENERIC_WRITE = cpu_to_le32(0x40000000), /* * Read access. For files, this maps onto: @@ -1564,7 +1553,7 @@ enum { * For directories, the mapping has the same numberical value. See * above for the descriptions of the rights granted. */ - GENERIC_READ = const_cpu_to_le32(0x80000000), + GENERIC_READ = cpu_to_le32(0x80000000), }; typedef le32 ACCESS_MASK; @@ -1604,8 +1593,8 @@ typedef struct { * The object ACE flags (32-bit). */ enum { - ACE_OBJECT_TYPE_PRESENT = const_cpu_to_le32(1), - ACE_INHERITED_OBJECT_TYPE_PRESENT = const_cpu_to_le32(2), + ACE_OBJECT_TYPE_PRESENT = cpu_to_le32(1), + ACE_INHERITED_OBJECT_TYPE_PRESENT = cpu_to_le32(2), }; typedef le32 OBJECT_ACE_FLAGS; @@ -1706,23 +1695,23 @@ typedef enum { * expressed as offsets from the beginning of the security descriptor. */ enum { - SE_OWNER_DEFAULTED = const_cpu_to_le16(0x0001), - SE_GROUP_DEFAULTED = const_cpu_to_le16(0x0002), - SE_DACL_PRESENT = const_cpu_to_le16(0x0004), - SE_DACL_DEFAULTED = const_cpu_to_le16(0x0008), - - SE_SACL_PRESENT = const_cpu_to_le16(0x0010), - SE_SACL_DEFAULTED = const_cpu_to_le16(0x0020), - - SE_DACL_AUTO_INHERIT_REQ = const_cpu_to_le16(0x0100), - SE_SACL_AUTO_INHERIT_REQ = const_cpu_to_le16(0x0200), - SE_DACL_AUTO_INHERITED = const_cpu_to_le16(0x0400), - SE_SACL_AUTO_INHERITED = const_cpu_to_le16(0x0800), - - SE_DACL_PROTECTED = const_cpu_to_le16(0x1000), - SE_SACL_PROTECTED = const_cpu_to_le16(0x2000), - SE_RM_CONTROL_VALID = const_cpu_to_le16(0x4000), - SE_SELF_RELATIVE = const_cpu_to_le16(0x8000) + SE_OWNER_DEFAULTED = cpu_to_le16(0x0001), + SE_GROUP_DEFAULTED = cpu_to_le16(0x0002), + SE_DACL_PRESENT = cpu_to_le16(0x0004), + SE_DACL_DEFAULTED = cpu_to_le16(0x0008), + + SE_SACL_PRESENT = cpu_to_le16(0x0010), + SE_SACL_DEFAULTED = cpu_to_le16(0x0020), + + SE_DACL_AUTO_INHERIT_REQ = cpu_to_le16(0x0100), + SE_SACL_AUTO_INHERIT_REQ = cpu_to_le16(0x0200), + SE_DACL_AUTO_INHERITED = cpu_to_le16(0x0400), + SE_SACL_AUTO_INHERITED = cpu_to_le16(0x0800), + + SE_DACL_PROTECTED = cpu_to_le16(0x1000), + SE_SACL_PROTECTED = cpu_to_le16(0x2000), + SE_RM_CONTROL_VALID = cpu_to_le16(0x4000), + SE_SELF_RELATIVE = cpu_to_le16(0x8000) } __attribute__ ((__packed__)); typedef le16 SECURITY_DESCRIPTOR_CONTROL; @@ -1910,21 +1899,21 @@ typedef struct { * Possible flags for the volume (16-bit). */ enum { - VOLUME_IS_DIRTY = const_cpu_to_le16(0x0001), - VOLUME_RESIZE_LOG_FILE = const_cpu_to_le16(0x0002), - VOLUME_UPGRADE_ON_MOUNT = const_cpu_to_le16(0x0004), - VOLUME_MOUNTED_ON_NT4 = const_cpu_to_le16(0x0008), + VOLUME_IS_DIRTY = cpu_to_le16(0x0001), + VOLUME_RESIZE_LOG_FILE = cpu_to_le16(0x0002), + VOLUME_UPGRADE_ON_MOUNT = cpu_to_le16(0x0004), + VOLUME_MOUNTED_ON_NT4 = cpu_to_le16(0x0008), - VOLUME_DELETE_USN_UNDERWAY = const_cpu_to_le16(0x0010), - VOLUME_REPAIR_OBJECT_ID = const_cpu_to_le16(0x0020), + VOLUME_DELETE_USN_UNDERWAY = cpu_to_le16(0x0010), + VOLUME_REPAIR_OBJECT_ID = cpu_to_le16(0x0020), - VOLUME_CHKDSK_UNDERWAY = const_cpu_to_le16(0x4000), - VOLUME_MODIFIED_BY_CHKDSK = const_cpu_to_le16(0x8000), + VOLUME_CHKDSK_UNDERWAY = cpu_to_le16(0x4000), + VOLUME_MODIFIED_BY_CHKDSK = cpu_to_le16(0x8000), - VOLUME_FLAGS_MASK = const_cpu_to_le16(0xc03f), + VOLUME_FLAGS_MASK = cpu_to_le16(0xc03f), /* To make our life easier when checking if we must mount read-only. */ - VOLUME_MUST_MOUNT_RO_MASK = const_cpu_to_le16(0xc027), + VOLUME_MUST_MOUNT_RO_MASK = cpu_to_le16(0xc027), } __attribute__ ((__packed__)); typedef le16 VOLUME_FLAGS; @@ -2109,26 +2098,26 @@ typedef struct { * The user quota flags. Names explain meaning. */ enum { - QUOTA_FLAG_DEFAULT_LIMITS = const_cpu_to_le32(0x00000001), - QUOTA_FLAG_LIMIT_REACHED = const_cpu_to_le32(0x00000002), - QUOTA_FLAG_ID_DELETED = const_cpu_to_le32(0x00000004), + QUOTA_FLAG_DEFAULT_LIMITS = cpu_to_le32(0x00000001), + QUOTA_FLAG_LIMIT_REACHED = cpu_to_le32(0x00000002), + QUOTA_FLAG_ID_DELETED = cpu_to_le32(0x00000004), - QUOTA_FLAG_USER_MASK = const_cpu_to_le32(0x00000007), + QUOTA_FLAG_USER_MASK = cpu_to_le32(0x00000007), /* This is a bit mask for the user quota flags. */ /* * These flags are only present in the quota defaults index entry, i.e. * in the entry where owner_id = QUOTA_DEFAULTS_ID. */ - QUOTA_FLAG_TRACKING_ENABLED = const_cpu_to_le32(0x00000010), - QUOTA_FLAG_ENFORCEMENT_ENABLED = const_cpu_to_le32(0x00000020), - QUOTA_FLAG_TRACKING_REQUESTED = const_cpu_to_le32(0x00000040), - QUOTA_FLAG_LOG_THRESHOLD = const_cpu_to_le32(0x00000080), - - QUOTA_FLAG_LOG_LIMIT = const_cpu_to_le32(0x00000100), - QUOTA_FLAG_OUT_OF_DATE = const_cpu_to_le32(0x00000200), - QUOTA_FLAG_CORRUPT = const_cpu_to_le32(0x00000400), - QUOTA_FLAG_PENDING_DELETES = const_cpu_to_le32(0x00000800), + QUOTA_FLAG_TRACKING_ENABLED = cpu_to_le32(0x00000010), + QUOTA_FLAG_ENFORCEMENT_ENABLED = cpu_to_le32(0x00000020), + QUOTA_FLAG_TRACKING_REQUESTED = cpu_to_le32(0x00000040), + QUOTA_FLAG_LOG_THRESHOLD = cpu_to_le32(0x00000080), + + QUOTA_FLAG_LOG_LIMIT = cpu_to_le32(0x00000100), + QUOTA_FLAG_OUT_OF_DATE = cpu_to_le32(0x00000200), + QUOTA_FLAG_CORRUPT = cpu_to_le32(0x00000400), + QUOTA_FLAG_PENDING_DELETES = cpu_to_le32(0x00000800), }; typedef le32 QUOTA_FLAGS; @@ -2172,9 +2161,9 @@ typedef struct { * Predefined owner_id values (32-bit). */ enum { - QUOTA_INVALID_ID = const_cpu_to_le32(0x00000000), - QUOTA_DEFAULTS_ID = const_cpu_to_le32(0x00000001), - QUOTA_FIRST_USER_ID = const_cpu_to_le32(0x00000100), + QUOTA_INVALID_ID = cpu_to_le32(0x00000000), + QUOTA_DEFAULTS_ID = cpu_to_le32(0x00000001), + QUOTA_FIRST_USER_ID = cpu_to_le32(0x00000100), }; /* @@ -2189,14 +2178,14 @@ typedef enum { * Index entry flags (16-bit). */ enum { - INDEX_ENTRY_NODE = const_cpu_to_le16(1), /* This entry contains a + INDEX_ENTRY_NODE = cpu_to_le16(1), /* This entry contains a sub-node, i.e. a reference to an index block in form of a virtual cluster number (see below). */ - INDEX_ENTRY_END = const_cpu_to_le16(2), /* This signifies the last + INDEX_ENTRY_END = cpu_to_le16(2), /* This signifies the last entry in an index block. The index entry does not represent a file but it can point to a sub-node. */ - INDEX_ENTRY_SPACE_FILLER = const_cpu_to_le16(0xffff), /* gcc: Force + INDEX_ENTRY_SPACE_FILLER = cpu_to_le16(0xffff), /* gcc: Force enum bit width to 16-bit. */ } __attribute__ ((__packed__)); @@ -2334,26 +2323,26 @@ typedef struct { * These are the predefined reparse point tags: */ enum { - IO_REPARSE_TAG_IS_ALIAS = const_cpu_to_le32(0x20000000), - IO_REPARSE_TAG_IS_HIGH_LATENCY = const_cpu_to_le32(0x40000000), - IO_REPARSE_TAG_IS_MICROSOFT = const_cpu_to_le32(0x80000000), + IO_REPARSE_TAG_IS_ALIAS = cpu_to_le32(0x20000000), + IO_REPARSE_TAG_IS_HIGH_LATENCY = cpu_to_le32(0x40000000), + IO_REPARSE_TAG_IS_MICROSOFT = cpu_to_le32(0x80000000), - IO_REPARSE_TAG_RESERVED_ZERO = const_cpu_to_le32(0x00000000), - IO_REPARSE_TAG_RESERVED_ONE = const_cpu_to_le32(0x00000001), - IO_REPARSE_TAG_RESERVED_RANGE = const_cpu_to_le32(0x00000001), + IO_REPARSE_TAG_RESERVED_ZERO = cpu_to_le32(0x00000000), + IO_REPARSE_TAG_RESERVED_ONE = cpu_to_le32(0x00000001), + IO_REPARSE_TAG_RESERVED_RANGE = cpu_to_le32(0x00000001), - IO_REPARSE_TAG_NSS = const_cpu_to_le32(0x68000005), - IO_REPARSE_TAG_NSS_RECOVER = const_cpu_to_le32(0x68000006), - IO_REPARSE_TAG_SIS = const_cpu_to_le32(0x68000007), - IO_REPARSE_TAG_DFS = const_cpu_to_le32(0x68000008), + IO_REPARSE_TAG_NSS = cpu_to_le32(0x68000005), + IO_REPARSE_TAG_NSS_RECOVER = cpu_to_le32(0x68000006), + IO_REPARSE_TAG_SIS = cpu_to_le32(0x68000007), + IO_REPARSE_TAG_DFS = cpu_to_le32(0x68000008), - IO_REPARSE_TAG_MOUNT_POINT = const_cpu_to_le32(0x88000003), + IO_REPARSE_TAG_MOUNT_POINT = cpu_to_le32(0x88000003), - IO_REPARSE_TAG_HSM = const_cpu_to_le32(0xa8000004), + IO_REPARSE_TAG_HSM = cpu_to_le32(0xa8000004), - IO_REPARSE_TAG_SYMBOLIC_LINK = const_cpu_to_le32(0xe8000000), + IO_REPARSE_TAG_SYMBOLIC_LINK = cpu_to_le32(0xe8000000), - IO_REPARSE_TAG_VALID_VALUES = const_cpu_to_le32(0xe000ffff), + IO_REPARSE_TAG_VALID_VALUES = cpu_to_le32(0xe000ffff), }; /* diff --git a/fs/ntfs/logfile.h b/fs/ntfs/logfile.h index 9468e1c45ae..b5a6f08bd35 100644 --- a/fs/ntfs/logfile.h +++ b/fs/ntfs/logfile.h @@ -104,7 +104,7 @@ typedef struct { * in this particular client array. Also inside the client records themselves, * this means that there are no client records preceding or following this one. */ -#define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff) +#define LOGFILE_NO_CLIENT cpu_to_le16(0xffff) #define LOGFILE_NO_CLIENT_CPU 0xffff /* @@ -112,8 +112,8 @@ typedef struct { * information about the log file in which they are present. */ enum { - RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002), - RESTART_SPACE_FILLER = const_cpu_to_le16(0xffff), /* gcc: Force enum bit width to 16. */ + RESTART_VOLUME_IS_CLEAN = cpu_to_le16(0x0002), + RESTART_SPACE_FILLER = cpu_to_le16(0xffff), /* gcc: Force enum bit width to 16. */ } __attribute__ ((__packed__)); typedef le16 RESTART_AREA_FLAGS; diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 17d32ca6bc3..23bf68453d7 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -2839,7 +2839,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m) */ /* Mark the mft record as not in use. */ - m->flags &= const_cpu_to_le16(~const_le16_to_cpu(MFT_RECORD_IN_USE)); + m->flags &= ~MFT_RECORD_IN_USE; /* Increment the sequence number, skipping zero, if it is not zero. */ old_seq_no = m->sequence_number; diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 4a46743b507..f76951dcd4a 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -618,7 +618,7 @@ static bool is_boot_sector_ntfs(const struct super_block *sb, * many BIOSes will refuse to boot from a bootsector if the magic is * incorrect, so we emit a warning. */ - if (!silent && b->end_of_sector_marker != const_cpu_to_le16(0xaa55)) + if (!silent && b->end_of_sector_marker != cpu_to_le16(0xaa55)) ntfs_warning(sb, "Invalid end of sector marker."); return true; not_ntfs: @@ -1242,13 +1242,13 @@ static int check_windows_hibernation_status(ntfs_volume *vol) u32 *kaddr, *kend; ntfs_name *name = NULL; int ret = 1; - static const ntfschar hiberfil[13] = { const_cpu_to_le16('h'), - const_cpu_to_le16('i'), const_cpu_to_le16('b'), - const_cpu_to_le16('e'), const_cpu_to_le16('r'), - const_cpu_to_le16('f'), const_cpu_to_le16('i'), - const_cpu_to_le16('l'), const_cpu_to_le16('.'), - const_cpu_to_le16('s'), const_cpu_to_le16('y'), - const_cpu_to_le16('s'), 0 }; + static const ntfschar hiberfil[13] = { cpu_to_le16('h'), + cpu_to_le16('i'), cpu_to_le16('b'), + cpu_to_le16('e'), cpu_to_le16('r'), + cpu_to_le16('f'), cpu_to_le16('i'), + cpu_to_le16('l'), cpu_to_le16('.'), + cpu_to_le16('s'), cpu_to_le16('y'), + cpu_to_le16('s'), 0 }; ntfs_debug("Entering."); /* @@ -1296,7 +1296,7 @@ static int check_windows_hibernation_status(ntfs_volume *vol) goto iput_out; } kaddr = (u32*)page_address(page); - if (*(le32*)kaddr == const_cpu_to_le32(0x72626968)/*'hibr'*/) { + if (*(le32*)kaddr == cpu_to_le32(0x72626968)/*'hibr'*/) { ntfs_debug("Magic \"hibr\" found in hiberfil.sys. Windows is " "hibernated on the volume. This is the " "system volume."); @@ -1337,12 +1337,12 @@ static bool load_and_init_quota(ntfs_volume *vol) MFT_REF mref; struct inode *tmp_ino; ntfs_name *name = NULL; - static const ntfschar Quota[7] = { const_cpu_to_le16('$'), - const_cpu_to_le16('Q'), const_cpu_to_le16('u'), - const_cpu_to_le16('o'), const_cpu_to_le16('t'), - const_cpu_to_le16('a'), 0 }; - static ntfschar Q[3] = { const_cpu_to_le16('$'), - const_cpu_to_le16('Q'), 0 }; + static const ntfschar Quota[7] = { cpu_to_le16('$'), + cpu_to_le16('Q'), cpu_to_le16('u'), + cpu_to_le16('o'), cpu_to_le16('t'), + cpu_to_le16('a'), 0 }; + static ntfschar Q[3] = { cpu_to_le16('$'), + cpu_to_le16('Q'), 0 }; ntfs_debug("Entering."); /* @@ -1416,16 +1416,16 @@ static bool load_and_init_usnjrnl(ntfs_volume *vol) struct page *page; ntfs_name *name = NULL; USN_HEADER *uh; - static const ntfschar UsnJrnl[9] = { const_cpu_to_le16('$'), - const_cpu_to_le16('U'), const_cpu_to_le16('s'), - const_cpu_to_le16('n'), const_cpu_to_le16('J'), - const_cpu_to_le16('r'), const_cpu_to_le16('n'), - const_cpu_to_le16('l'), 0 }; - static ntfschar Max[5] = { const_cpu_to_le16('$'), - const_cpu_to_le16('M'), const_cpu_to_le16('a'), - const_cpu_to_le16('x'), 0 }; - static ntfschar J[3] = { const_cpu_to_le16('$'), - const_cpu_to_le16('J'), 0 }; + static const ntfschar UsnJrnl[9] = { cpu_to_le16('$'), + cpu_to_le16('U'), cpu_to_le16('s'), + cpu_to_le16('n'), cpu_to_le16('J'), + cpu_to_le16('r'), cpu_to_le16('n'), + cpu_to_le16('l'), 0 }; + static ntfschar Max[5] = { cpu_to_le16('$'), + cpu_to_le16('M'), cpu_to_le16('a'), + cpu_to_le16('x'), 0 }; + static ntfschar J[3] = { cpu_to_le16('$'), + cpu_to_le16('J'), 0 }; ntfs_debug("Entering."); /* diff --git a/fs/ntfs/usnjrnl.h b/fs/ntfs/usnjrnl.h index 4087fbdac32..00d8e6bd7c3 100644 --- a/fs/ntfs/usnjrnl.h +++ b/fs/ntfs/usnjrnl.h @@ -116,27 +116,27 @@ typedef struct { * documentation: http://www.linux-ntfs.org/ */ enum { - USN_REASON_DATA_OVERWRITE = const_cpu_to_le32(0x00000001), - USN_REASON_DATA_EXTEND = const_cpu_to_le32(0x00000002), - USN_REASON_DATA_TRUNCATION = const_cpu_to_le32(0x00000004), - USN_REASON_NAMED_DATA_OVERWRITE = const_cpu_to_le32(0x00000010), - USN_REASON_NAMED_DATA_EXTEND = const_cpu_to_le32(0x00000020), - USN_REASON_NAMED_DATA_TRUNCATION= const_cpu_to_le32(0x00000040), - USN_REASON_FILE_CREATE = const_cpu_to_le32(0x00000100), - USN_REASON_FILE_DELETE = const_cpu_to_le32(0x00000200), - USN_REASON_EA_CHANGE = const_cpu_to_le32(0x00000400), - USN_REASON_SECURITY_CHANGE = const_cpu_to_le32(0x00000800), - USN_REASON_RENAME_OLD_NAME = const_cpu_to_le32(0x00001000), - USN_REASON_RENAME_NEW_NAME = const_cpu_to_le32(0x00002000), - USN_REASON_INDEXABLE_CHANGE = const_cpu_to_le32(0x00004000), - USN_REASON_BASIC_INFO_CHANGE = const_cpu_to_le32(0x00008000), - USN_REASON_HARD_LINK_CHANGE = const_cpu_to_le32(0x00010000), - USN_REASON_COMPRESSION_CHANGE = const_cpu_to_le32(0x00020000), - USN_REASON_ENCRYPTION_CHANGE = const_cpu_to_le32(0x00040000), - USN_REASON_OBJECT_ID_CHANGE = const_cpu_to_le32(0x00080000), - USN_REASON_REPARSE_POINT_CHANGE = const_cpu_to_le32(0x00100000), - USN_REASON_STREAM_CHANGE = const_cpu_to_le32(0x00200000), - USN_REASON_CLOSE = const_cpu_to_le32(0x80000000), + USN_REASON_DATA_OVERWRITE = cpu_to_le32(0x00000001), + USN_REASON_DATA_EXTEND = cpu_to_le32(0x00000002), + USN_REASON_DATA_TRUNCATION = cpu_to_le32(0x00000004), + USN_REASON_NAMED_DATA_OVERWRITE = cpu_to_le32(0x00000010), + USN_REASON_NAMED_DATA_EXTEND = cpu_to_le32(0x00000020), + USN_REASON_NAMED_DATA_TRUNCATION= cpu_to_le32(0x00000040), + USN_REASON_FILE_CREATE = cpu_to_le32(0x00000100), + USN_REASON_FILE_DELETE = cpu_to_le32(0x00000200), + USN_REASON_EA_CHANGE = cpu_to_le32(0x00000400), + USN_REASON_SECURITY_CHANGE = cpu_to_le32(0x00000800), + USN_REASON_RENAME_OLD_NAME = cpu_to_le32(0x00001000), + USN_REASON_RENAME_NEW_NAME = cpu_to_le32(0x00002000), + USN_REASON_INDEXABLE_CHANGE = cpu_to_le32(0x00004000), + USN_REASON_BASIC_INFO_CHANGE = cpu_to_le32(0x00008000), + USN_REASON_HARD_LINK_CHANGE = cpu_to_le32(0x00010000), + USN_REASON_COMPRESSION_CHANGE = cpu_to_le32(0x00020000), + USN_REASON_ENCRYPTION_CHANGE = cpu_to_le32(0x00040000), + USN_REASON_OBJECT_ID_CHANGE = cpu_to_le32(0x00080000), + USN_REASON_REPARSE_POINT_CHANGE = cpu_to_le32(0x00100000), + USN_REASON_STREAM_CHANGE = cpu_to_le32(0x00200000), + USN_REASON_CLOSE = cpu_to_le32(0x80000000), }; typedef le32 USN_REASON_FLAGS; @@ -148,9 +148,9 @@ typedef le32 USN_REASON_FLAGS; * http://www.linux-ntfs.org/ */ enum { - USN_SOURCE_DATA_MANAGEMENT = const_cpu_to_le32(0x00000001), - USN_SOURCE_AUXILIARY_DATA = const_cpu_to_le32(0x00000002), - USN_SOURCE_REPLICATION_MANAGEMENT = const_cpu_to_le32(0x00000004), + USN_SOURCE_DATA_MANAGEMENT = cpu_to_le32(0x00000001), + USN_SOURCE_AUXILIARY_DATA = cpu_to_le32(0x00000002), + USN_SOURCE_REPLICATION_MANAGEMENT = cpu_to_le32(0x00000004), }; typedef le32 USN_SOURCE_INFO_FLAGS; diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 3a9e5deed74..19e3a96aa02 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -176,7 +176,8 @@ static int ocfs2_dinode_insert_check(struct inode *inode, BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); mlog_bug_on_msg(!ocfs2_sparse_alloc(osb) && - (OCFS2_I(inode)->ip_clusters != rec->e_cpos), + (OCFS2_I(inode)->ip_clusters != + le32_to_cpu(rec->e_cpos)), "Device %s, asking for sparse allocation: inode %llu, " "cpos %u, clusters %u\n", osb->dev_str, diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index a067a6cffb0..8e1709a679b 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -227,7 +227,7 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page, size = i_size_read(inode); if (size > PAGE_CACHE_SIZE || - size > ocfs2_max_inline_data(inode->i_sb)) { + size > ocfs2_max_inline_data_with_xattr(inode->i_sb, di)) { ocfs2_error(inode->i_sb, "Inode %llu has with inline data has bad size: %Lu", (unsigned long long)OCFS2_I(inode)->ip_blkno, @@ -1555,6 +1555,7 @@ static int ocfs2_try_to_write_inline_data(struct address_space *mapping, int ret, written = 0; loff_t end = pos + len; struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct ocfs2_dinode *di = NULL; mlog(0, "Inode %llu, write of %u bytes at off %llu. features: 0x%x\n", (unsigned long long)oi->ip_blkno, len, (unsigned long long)pos, @@ -1587,7 +1588,9 @@ static int ocfs2_try_to_write_inline_data(struct address_space *mapping, /* * Check whether the write can fit. */ - if (mmap_page || end > ocfs2_max_inline_data(inode->i_sb)) + di = (struct ocfs2_dinode *)wc->w_di_bh->b_data; + if (mmap_page || + end > ocfs2_max_inline_data_with_xattr(inode->i_sb, di)) return 0; do_inline_write: diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c index e9d7c2038c0..7d604480557 100644 --- a/fs/ocfs2/dcache.c +++ b/fs/ocfs2/dcache.c @@ -455,7 +455,7 @@ out_move: d_move(dentry, target); } -struct dentry_operations ocfs2_dentry_ops = { +const struct dentry_operations ocfs2_dentry_ops = { .d_revalidate = ocfs2_dentry_revalidate, .d_iput = ocfs2_dentry_iput, }; diff --git a/fs/ocfs2/dcache.h b/fs/ocfs2/dcache.h index d06e16c0664..faa12e75f98 100644 --- a/fs/ocfs2/dcache.h +++ b/fs/ocfs2/dcache.h @@ -26,7 +26,7 @@ #ifndef OCFS2_DCACHE_H #define OCFS2_DCACHE_H -extern struct dentry_operations ocfs2_dentry_ops; +extern const struct dentry_operations ocfs2_dentry_ops; struct ocfs2_dentry_lock { /* Use count of dentry lock */ diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c index eea1d24713e..b606496b72e 100644 --- a/fs/ocfs2/mmap.c +++ b/fs/ocfs2/mmap.c @@ -154,8 +154,9 @@ out: return ret; } -static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page) +static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { + struct page *page = vmf->page; struct inode *inode = vma->vm_file->f_path.dentry->d_inode; struct buffer_head *di_bh = NULL; sigset_t blocked, oldset; @@ -196,7 +197,8 @@ out: ret2 = ocfs2_vm_op_unblock_sigs(&oldset); if (ret2 < 0) mlog_errno(ret2); - + if (ret) + ret = VM_FAULT_SIGBUS; return ret; } diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 084aba86c3b..4b11762f249 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -532,7 +532,8 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL); - fe->id2.i_data.id_count = cpu_to_le16(ocfs2_max_inline_data(osb->sb)); + fe->id2.i_data.id_count = cpu_to_le16( + ocfs2_max_inline_data_with_xattr(osb->sb, fe)); } else { fel = &fe->id2.i_list; fel->l_tree_depth = 0; diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index c7ae45aaa36..2332ef740f4 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h @@ -1070,12 +1070,6 @@ static inline int ocfs2_fast_symlink_chars(struct super_block *sb) offsetof(struct ocfs2_dinode, id2.i_symlink); } -static inline int ocfs2_max_inline_data(struct super_block *sb) -{ - return sb->s_blocksize - - offsetof(struct ocfs2_dinode, id2.i_data.id_data); -} - static inline int ocfs2_max_inline_data_with_xattr(struct super_block *sb, struct ocfs2_dinode *di) { diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 4ddd788add6..2563df89fc2 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -547,8 +547,12 @@ int ocfs2_calc_xattr_init(struct inode *dir, * when blocksize = 512, may reserve one more cluser for * xattr bucket, otherwise reserve one metadata block * for them is ok. + * If this is a new directory with inline data, + * we choose to reserve the entire inline area for + * directory contents and force an external xattr block. */ if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE || + (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) || (s_size + a_size) > OCFS2_XATTR_FREE_IN_IBODY) { ret = ocfs2_reserve_new_metadata_blocks(osb, 1, xattr_ac); if (ret) { @@ -4791,19 +4795,33 @@ static int ocfs2_xattr_bucket_set_value_outside(struct inode *inode, char *val, int value_len) { - int offset; + int ret, offset, block_off; struct ocfs2_xattr_value_root *xv; struct ocfs2_xattr_entry *xe = xs->here; + struct ocfs2_xattr_header *xh = bucket_xh(xs->bucket); + void *base; BUG_ON(!xs->base || !xe || ocfs2_xattr_is_local(xe)); - offset = le16_to_cpu(xe->xe_name_offset) + - OCFS2_XATTR_SIZE(xe->xe_name_len); + ret = ocfs2_xattr_bucket_get_name_value(inode, xh, + xe - xh->xh_entries, + &block_off, + &offset); + if (ret) { + mlog_errno(ret); + goto out; + } - xv = (struct ocfs2_xattr_value_root *)(xs->base + offset); + base = bucket_block(xs->bucket, block_off); + xv = (struct ocfs2_xattr_value_root *)(base + offset + + OCFS2_XATTR_SIZE(xe->xe_name_len)); - return __ocfs2_xattr_set_value_outside(inode, handle, - xv, val, value_len); + ret = __ocfs2_xattr_set_value_outside(inode, handle, + xv, val, value_len); + if (ret) + mlog_errno(ret); +out: + return ret; } static int ocfs2_rm_xattr_cluster(struct inode *inode, diff --git a/fs/open.c b/fs/open.c index a3a78ceb2a2..75b61677daa 100644 --- a/fs/open.c +++ b/fs/open.c @@ -273,7 +273,7 @@ static long do_sys_truncate(const char __user *pathname, loff_t length) if (!error) error = security_path_truncate(&path, length, 0); if (!error) { - DQUOT_INIT(inode); + vfs_dq_init(inode); error = do_truncate(path.dentry, length, 0, NULL); } diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 6d720243f5f..38e337d51ce 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -400,7 +400,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, pdev->devt = devt; /* delay uevent until 'holders' subdir is created */ - pdev->uevent_suppress = 1; + dev_set_uevent_suppress(pdev, 1); err = device_add(pdev); if (err) goto out_put; @@ -410,7 +410,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, if (!p->holder_dir) goto out_del; - pdev->uevent_suppress = 0; + dev_set_uevent_suppress(pdev, 0); if (flags & ADDPART_FLAG_WHOLEDISK) { err = device_create_file(pdev, &dev_attr_whole_disk); if (err) @@ -422,7 +422,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, rcu_assign_pointer(ptbl->part[partno], p); /* suppress uevent if the disk supresses it */ - if (!ddev->uevent_suppress) + if (!dev_get_uevent_suppress(pdev)) kobject_uevent(&pdev->kobj, KOBJ_ADD); return p; @@ -455,7 +455,7 @@ void register_disk(struct gendisk *disk) dev_set_name(ddev, disk->disk_name); /* delay uevents, until we scanned partition table */ - ddev->uevent_suppress = 1; + dev_set_uevent_suppress(ddev, 1); if (device_add(ddev)) return; @@ -490,7 +490,7 @@ void register_disk(struct gendisk *disk) exit: /* announce disk after possible partitions are created */ - ddev->uevent_suppress = 0; + dev_set_uevent_suppress(ddev, 0); kobject_uevent(&ddev->kobj, KOBJ_ADD); /* announce possible partitions */ diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c index 1e064c4a4f8..46297683cd3 100644 --- a/fs/partitions/ibm.c +++ b/fs/partitions/ibm.c @@ -21,20 +21,38 @@ * compute the block number from a * cyl-cyl-head-head structure */ -static inline int +static sector_t cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) { - return ptr->cc * geo->heads * geo->sectors + - ptr->hh * geo->sectors; + + sector_t cyl; + __u16 head; + + /*decode cylinder and heads for large volumes */ + cyl = ptr->hh & 0xFFF0; + cyl <<= 12; + cyl |= ptr->cc; + head = ptr->hh & 0x000F; + return cyl * geo->heads * geo->sectors + + head * geo->sectors; } /* * compute the block number from a * cyl-cyl-head-head-block structure */ -static inline int +static sector_t cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) { - return ptr->cc * geo->heads * geo->sectors + - ptr->hh * geo->sectors + + + sector_t cyl; + __u16 head; + + /*decode cylinder and heads for large volumes */ + cyl = ptr->hh & 0xFFF0; + cyl <<= 12; + cyl |= ptr->cc; + head = ptr->hh & 0x000F; + return cyl * geo->heads * geo->sectors + + head * geo->sectors + ptr->b; } @@ -43,14 +61,15 @@ cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) { int ibm_partition(struct parsed_partitions *state, struct block_device *bdev) { - int blocksize, offset, size,res; - loff_t i_size; + int blocksize, res; + loff_t i_size, offset, size, fmt_size; dasd_information2_t *info; struct hd_geometry *geo; char type[5] = {0,}; char name[7] = {0,}; union label_t { - struct vtoc_volume_label vol; + struct vtoc_volume_label_cdl vol; + struct vtoc_volume_label_ldl lnx; struct vtoc_cms_label cms; } *label; unsigned char *data; @@ -85,14 +104,16 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) if (data == NULL) goto out_readerr; - strncpy (type, data, 4); - if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) - strncpy(name, data + 8, 6); - else - strncpy(name, data + 4, 6); memcpy(label, data, sizeof(union label_t)); put_dev_sector(sect); + if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) { + strncpy(type, label->vol.vollbl, 4); + strncpy(name, label->vol.volid, 6); + } else { + strncpy(type, label->lnx.vollbl, 4); + strncpy(name, label->lnx.volid, 6); + } EBCASC(type, 4); EBCASC(name, 6); @@ -110,36 +131,54 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) /* * VM style CMS1 labeled disk */ + blocksize = label->cms.block_size; if (label->cms.disk_offset != 0) { printk("CMS1/%8s(MDSK):", name); /* disk is reserved minidisk */ - blocksize = label->cms.block_size; offset = label->cms.disk_offset; size = (label->cms.block_count - 1) * (blocksize >> 9); } else { printk("CMS1/%8s:", name); offset = (info->label_block + 1); - size = i_size >> 9; + size = label->cms.block_count + * (blocksize >> 9); } + put_partition(state, 1, offset*(blocksize >> 9), + size-offset*(blocksize >> 9)); } else { - /* - * Old style LNX1 or unlabeled disk - */ - if (strncmp(type, "LNX1", 4) == 0) - printk ("LNX1/%8s:", name); - else + if (strncmp(type, "LNX1", 4) == 0) { + printk("LNX1/%8s:", name); + if (label->lnx.ldl_version == 0xf2) { + fmt_size = label->lnx.formatted_blocks + * (blocksize >> 9); + } else if (!strcmp(info->type, "ECKD")) { + /* formated w/o large volume support */ + fmt_size = geo->cylinders * geo->heads + * geo->sectors * (blocksize >> 9); + } else { + /* old label and no usable disk geometry + * (e.g. DIAG) */ + fmt_size = i_size >> 9; + } + size = i_size >> 9; + if (fmt_size < size) + size = fmt_size; + offset = (info->label_block + 1); + } else { + /* unlabeled disk */ printk("(nonl)"); - offset = (info->label_block + 1); - size = i_size >> 9; - } - put_partition(state, 1, offset*(blocksize >> 9), + size = i_size >> 9; + offset = (info->label_block + 1); + } + put_partition(state, 1, offset*(blocksize >> 9), size-offset*(blocksize >> 9)); + } } else if (info->format == DASD_FORMAT_CDL) { /* * New style CDL formatted disk */ - unsigned int blk; + sector_t blk; int counter; /* @@ -166,7 +205,8 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) /* skip FMT4 / FMT5 / FMT7 labels */ if (f1.DS1FMTID == _ascebc['4'] || f1.DS1FMTID == _ascebc['5'] - || f1.DS1FMTID == _ascebc['7']) { + || f1.DS1FMTID == _ascebc['7'] + || f1.DS1FMTID == _ascebc['9']) { blk++; data = read_dev_sector(bdev, blk * (blocksize/512), @@ -174,8 +214,9 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) continue; } - /* only FMT1 valid at this point */ - if (f1.DS1FMTID != _ascebc['1']) + /* only FMT1 and 8 labels valid at this point */ + if (f1.DS1FMTID != _ascebc['1'] && + f1.DS1FMTID != _ascebc['8']) break; /* OK, we got valid partition data */ diff --git a/fs/pipe.c b/fs/pipe.c index 3a48ba5179d..4af7aa52181 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -667,10 +667,7 @@ pipe_read_fasync(int fd, struct file *filp, int on) retval = fasync_helper(fd, filp, on, &inode->i_pipe->fasync_readers); mutex_unlock(&inode->i_mutex); - if (retval < 0) - return retval; - - return 0; + return retval; } @@ -684,10 +681,7 @@ pipe_write_fasync(int fd, struct file *filp, int on) retval = fasync_helper(fd, filp, on, &inode->i_pipe->fasync_writers); mutex_unlock(&inode->i_mutex); - if (retval < 0) - return retval; - - return 0; + return retval; } @@ -699,18 +693,14 @@ pipe_rdwr_fasync(int fd, struct file *filp, int on) int retval; mutex_lock(&inode->i_mutex); - retval = fasync_helper(fd, filp, on, &pipe->fasync_readers); - - if (retval >= 0) + if (retval >= 0) { retval = fasync_helper(fd, filp, on, &pipe->fasync_writers); - + if (retval < 0) /* this can happen only if on == T */ + fasync_helper(-1, filp, 0, &pipe->fasync_readers); + } mutex_unlock(&inode->i_mutex); - - if (retval < 0) - return retval; - - return 0; + return retval; } @@ -870,7 +860,7 @@ static char *pipefs_dname(struct dentry *dentry, char *buffer, int buflen) dentry->d_inode->i_ino); } -static struct dentry_operations pipefs_dentry_operations = { +static const struct dentry_operations pipefs_dentry_operations = { .d_delete = pipefs_delete_dentry, .d_dname = pipefs_dname, }; @@ -1034,11 +1024,6 @@ int do_pipe_flags(int *fd, int flags) return error; } -int do_pipe(int *fd) -{ - return do_pipe_flags(fd, 0); -} - /* * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way Unix traditionally does this, though. diff --git a/fs/proc/base.c b/fs/proc/base.c index 0c9de19a163..e0afd326b68 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -146,15 +146,22 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries, return count; } -static struct fs_struct *get_fs_struct(struct task_struct *task) +static int get_fs_path(struct task_struct *task, struct path *path, bool root) { struct fs_struct *fs; + int result = -ENOENT; + task_lock(task); fs = task->fs; - if(fs) - atomic_inc(&fs->count); + if (fs) { + read_lock(&fs->lock); + *path = root ? fs->root : fs->pwd; + path_get(path); + read_unlock(&fs->lock); + result = 0; + } task_unlock(task); - return fs; + return result; } static int get_nr_threads(struct task_struct *tsk) @@ -172,42 +179,24 @@ static int get_nr_threads(struct task_struct *tsk) static int proc_cwd_link(struct inode *inode, struct path *path) { struct task_struct *task = get_proc_task(inode); - struct fs_struct *fs = NULL; int result = -ENOENT; if (task) { - fs = get_fs_struct(task); + result = get_fs_path(task, path, 0); put_task_struct(task); } - if (fs) { - read_lock(&fs->lock); - *path = fs->pwd; - path_get(&fs->pwd); - read_unlock(&fs->lock); - result = 0; - put_fs_struct(fs); - } return result; } static int proc_root_link(struct inode *inode, struct path *path) { struct task_struct *task = get_proc_task(inode); - struct fs_struct *fs = NULL; int result = -ENOENT; if (task) { - fs = get_fs_struct(task); + result = get_fs_path(task, path, 1); put_task_struct(task); } - if (fs) { - read_lock(&fs->lock); - *path = fs->root; - path_get(&fs->root); - read_unlock(&fs->lock); - result = 0; - put_fs_struct(fs); - } return result; } @@ -596,7 +585,6 @@ static int mounts_open_common(struct inode *inode, struct file *file, struct task_struct *task = get_proc_task(inode); struct nsproxy *nsp; struct mnt_namespace *ns = NULL; - struct fs_struct *fs = NULL; struct path root; struct proc_mounts *p; int ret = -EINVAL; @@ -610,22 +598,16 @@ static int mounts_open_common(struct inode *inode, struct file *file, get_mnt_ns(ns); } rcu_read_unlock(); - if (ns) - fs = get_fs_struct(task); + if (ns && get_fs_path(task, &root, 1) == 0) + ret = 0; put_task_struct(task); } if (!ns) goto err; - if (!fs) + if (ret) goto err_put_ns; - read_lock(&fs->lock); - root = fs->root; - path_get(&root); - read_unlock(&fs->lock); - put_fs_struct(fs); - ret = -ENOMEM; p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); if (!p) @@ -1545,7 +1527,7 @@ static int pid_delete_dentry(struct dentry * dentry) return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first; } -static struct dentry_operations pid_dentry_operations = +static const struct dentry_operations pid_dentry_operations = { .d_revalidate = pid_revalidate, .d_delete = pid_delete_dentry, @@ -1717,7 +1699,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) return 0; } -static struct dentry_operations tid_fd_dentry_operations = +static const struct dentry_operations tid_fd_dentry_operations = { .d_revalidate = tid_fd_revalidate, .d_delete = pid_delete_dentry, @@ -2339,7 +2321,7 @@ static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd) return 0; } -static struct dentry_operations proc_base_dentry_operations = +static const struct dentry_operations proc_base_dentry_operations = { .d_revalidate = proc_base_revalidate, .d_delete = pid_delete_dentry, @@ -3066,7 +3048,6 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi int retval = -ENOENT; ino_t ino; int tid; - unsigned long pos = filp->f_pos; /* avoiding "long long" filp->f_pos */ struct pid_namespace *ns; task = get_proc_task(inode); @@ -3083,18 +3064,18 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi goto out_no_task; retval = 0; - switch (pos) { + switch ((unsigned long)filp->f_pos) { case 0: ino = inode->i_ino; - if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0) + if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0) goto out; - pos++; + filp->f_pos++; /* fall through */ case 1: ino = parent_ino(dentry); - if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0) + if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) < 0) goto out; - pos++; + filp->f_pos++; /* fall through */ } @@ -3104,9 +3085,9 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi ns = filp->f_dentry->d_sb->s_fs_info; tid = (int)filp->f_version; filp->f_version = 0; - for (task = first_tid(leader, tid, pos - 2, ns); + for (task = first_tid(leader, tid, filp->f_pos - 2, ns); task; - task = next_tid(task), pos++) { + task = next_tid(task), filp->f_pos++) { tid = task_pid_nr_ns(task, ns); if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) { /* returning this tgid failed, save it as the first @@ -3117,7 +3098,6 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi } } out: - filp->f_pos = pos; put_task_struct(leader); out_no_task: return retval; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index db7fa5cab98..fa678abc9db 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -37,7 +37,7 @@ static int proc_match(int len, const char *name, struct proc_dir_entry *de) #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024) static ssize_t -proc_file_read(struct file *file, char __user *buf, size_t nbytes, +__proc_file_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { struct inode * inode = file->f_path.dentry->d_inode; @@ -183,19 +183,47 @@ proc_file_read(struct file *file, char __user *buf, size_t nbytes, } static ssize_t +proc_file_read(struct file *file, char __user *buf, size_t nbytes, + loff_t *ppos) +{ + struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); + ssize_t rv = -EIO; + + spin_lock(&pde->pde_unload_lock); + if (!pde->proc_fops) { + spin_unlock(&pde->pde_unload_lock); + return rv; + } + pde->pde_users++; + spin_unlock(&pde->pde_unload_lock); + + rv = __proc_file_read(file, buf, nbytes, ppos); + + pde_users_dec(pde); + return rv; +} + +static ssize_t proc_file_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { - struct inode *inode = file->f_path.dentry->d_inode; - struct proc_dir_entry * dp; - - dp = PDE(inode); - - if (!dp->write_proc) - return -EIO; + struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); + ssize_t rv = -EIO; + + if (pde->write_proc) { + spin_lock(&pde->pde_unload_lock); + if (!pde->proc_fops) { + spin_unlock(&pde->pde_unload_lock); + return rv; + } + pde->pde_users++; + spin_unlock(&pde->pde_unload_lock); - /* FIXME: does this routine need ppos? probably... */ - return dp->write_proc(file, buffer, count, dp->data); + /* FIXME: does this routine need ppos? probably... */ + rv = pde->write_proc(file, buffer, count, pde->data); + pde_users_dec(pde); + } + return rv; } @@ -307,6 +335,21 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ /* * Return an inode number between PROC_DYNAMIC_FIRST and * 0xffffffff, or zero on failure. + * + * Current inode allocations in the proc-fs (hex-numbers): + * + * 00000000 reserved + * 00000001-00000fff static entries (goners) + * 001 root-ino + * + * 00001000-00001fff unused + * 0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff + * 80000000-efffffff unused + * f0000000-ffffffff dynamic entries + * + * Goal: + * Once we split the thing into several virtual filesystems, + * we will get rid of magical ranges (and this comment, BTW). */ static unsigned int get_inode_number(void) { @@ -363,7 +406,7 @@ static int proc_delete_dentry(struct dentry * dentry) return 1; } -static struct dentry_operations proc_dentry_operations = +static const struct dentry_operations proc_dentry_operations = { .d_delete = proc_delete_dentry, }; diff --git a/fs/proc/inode-alloc.txt b/fs/proc/inode-alloc.txt deleted file mode 100644 index 77212f938c2..00000000000 --- a/fs/proc/inode-alloc.txt +++ /dev/null @@ -1,14 +0,0 @@ -Current inode allocations in the proc-fs (hex-numbers): - - 00000000 reserved - 00000001-00000fff static entries (goners) - 001 root-ino - - 00001000-00001fff unused - 0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff - 80000000-efffffff unused - f0000000-ffffffff dynamic entries - -Goal: - a) once we'll split the thing into several virtual filesystems we - will get rid of magical ranges (and this file, BTW). diff --git a/fs/proc/inode.c b/fs/proc/inode.c index d8bb5c671f4..d78ade30554 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -58,11 +58,8 @@ static void proc_delete_inode(struct inode *inode) /* Let go of any associated proc directory entry */ de = PROC_I(inode)->pde; - if (de) { - if (de->owner) - module_put(de->owner); + if (de) de_put(de); - } if (PROC_I(inode)->sysctl) sysctl_head_put(PROC_I(inode)->sysctl); clear_inode(inode); @@ -127,7 +124,7 @@ static void __pde_users_dec(struct proc_dir_entry *pde) complete(pde->pde_unload_completion); } -static void pde_users_dec(struct proc_dir_entry *pde) +void pde_users_dec(struct proc_dir_entry *pde) { spin_lock(&pde->pde_unload_lock); __pde_users_dec(pde); @@ -449,12 +446,9 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, { struct inode * inode; - if (!try_module_get(de->owner)) - goto out_mod; - inode = iget_locked(sb, ino); if (!inode) - goto out_ino; + return NULL; if (inode->i_state & I_NEW) { inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; PROC_I(inode)->fd = 0; @@ -485,16 +479,9 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, } } unlock_new_inode(inode); - } else { - module_put(de->owner); + } else de_put(de); - } return inode; - -out_ino: - module_put(de->owner); -out_mod: - return NULL; } int proc_fill_super(struct super_block *s) diff --git a/fs/proc/internal.h b/fs/proc/internal.h index cd53ff83849..f6db9618a88 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -91,3 +91,4 @@ struct pde_opener { int (*release)(struct inode *, struct file *); struct list_head lh; }; +void pde_users_dec(struct proc_dir_entry *pde); diff --git a/fs/proc/page.c b/fs/proc/page.c index 2d1345112a4..e9983837d08 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -80,7 +80,7 @@ static const struct file_operations proc_kpagecount_operations = { #define KPF_RECLAIM 9 #define KPF_BUDDY 10 -#define kpf_copy_bit(flags, srcpos, dstpos) (((flags >> srcpos) & 1) << dstpos) +#define kpf_copy_bit(flags, dstpos, srcpos) (((flags >> srcpos) & 1) << dstpos) static ssize_t kpageflags_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 94fcfff6863..9b1e4e9a16b 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -7,7 +7,7 @@ #include <linux/security.h> #include "internal.h" -static struct dentry_operations proc_sys_dentry_operations; +static const struct dentry_operations proc_sys_dentry_operations; static const struct file_operations proc_sys_file_operations; static const struct inode_operations proc_sys_inode_operations; static const struct file_operations proc_sys_dir_file_operations; @@ -396,7 +396,7 @@ static int proc_sys_compare(struct dentry *dir, struct qstr *qstr, return !sysctl_is_seen(PROC_I(dentry->d_inode)->sysctl); } -static struct dentry_operations proc_sys_dentry_operations = { +static const struct dentry_operations proc_sys_dentry_operations = { .d_revalidate = proc_sys_revalidate, .d_delete = proc_sys_delete, .d_compare = proc_sys_compare, diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index d153946d6d1..83adcc86943 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c @@ -144,17 +144,12 @@ void proc_tty_register_driver(struct tty_driver *driver) { struct proc_dir_entry *ent; - if (!driver->ops->read_proc || !driver->driver_name || - driver->proc_entry) + if (!driver->driver_name || driver->proc_entry || + !driver->ops->proc_fops) return; - ent = create_proc_entry(driver->driver_name, 0, proc_tty_driver); - if (!ent) - return; - ent->read_proc = driver->ops->read_proc; - ent->owner = driver->owner; - ent->data = driver; - + ent = proc_create_data(driver->driver_name, 0, proc_tty_driver, + driver->ops->proc_fops, driver); driver->proc_entry = ent; } diff --git a/fs/proc/root.c b/fs/proc/root.c index f6299a25594..1e15a2b176e 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -83,7 +83,8 @@ static int proc_get_sb(struct file_system_type *fs_type, ns->proc_mnt = mnt; } - return simple_set_mnt(mnt, sb); + simple_set_mnt(mnt, sb); + return 0; } static void proc_kill_sb(struct super_block *sb) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 94063840832..b0ae0be4801 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -693,8 +693,8 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, goto out_pages; } - pm.out = (u64 *)buf; - pm.end = (u64 *)(buf + count); + pm.out = (u64 __user *)buf; + pm.end = (u64 __user *)(buf + count); pagemap_walk.pmd_entry = pagemap_pte_range; pagemap_walk.pte_hole = pagemap_pte_hole; @@ -720,9 +720,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, if (ret == PM_END_OF_BUFFER) ret = 0; /* don't need mmap_sem for these, but this looks cleaner */ - *ppos += (char *)pm.out - buf; + *ppos += (char __user *)pm.out - buf; if (!ret) - ret = (char *)pm.out - buf; + ret = (char __user *)pm.out - buf; out_pages: for (; pagecount; pagecount--) { diff --git a/fs/proc/uptime.c b/fs/proc/uptime.c index df26aa88fa4..0c10a0b3f14 100644 --- a/fs/proc/uptime.c +++ b/fs/proc/uptime.c @@ -1,45 +1,43 @@ +#include <linux/fs.h> #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/sched.h> +#include <linux/seq_file.h> #include <linux/time.h> #include <asm/cputime.h> -static int proc_calc_metrics(char *page, char **start, off_t off, - int count, int *eof, int len) -{ - if (len <= off + count) - *eof = 1; - *start = page + off; - len -= off; - if (len > count) - len = count; - if (len < 0) - len = 0; - return len; -} - -static int uptime_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int uptime_proc_show(struct seq_file *m, void *v) { struct timespec uptime; struct timespec idle; - int len; cputime_t idletime = cputime_add(init_task.utime, init_task.stime); do_posix_clock_monotonic_gettime(&uptime); monotonic_to_bootbased(&uptime); cputime_to_timespec(idletime, &idle); - len = sprintf(page, "%lu.%02lu %lu.%02lu\n", + seq_printf(m, "%lu.%02lu %lu.%02lu\n", (unsigned long) uptime.tv_sec, (uptime.tv_nsec / (NSEC_PER_SEC / 100)), (unsigned long) idle.tv_sec, (idle.tv_nsec / (NSEC_PER_SEC / 100))); - return proc_calc_metrics(page, start, off, count, eof, len); + return 0; } +static int uptime_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, uptime_proc_show, NULL); +} + +static const struct file_operations uptime_proc_fops = { + .open = uptime_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int __init proc_uptime_init(void) { - create_proc_read_entry("uptime", 0, NULL, uptime_read_proc, NULL); + proc_create("uptime", 0, NULL, &uptime_proc_fops); return 0; } module_init(proc_uptime_init); diff --git a/fs/quota/Kconfig b/fs/quota/Kconfig new file mode 100644 index 00000000000..8047e01ef46 --- /dev/null +++ b/fs/quota/Kconfig @@ -0,0 +1,59 @@ +# +# Quota configuration +# + +config QUOTA + bool "Quota support" + help + If you say Y here, you will be able to set per user limits for disk + usage (also called disk quotas). Currently, it works for the + ext2, ext3, and reiserfs file system. ext3 also supports journalled + quotas for which you don't need to run quotacheck(8) after an unclean + shutdown. + For further details, read the Quota mini-HOWTO, available from + <http://www.tldp.org/docs.html#howto>, or the documentation provided + with the quota tools. Probably the quota support is only useful for + multi user systems. If unsure, say N. + +config QUOTA_NETLINK_INTERFACE + bool "Report quota messages through netlink interface" + depends on QUOTA && NET + help + If you say Y here, quota warnings (about exceeding softlimit, reaching + hardlimit, etc.) will be reported through netlink interface. If unsure, + say Y. + +config PRINT_QUOTA_WARNING + bool "Print quota warnings to console (OBSOLETE)" + depends on QUOTA + default y + help + If you say Y here, quota warnings (about exceeding softlimit, reaching + hardlimit, etc.) will be printed to the process' controlling terminal. + Note that this behavior is currently deprecated and may go away in + future. Please use notification via netlink socket instead. + +# Generic support for tree structured quota files. Selected when needed. +config QUOTA_TREE + tristate + +config QFMT_V1 + tristate "Old quota format support" + depends on QUOTA + help + This quota format was (is) used by kernels earlier than 2.4.22. If + you have quota working and you don't want to convert to new quota + format say Y here. + +config QFMT_V2 + tristate "Quota format v2 support" + depends on QUOTA + select QUOTA_TREE + help + This quota format allows using quotas with 32-bit UIDs/GIDs. If you + need this functionality say Y here. + +config QUOTACTL + bool + depends on XFS_QUOTA || QUOTA + default y diff --git a/fs/quota/Makefile b/fs/quota/Makefile new file mode 100644 index 00000000000..385a0831cc9 --- /dev/null +++ b/fs/quota/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the Linux filesystems. +# +# 14 Sep 2000, Christoph Hellwig <hch@infradead.org> +# Rewritten to use lists instead of if-statements. +# + +obj-y := + +obj-$(CONFIG_QUOTA) += dquot.o +obj-$(CONFIG_QFMT_V1) += quota_v1.o +obj-$(CONFIG_QFMT_V2) += quota_v2.o +obj-$(CONFIG_QUOTA_TREE) += quota_tree.o +obj-$(CONFIG_QUOTACTL) += quota.o diff --git a/fs/dquot.c b/fs/quota/dquot.c index bca3cac4bee..2ca967a5ef7 100644 --- a/fs/dquot.c +++ b/fs/quota/dquot.c @@ -129,9 +129,10 @@ * i_mutex on quota files is special (it's below dqio_mutex) */ -static DEFINE_SPINLOCK(dq_list_lock); -static DEFINE_SPINLOCK(dq_state_lock); -DEFINE_SPINLOCK(dq_data_lock); +static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_list_lock); +static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_state_lock); +__cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_data_lock); +EXPORT_SYMBOL(dq_data_lock); static char *quotatypes[] = INITQFNAMES; static struct quota_format_type *quota_formats; /* List of registered formats */ @@ -148,35 +149,46 @@ int register_quota_format(struct quota_format_type *fmt) spin_unlock(&dq_list_lock); return 0; } +EXPORT_SYMBOL(register_quota_format); void unregister_quota_format(struct quota_format_type *fmt) { struct quota_format_type **actqf; spin_lock(&dq_list_lock); - for (actqf = "a_formats; *actqf && *actqf != fmt; actqf = &(*actqf)->qf_next); + for (actqf = "a_formats; *actqf && *actqf != fmt; + actqf = &(*actqf)->qf_next) + ; if (*actqf) *actqf = (*actqf)->qf_next; spin_unlock(&dq_list_lock); } +EXPORT_SYMBOL(unregister_quota_format); static struct quota_format_type *find_quota_format(int id) { struct quota_format_type *actqf; spin_lock(&dq_list_lock); - for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next); + for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; + actqf = actqf->qf_next) + ; if (!actqf || !try_module_get(actqf->qf_owner)) { int qm; spin_unlock(&dq_list_lock); - for (qm = 0; module_names[qm].qm_fmt_id && module_names[qm].qm_fmt_id != id; qm++); - if (!module_names[qm].qm_fmt_id || request_module(module_names[qm].qm_mod_name)) + for (qm = 0; module_names[qm].qm_fmt_id && + module_names[qm].qm_fmt_id != id; qm++) + ; + if (!module_names[qm].qm_fmt_id || + request_module(module_names[qm].qm_mod_name)) return NULL; spin_lock(&dq_list_lock); - for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next); + for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; + actqf = actqf->qf_next) + ; if (actqf && !try_module_get(actqf->qf_owner)) actqf = NULL; } @@ -215,6 +227,7 @@ static unsigned int dq_hash_bits, dq_hash_mask; static struct hlist_head *dquot_hash; struct dqstats dqstats; +EXPORT_SYMBOL(dqstats); static inline unsigned int hashfn(const struct super_block *sb, unsigned int id, int type) @@ -230,7 +243,8 @@ hashfn(const struct super_block *sb, unsigned int id, int type) */ static inline void insert_dquot_hash(struct dquot *dquot) { - struct hlist_head *head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type); + struct hlist_head *head; + head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type); hlist_add_head(&dquot->dq_hash, head); } @@ -239,17 +253,19 @@ static inline void remove_dquot_hash(struct dquot *dquot) hlist_del_init(&dquot->dq_hash); } -static inline struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, unsigned int id, int type) +static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, + unsigned int id, int type) { struct hlist_node *node; struct dquot *dquot; hlist_for_each (node, dquot_hash+hashent) { dquot = hlist_entry(node, struct dquot, dq_hash); - if (dquot->dq_sb == sb && dquot->dq_id == id && dquot->dq_type == type) + if (dquot->dq_sb == sb && dquot->dq_id == id && + dquot->dq_type == type) return dquot; } - return NODQUOT; + return NULL; } /* Add a dquot to the tail of the free list */ @@ -309,6 +325,7 @@ int dquot_mark_dquot_dirty(struct dquot *dquot) spin_unlock(&dq_list_lock); return 0; } +EXPORT_SYMBOL(dquot_mark_dquot_dirty); /* This function needs dq_list_lock */ static inline int clear_dquot_dirty(struct dquot *dquot) @@ -345,8 +362,10 @@ int dquot_acquire(struct dquot *dquot) if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) { ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot); /* Write the info if needed */ - if (info_dirty(&dqopt->info[dquot->dq_type])) - ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type); + if (info_dirty(&dqopt->info[dquot->dq_type])) { + ret2 = dqopt->ops[dquot->dq_type]->write_file_info( + dquot->dq_sb, dquot->dq_type); + } if (ret < 0) goto out_iolock; if (ret2 < 0) { @@ -360,6 +379,7 @@ out_iolock: mutex_unlock(&dquot->dq_lock); return ret; } +EXPORT_SYMBOL(dquot_acquire); /* * Write dquot to disk @@ -380,8 +400,10 @@ int dquot_commit(struct dquot *dquot) * => we have better not writing it */ if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot); - if (info_dirty(&dqopt->info[dquot->dq_type])) - ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type); + if (info_dirty(&dqopt->info[dquot->dq_type])) { + ret2 = dqopt->ops[dquot->dq_type]->write_file_info( + dquot->dq_sb, dquot->dq_type); + } if (ret >= 0) ret = ret2; } @@ -389,6 +411,7 @@ out_sem: mutex_unlock(&dqopt->dqio_mutex); return ret; } +EXPORT_SYMBOL(dquot_commit); /* * Release dquot @@ -406,8 +429,10 @@ int dquot_release(struct dquot *dquot) if (dqopt->ops[dquot->dq_type]->release_dqblk) { ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot); /* Write the info */ - if (info_dirty(&dqopt->info[dquot->dq_type])) - ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type); + if (info_dirty(&dqopt->info[dquot->dq_type])) { + ret2 = dqopt->ops[dquot->dq_type]->write_file_info( + dquot->dq_sb, dquot->dq_type); + } if (ret >= 0) ret = ret2; } @@ -417,6 +442,7 @@ out_dqlock: mutex_unlock(&dquot->dq_lock); return ret; } +EXPORT_SYMBOL(dquot_release); void dquot_destroy(struct dquot *dquot) { @@ -516,6 +542,7 @@ out: mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); return ret; } +EXPORT_SYMBOL(dquot_scan_active); int vfs_quota_sync(struct super_block *sb, int type) { @@ -533,7 +560,8 @@ int vfs_quota_sync(struct super_block *sb, int type) spin_lock(&dq_list_lock); dirty = &dqopt->info[cnt].dqi_dirty_list; while (!list_empty(dirty)) { - dquot = list_first_entry(dirty, struct dquot, dq_dirty); + dquot = list_first_entry(dirty, struct dquot, + dq_dirty); /* Dirty and inactive can be only bad dquot... */ if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { clear_dquot_dirty(dquot); @@ -563,6 +591,7 @@ int vfs_quota_sync(struct super_block *sb, int type) return 0; } +EXPORT_SYMBOL(vfs_quota_sync); /* Free unused dquots from cache */ static void prune_dqcache(int count) @@ -672,6 +701,7 @@ we_slept: put_dquot_last(dquot); spin_unlock(&dq_list_lock); } +EXPORT_SYMBOL(dqput); struct dquot *dquot_alloc(struct super_block *sb, int type) { @@ -685,7 +715,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type) dquot = sb->dq_op->alloc_dquot(sb, type); if(!dquot) - return NODQUOT; + return NULL; mutex_init(&dquot->dq_lock); INIT_LIST_HEAD(&dquot->dq_free); @@ -711,10 +741,10 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type) struct dquot *dqget(struct super_block *sb, unsigned int id, int type) { unsigned int hashent = hashfn(sb, id, type); - struct dquot *dquot = NODQUOT, *empty = NODQUOT; + struct dquot *dquot = NULL, *empty = NULL; if (!sb_has_quota_active(sb, type)) - return NODQUOT; + return NULL; we_slept: spin_lock(&dq_list_lock); spin_lock(&dq_state_lock); @@ -725,15 +755,17 @@ we_slept: } spin_unlock(&dq_state_lock); - if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) { - if (empty == NODQUOT) { + dquot = find_dquot(hashent, sb, id, type); + if (!dquot) { + if (!empty) { spin_unlock(&dq_list_lock); - if ((empty = get_empty_dquot(sb, type)) == NODQUOT) + empty = get_empty_dquot(sb, type); + if (!empty) schedule(); /* Try to wait for a moment... */ goto we_slept; } dquot = empty; - empty = NODQUOT; + empty = NULL; dquot->dq_id = id; /* all dquots go on the inuse_list */ put_inuse(dquot); @@ -749,13 +781,14 @@ we_slept: dqstats.lookups++; spin_unlock(&dq_list_lock); } - /* Wait for dq_lock - after this we know that either dquot_release() is already - * finished or it will be canceled due to dq_count > 1 test */ + /* Wait for dq_lock - after this we know that either dquot_release() is + * already finished or it will be canceled due to dq_count > 1 test */ wait_on_dquot(dquot); - /* Read the dquot and instantiate it (everything done only if needed) */ - if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && sb->dq_op->acquire_dquot(dquot) < 0) { + /* Read the dquot / allocate space in quota file */ + if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && + sb->dq_op->acquire_dquot(dquot) < 0) { dqput(dquot); - dquot = NODQUOT; + dquot = NULL; goto out; } #ifdef __DQUOT_PARANOIA @@ -767,6 +800,7 @@ out: return dquot; } +EXPORT_SYMBOL(dqget); static int dqinit_needed(struct inode *inode, int type) { @@ -775,9 +809,9 @@ static int dqinit_needed(struct inode *inode, int type) if (IS_NOQUOTA(inode)) return 0; if (type != -1) - return inode->i_dquot[type] == NODQUOT; + return !inode->i_dquot[type]; for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if (inode->i_dquot[cnt] == NODQUOT) + if (!inode->i_dquot[cnt]) return 1; return 0; } @@ -789,12 +823,12 @@ static void add_dquot_ref(struct super_block *sb, int type) spin_lock(&inode_lock); list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { + if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) + continue; if (!atomic_read(&inode->i_writecount)) continue; if (!dqinit_needed(inode, type)) continue; - if (inode->i_state & (I_FREEING|I_WILL_FREE)) - continue; __iget(inode); spin_unlock(&inode_lock); @@ -813,7 +847,10 @@ static void add_dquot_ref(struct super_block *sb, int type) iput(old_inode); } -/* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ +/* + * Return 0 if dqput() won't block. + * (note that 1 doesn't necessarily mean blocking) + */ static inline int dqput_blocks(struct dquot *dquot) { if (atomic_read(&dquot->dq_count) <= 1) @@ -821,22 +858,27 @@ static inline int dqput_blocks(struct dquot *dquot) return 0; } -/* Remove references to dquots from inode - add dquot to list for freeing if needed */ -/* We can't race with anybody because we hold dqptr_sem for writing... */ +/* + * Remove references to dquots from inode and add dquot to list for freeing + * if we have the last referece to dquot + * We can't race with anybody because we hold dqptr_sem for writing... + */ static int remove_inode_dquot_ref(struct inode *inode, int type, struct list_head *tofree_head) { struct dquot *dquot = inode->i_dquot[type]; - inode->i_dquot[type] = NODQUOT; - if (dquot != NODQUOT) { + inode->i_dquot[type] = NULL; + if (dquot) { if (dqput_blocks(dquot)) { #ifdef __DQUOT_PARANOIA if (atomic_read(&dquot->dq_count) != 1) printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", atomic_read(&dquot->dq_count)); #endif spin_lock(&dq_list_lock); - list_add(&dquot->dq_free, tofree_head); /* As dquot must have currently users it can't be on the free list... */ + /* As dquot must have currently users it can't be on + * the free list... */ + list_add(&dquot->dq_free, tofree_head); spin_unlock(&dq_list_lock); return 1; } @@ -846,19 +888,22 @@ static int remove_inode_dquot_ref(struct inode *inode, int type, return 0; } -/* Free list of dquots - called from inode.c */ -/* dquots are removed from inodes, no new references can be got so we are the only ones holding reference */ +/* + * Free list of dquots + * Dquots are removed from inodes and no new references can be got so we are + * the only ones holding reference + */ static void put_dquot_list(struct list_head *tofree_head) { struct list_head *act_head; struct dquot *dquot; act_head = tofree_head->next; - /* So now we have dquots on the list... Just free them */ while (act_head != tofree_head) { dquot = list_entry(act_head, struct dquot, dq_free); act_head = act_head->next; - list_del_init(&dquot->dq_free); /* Remove dquot from the list so we won't have problems... */ + /* Remove dquot from the list so we won't have problems... */ + list_del_init(&dquot->dq_free); dqput(dquot); } } @@ -870,6 +915,12 @@ static void remove_dquot_ref(struct super_block *sb, int type, spin_lock(&inode_lock); list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { + /* + * We have to scan also I_NEW inodes because they can already + * have quota pointer initialized. Luckily, we need to touch + * only quota pointers and these have separate locking + * (dqptr_sem). + */ if (!IS_NOQUOTA(inode)) remove_inode_dquot_ref(inode, type, tofree_head); } @@ -899,7 +950,29 @@ static inline void dquot_incr_space(struct dquot *dquot, qsize_t number) dquot->dq_dqb.dqb_curspace += number; } -static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number) +static inline void dquot_resv_space(struct dquot *dquot, qsize_t number) +{ + dquot->dq_dqb.dqb_rsvspace += number; +} + +/* + * Claim reserved quota space + */ +static void dquot_claim_reserved_space(struct dquot *dquot, + qsize_t number) +{ + WARN_ON(dquot->dq_dqb.dqb_rsvspace < number); + dquot->dq_dqb.dqb_curspace += number; + dquot->dq_dqb.dqb_rsvspace -= number; +} + +static inline +void dquot_free_reserved_space(struct dquot *dquot, qsize_t number) +{ + dquot->dq_dqb.dqb_rsvspace -= number; +} + +static void dquot_decr_inodes(struct dquot *dquot, qsize_t number) { if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE || dquot->dq_dqb.dqb_curinodes >= number) @@ -911,7 +984,7 @@ static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number) clear_bit(DQ_INODES_B, &dquot->dq_flags); } -static inline void dquot_decr_space(struct dquot *dquot, qsize_t number) +static void dquot_decr_space(struct dquot *dquot, qsize_t number) { if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE || dquot->dq_dqb.dqb_curspace >= number) @@ -938,7 +1011,7 @@ static int warning_issued(struct dquot *dquot, const int warntype) #ifdef CONFIG_PRINT_QUOTA_WARNING static int flag_print_warnings = 1; -static inline int need_print_warning(struct dquot *dquot) +static int need_print_warning(struct dquot *dquot) { if (!flag_print_warnings) return 0; @@ -1057,10 +1130,7 @@ static void send_warning(const struct dquot *dquot, const char warntype) goto attr_err_out; genlmsg_end(skb, msg_head); - ret = genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); - if (ret < 0 && ret != -ESRCH) - printk(KERN_ERR - "VFS: Failed to send notification message: %d\n", ret); + genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); return; attr_err_out: printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); @@ -1068,13 +1138,17 @@ err_out: kfree_skb(skb); } #endif - -static inline void flush_warnings(struct dquot * const *dquots, char *warntype) +/* + * Write warnings to the console and send warning messages over netlink. + * + * Note that this function can sleep. + */ +static void flush_warnings(struct dquot *const *dquots, char *warntype) { int i; for (i = 0; i < MAXQUOTAS; i++) - if (dquots[i] != NODQUOT && warntype[i] != QUOTA_NL_NOWARN && + if (dquots[i] && warntype[i] != QUOTA_NL_NOWARN && !warning_issued(dquots[i], warntype[i])) { #ifdef CONFIG_PRINT_QUOTA_WARNING print_warning(dquots[i], warntype[i]); @@ -1085,42 +1159,47 @@ static inline void flush_warnings(struct dquot * const *dquots, char *warntype) } } -static inline char ignore_hardlimit(struct dquot *dquot) +static int ignore_hardlimit(struct dquot *dquot) { struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type]; return capable(CAP_SYS_RESOURCE) && - (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || !(info->dqi_flags & V1_DQF_RSQUASH)); + (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || + !(info->dqi_flags & V1_DQF_RSQUASH)); } /* needs dq_data_lock */ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype) { + qsize_t newinodes = dquot->dq_dqb.dqb_curinodes + inodes; + *warntype = QUOTA_NL_NOWARN; if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) || test_bit(DQ_FAKE_B, &dquot->dq_flags)) return QUOTA_OK; if (dquot->dq_dqb.dqb_ihardlimit && - (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_ihardlimit && + newinodes > dquot->dq_dqb.dqb_ihardlimit && !ignore_hardlimit(dquot)) { *warntype = QUOTA_NL_IHARDWARN; return NO_QUOTA; } if (dquot->dq_dqb.dqb_isoftlimit && - (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit && - dquot->dq_dqb.dqb_itime && get_seconds() >= dquot->dq_dqb.dqb_itime && + newinodes > dquot->dq_dqb.dqb_isoftlimit && + dquot->dq_dqb.dqb_itime && + get_seconds() >= dquot->dq_dqb.dqb_itime && !ignore_hardlimit(dquot)) { *warntype = QUOTA_NL_ISOFTLONGWARN; return NO_QUOTA; } if (dquot->dq_dqb.dqb_isoftlimit && - (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit && + newinodes > dquot->dq_dqb.dqb_isoftlimit && dquot->dq_dqb.dqb_itime == 0) { *warntype = QUOTA_NL_ISOFTWARN; - dquot->dq_dqb.dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; + dquot->dq_dqb.dqb_itime = get_seconds() + + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; } return QUOTA_OK; @@ -1129,13 +1208,19 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype) /* needs dq_data_lock */ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype) { + qsize_t tspace; + struct super_block *sb = dquot->dq_sb; + *warntype = QUOTA_NL_NOWARN; - if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) || + if (!sb_has_quota_limits_enabled(sb, dquot->dq_type) || test_bit(DQ_FAKE_B, &dquot->dq_flags)) return QUOTA_OK; + tspace = dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace + + space; + if (dquot->dq_dqb.dqb_bhardlimit && - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bhardlimit && + tspace > dquot->dq_dqb.dqb_bhardlimit && !ignore_hardlimit(dquot)) { if (!prealloc) *warntype = QUOTA_NL_BHARDWARN; @@ -1143,8 +1228,9 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war } if (dquot->dq_dqb.dqb_bsoftlimit && - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit && - dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime && + tspace > dquot->dq_dqb.dqb_bsoftlimit && + dquot->dq_dqb.dqb_btime && + get_seconds() >= dquot->dq_dqb.dqb_btime && !ignore_hardlimit(dquot)) { if (!prealloc) *warntype = QUOTA_NL_BSOFTLONGWARN; @@ -1152,11 +1238,12 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war } if (dquot->dq_dqb.dqb_bsoftlimit && - dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit && + tspace > dquot->dq_dqb.dqb_bsoftlimit && dquot->dq_dqb.dqb_btime == 0) { if (!prealloc) { *warntype = QUOTA_NL_BSOFTWARN; - dquot->dq_dqb.dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace; + dquot->dq_dqb.dqb_btime = get_seconds() + + sb_dqopt(sb)->info[dquot->dq_type].dqi_bgrace; } else /* @@ -1171,15 +1258,18 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war static int info_idq_free(struct dquot *dquot, qsize_t inodes) { + qsize_t newinodes; + if (test_bit(DQ_FAKE_B, &dquot->dq_flags) || dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit || !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type)) return QUOTA_NL_NOWARN; - if (dquot->dq_dqb.dqb_curinodes - inodes <= dquot->dq_dqb.dqb_isoftlimit) + newinodes = dquot->dq_dqb.dqb_curinodes - inodes; + if (newinodes <= dquot->dq_dqb.dqb_isoftlimit) return QUOTA_NL_ISOFTBELOW; if (dquot->dq_dqb.dqb_curinodes >= dquot->dq_dqb.dqb_ihardlimit && - dquot->dq_dqb.dqb_curinodes - inodes < dquot->dq_dqb.dqb_ihardlimit) + newinodes < dquot->dq_dqb.dqb_ihardlimit) return QUOTA_NL_IHARDBELOW; return QUOTA_NL_NOWARN; } @@ -1206,7 +1296,7 @@ int dquot_initialize(struct inode *inode, int type) { unsigned int id = 0; int cnt, ret = 0; - struct dquot *got[MAXQUOTAS] = { NODQUOT, NODQUOT }; + struct dquot *got[MAXQUOTAS] = { NULL, NULL }; struct super_block *sb = inode->i_sb; /* First test before acquiring mutex - solves deadlocks when we @@ -1239,9 +1329,9 @@ int dquot_initialize(struct inode *inode, int type) /* Avoid races with quotaoff() */ if (!sb_has_quota_active(sb, cnt)) continue; - if (inode->i_dquot[cnt] == NODQUOT) { + if (!inode->i_dquot[cnt]) { inode->i_dquot[cnt] = got[cnt]; - got[cnt] = NODQUOT; + got[cnt] = NULL; } } out_err: @@ -1251,6 +1341,7 @@ out_err: dqput(got[cnt]); return ret; } +EXPORT_SYMBOL(dquot_initialize); /* * Release all quotas referenced by inode @@ -1263,7 +1354,7 @@ int dquot_drop(struct inode *inode) down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { put[cnt] = inode->i_dquot[cnt]; - inode->i_dquot[cnt] = NODQUOT; + inode->i_dquot[cnt] = NULL; } up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); @@ -1271,6 +1362,7 @@ int dquot_drop(struct inode *inode) dqput(put[cnt]); return 0; } +EXPORT_SYMBOL(dquot_drop); /* Wrapper to remove references to quota structures from inode */ void vfs_dq_drop(struct inode *inode) @@ -1287,12 +1379,13 @@ void vfs_dq_drop(struct inode *inode) * must assure that nobody can come after the DQUOT_DROP and * add quota pointers back anyway */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if (inode->i_dquot[cnt] != NODQUOT) + if (inode->i_dquot[cnt]) break; if (cnt < MAXQUOTAS) inode->i_sb->dq_op->drop(inode); } } +EXPORT_SYMBOL(vfs_dq_drop); /* * Following four functions update i_blocks+i_bytes fields and @@ -1306,51 +1399,93 @@ void vfs_dq_drop(struct inode *inode) /* * This operation can block, but only after everything is updated */ -int dquot_alloc_space(struct inode *inode, qsize_t number, int warn) +int __dquot_alloc_space(struct inode *inode, qsize_t number, + int warn, int reserve) { - int cnt, ret = NO_QUOTA; + int cnt, ret = QUOTA_OK; char warntype[MAXQUOTAS]; - /* First test before acquiring mutex - solves deadlocks when we - * re-enter the quota code and are already holding the mutex */ - if (IS_NOQUOTA(inode)) { -out_add: - inode_add_bytes(inode, number); - return QUOTA_OK; - } for (cnt = 0; cnt < MAXQUOTAS; cnt++) warntype[cnt] = QUOTA_NL_NOWARN; - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); - if (IS_NOQUOTA(inode)) { /* Now we can do reliable test... */ - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); - goto out_add; - } spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (inode->i_dquot[cnt] == NODQUOT) + if (!inode->i_dquot[cnt]) continue; - if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt) == NO_QUOTA) - goto warn_put_all; + if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt) + == NO_QUOTA) { + ret = NO_QUOTA; + goto out_unlock; + } } for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (inode->i_dquot[cnt] == NODQUOT) + if (!inode->i_dquot[cnt]) continue; - dquot_incr_space(inode->i_dquot[cnt], number); + if (reserve) + dquot_resv_space(inode->i_dquot[cnt], number); + else + dquot_incr_space(inode->i_dquot[cnt], number); } - inode_add_bytes(inode, number); - ret = QUOTA_OK; -warn_put_all: + if (!reserve) + inode_add_bytes(inode, number); +out_unlock: spin_unlock(&dq_data_lock); - if (ret == QUOTA_OK) - /* Dirtify all the dquots - this can block when journalling */ - for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if (inode->i_dquot[cnt]) - mark_dquot_dirty(inode->i_dquot[cnt]); flush_warnings(inode->i_dquot, warntype); + return ret; +} + +int dquot_alloc_space(struct inode *inode, qsize_t number, int warn) +{ + int cnt, ret = QUOTA_OK; + + /* + * First test before acquiring mutex - solves deadlocks when we + * re-enter the quota code and are already holding the mutex + */ + if (IS_NOQUOTA(inode)) { + inode_add_bytes(inode, number); + goto out; + } + + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + if (IS_NOQUOTA(inode)) { + inode_add_bytes(inode, number); + goto out_unlock; + } + + ret = __dquot_alloc_space(inode, number, warn, 0); + if (ret == NO_QUOTA) + goto out_unlock; + + /* Dirtify all the dquots - this can block when journalling */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if (inode->i_dquot[cnt]) + mark_dquot_dirty(inode->i_dquot[cnt]); +out_unlock: up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); +out: return ret; } +EXPORT_SYMBOL(dquot_alloc_space); + +int dquot_reserve_space(struct inode *inode, qsize_t number, int warn) +{ + int ret = QUOTA_OK; + + if (IS_NOQUOTA(inode)) + goto out; + + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + if (IS_NOQUOTA(inode)) + goto out_unlock; + + ret = __dquot_alloc_space(inode, number, warn, 1); +out_unlock: + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); +out: + return ret; +} +EXPORT_SYMBOL(dquot_reserve_space); /* * This operation can block, but only after everything is updated @@ -1373,14 +1508,15 @@ int dquot_alloc_inode(const struct inode *inode, qsize_t number) } spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (inode->i_dquot[cnt] == NODQUOT) + if (!inode->i_dquot[cnt]) continue; - if (check_idq(inode->i_dquot[cnt], number, warntype+cnt) == NO_QUOTA) + if (check_idq(inode->i_dquot[cnt], number, warntype+cnt) + == NO_QUOTA) goto warn_put_all; } for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (inode->i_dquot[cnt] == NODQUOT) + if (!inode->i_dquot[cnt]) continue; dquot_incr_inodes(inode->i_dquot[cnt], number); } @@ -1396,6 +1532,73 @@ warn_put_all: up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); return ret; } +EXPORT_SYMBOL(dquot_alloc_inode); + +int dquot_claim_space(struct inode *inode, qsize_t number) +{ + int cnt; + int ret = QUOTA_OK; + + if (IS_NOQUOTA(inode)) { + inode_add_bytes(inode, number); + goto out; + } + + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + if (IS_NOQUOTA(inode)) { + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + inode_add_bytes(inode, number); + goto out; + } + + spin_lock(&dq_data_lock); + /* Claim reserved quotas to allocated quotas */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (inode->i_dquot[cnt]) + dquot_claim_reserved_space(inode->i_dquot[cnt], + number); + } + /* Update inode bytes */ + inode_add_bytes(inode, number); + spin_unlock(&dq_data_lock); + /* Dirtify all the dquots - this can block when journalling */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if (inode->i_dquot[cnt]) + mark_dquot_dirty(inode->i_dquot[cnt]); + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); +out: + return ret; +} +EXPORT_SYMBOL(dquot_claim_space); + +/* + * Release reserved quota space + */ +void dquot_release_reserved_space(struct inode *inode, qsize_t number) +{ + int cnt; + + if (IS_NOQUOTA(inode)) + goto out; + + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + if (IS_NOQUOTA(inode)) + goto out_unlock; + + spin_lock(&dq_data_lock); + /* Release reserved dquots */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (inode->i_dquot[cnt]) + dquot_free_reserved_space(inode->i_dquot[cnt], number); + } + spin_unlock(&dq_data_lock); + +out_unlock: + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); +out: + return; +} +EXPORT_SYMBOL(dquot_release_reserved_space); /* * This operation can block, but only after everything is updated @@ -1421,7 +1624,7 @@ out_sub: } spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (inode->i_dquot[cnt] == NODQUOT) + if (!inode->i_dquot[cnt]) continue; warntype[cnt] = info_bdq_free(inode->i_dquot[cnt], number); dquot_decr_space(inode->i_dquot[cnt], number); @@ -1436,6 +1639,7 @@ out_sub: up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); return QUOTA_OK; } +EXPORT_SYMBOL(dquot_free_space); /* * This operation can block, but only after everything is updated @@ -1458,7 +1662,7 @@ int dquot_free_inode(const struct inode *inode, qsize_t number) } spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (inode->i_dquot[cnt] == NODQUOT) + if (!inode->i_dquot[cnt]) continue; warntype[cnt] = info_idq_free(inode->i_dquot[cnt], number); dquot_decr_inodes(inode->i_dquot[cnt], number); @@ -1472,6 +1676,20 @@ int dquot_free_inode(const struct inode *inode, qsize_t number) up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); return QUOTA_OK; } +EXPORT_SYMBOL(dquot_free_inode); + +/* + * call back function, get reserved quota space from underlying fs + */ +qsize_t dquot_get_reserved_space(struct inode *inode) +{ + qsize_t reserved_space = 0; + + if (sb_any_quota_active(inode->i_sb) && + inode->i_sb->dq_op->get_reserved_space) + reserved_space = inode->i_sb->dq_op->get_reserved_space(inode); + return reserved_space; +} /* * Transfer the number of inode and blocks from one diskquota to an other. @@ -1481,7 +1699,8 @@ int dquot_free_inode(const struct inode *inode, qsize_t number) */ int dquot_transfer(struct inode *inode, struct iattr *iattr) { - qsize_t space; + qsize_t space, cur_space; + qsize_t rsv_space = 0; struct dquot *transfer_from[MAXQUOTAS]; struct dquot *transfer_to[MAXQUOTAS]; int cnt, ret = QUOTA_OK; @@ -1496,22 +1715,16 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) return QUOTA_OK; /* Initialize the arrays */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - transfer_from[cnt] = NODQUOT; - transfer_to[cnt] = NODQUOT; + transfer_from[cnt] = NULL; + transfer_to[cnt] = NULL; warntype_to[cnt] = QUOTA_NL_NOWARN; - switch (cnt) { - case USRQUOTA: - if (!chuid) - continue; - transfer_to[cnt] = dqget(inode->i_sb, iattr->ia_uid, cnt); - break; - case GRPQUOTA: - if (!chgid) - continue; - transfer_to[cnt] = dqget(inode->i_sb, iattr->ia_gid, cnt); - break; - } } + if (chuid) + transfer_to[USRQUOTA] = dqget(inode->i_sb, iattr->ia_uid, + USRQUOTA); + if (chgid) + transfer_to[GRPQUOTA] = dqget(inode->i_sb, iattr->ia_gid, + GRPQUOTA); down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); /* Now recheck reliably when holding dqptr_sem */ @@ -1520,10 +1733,12 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) goto put_all; } spin_lock(&dq_data_lock); - space = inode_get_bytes(inode); + cur_space = inode_get_bytes(inode); + rsv_space = dquot_get_reserved_space(inode); + space = cur_space + rsv_space; /* Build the transfer_from list and check the limits */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (transfer_to[cnt] == NODQUOT) + if (!transfer_to[cnt]) continue; transfer_from[cnt] = inode->i_dquot[cnt]; if (check_idq(transfer_to[cnt], 1, warntype_to + cnt) == @@ -1539,7 +1754,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) /* * Skip changes for same uid or gid or for turned off quota-type. */ - if (transfer_to[cnt] == NODQUOT) + if (!transfer_to[cnt]) continue; /* Due to IO error we might not have transfer_from[] structure */ @@ -1549,11 +1764,14 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) warntype_from_space[cnt] = info_bdq_free(transfer_from[cnt], space); dquot_decr_inodes(transfer_from[cnt], 1); - dquot_decr_space(transfer_from[cnt], space); + dquot_decr_space(transfer_from[cnt], cur_space); + dquot_free_reserved_space(transfer_from[cnt], + rsv_space); } dquot_incr_inodes(transfer_to[cnt], 1); - dquot_incr_space(transfer_to[cnt], space); + dquot_incr_space(transfer_to[cnt], cur_space); + dquot_resv_space(transfer_to[cnt], rsv_space); inode->i_dquot[cnt] = transfer_to[cnt]; } @@ -1567,7 +1785,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) if (transfer_to[cnt]) { mark_dquot_dirty(transfer_to[cnt]); /* The reference we got is transferred to the inode */ - transfer_to[cnt] = NODQUOT; + transfer_to[cnt] = NULL; } } warn_put_all: @@ -1585,10 +1803,11 @@ over_quota: up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); /* Clear dquot pointers we don't want to dqput() */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) - transfer_from[cnt] = NODQUOT; + transfer_from[cnt] = NULL; ret = NO_QUOTA; goto warn_put_all; } +EXPORT_SYMBOL(dquot_transfer); /* Wrapper for transferring ownership of an inode */ int vfs_dq_transfer(struct inode *inode, struct iattr *iattr) @@ -1600,7 +1819,7 @@ int vfs_dq_transfer(struct inode *inode, struct iattr *iattr) } return 0; } - +EXPORT_SYMBOL(vfs_dq_transfer); /* * Write info of quota file to disk @@ -1615,6 +1834,7 @@ int dquot_commit_info(struct super_block *sb, int type) mutex_unlock(&dqopt->dqio_mutex); return ret; } +EXPORT_SYMBOL(dquot_commit_info); /* * Definitions of diskquota operations. @@ -1700,8 +1920,8 @@ int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags) drop_dquot_ref(sb, cnt); invalidate_dquots(sb, cnt); /* - * Now all dquots should be invalidated, all writes done so we should be only - * users of the info. No locks needed. + * Now all dquots should be invalidated, all writes done so we + * should be only users of the info. No locks needed. */ if (info_dirty(&dqopt->info[cnt])) sb->dq_op->write_info(sb, cnt); @@ -1739,10 +1959,12 @@ int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags) /* If quota was reenabled in the meantime, we have * nothing to do */ if (!sb_has_quota_loaded(sb, cnt)) { - mutex_lock_nested(&toputinode[cnt]->i_mutex, I_MUTEX_QUOTA); + mutex_lock_nested(&toputinode[cnt]->i_mutex, + I_MUTEX_QUOTA); toputinode[cnt]->i_flags &= ~(S_IMMUTABLE | S_NOATIME | S_NOQUOTA); - truncate_inode_pages(&toputinode[cnt]->i_data, 0); + truncate_inode_pages(&toputinode[cnt]->i_data, + 0); mutex_unlock(&toputinode[cnt]->i_mutex); mark_inode_dirty(toputinode[cnt]); } @@ -1767,13 +1989,14 @@ put_inodes: } return ret; } +EXPORT_SYMBOL(vfs_quota_disable); int vfs_quota_off(struct super_block *sb, int type, int remount) { return vfs_quota_disable(sb, type, remount ? DQUOT_SUSPENDED : (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED)); } - +EXPORT_SYMBOL(vfs_quota_off); /* * Turn quotas on on a device */ @@ -1831,7 +2054,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, * possible) Also nobody should write to the file - we use * special IO operations which ignore the immutable bit. */ down_write(&dqopt->dqptr_sem); - oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE | S_NOQUOTA); + oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE | + S_NOQUOTA); inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE; up_write(&dqopt->dqptr_sem); sb->dq_op->drop(inode); @@ -1850,7 +2074,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, dqopt->info[type].dqi_fmt_id = format_id; INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list); mutex_lock(&dqopt->dqio_mutex); - if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0) { + error = dqopt->ops[type]->read_file_info(sb, type); + if (error < 0) { mutex_unlock(&dqopt->dqio_mutex); goto out_file_init; } @@ -1930,6 +2155,7 @@ int vfs_quota_on_path(struct super_block *sb, int type, int format_id, DQUOT_LIMITS_ENABLED); return error; } +EXPORT_SYMBOL(vfs_quota_on_path); int vfs_quota_on(struct super_block *sb, int type, int format_id, char *name, int remount) @@ -1947,6 +2173,7 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *name, } return error; } +EXPORT_SYMBOL(vfs_quota_on); /* * More powerful function for turning on quotas allowing setting @@ -1993,6 +2220,7 @@ out_lock: load_quota: return vfs_load_quota_inode(inode, type, format_id, flags); } +EXPORT_SYMBOL(vfs_quota_enable); /* * This function is used when filesystem needs to initialize quotas @@ -2022,6 +2250,7 @@ out: dput(dentry); return error; } +EXPORT_SYMBOL(vfs_quota_on_mount); /* Wrapper to turn on quotas when remounting rw */ int vfs_dq_quota_on_remount(struct super_block *sb) @@ -2038,6 +2267,7 @@ int vfs_dq_quota_on_remount(struct super_block *sb) } return ret; } +EXPORT_SYMBOL(vfs_dq_quota_on_remount); static inline qsize_t qbtos(qsize_t blocks) { @@ -2057,7 +2287,7 @@ static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di) spin_lock(&dq_data_lock); di->dqb_bhardlimit = stoqb(dm->dqb_bhardlimit); di->dqb_bsoftlimit = stoqb(dm->dqb_bsoftlimit); - di->dqb_curspace = dm->dqb_curspace; + di->dqb_curspace = dm->dqb_curspace + dm->dqb_rsvspace; di->dqb_ihardlimit = dm->dqb_ihardlimit; di->dqb_isoftlimit = dm->dqb_isoftlimit; di->dqb_curinodes = dm->dqb_curinodes; @@ -2067,18 +2297,20 @@ static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di) spin_unlock(&dq_data_lock); } -int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di) +int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, + struct if_dqblk *di) { struct dquot *dquot; dquot = dqget(sb, id, type); - if (dquot == NODQUOT) + if (!dquot) return -ESRCH; do_get_dqblk(dquot, di); dqput(dquot); return 0; } +EXPORT_SYMBOL(vfs_get_dqblk); /* Generic routine for setting common part of quota structure */ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) @@ -2097,7 +2329,7 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) spin_lock(&dq_data_lock); if (di->dqb_valid & QIF_SPACE) { - dm->dqb_curspace = di->dqb_curspace; + dm->dqb_curspace = di->dqb_curspace - dm->dqb_rsvspace; check_blim = 1; __set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags); } @@ -2130,22 +2362,25 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) } if (check_blim) { - if (!dm->dqb_bsoftlimit || dm->dqb_curspace < dm->dqb_bsoftlimit) { + if (!dm->dqb_bsoftlimit || + dm->dqb_curspace < dm->dqb_bsoftlimit) { dm->dqb_btime = 0; clear_bit(DQ_BLKS_B, &dquot->dq_flags); - } - else if (!(di->dqb_valid & QIF_BTIME)) /* Set grace only if user hasn't provided his own... */ + } else if (!(di->dqb_valid & QIF_BTIME)) + /* Set grace only if user hasn't provided his own... */ dm->dqb_btime = get_seconds() + dqi->dqi_bgrace; } if (check_ilim) { - if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) { + if (!dm->dqb_isoftlimit || + dm->dqb_curinodes < dm->dqb_isoftlimit) { dm->dqb_itime = 0; clear_bit(DQ_INODES_B, &dquot->dq_flags); - } - else if (!(di->dqb_valid & QIF_ITIME)) /* Set grace only if user hasn't provided his own... */ + } else if (!(di->dqb_valid & QIF_ITIME)) + /* Set grace only if user hasn't provided his own... */ dm->dqb_itime = get_seconds() + dqi->dqi_igrace; } - if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit) + if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || + dm->dqb_isoftlimit) clear_bit(DQ_FAKE_B, &dquot->dq_flags); else set_bit(DQ_FAKE_B, &dquot->dq_flags); @@ -2155,7 +2390,8 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) return 0; } -int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di) +int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, + struct if_dqblk *di) { struct dquot *dquot; int rc; @@ -2170,6 +2406,7 @@ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d out: return rc; } +EXPORT_SYMBOL(vfs_set_dqblk); /* Generic routine for getting common part of quota file information */ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) @@ -2191,6 +2428,7 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); return 0; } +EXPORT_SYMBOL(vfs_get_dqinfo); /* Generic routine for setting common part of quota file information */ int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) @@ -2210,7 +2448,8 @@ int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) if (ii->dqi_valid & IIF_IGRACE) mi->dqi_igrace = ii->dqi_igrace; if (ii->dqi_valid & IIF_FLAGS) - mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | (ii->dqi_flags & DQF_MASK); + mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | + (ii->dqi_flags & DQF_MASK); spin_unlock(&dq_data_lock); mark_info_dirty(sb, type); /* Force write to disk */ @@ -2219,6 +2458,7 @@ out: mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); return err; } +EXPORT_SYMBOL(vfs_set_dqinfo); struct quotactl_ops vfs_quotactl_ops = { .quota_on = vfs_quota_on, @@ -2368,43 +2608,10 @@ static int __init dquot_init(void) #ifdef CONFIG_QUOTA_NETLINK_INTERFACE if (genl_register_family("a_genl_family) != 0) - printk(KERN_ERR "VFS: Failed to create quota netlink interface.\n"); + printk(KERN_ERR + "VFS: Failed to create quota netlink interface.\n"); #endif return 0; } module_init(dquot_init); - -EXPORT_SYMBOL(register_quota_format); -EXPORT_SYMBOL(unregister_quota_format); -EXPORT_SYMBOL(dqstats); -EXPORT_SYMBOL(dq_data_lock); -EXPORT_SYMBOL(vfs_quota_enable); -EXPORT_SYMBOL(vfs_quota_on); -EXPORT_SYMBOL(vfs_quota_on_path); -EXPORT_SYMBOL(vfs_quota_on_mount); -EXPORT_SYMBOL(vfs_quota_disable); -EXPORT_SYMBOL(vfs_quota_off); -EXPORT_SYMBOL(dquot_scan_active); -EXPORT_SYMBOL(vfs_quota_sync); -EXPORT_SYMBOL(vfs_get_dqinfo); -EXPORT_SYMBOL(vfs_set_dqinfo); -EXPORT_SYMBOL(vfs_get_dqblk); -EXPORT_SYMBOL(vfs_set_dqblk); -EXPORT_SYMBOL(dquot_commit); -EXPORT_SYMBOL(dquot_commit_info); -EXPORT_SYMBOL(dquot_acquire); -EXPORT_SYMBOL(dquot_release); -EXPORT_SYMBOL(dquot_mark_dquot_dirty); -EXPORT_SYMBOL(dquot_initialize); -EXPORT_SYMBOL(dquot_drop); -EXPORT_SYMBOL(vfs_dq_drop); -EXPORT_SYMBOL(dqget); -EXPORT_SYMBOL(dqput); -EXPORT_SYMBOL(dquot_alloc_space); -EXPORT_SYMBOL(dquot_alloc_inode); -EXPORT_SYMBOL(dquot_free_space); -EXPORT_SYMBOL(dquot_free_inode); -EXPORT_SYMBOL(dquot_transfer); -EXPORT_SYMBOL(vfs_dq_transfer); -EXPORT_SYMBOL(vfs_dq_quota_on_remount); diff --git a/fs/quota.c b/fs/quota/quota.c index d76ada914f9..b7f5a468f07 100644 --- a/fs/quota.c +++ b/fs/quota/quota.c @@ -20,7 +20,8 @@ #include <linux/types.h> /* Check validity of generic quotactl commands */ -static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) +static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, + qid_t id) { if (type >= MAXQUOTAS) return -EINVAL; @@ -72,7 +73,8 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid case Q_SETINFO: case Q_SETQUOTA: case Q_GETQUOTA: - /* This is just informative test so we are satisfied without a lock */ + /* This is just an informative test so we are satisfied + * without the lock */ if (!sb_has_quota_active(sb, type)) return -ESRCH; } @@ -92,7 +94,8 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid } /* Check validity of XFS Quota Manager commands */ -static int xqm_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) +static int xqm_quotactl_valid(struct super_block *sb, int type, int cmd, + qid_t id) { if (type >= XQM_MAXQUOTAS) return -EINVAL; @@ -142,7 +145,8 @@ static int xqm_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t i return 0; } -static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) +static int check_quotactl_valid(struct super_block *sb, int type, int cmd, + qid_t id) { int error; @@ -180,7 +184,8 @@ static void quota_sync_sb(struct super_block *sb, int type) continue; if (!sb_has_quota_active(sb, cnt)) continue; - mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex, I_MUTEX_QUOTA); + mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex, + I_MUTEX_QUOTA); truncate_inode_pages(&sb_dqopt(sb)->files[cnt]->i_data, 0); mutex_unlock(&sb_dqopt(sb)->files[cnt]->i_mutex); } @@ -200,14 +205,15 @@ void sync_dquots(struct super_block *sb, int type) spin_lock(&sb_lock); restart: list_for_each_entry(sb, &super_blocks, s_list) { - /* This test just improves performance so it needn't be reliable... */ + /* This test just improves performance so it needn't be + * reliable... */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (type != -1 && type != cnt) continue; if (!sb_has_quota_active(sb, cnt)) continue; if (!info_dirty(&sb_dqopt(sb)->info[cnt]) && - list_empty(&sb_dqopt(sb)->info[cnt].dqi_dirty_list)) + list_empty(&sb_dqopt(sb)->info[cnt].dqi_dirty_list)) continue; break; } @@ -227,7 +233,8 @@ restart: } /* Copy parameters and call proper function */ -static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void __user *addr) +static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, + void __user *addr) { int ret; @@ -235,7 +242,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void case Q_QUOTAON: { char *pathname; - if (IS_ERR(pathname = getname(addr))) + pathname = getname(addr); + if (IS_ERR(pathname)) return PTR_ERR(pathname); ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0); putname(pathname); @@ -261,7 +269,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void case Q_GETINFO: { struct if_dqinfo info; - if ((ret = sb->s_qcop->get_info(sb, type, &info))) + ret = sb->s_qcop->get_info(sb, type, &info); + if (ret) return ret; if (copy_to_user(addr, &info, sizeof(info))) return -EFAULT; @@ -277,7 +286,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void case Q_GETQUOTA: { struct if_dqblk idq; - if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq))) + ret = sb->s_qcop->get_dqblk(sb, type, id, &idq); + if (ret) return ret; if (copy_to_user(addr, &idq, sizeof(idq))) return -EFAULT; @@ -322,7 +332,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void case Q_XGETQUOTA: { struct fs_disk_quota fdq; - if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq))) + ret = sb->s_qcop->get_xquota(sb, type, id, &fdq); + if (ret) return ret; if (copy_to_user(addr, &fdq, sizeof(fdq))) return -EFAULT; @@ -341,7 +352,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void * look up a superblock on which quota ops will be performed * - use the name of a block device to find the superblock thereon */ -static inline struct super_block *quotactl_block(const char __user *special) +static struct super_block *quotactl_block(const char __user *special) { #ifdef CONFIG_BLOCK struct block_device *bdev; diff --git a/fs/quota_tree.c b/fs/quota/quota_tree.c index 953404c95b1..f81f4bcfb17 100644 --- a/fs/quota_tree.c +++ b/fs/quota/quota_tree.c @@ -22,8 +22,6 @@ MODULE_LICENSE("GPL"); #define __QUOTA_QT_PARANOIA -typedef char *dqbuf_t; - static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth) { unsigned int epb = info->dqi_usable_bs >> 2; @@ -35,46 +33,42 @@ static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth) } /* Number of entries in one blocks */ -static inline int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) +static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) { return (info->dqi_usable_bs - sizeof(struct qt_disk_dqdbheader)) / info->dqi_entry_size; } -static dqbuf_t getdqbuf(size_t size) +static char *getdqbuf(size_t size) { - dqbuf_t buf = kmalloc(size, GFP_NOFS); + char *buf = kmalloc(size, GFP_NOFS); if (!buf) - printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n"); + printk(KERN_WARNING + "VFS: Not enough memory for quota buffers.\n"); return buf; } -static inline void freedqbuf(dqbuf_t buf) -{ - kfree(buf); -} - -static inline ssize_t read_blk(struct qtree_mem_dqinfo *info, uint blk, dqbuf_t buf) +static ssize_t read_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf) { struct super_block *sb = info->dqi_sb; memset(buf, 0, info->dqi_usable_bs); - return sb->s_op->quota_read(sb, info->dqi_type, (char *)buf, + return sb->s_op->quota_read(sb, info->dqi_type, buf, info->dqi_usable_bs, blk << info->dqi_blocksize_bits); } -static inline ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, dqbuf_t buf) +static ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf) { struct super_block *sb = info->dqi_sb; - return sb->s_op->quota_write(sb, info->dqi_type, (char *)buf, + return sb->s_op->quota_write(sb, info->dqi_type, buf, info->dqi_usable_bs, blk << info->dqi_blocksize_bits); } /* Remove empty block from list and return it */ static int get_free_dqblk(struct qtree_mem_dqinfo *info) { - dqbuf_t buf = getdqbuf(info->dqi_usable_bs); + char *buf = getdqbuf(info->dqi_usable_bs); struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; int ret, blk; @@ -98,12 +92,12 @@ static int get_free_dqblk(struct qtree_mem_dqinfo *info) mark_info_dirty(info->dqi_sb, info->dqi_type); ret = blk; out_buf: - freedqbuf(buf); + kfree(buf); return ret; } /* Insert empty block to the list */ -static int put_free_dqblk(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk) +static int put_free_dqblk(struct qtree_mem_dqinfo *info, char *buf, uint blk) { struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; int err; @@ -120,9 +114,10 @@ static int put_free_dqblk(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk) } /* Remove given block from the list of blocks with free entries */ -static int remove_free_dqentry(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk) +static int remove_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, + uint blk) { - dqbuf_t tmpbuf = getdqbuf(info->dqi_usable_bs); + char *tmpbuf = getdqbuf(info->dqi_usable_bs); struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; uint nextblk = le32_to_cpu(dh->dqdh_next_free); uint prevblk = le32_to_cpu(dh->dqdh_prev_free); @@ -153,21 +148,24 @@ static int remove_free_dqentry(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint info->dqi_free_entry = nextblk; mark_info_dirty(info->dqi_sb, info->dqi_type); } - freedqbuf(tmpbuf); + kfree(tmpbuf); dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); /* No matter whether write succeeds block is out of list */ if (write_blk(info, blk, buf) < 0) - printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk); + printk(KERN_ERR + "VFS: Can't write block (%u) with free entries.\n", + blk); return 0; out_buf: - freedqbuf(tmpbuf); + kfree(tmpbuf); return err; } /* Insert given block to the beginning of list with free entries */ -static int insert_free_dqentry(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk) +static int insert_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, + uint blk) { - dqbuf_t tmpbuf = getdqbuf(info->dqi_usable_bs); + char *tmpbuf = getdqbuf(info->dqi_usable_bs); struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; int err; @@ -188,12 +186,12 @@ static int insert_free_dqentry(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint if (err < 0) goto out_buf; } - freedqbuf(tmpbuf); + kfree(tmpbuf); info->dqi_free_entry = blk; mark_info_dirty(info->dqi_sb, info->dqi_type); return 0; out_buf: - freedqbuf(tmpbuf); + kfree(tmpbuf); return err; } @@ -215,7 +213,7 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info, { uint blk, i; struct qt_disk_dqdbheader *dh; - dqbuf_t buf = getdqbuf(info->dqi_usable_bs); + char *buf = getdqbuf(info->dqi_usable_bs); char *ddquot; *err = 0; @@ -233,11 +231,12 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info, blk = get_free_dqblk(info); if ((int)blk < 0) { *err = blk; - freedqbuf(buf); + kfree(buf); return 0; } memset(buf, 0, info->dqi_usable_bs); - /* This is enough as block is already zeroed and entry list is empty... */ + /* This is enough as the block is already zeroed and the entry + * list is empty... */ info->dqi_free_entry = blk; mark_info_dirty(dquot->dq_sb, dquot->dq_type); } @@ -253,9 +252,12 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info, } le16_add_cpu(&dh->dqdh_entries, 1); /* Find free structure in block */ - for (i = 0, ddquot = ((char *)buf) + sizeof(struct qt_disk_dqdbheader); - i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot); - i++, ddquot += info->dqi_entry_size); + ddquot = buf + sizeof(struct qt_disk_dqdbheader); + for (i = 0; i < qtree_dqstr_in_blk(info); i++) { + if (qtree_entry_unused(info, ddquot)) + break; + ddquot += info->dqi_entry_size; + } #ifdef __QUOTA_QT_PARANOIA if (i == qtree_dqstr_in_blk(info)) { printk(KERN_ERR "VFS: find_free_dqentry(): Data block full " @@ -273,10 +275,10 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info, dquot->dq_off = (blk << info->dqi_blocksize_bits) + sizeof(struct qt_disk_dqdbheader) + i * info->dqi_entry_size; - freedqbuf(buf); + kfree(buf); return blk; out_buf: - freedqbuf(buf); + kfree(buf); return 0; } @@ -284,7 +286,7 @@ out_buf: static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, uint *treeblk, int depth) { - dqbuf_t buf = getdqbuf(info->dqi_usable_bs); + char *buf = getdqbuf(info->dqi_usable_bs); int ret = 0, newson = 0, newact = 0; __le32 *ref; uint newblk; @@ -333,7 +335,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, put_free_dqblk(info, buf, *treeblk); } out_buf: - freedqbuf(buf); + kfree(buf); return ret; } @@ -346,14 +348,15 @@ static inline int dq_insert_tree(struct qtree_mem_dqinfo *info, } /* - * We don't have to be afraid of deadlocks as we never have quotas on quota files... + * We don't have to be afraid of deadlocks as we never have quotas on quota + * files... */ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) { int type = dquot->dq_type; struct super_block *sb = dquot->dq_sb; ssize_t ret; - dqbuf_t ddquot = getdqbuf(info->dqi_entry_size); + char *ddquot = getdqbuf(info->dqi_entry_size); if (!ddquot) return -ENOMEM; @@ -364,15 +367,15 @@ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) if (ret < 0) { printk(KERN_ERR "VFS: Error %zd occurred while " "creating quota.\n", ret); - freedqbuf(ddquot); + kfree(ddquot); return ret; } } spin_lock(&dq_data_lock); info->dqi_ops->mem2disk_dqblk(ddquot, dquot); spin_unlock(&dq_data_lock); - ret = sb->s_op->quota_write(sb, type, (char *)ddquot, - info->dqi_entry_size, dquot->dq_off); + ret = sb->s_op->quota_write(sb, type, ddquot, info->dqi_entry_size, + dquot->dq_off); if (ret != info->dqi_entry_size) { printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", sb->s_id); @@ -382,7 +385,7 @@ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) ret = 0; } dqstats.writes++; - freedqbuf(ddquot); + kfree(ddquot); return ret; } @@ -393,7 +396,7 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, uint blk) { struct qt_disk_dqdbheader *dh; - dqbuf_t buf = getdqbuf(info->dqi_usable_bs); + char *buf = getdqbuf(info->dqi_usable_bs); int ret = 0; if (!buf) @@ -444,7 +447,7 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, } dquot->dq_off = 0; /* Quota is now unattached */ out_buf: - freedqbuf(buf); + kfree(buf); return ret; } @@ -452,7 +455,7 @@ out_buf: static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, uint *blk, int depth) { - dqbuf_t buf = getdqbuf(info->dqi_usable_bs); + char *buf = getdqbuf(info->dqi_usable_bs); int ret = 0; uint newblk; __le32 *ref = (__le32 *)buf; @@ -475,9 +478,8 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, int i; ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0); /* Block got empty? */ - for (i = 0; - i < (info->dqi_usable_bs >> 2) && !ref[i]; - i++); + for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++) + ; /* Don't put the root block into the free block list */ if (i == (info->dqi_usable_bs >> 2) && *blk != QT_TREEOFF) { @@ -491,7 +493,7 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, } } out_buf: - freedqbuf(buf); + kfree(buf); return ret; } @@ -510,7 +512,7 @@ EXPORT_SYMBOL(qtree_delete_dquot); static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, uint blk) { - dqbuf_t buf = getdqbuf(info->dqi_usable_bs); + char *buf = getdqbuf(info->dqi_usable_bs); loff_t ret = 0; int i; char *ddquot; @@ -522,9 +524,12 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info, printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); goto out_buf; } - for (i = 0, ddquot = ((char *)buf) + sizeof(struct qt_disk_dqdbheader); - i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot); - i++, ddquot += info->dqi_entry_size); + ddquot = buf + sizeof(struct qt_disk_dqdbheader); + for (i = 0; i < qtree_dqstr_in_blk(info); i++) { + if (info->dqi_ops->is_id(ddquot, dquot)) + break; + ddquot += info->dqi_entry_size; + } if (i == qtree_dqstr_in_blk(info)) { printk(KERN_ERR "VFS: Quota for id %u referenced " "but not present.\n", dquot->dq_id); @@ -535,7 +540,7 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info, qt_disk_dqdbheader) + i * info->dqi_entry_size; } out_buf: - freedqbuf(buf); + kfree(buf); return ret; } @@ -543,7 +548,7 @@ out_buf: static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, uint blk, int depth) { - dqbuf_t buf = getdqbuf(info->dqi_usable_bs); + char *buf = getdqbuf(info->dqi_usable_bs); loff_t ret = 0; __le32 *ref = (__le32 *)buf; @@ -563,7 +568,7 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info, else ret = find_block_dqentry(info, dquot, blk); out_buf: - freedqbuf(buf); + kfree(buf); return ret; } @@ -579,7 +584,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) int type = dquot->dq_type; struct super_block *sb = dquot->dq_sb; loff_t offset; - dqbuf_t ddquot; + char *ddquot; int ret = 0; #ifdef __QUOTA_QT_PARANOIA @@ -607,8 +612,8 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) ddquot = getdqbuf(info->dqi_entry_size); if (!ddquot) return -ENOMEM; - ret = sb->s_op->quota_read(sb, type, (char *)ddquot, - info->dqi_entry_size, dquot->dq_off); + ret = sb->s_op->quota_read(sb, type, ddquot, info->dqi_entry_size, + dquot->dq_off); if (ret != info->dqi_entry_size) { if (ret >= 0) ret = -EIO; @@ -616,7 +621,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) "structure for id %u.\n", dquot->dq_id); set_bit(DQ_FAKE_B, &dquot->dq_flags); memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); - freedqbuf(ddquot); + kfree(ddquot); goto out; } spin_lock(&dq_data_lock); @@ -627,7 +632,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) !dquot->dq_dqb.dqb_isoftlimit) set_bit(DQ_FAKE_B, &dquot->dq_flags); spin_unlock(&dq_data_lock); - freedqbuf(ddquot); + kfree(ddquot); out: dqstats.reads++; return ret; @@ -638,7 +643,8 @@ EXPORT_SYMBOL(qtree_read_dquot); * the only one operating on dquot (thanks to dq_lock) */ int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) { - if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) + if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && + !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) return qtree_delete_dquot(info, dquot); return 0; } diff --git a/fs/quota_tree.h b/fs/quota/quota_tree.h index a1ab8db81a5..a1ab8db81a5 100644 --- a/fs/quota_tree.h +++ b/fs/quota/quota_tree.h diff --git a/fs/quota_v1.c b/fs/quota/quota_v1.c index b4af1c69ad1..0edcf42b177 100644 --- a/fs/quota_v1.c +++ b/fs/quota/quota_v1.c @@ -62,11 +62,14 @@ static int v1_read_dqblk(struct dquot *dquot) /* Set structure to 0s in case read fails/is after end of file */ memset(&dqblk, 0, sizeof(struct v1_disk_dqblk)); - dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk, sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id)); + dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk, + sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id)); v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk); - if (dquot->dq_dqb.dqb_bhardlimit == 0 && dquot->dq_dqb.dqb_bsoftlimit == 0 && - dquot->dq_dqb.dqb_ihardlimit == 0 && dquot->dq_dqb.dqb_isoftlimit == 0) + if (dquot->dq_dqb.dqb_bhardlimit == 0 && + dquot->dq_dqb.dqb_bsoftlimit == 0 && + dquot->dq_dqb.dqb_ihardlimit == 0 && + dquot->dq_dqb.dqb_isoftlimit == 0) set_bit(DQ_FAKE_B, &dquot->dq_flags); dqstats.reads++; @@ -81,13 +84,16 @@ static int v1_commit_dqblk(struct dquot *dquot) v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb); if (dquot->dq_id == 0) { - dqblk.dqb_btime = sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace; - dqblk.dqb_itime = sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace; + dqblk.dqb_btime = + sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace; + dqblk.dqb_itime = + sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace; } ret = 0; if (sb_dqopt(dquot->dq_sb)->files[type]) - ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type, (char *)&dqblk, - sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id)); + ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type, + (char *)&dqblk, sizeof(struct v1_disk_dqblk), + v1_dqoff(dquot->dq_id)); if (ret != sizeof(struct v1_disk_dqblk)) { printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id); @@ -130,15 +136,20 @@ static int v1_check_quota_file(struct super_block *sb, int type) return 0; blocks = isize >> BLOCK_SIZE_BITS; off = isize & (BLOCK_SIZE - 1); - if ((blocks % sizeof(struct v1_disk_dqblk) * BLOCK_SIZE + off) % sizeof(struct v1_disk_dqblk)) + if ((blocks % sizeof(struct v1_disk_dqblk) * BLOCK_SIZE + off) % + sizeof(struct v1_disk_dqblk)) return 0; - /* Doublecheck whether we didn't get file with new format - with old quotactl() this could happen */ - size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0); + /* Doublecheck whether we didn't get file with new format - with old + * quotactl() this could happen */ + size = sb->s_op->quota_read(sb, type, (char *)&dqhead, + sizeof(struct v2_disk_dqheader), 0); if (size != sizeof(struct v2_disk_dqheader)) return 1; /* Probably not new format */ if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type]) return 1; /* Definitely not new format */ - printk(KERN_INFO "VFS: %s: Refusing to turn on old quota format on given file. It probably contains newer quota format.\n", sb->s_id); + printk(KERN_INFO + "VFS: %s: Refusing to turn on old quota format on given file." + " It probably contains newer quota format.\n", sb->s_id); return 0; /* Seems like a new format file -> refuse it */ } @@ -148,7 +159,9 @@ static int v1_read_file_info(struct super_block *sb, int type) struct v1_disk_dqblk dqblk; int ret; - if ((ret = sb->s_op->quota_read(sb, type, (char *)&dqblk, sizeof(struct v1_disk_dqblk), v1_dqoff(0))) != sizeof(struct v1_disk_dqblk)) { + ret = sb->s_op->quota_read(sb, type, (char *)&dqblk, + sizeof(struct v1_disk_dqblk), v1_dqoff(0)); + if (ret != sizeof(struct v1_disk_dqblk)) { if (ret >= 0) ret = -EIO; goto out; @@ -157,8 +170,10 @@ static int v1_read_file_info(struct super_block *sb, int type) /* limits are stored as unsigned 32-bit data */ dqopt->info[type].dqi_maxblimit = 0xffffffff; dqopt->info[type].dqi_maxilimit = 0xffffffff; - dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME; - dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME; + dqopt->info[type].dqi_igrace = + dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME; + dqopt->info[type].dqi_bgrace = + dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME; out: return ret; } @@ -170,8 +185,9 @@ static int v1_write_file_info(struct super_block *sb, int type) int ret; dqopt->info[type].dqi_flags &= ~DQF_INFO_DIRTY; - if ((ret = sb->s_op->quota_read(sb, type, (char *)&dqblk, - sizeof(struct v1_disk_dqblk), v1_dqoff(0))) != sizeof(struct v1_disk_dqblk)) { + ret = sb->s_op->quota_read(sb, type, (char *)&dqblk, + sizeof(struct v1_disk_dqblk), v1_dqoff(0)); + if (ret != sizeof(struct v1_disk_dqblk)) { if (ret >= 0) ret = -EIO; goto out; diff --git a/fs/quota_v2.c b/fs/quota/quota_v2.c index b618b563635..a5475fb1ae4 100644 --- a/fs/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -54,7 +54,8 @@ static int v2_check_quota_file(struct super_block *sb, int type) static const uint quota_magics[] = V2_INITQMAGICS; static const uint quota_versions[] = V2_INITQVERSIONS; - size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0); + size = sb->s_op->quota_read(sb, type, (char *)&dqhead, + sizeof(struct v2_disk_dqheader), 0); if (size != sizeof(struct v2_disk_dqheader)) { printk("quota_v2: failed read expected=%zd got=%zd\n", sizeof(struct v2_disk_dqheader), size); diff --git a/fs/quotaio_v1.h b/fs/quota/quotaio_v1.h index 746654b5de7..746654b5de7 100644 --- a/fs/quotaio_v1.h +++ b/fs/quota/quotaio_v1.h diff --git a/fs/quotaio_v2.h b/fs/quota/quotaio_v2.h index 530fe580685..530fe580685 100644 --- a/fs/quotaio_v2.h +++ b/fs/quota/quotaio_v2.h diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index b9b567a2837..ebb2c417912 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -18,7 +18,6 @@ #include <linux/string.h> #include <linux/backing-dev.h> #include <linux/ramfs.h> -#include <linux/quotaops.h> #include <linux/pagevec.h> #include <linux/mman.h> @@ -60,7 +59,6 @@ const struct inode_operations ramfs_file_inode_operations = { */ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) { - struct pagevec lru_pvec; unsigned long npages, xpages, loop, limit; struct page *pages; unsigned order; @@ -103,21 +101,20 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) memset(data, 0, newsize); /* attach all the pages to the inode's address space */ - pagevec_init(&lru_pvec, 0); for (loop = 0; loop < npages; loop++) { struct page *page = pages + loop; - ret = add_to_page_cache(page, inode->i_mapping, loop, GFP_KERNEL); + ret = add_to_page_cache_lru(page, inode->i_mapping, loop, + GFP_KERNEL); if (ret < 0) goto add_error; - if (!pagevec_add(&lru_pvec, page)) - __pagevec_lru_add_file(&lru_pvec); + /* prevent the page from being discarded on memory pressure */ + SetPageDirty(page); unlock_page(page); } - pagevec_lru_add_file(&lru_pvec); return 0; fsize_exceeded: @@ -126,9 +123,8 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) return -EFBIG; add_error: - page_cache_release(pages + loop); - for (loop++; loop < npages; loop++) - __free_page(pages + loop); + while (loop < npages) + __free_page(pages + loop++); return ret; } @@ -201,11 +197,6 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia) if (ret) return ret; - /* by providing our own setattr() method, we skip this quotaism */ - if ((old_ia_valid & ATTR_UID && ia->ia_uid != inode->i_uid) || - (old_ia_valid & ATTR_GID && ia->ia_gid != inode->i_gid)) - ret = DQUOT_TRANSFER(inode, ia) ? -EDQUOT : 0; - /* pick out size-changing events */ if (ia->ia_valid & ATTR_SIZE) { loff_t size = i_size_read(inode); diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index b7e6ac706b8..a404fb88e45 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -33,12 +33,15 @@ #include <linux/backing-dev.h> #include <linux/ramfs.h> #include <linux/sched.h> +#include <linux/parser.h> #include <asm/uaccess.h> #include "internal.h" /* some random number */ #define RAMFS_MAGIC 0x858458f6 +#define RAMFS_DEFAULT_MODE 0755 + static const struct super_operations ramfs_ops; static const struct inode_operations ramfs_dir_inode_operations; @@ -158,12 +161,75 @@ static const struct inode_operations ramfs_dir_inode_operations = { static const struct super_operations ramfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, + .show_options = generic_show_options, +}; + +struct ramfs_mount_opts { + umode_t mode; +}; + +enum { + Opt_mode, + Opt_err +}; + +static const match_table_t tokens = { + {Opt_mode, "mode=%o"}, + {Opt_err, NULL} +}; + +struct ramfs_fs_info { + struct ramfs_mount_opts mount_opts; }; +static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts) +{ + substring_t args[MAX_OPT_ARGS]; + int option; + int token; + char *p; + + opts->mode = RAMFS_DEFAULT_MODE; + + while ((p = strsep(&data, ",")) != NULL) { + if (!*p) + continue; + + token = match_token(p, tokens, args); + switch (token) { + case Opt_mode: + if (match_octal(&args[0], &option)) + return -EINVAL; + opts->mode = option & S_IALLUGO; + break; + default: + printk(KERN_ERR "ramfs: bad mount option: %s\n", p); + return -EINVAL; + } + } + + return 0; +} + static int ramfs_fill_super(struct super_block * sb, void * data, int silent) { - struct inode * inode; - struct dentry * root; + struct ramfs_fs_info *fsi; + struct inode *inode = NULL; + struct dentry *root; + int err; + + save_mount_options(sb, data); + + fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL); + if (!fsi) { + err = -ENOMEM; + goto fail; + } + sb->s_fs_info = fsi; + + err = ramfs_parse_options(data, &fsi->mount_opts); + if (err) + goto fail; sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_blocksize = PAGE_CACHE_SIZE; @@ -171,17 +237,23 @@ static int ramfs_fill_super(struct super_block * sb, void * data, int silent) sb->s_magic = RAMFS_MAGIC; sb->s_op = &ramfs_ops; sb->s_time_gran = 1; - inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0); - if (!inode) - return -ENOMEM; + inode = ramfs_get_inode(sb, S_IFDIR | fsi->mount_opts.mode, 0); + if (!inode) { + err = -ENOMEM; + goto fail; + } root = d_alloc_root(inode); if (!root) { - iput(inode); - return -ENOMEM; + err = -ENOMEM; + goto fail; } sb->s_root = root; return 0; +fail: + kfree(fsi); + iput(inode); + return err; } int ramfs_get_sb(struct file_system_type *fs_type, @@ -197,10 +269,16 @@ static int rootfs_get_sb(struct file_system_type *fs_type, mnt); } +static void ramfs_kill_sb(struct super_block *sb) +{ + kfree(sb->s_fs_info); + kill_litter_super(sb); +} + static struct file_system_type ramfs_fs_type = { .name = "ramfs", .get_sb = ramfs_get_sb, - .kill_sb = kill_litter_super, + .kill_sb = ramfs_kill_sb, }; static struct file_system_type rootfs_fs_type = { .name = "rootfs", diff --git a/fs/reiserfs/Makefile b/fs/reiserfs/Makefile index 0eb7ac08048..7c5ab6330dd 100644 --- a/fs/reiserfs/Makefile +++ b/fs/reiserfs/Makefile @@ -7,10 +7,10 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs.o reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \ super.o prints.o objectid.o lbalance.o ibalance.o stree.o \ hashes.o tail_conversion.o journal.o resize.o \ - item_ops.o ioctl.o procfs.o + item_ops.o ioctl.o procfs.o xattr.o ifeq ($(CONFIG_REISERFS_FS_XATTR),y) -reiserfs-objs += xattr.o xattr_user.o xattr_trusted.o +reiserfs-objs += xattr_user.o xattr_trusted.o endif ifeq ($(CONFIG_REISERFS_FS_SECURITY),y) diff --git a/fs/reiserfs/README b/fs/reiserfs/README index 90e1670e4e6..14e8c9d460e 100644 --- a/fs/reiserfs/README +++ b/fs/reiserfs/README @@ -1,4 +1,4 @@ -[LICENSING] +[LICENSING] ReiserFS is hereby licensed under the GNU General Public License version 2. @@ -31,7 +31,7 @@ the GPL as not allowing those additional licensing options, you read it wrongly, and Richard Stallman agrees with me, when carefully read you can see that those restrictions on additional terms do not apply to the owner of the copyright, and my interpretation of this shall -govern for this license. +govern for this license. Finally, nothing in this license shall be interpreted to allow you to fail to fairly credit me, or to remove my credits, without my diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index 4646caa6045..e716161ab32 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -40,8 +40,8 @@ #define SET_OPTION(optname) \ do { \ - reiserfs_warning(s, "reiserfs: option \"%s\" is set", #optname); \ - set_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)); \ + reiserfs_info(s, "block allocator option \"%s\" is set", #optname); \ + set_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)); \ } while(0) #define TEST_OPTION(optname, s) \ test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)) @@ -64,9 +64,9 @@ int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) unsigned int bmap_count = reiserfs_bmap_count(s); if (block == 0 || block >= SB_BLOCK_COUNT(s)) { - reiserfs_warning(s, - "vs-4010: is_reusable: block number is out of range %lu (%u)", - block, SB_BLOCK_COUNT(s)); + reiserfs_error(s, "vs-4010", + "block number is out of range %lu (%u)", + block, SB_BLOCK_COUNT(s)); return 0; } @@ -79,31 +79,30 @@ int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) b_blocknr_t bmap1 = REISERFS_SB(s)->s_sbh->b_blocknr + 1; if (block >= bmap1 && block <= bmap1 + bmap_count) { - reiserfs_warning(s, "vs: 4019: is_reusable: " - "bitmap block %lu(%u) can't be freed or reused", - block, bmap_count); + reiserfs_error(s, "vs-4019", "bitmap block %lu(%u) " + "can't be freed or reused", + block, bmap_count); return 0; } } else { if (offset == 0) { - reiserfs_warning(s, "vs: 4020: is_reusable: " - "bitmap block %lu(%u) can't be freed or reused", - block, bmap_count); + reiserfs_error(s, "vs-4020", "bitmap block %lu(%u) " + "can't be freed or reused", + block, bmap_count); return 0; } } if (bmap >= bmap_count) { - reiserfs_warning(s, - "vs-4030: is_reusable: there is no so many bitmap blocks: " - "block=%lu, bitmap_nr=%u", block, bmap); + reiserfs_error(s, "vs-4030", "bitmap for requested block " + "is out of range: block=%lu, bitmap_nr=%u", + block, bmap); return 0; } if (bit_value == 0 && block == SB_ROOT_BLOCK(s)) { - reiserfs_warning(s, - "vs-4050: is_reusable: this is root block (%u), " - "it must be busy", SB_ROOT_BLOCK(s)); + reiserfs_error(s, "vs-4050", "this is root block (%u), " + "it must be busy", SB_ROOT_BLOCK(s)); return 0; } @@ -154,8 +153,8 @@ static int scan_bitmap_block(struct reiserfs_transaction_handle *th, /* - I mean `a window of zero bits' as in description of this function - Zam. */ if (!bi) { - reiserfs_warning(s, "NULL bitmap info pointer for bitmap %d", - bmap_n); + reiserfs_error(s, "jdm-4055", "NULL bitmap info pointer " + "for bitmap %d", bmap_n); return 0; } @@ -400,11 +399,8 @@ static void _reiserfs_free_block(struct reiserfs_transaction_handle *th, get_bit_address(s, block, &nr, &offset); if (nr >= reiserfs_bmap_count(s)) { - reiserfs_warning(s, "vs-4075: reiserfs_free_block: " - "block %lu is out of range on %s " - "(nr=%u,max=%u)", block, - reiserfs_bdevname(s), nr, - reiserfs_bmap_count(s)); + reiserfs_error(s, "vs-4075", "block %lu is out of range", + block); return; } @@ -416,9 +412,8 @@ static void _reiserfs_free_block(struct reiserfs_transaction_handle *th, /* clear bit for the given block in bit map */ if (!reiserfs_test_and_clear_le_bit(offset, bmbh->b_data)) { - reiserfs_warning(s, "vs-4080: reiserfs_free_block: " - "free_block (%s:%lu)[dev:blocknr]: bit already cleared", - reiserfs_bdevname(s), block); + reiserfs_error(s, "vs-4080", + "block %lu: bit already cleared", block); } apbi[nr].free_count++; journal_mark_dirty(th, s, bmbh); @@ -430,7 +425,7 @@ static void _reiserfs_free_block(struct reiserfs_transaction_handle *th, journal_mark_dirty(th, s, sbh); if (for_unformatted) - DQUOT_FREE_BLOCK_NODIRTY(inode, 1); + vfs_dq_free_block_nodirty(inode, 1); } void reiserfs_free_block(struct reiserfs_transaction_handle *th, @@ -445,7 +440,7 @@ void reiserfs_free_block(struct reiserfs_transaction_handle *th, return; if (block > sb_block_count(REISERFS_SB(s)->s_rs)) { - reiserfs_panic(th->t_super, "bitmap-4072", + reiserfs_error(th->t_super, "bitmap-4072", "Trying to free block outside file system " "boundaries (%lu > %lu)", block, sb_block_count(REISERFS_SB(s)->s_rs)); @@ -477,9 +472,8 @@ static void __discard_prealloc(struct reiserfs_transaction_handle *th, BUG_ON(!th->t_trans_id); #ifdef CONFIG_REISERFS_CHECK if (ei->i_prealloc_count < 0) - reiserfs_warning(th->t_super, - "zam-4001:%s: inode has negative prealloc blocks count.", - __func__); + reiserfs_error(th->t_super, "zam-4001", + "inode has negative prealloc blocks count."); #endif while (ei->i_prealloc_count > 0) { reiserfs_free_prealloc_block(th, inode, ei->i_prealloc_block); @@ -515,9 +509,9 @@ void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th) i_prealloc_list); #ifdef CONFIG_REISERFS_CHECK if (!ei->i_prealloc_count) { - reiserfs_warning(th->t_super, - "zam-4001:%s: inode is in prealloc list but has no preallocated blocks.", - __func__); + reiserfs_error(th->t_super, "zam-4001", + "inode is in prealloc list but has " + "no preallocated blocks."); } #endif __discard_prealloc(th, ei); @@ -631,12 +625,12 @@ int reiserfs_parse_alloc_options(struct super_block *s, char *options) continue; } - reiserfs_warning(s, "zam-4001: %s : unknown option - %s", - __func__, this_char); + reiserfs_warning(s, "zam-4001", "unknown option - %s", + this_char); return 1; } - reiserfs_warning(s, "allocator options = [%08x]\n", SB_ALLOC_OPTS(s)); + reiserfs_info(s, "allocator options = [%08x]\n", SB_ALLOC_OPTS(s)); return 0; } @@ -1055,7 +1049,7 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start amount_needed, hint->inode->i_uid); #endif quota_ret = - DQUOT_ALLOC_BLOCK_NODIRTY(hint->inode, amount_needed); + vfs_dq_alloc_block_nodirty(hint->inode, amount_needed); if (quota_ret) /* Quota exceeded? */ return QUOTA_EXCEEDED; if (hint->preallocate && hint->prealloc_size) { @@ -1064,8 +1058,7 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start "reiserquota: allocating (prealloc) %d blocks id=%u", hint->prealloc_size, hint->inode->i_uid); #endif - quota_ret = - DQUOT_PREALLOC_BLOCK_NODIRTY(hint->inode, + quota_ret = vfs_dq_prealloc_block_nodirty(hint->inode, hint->prealloc_size); if (quota_ret) hint->preallocate = hint->prealloc_size = 0; @@ -1098,7 +1091,10 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start nr_allocated, hint->inode->i_uid); #endif - DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed + hint->prealloc_size - nr_allocated); /* Free not allocated blocks */ + /* Free not allocated blocks */ + vfs_dq_free_block_nodirty(hint->inode, + amount_needed + hint->prealloc_size - + nr_allocated); } while (nr_allocated--) reiserfs_free_block(hint->th, hint->inode, @@ -1129,7 +1125,7 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start REISERFS_I(hint->inode)->i_prealloc_count, hint->inode->i_uid); #endif - DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed + + vfs_dq_free_block_nodirty(hint->inode, amount_needed + hint->prealloc_size - nr_allocated - REISERFS_I(hint->inode)-> i_prealloc_count); @@ -1219,7 +1215,9 @@ void reiserfs_cache_bitmap_metadata(struct super_block *sb, unsigned long *cur = (unsigned long *)(bh->b_data + bh->b_size); /* The first bit must ALWAYS be 1 */ - BUG_ON(!reiserfs_test_le_bit(0, (unsigned long *)bh->b_data)); + if (!reiserfs_test_le_bit(0, (unsigned long *)bh->b_data)) + reiserfs_error(sb, "reiserfs-2025", "bitmap block %lu is " + "corrupted: first bit must be 1", bh->b_blocknr); info->free_count = 0; diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index e6b03d2020c..67a80d7e59e 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c @@ -41,10 +41,10 @@ static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, #define store_ih(where,what) copy_item_head (where, what) -// -static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir) +int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent, + filldir_t filldir, loff_t *pos) { - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = dentry->d_inode; struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */ INITIALIZE_PATH(path_to_entry); struct buffer_head *bh; @@ -64,13 +64,9 @@ static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir) /* form key for search the next directory entry using f_pos field of file structure */ - make_cpu_key(&pos_key, inode, - (filp->f_pos) ? (filp->f_pos) : DOT_OFFSET, TYPE_DIRENTRY, - 3); + make_cpu_key(&pos_key, inode, *pos ?: DOT_OFFSET, TYPE_DIRENTRY, 3); next_pos = cpu_key_k_offset(&pos_key); - /* reiserfs_warning (inode->i_sb, "reiserfs_readdir 1: f_pos = %Ld", filp->f_pos); */ - path_to_entry.reada = PATH_READA; while (1) { research: @@ -144,7 +140,7 @@ static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir) /* Ignore the .reiserfs_priv entry */ if (reiserfs_xattrs(inode->i_sb) && !old_format_only(inode->i_sb) && - filp->f_path.dentry == inode->i_sb->s_root && + dentry == inode->i_sb->s_root && REISERFS_SB(inode->i_sb)->priv_root && REISERFS_SB(inode->i_sb)->priv_root->d_inode && deh_objectid(deh) == @@ -156,7 +152,7 @@ static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir) } d_off = deh_offset(deh); - filp->f_pos = d_off; + *pos = d_off; d_ino = deh_objectid(deh); if (d_reclen <= 32) { local_buf = small_buf; @@ -223,15 +219,21 @@ static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir) } /* while */ - end: - filp->f_pos = next_pos; +end: + *pos = next_pos; pathrelse(&path_to_entry); reiserfs_check_path(&path_to_entry); - out: +out: reiserfs_write_unlock(inode->i_sb); return ret; } +static int reiserfs_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + struct dentry *dentry = file->f_path.dentry; + return reiserfs_readdir_dentry(dentry, dirent, filldir, &file->f_pos); +} + /* compose directory item containing "." and ".." entries (entries are not aligned to 4 byte boundary) */ /* the last four params are LE */ diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c index 2f87f5b1463..4beb964a2a3 100644 --- a/fs/reiserfs/do_balan.c +++ b/fs/reiserfs/do_balan.c @@ -29,6 +29,43 @@ struct tree_balance *cur_tb = NULL; /* detects whether more than one is interrupting do_balance */ #endif +static inline void buffer_info_init_left(struct tree_balance *tb, + struct buffer_info *bi) +{ + bi->tb = tb; + bi->bi_bh = tb->L[0]; + bi->bi_parent = tb->FL[0]; + bi->bi_position = get_left_neighbor_position(tb, 0); +} + +static inline void buffer_info_init_right(struct tree_balance *tb, + struct buffer_info *bi) +{ + bi->tb = tb; + bi->bi_bh = tb->R[0]; + bi->bi_parent = tb->FR[0]; + bi->bi_position = get_right_neighbor_position(tb, 0); +} + +static inline void buffer_info_init_tbS0(struct tree_balance *tb, + struct buffer_info *bi) +{ + bi->tb = tb; + bi->bi_bh = PATH_PLAST_BUFFER(tb->tb_path); + bi->bi_parent = PATH_H_PPARENT(tb->tb_path, 0); + bi->bi_position = PATH_H_POSITION(tb->tb_path, 1); +} + +static inline void buffer_info_init_bh(struct tree_balance *tb, + struct buffer_info *bi, + struct buffer_head *bh) +{ + bi->tb = tb; + bi->bi_bh = bh; + bi->bi_parent = NULL; + bi->bi_position = 0; +} + inline void do_balance_mark_leaf_dirty(struct tree_balance *tb, struct buffer_head *bh, int flag) { @@ -39,21 +76,21 @@ inline void do_balance_mark_leaf_dirty(struct tree_balance *tb, #define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty #define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty -/* summary: +/* summary: if deleting something ( tb->insert_size[0] < 0 ) return(balance_leaf_when_delete()); (flag d handled here) else if lnum is larger than 0 we put items into the left node if rnum is larger than 0 we put items into the right node if snum1 is larger than 0 we put items into the new node s1 - if snum2 is larger than 0 we put items into the new node s2 + if snum2 is larger than 0 we put items into the new node s2 Note that all *num* count new items being created. It would be easier to read balance_leaf() if each of these summary lines was a separate procedure rather than being inlined. I think that there are many passages here and in balance_leaf_when_delete() in which two calls to one procedure can replace two passages, and it -might save cache space and improve software maintenance costs to do so. +might save cache space and improve software maintenance costs to do so. Vladimir made the perceptive comment that we should offload most of the decision making in this function into fix_nodes/check_balance, and @@ -86,6 +123,7 @@ static int balance_leaf_when_delete(struct tree_balance *tb, int flag) "PAP-12010: tree can not be empty"); ih = B_N_PITEM_HEAD(tbS0, item_pos); + buffer_info_init_tbS0(tb, &bi); /* Delete or truncate the item */ @@ -96,10 +134,6 @@ static int balance_leaf_when_delete(struct tree_balance *tb, int flag) "vs-12013: mode Delete, insert size %d, ih to be deleted %h", -tb->insert_size[0], ih); - bi.tb = tb; - bi.bi_bh = tbS0; - bi.bi_parent = PATH_H_PPARENT(tb->tb_path, 0); - bi.bi_position = PATH_H_POSITION(tb->tb_path, 1); leaf_delete_items(&bi, 0, item_pos, 1, -1); if (!item_pos && tb->CFL[0]) { @@ -121,10 +155,6 @@ static int balance_leaf_when_delete(struct tree_balance *tb, int flag) break; case M_CUT:{ /* cut item in S[0] */ - bi.tb = tb; - bi.bi_bh = tbS0; - bi.bi_parent = PATH_H_PPARENT(tb->tb_path, 0); - bi.bi_position = PATH_H_POSITION(tb->tb_path, 1); if (is_direntry_le_ih(ih)) { /* UFS unlink semantics are such that you can only delete one directory entry at a time. */ @@ -153,8 +183,8 @@ static int balance_leaf_when_delete(struct tree_balance *tb, int flag) default: print_cur_tb("12040"); - reiserfs_panic(tb->tb_sb, - "PAP-12040: balance_leaf_when_delete: unexpectable mode: %s(%d)", + reiserfs_panic(tb->tb_sb, "PAP-12040", + "unexpected mode: %s(%d)", (flag == M_PASTE) ? "PASTE" : ((flag == M_INSERT) ? "INSERT" : @@ -258,15 +288,15 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h ) { struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path); - int item_pos = PATH_LAST_POSITION(tb->tb_path); /* index into the array of item headers in S[0] + int item_pos = PATH_LAST_POSITION(tb->tb_path); /* index into the array of item headers in S[0] of the affected item */ struct buffer_info bi; struct buffer_head *S_new[2]; /* new nodes allocated to hold what could not fit into S */ int snum[2]; /* number of items that will be placed into S_new (includes partially shifted items) */ - int sbytes[2]; /* if an item is partially shifted into S_new then - if it is a directory item + int sbytes[2]; /* if an item is partially shifted into S_new then + if it is a directory item it is the number of entries from the item that are shifted into S_new else it is the number of bytes from the item that are shifted into S_new @@ -325,11 +355,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h ih_item_len(ih)); /* Insert new item into L[0] */ - bi.tb = tb; - bi.bi_bh = tb->L[0]; - bi.bi_parent = tb->FL[0]; - bi.bi_position = - get_left_neighbor_position(tb, 0); + buffer_info_init_left(tb, &bi); leaf_insert_into_buf(&bi, n + item_pos - ret_val, ih, body, @@ -369,11 +395,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h leaf_shift_left(tb, tb->lnum[0] - 1, tb->lbytes); /* Insert new item into L[0] */ - bi.tb = tb; - bi.bi_bh = tb->L[0]; - bi.bi_parent = tb->FL[0]; - bi.bi_position = - get_left_neighbor_position(tb, 0); + buffer_info_init_left(tb, &bi); leaf_insert_into_buf(&bi, n + item_pos - ret_val, ih, body, @@ -429,13 +451,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h } /* Append given directory entry to directory item */ - bi.tb = tb; - bi.bi_bh = tb->L[0]; - bi.bi_parent = - tb->FL[0]; - bi.bi_position = - get_left_neighbor_position - (tb, 0); + buffer_info_init_left(tb, &bi); leaf_paste_in_buffer (&bi, n + item_pos - @@ -449,8 +465,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h /* when we have merge directory item, pos_in_item has been changed too */ /* paste new directory entry. 1 is entry number */ - leaf_paste_entries(bi. - bi_bh, + leaf_paste_entries(&bi, n + item_pos - @@ -524,13 +539,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h (tbS0, item_pos))); /* Append to body of item in L[0] */ - bi.tb = tb; - bi.bi_bh = tb->L[0]; - bi.bi_parent = - tb->FL[0]; - bi.bi_position = - get_left_neighbor_position - (tb, 0); + buffer_info_init_left(tb, &bi); leaf_paste_in_buffer (&bi, n + item_pos - @@ -681,11 +690,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h leaf_shift_left(tb, tb->lnum[0], tb->lbytes); /* Append to body of item in L[0] */ - bi.tb = tb; - bi.bi_bh = tb->L[0]; - bi.bi_parent = tb->FL[0]; - bi.bi_position = - get_left_neighbor_position(tb, 0); + buffer_info_init_left(tb, &bi); leaf_paste_in_buffer(&bi, n + item_pos - ret_val, @@ -699,7 +704,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h n + item_pos - ret_val); if (is_direntry_le_ih(pasted)) - leaf_paste_entries(bi.bi_bh, + leaf_paste_entries(&bi, n + item_pos - ret_val, @@ -722,8 +727,9 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h } break; default: /* cases d and t */ - reiserfs_panic(tb->tb_sb, - "PAP-12130: balance_leaf: lnum > 0: unexpectable mode: %s(%d)", + reiserfs_panic(tb->tb_sb, "PAP-12130", + "lnum > 0: unexpected mode: " + " %s(%d)", (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) @@ -776,11 +782,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h set_le_ih_k_offset(ih, offset); put_ih_item_len(ih, tb->rbytes); /* Insert part of the item into R[0] */ - bi.tb = tb; - bi.bi_bh = tb->R[0]; - bi.bi_parent = tb->FR[0]; - bi.bi_position = - get_right_neighbor_position(tb, 0); + buffer_info_init_right(tb, &bi); if ((old_len - tb->rbytes) > zeros_num) { r_zeros_number = 0; r_body = @@ -817,11 +819,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h tb->rnum[0] - 1, tb->rbytes); /* Insert new item into R[0] */ - bi.tb = tb; - bi.bi_bh = tb->R[0]; - bi.bi_parent = tb->FR[0]; - bi.bi_position = - get_right_neighbor_position(tb, 0); + buffer_info_init_right(tb, &bi); leaf_insert_into_buf(&bi, item_pos - n + tb->rnum[0] - 1, @@ -881,21 +879,14 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h pos_in_item - entry_count + tb->rbytes - 1; - bi.tb = tb; - bi.bi_bh = tb->R[0]; - bi.bi_parent = - tb->FR[0]; - bi.bi_position = - get_right_neighbor_position - (tb, 0); + buffer_info_init_right(tb, &bi); leaf_paste_in_buffer (&bi, 0, paste_entry_position, tb->insert_size[0], body, zeros_num); /* paste entry */ - leaf_paste_entries(bi. - bi_bh, + leaf_paste_entries(&bi, 0, paste_entry_position, 1, @@ -1019,12 +1010,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h (tb, tb->CFR[0], 0); /* Append part of body into R[0] */ - bi.tb = tb; - bi.bi_bh = tb->R[0]; - bi.bi_parent = tb->FR[0]; - bi.bi_position = - get_right_neighbor_position - (tb, 0); + buffer_info_init_right(tb, &bi); if (n_rem > zeros_num) { r_zeros_number = 0; r_body = @@ -1071,12 +1057,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h tb->rbytes); /* append item in R[0] */ if (pos_in_item >= 0) { - bi.tb = tb; - bi.bi_bh = tb->R[0]; - bi.bi_parent = tb->FR[0]; - bi.bi_position = - get_right_neighbor_position - (tb, 0); + buffer_info_init_right(tb, &bi); leaf_paste_in_buffer(&bi, item_pos - n + @@ -1096,7 +1077,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h tb->rnum[0]); if (is_direntry_le_ih(pasted) && pos_in_item >= 0) { - leaf_paste_entries(bi.bi_bh, + leaf_paste_entries(&bi, item_pos - n + tb->rnum[0], @@ -1136,8 +1117,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h } break; default: /* cases d and t */ - reiserfs_panic(tb->tb_sb, - "PAP-12175: balance_leaf: rnum > 0: unexpectable mode: %s(%d)", + reiserfs_panic(tb->tb_sb, "PAP-12175", + "rnum > 0: unexpected mode: %s(%d)", (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" @@ -1167,8 +1148,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h not set correctly */ if (tb->CFL[0]) { if (!tb->CFR[0]) - reiserfs_panic(tb->tb_sb, - "vs-12195: balance_leaf: CFR not initialized"); + reiserfs_panic(tb->tb_sb, "vs-12195", + "CFR not initialized"); copy_key(B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]), B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0])); do_balance_mark_internal_dirty(tb, tb->CFL[0], 0); @@ -1232,10 +1213,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h put_ih_item_len(ih, sbytes[i]); /* Insert part of the item into S_new[i] before 0-th item */ - bi.tb = tb; - bi.bi_bh = S_new[i]; - bi.bi_parent = NULL; - bi.bi_position = 0; + buffer_info_init_bh(tb, &bi, S_new[i]); if ((old_len - sbytes[i]) > zeros_num) { r_zeros_number = 0; @@ -1267,10 +1245,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h S_new[i]); /* Insert new item into S_new[i] */ - bi.tb = tb; - bi.bi_bh = S_new[i]; - bi.bi_parent = NULL; - bi.bi_position = 0; + buffer_info_init_bh(tb, &bi, S_new[i]); leaf_insert_into_buf(&bi, item_pos - n + snum[i] - 1, ih, @@ -1327,10 +1302,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h sbytes[i] - 1, S_new[i]); /* Paste given directory entry to directory item */ - bi.tb = tb; - bi.bi_bh = S_new[i]; - bi.bi_parent = NULL; - bi.bi_position = 0; + buffer_info_init_bh(tb, &bi, S_new[i]); leaf_paste_in_buffer (&bi, 0, pos_in_item - @@ -1339,8 +1311,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h tb->insert_size[0], body, zeros_num); /* paste new directory entry */ - leaf_paste_entries(bi. - bi_bh, + leaf_paste_entries(&bi, 0, pos_in_item - @@ -1401,11 +1372,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h if (n_rem < 0) n_rem = 0; /* Append part of body into S_new[0] */ - bi.tb = tb; - bi.bi_bh = S_new[i]; - bi.bi_parent = NULL; - bi.bi_position = 0; - + buffer_info_init_bh(tb, &bi, S_new[i]); if (n_rem > zeros_num) { r_zeros_number = 0; r_body = @@ -1475,7 +1442,10 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h && (pos_in_item != ih_item_len(ih_check) || tb->insert_size[0] <= 0)) reiserfs_panic(tb->tb_sb, - "PAP-12235: balance_leaf: pos_in_item must be equal to ih_item_len"); + "PAP-12235", + "pos_in_item " + "must be equal " + "to ih_item_len"); #endif /* CONFIG_REISERFS_CHECK */ leaf_mi = @@ -1489,10 +1459,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h leaf_mi); /* paste into item */ - bi.tb = tb; - bi.bi_bh = S_new[i]; - bi.bi_parent = NULL; - bi.bi_position = 0; + buffer_info_init_bh(tb, &bi, S_new[i]); leaf_paste_in_buffer(&bi, item_pos - n + snum[i], @@ -1505,7 +1472,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h item_pos - n + snum[i]); if (is_direntry_le_ih(pasted)) { - leaf_paste_entries(bi.bi_bh, + leaf_paste_entries(&bi, item_pos - n + snum[i], pos_in_item, @@ -1535,8 +1502,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h } break; default: /* cases d and t */ - reiserfs_panic(tb->tb_sb, - "PAP-12245: balance_leaf: blknum > 2: unexpectable mode: %s(%d)", + reiserfs_panic(tb->tb_sb, "PAP-12245", + "blknum > 2: unexpected mode: %s(%d)", (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" @@ -1559,10 +1526,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h switch (flag) { case M_INSERT: /* insert item into S[0] */ - bi.tb = tb; - bi.bi_bh = tbS0; - bi.bi_parent = PATH_H_PPARENT(tb->tb_path, 0); - bi.bi_position = PATH_H_POSITION(tb->tb_path, 1); + buffer_info_init_tbS0(tb, &bi); leaf_insert_into_buf(&bi, item_pos, ih, body, zeros_num); @@ -1589,14 +1553,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h "PAP-12260: insert_size is 0 already"); /* prepare space */ - bi.tb = tb; - bi.bi_bh = tbS0; - bi.bi_parent = - PATH_H_PPARENT(tb->tb_path, - 0); - bi.bi_position = - PATH_H_POSITION(tb->tb_path, - 1); + buffer_info_init_tbS0(tb, &bi); leaf_paste_in_buffer(&bi, item_pos, pos_in_item, @@ -1606,7 +1563,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h zeros_num); /* paste entry */ - leaf_paste_entries(bi.bi_bh, + leaf_paste_entries(&bi, item_pos, pos_in_item, 1, @@ -1644,14 +1601,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h RFALSE(tb->insert_size[0] <= 0, "PAP-12275: insert size must not be %d", tb->insert_size[0]); - bi.tb = tb; - bi.bi_bh = tbS0; - bi.bi_parent = - PATH_H_PPARENT(tb->tb_path, - 0); - bi.bi_position = - PATH_H_POSITION(tb->tb_path, - 1); + buffer_info_init_tbS0(tb, &bi); leaf_paste_in_buffer(&bi, item_pos, pos_in_item, @@ -1681,10 +1631,11 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h print_cur_tb("12285"); reiserfs_panic(tb-> tb_sb, - "PAP-12285: balance_leaf: insert_size must be 0 (%d)", - tb-> - insert_size - [0]); + "PAP-12285", + "insert_size " + "must be 0 " + "(%d)", + tb->insert_size[0]); } } #endif /* CONFIG_REISERFS_CHECK */ @@ -1697,11 +1648,10 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h if (flag == M_PASTE && tb->insert_size[0]) { print_cur_tb("12290"); reiserfs_panic(tb->tb_sb, - "PAP-12290: balance_leaf: insert_size is still not 0 (%d)", + "PAP-12290", "insert_size is still not 0 (%d)", tb->insert_size[0]); } #endif /* CONFIG_REISERFS_CHECK */ - return 0; } /* Leaf level of the tree is balanced (end of balance_leaf) */ @@ -1724,7 +1674,6 @@ void make_empty_node(struct buffer_info *bi) struct buffer_head *get_FEB(struct tree_balance *tb) { int i; - struct buffer_head *first_b; struct buffer_info bi; for (i = 0; i < MAX_FEB_SIZE; i++) @@ -1732,19 +1681,15 @@ struct buffer_head *get_FEB(struct tree_balance *tb) break; if (i == MAX_FEB_SIZE) - reiserfs_panic(tb->tb_sb, - "vs-12300: get_FEB: FEB list is empty"); + reiserfs_panic(tb->tb_sb, "vs-12300", "FEB list is empty"); - bi.tb = tb; - bi.bi_bh = first_b = tb->FEB[i]; - bi.bi_parent = NULL; - bi.bi_position = 0; + buffer_info_init_bh(tb, &bi, tb->FEB[i]); make_empty_node(&bi); - set_buffer_uptodate(first_b); + set_buffer_uptodate(tb->FEB[i]); + tb->used[i] = tb->FEB[i]; tb->FEB[i] = NULL; - tb->used[i] = first_b; - return (first_b); + return tb->used[i]; } /* This is now used because reiserfs_free_block has to be able to @@ -1755,15 +1700,16 @@ static void store_thrown(struct tree_balance *tb, struct buffer_head *bh) int i; if (buffer_dirty(bh)) - reiserfs_warning(tb->tb_sb, - "store_thrown deals with dirty buffer"); + reiserfs_warning(tb->tb_sb, "reiserfs-12320", + "called with dirty buffer"); for (i = 0; i < ARRAY_SIZE(tb->thrown); i++) if (!tb->thrown[i]) { tb->thrown[i] = bh; get_bh(bh); /* free_thrown puts this */ return; } - reiserfs_warning(tb->tb_sb, "store_thrown: too many thrown buffers"); + reiserfs_warning(tb->tb_sb, "reiserfs-12321", + "too many thrown buffers"); } static void free_thrown(struct tree_balance *tb) @@ -1774,8 +1720,8 @@ static void free_thrown(struct tree_balance *tb) if (tb->thrown[i]) { blocknr = tb->thrown[i]->b_blocknr; if (buffer_dirty(tb->thrown[i])) - reiserfs_warning(tb->tb_sb, - "free_thrown deals with dirty buffer %d", + reiserfs_warning(tb->tb_sb, "reiserfs-12322", + "called with dirty buffer %d", blocknr); brelse(tb->thrown[i]); /* incremented in store_thrown */ reiserfs_free_block(tb->transaction_handle, NULL, @@ -1873,20 +1819,19 @@ static void check_internal_node(struct super_block *s, struct buffer_head *bh, for (i = 0; i <= B_NR_ITEMS(bh); i++, dc++) { if (!is_reusable(s, dc_block_number(dc), 1)) { print_cur_tb(mes); - reiserfs_panic(s, - "PAP-12338: check_internal_node: invalid child pointer %y in %b", + reiserfs_panic(s, "PAP-12338", + "invalid child pointer %y in %b", dc, bh); } } } -static int locked_or_not_in_tree(struct buffer_head *bh, char *which) +static int locked_or_not_in_tree(struct tree_balance *tb, + struct buffer_head *bh, char *which) { if ((!buffer_journal_prepared(bh) && buffer_locked(bh)) || !B_IS_IN_TREE(bh)) { - reiserfs_warning(NULL, - "vs-12339: locked_or_not_in_tree: %s (%b)", - which, bh); + reiserfs_warning(tb->tb_sb, "vs-12339", "%s (%b)", which, bh); return 1; } return 0; @@ -1897,26 +1842,28 @@ static int check_before_balancing(struct tree_balance *tb) int retval = 0; if (cur_tb) { - reiserfs_panic(tb->tb_sb, "vs-12335: check_before_balancing: " - "suspect that schedule occurred based on cur_tb not being null at this point in code. " - "do_balance cannot properly handle schedule occurring while it runs."); + reiserfs_panic(tb->tb_sb, "vs-12335", "suspect that schedule " + "occurred based on cur_tb not being null at " + "this point in code. do_balance cannot properly " + "handle schedule occurring while it runs."); } /* double check that buffers that we will modify are unlocked. (fix_nodes should already have prepped all of these for us). */ if (tb->lnum[0]) { - retval |= locked_or_not_in_tree(tb->L[0], "L[0]"); - retval |= locked_or_not_in_tree(tb->FL[0], "FL[0]"); - retval |= locked_or_not_in_tree(tb->CFL[0], "CFL[0]"); + retval |= locked_or_not_in_tree(tb, tb->L[0], "L[0]"); + retval |= locked_or_not_in_tree(tb, tb->FL[0], "FL[0]"); + retval |= locked_or_not_in_tree(tb, tb->CFL[0], "CFL[0]"); check_leaf(tb->L[0]); } if (tb->rnum[0]) { - retval |= locked_or_not_in_tree(tb->R[0], "R[0]"); - retval |= locked_or_not_in_tree(tb->FR[0], "FR[0]"); - retval |= locked_or_not_in_tree(tb->CFR[0], "CFR[0]"); + retval |= locked_or_not_in_tree(tb, tb->R[0], "R[0]"); + retval |= locked_or_not_in_tree(tb, tb->FR[0], "FR[0]"); + retval |= locked_or_not_in_tree(tb, tb->CFR[0], "CFR[0]"); check_leaf(tb->R[0]); } - retval |= locked_or_not_in_tree(PATH_PLAST_BUFFER(tb->tb_path), "S[0]"); + retval |= locked_or_not_in_tree(tb, PATH_PLAST_BUFFER(tb->tb_path), + "S[0]"); check_leaf(PATH_PLAST_BUFFER(tb->tb_path)); return retval; @@ -1930,8 +1877,8 @@ static void check_after_balance_leaf(struct tree_balance *tb) dc_size(B_N_CHILD (tb->FL[0], get_left_neighbor_position(tb, 0)))) { print_cur_tb("12221"); - reiserfs_panic(tb->tb_sb, - "PAP-12355: check_after_balance_leaf: shift to left was incorrect"); + reiserfs_panic(tb->tb_sb, "PAP-12355", + "shift to left was incorrect"); } } if (tb->rnum[0]) { @@ -1940,8 +1887,8 @@ static void check_after_balance_leaf(struct tree_balance *tb) dc_size(B_N_CHILD (tb->FR[0], get_right_neighbor_position(tb, 0)))) { print_cur_tb("12222"); - reiserfs_panic(tb->tb_sb, - "PAP-12360: check_after_balance_leaf: shift to right was incorrect"); + reiserfs_panic(tb->tb_sb, "PAP-12360", + "shift to right was incorrect"); } } if (PATH_H_PBUFFER(tb->tb_path, 1) && @@ -1955,7 +1902,7 @@ static void check_after_balance_leaf(struct tree_balance *tb) PATH_H_POSITION(tb->tb_path, 1)))); print_cur_tb("12223"); - reiserfs_warning(tb->tb_sb, + reiserfs_warning(tb->tb_sb, "reiserfs-12363", "B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0)) = %d; " "MAX_CHILD_SIZE (%d) - dc_size( %y, %d ) [%d] = %d", left, @@ -1966,8 +1913,7 @@ static void check_after_balance_leaf(struct tree_balance *tb) (PATH_H_PBUFFER(tb->tb_path, 1), PATH_H_POSITION(tb->tb_path, 1))), right); - reiserfs_panic(tb->tb_sb, - "PAP-12365: check_after_balance_leaf: S is incorrect"); + reiserfs_panic(tb->tb_sb, "PAP-12365", "S is incorrect"); } } @@ -2037,7 +1983,7 @@ static inline void do_balance_starts(struct tree_balance *tb) /* store_print_tb (tb); */ /* do not delete, just comment it out */ -/* print_tb(flag, PATH_LAST_POSITION(tb->tb_path), tb->tb_path->pos_in_item, tb, +/* print_tb(flag, PATH_LAST_POSITION(tb->tb_path), tb->tb_path->pos_in_item, tb, "check");*/ RFALSE(check_before_balancing(tb), "PAP-12340: locked buffers in TB"); #ifdef CONFIG_REISERFS_CHECK @@ -2102,14 +2048,13 @@ void do_balance(struct tree_balance *tb, /* tree_balance structure */ tb->need_balance_dirty = 0; if (FILESYSTEM_CHANGED_TB(tb)) { - reiserfs_panic(tb->tb_sb, - "clm-6000: do_balance, fs generation has changed\n"); + reiserfs_panic(tb->tb_sb, "clm-6000", "fs generation has " + "changed"); } /* if we have no real work to do */ if (!tb->insert_size[0]) { - reiserfs_warning(tb->tb_sb, - "PAP-12350: do_balance: insert_size == 0, mode == %c", - flag); + reiserfs_warning(tb->tb_sb, "PAP-12350", + "insert_size == 0, mode == %c", flag); unfix_nodes(tb); return; } diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 33408417038..9f436668b7f 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -20,14 +20,14 @@ ** insertion/balancing, for files that are written in one write. ** It avoids unnecessary tail packings (balances) for files that are written in ** multiple writes and are small enough to have tails. -** +** ** file_release is called by the VFS layer when the file is closed. If ** this is the last open file descriptor, and the file ** small enough to have a tail, and the tail is currently in an ** unformatted node, the tail is converted back into a direct item. -** +** ** We use reiserfs_truncate_file to pack the tail, since it already has -** all the conditions coded. +** all the conditions coded. */ static int reiserfs_file_release(struct inode *inode, struct file *filp) { @@ -76,7 +76,7 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp) * and let the admin know what is going on. */ igrab(inode); - reiserfs_warning(inode->i_sb, + reiserfs_warning(inode->i_sb, "clm-9001", "pinning inode %lu because the " "preallocation can't be freed", inode->i_ino); @@ -134,23 +134,23 @@ static void reiserfs_vfs_truncate_file(struct inode *inode) * be removed... */ -static int reiserfs_sync_file(struct file *p_s_filp, - struct dentry *p_s_dentry, int datasync) +static int reiserfs_sync_file(struct file *filp, + struct dentry *dentry, int datasync) { - struct inode *p_s_inode = p_s_dentry->d_inode; - int n_err; + struct inode *inode = dentry->d_inode; + int err; int barrier_done; - BUG_ON(!S_ISREG(p_s_inode->i_mode)); - n_err = sync_mapping_buffers(p_s_inode->i_mapping); - reiserfs_write_lock(p_s_inode->i_sb); - barrier_done = reiserfs_commit_for_inode(p_s_inode); - reiserfs_write_unlock(p_s_inode->i_sb); - if (barrier_done != 1 && reiserfs_barrier_flush(p_s_inode->i_sb)) - blkdev_issue_flush(p_s_inode->i_sb->s_bdev, NULL); + BUG_ON(!S_ISREG(inode->i_mode)); + err = sync_mapping_buffers(inode->i_mapping); + reiserfs_write_lock(inode->i_sb); + barrier_done = reiserfs_commit_for_inode(inode); + reiserfs_write_unlock(inode->i_sb); + if (barrier_done != 1 && reiserfs_barrier_flush(inode->i_sb)) + blkdev_issue_flush(inode->i_sb->s_bdev, NULL); if (barrier_done < 0) return barrier_done; - return (n_err < 0) ? -EIO : 0; + return (err < 0) ? -EIO : 0; } /* taken fs/buffer.c:__block_commit_write */ @@ -223,7 +223,7 @@ int reiserfs_commit_page(struct inode *inode, struct page *page, } /* Write @count bytes at position @ppos in a file indicated by @file - from the buffer @buf. + from the buffer @buf. generic_file_write() is only appropriate for filesystems that are not seeking to optimize performance and want something simple that works. It is not for serious use by general purpose filesystems, excepting the one that it was diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c index 07d05e0842b..5e5a4e6fbaf 100644 --- a/fs/reiserfs/fix_node.c +++ b/fs/reiserfs/fix_node.c @@ -30,8 +30,8 @@ ** get_direct_parent ** get_neighbors ** fix_nodes - ** - ** + ** + ** **/ #include <linux/time.h> @@ -135,8 +135,7 @@ static void create_virtual_node(struct tree_balance *tb, int h) vn->vn_free_ptr += op_create_vi(vn, vi, is_affected, tb->insert_size[0]); if (tb->vn_buf + tb->vn_buf_size < vn->vn_free_ptr) - reiserfs_panic(tb->tb_sb, - "vs-8030: create_virtual_node: " + reiserfs_panic(tb->tb_sb, "vs-8030", "virtual node space consumed"); if (!is_affected) @@ -186,8 +185,9 @@ static void create_virtual_node(struct tree_balance *tb, int h) && I_ENTRY_COUNT(B_N_PITEM_HEAD(Sh, 0)) == 1)) { /* node contains more than 1 item, or item is not directory item, or this item contains more than 1 entry */ print_block(Sh, 0, -1, -1); - reiserfs_panic(tb->tb_sb, - "vs-8045: create_virtual_node: rdkey %k, affected item==%d (mode==%c) Must be %c", + reiserfs_panic(tb->tb_sb, "vs-8045", + "rdkey %k, affected item==%d " + "(mode==%c) Must be %c", key, vn->vn_affected_item_num, vn->vn_mode, M_DELETE); } @@ -377,9 +377,9 @@ static int get_num_ver(int mode, struct tree_balance *tb, int h, int needed_nodes; int start_item, /* position of item we start filling node from */ end_item, /* position of item we finish filling node by */ - start_bytes, /* number of first bytes (entries for directory) of start_item-th item + start_bytes, /* number of first bytes (entries for directory) of start_item-th item we do not include into node that is being filled */ - end_bytes; /* number of last bytes (entries for directory) of end_item-th item + end_bytes; /* number of last bytes (entries for directory) of end_item-th item we do node include into node that is being filled */ int split_item_positions[2]; /* these are positions in virtual item of items, that are split between S[0] and @@ -496,8 +496,8 @@ static int get_num_ver(int mode, struct tree_balance *tb, int h, snum012[needed_nodes - 1 + 3] = units; if (needed_nodes > 2) - reiserfs_warning(tb->tb_sb, "vs-8111: get_num_ver: " - "split_item_position is out of boundary"); + reiserfs_warning(tb->tb_sb, "vs-8111", + "split_item_position is out of range"); snum012[needed_nodes - 1]++; split_item_positions[needed_nodes - 1] = i; needed_nodes++; @@ -533,8 +533,8 @@ static int get_num_ver(int mode, struct tree_balance *tb, int h, if (vn->vn_vi[split_item_num].vi_index != TYPE_DIRENTRY && vn->vn_vi[split_item_num].vi_index != TYPE_INDIRECT) - reiserfs_warning(tb->tb_sb, "vs-8115: get_num_ver: not " - "directory or indirect item"); + reiserfs_warning(tb->tb_sb, "vs-8115", + "not directory or indirect item"); } /* now we know S2bytes, calculate S1bytes */ @@ -569,7 +569,7 @@ extern struct tree_balance *cur_tb; /* Set parameters for balancing. * Performs write of results of analysis of balancing into structure tb, - * where it will later be used by the functions that actually do the balancing. + * where it will later be used by the functions that actually do the balancing. * Parameters: * tb tree_balance structure; * h current level of the node; @@ -749,25 +749,26 @@ else \ -1, -1);\ } -static void free_buffers_in_tb(struct tree_balance *p_s_tb) +static void free_buffers_in_tb(struct tree_balance *tb) { - int n_counter; - - decrement_counters_in_path(p_s_tb->tb_path); - - for (n_counter = 0; n_counter < MAX_HEIGHT; n_counter++) { - decrement_bcount(p_s_tb->L[n_counter]); - p_s_tb->L[n_counter] = NULL; - decrement_bcount(p_s_tb->R[n_counter]); - p_s_tb->R[n_counter] = NULL; - decrement_bcount(p_s_tb->FL[n_counter]); - p_s_tb->FL[n_counter] = NULL; - decrement_bcount(p_s_tb->FR[n_counter]); - p_s_tb->FR[n_counter] = NULL; - decrement_bcount(p_s_tb->CFL[n_counter]); - p_s_tb->CFL[n_counter] = NULL; - decrement_bcount(p_s_tb->CFR[n_counter]); - p_s_tb->CFR[n_counter] = NULL; + int i; + + pathrelse(tb->tb_path); + + for (i = 0; i < MAX_HEIGHT; i++) { + brelse(tb->L[i]); + brelse(tb->R[i]); + brelse(tb->FL[i]); + brelse(tb->FR[i]); + brelse(tb->CFL[i]); + brelse(tb->CFR[i]); + + tb->L[i] = NULL; + tb->R[i] = NULL; + tb->FL[i] = NULL; + tb->FR[i] = NULL; + tb->CFL[i] = NULL; + tb->CFR[i] = NULL; } } @@ -777,14 +778,14 @@ static void free_buffers_in_tb(struct tree_balance *p_s_tb) * NO_DISK_SPACE - no disk space. */ /* The function is NOT SCHEDULE-SAFE! */ -static int get_empty_nodes(struct tree_balance *p_s_tb, int n_h) +static int get_empty_nodes(struct tree_balance *tb, int h) { - struct buffer_head *p_s_new_bh, - *p_s_Sh = PATH_H_PBUFFER(p_s_tb->tb_path, n_h); - b_blocknr_t *p_n_blocknr, a_n_blocknrs[MAX_AMOUNT_NEEDED] = { 0, }; - int n_counter, n_number_of_freeblk, n_amount_needed, /* number of needed empty blocks */ - n_retval = CARRY_ON; - struct super_block *p_s_sb = p_s_tb->tb_sb; + struct buffer_head *new_bh, + *Sh = PATH_H_PBUFFER(tb->tb_path, h); + b_blocknr_t *blocknr, blocknrs[MAX_AMOUNT_NEEDED] = { 0, }; + int counter, number_of_freeblk, amount_needed, /* number of needed empty blocks */ + retval = CARRY_ON; + struct super_block *sb = tb->tb_sb; /* number_of_freeblk is the number of empty blocks which have been acquired for use by the balancing algorithm minus the number of @@ -792,7 +793,7 @@ static int get_empty_nodes(struct tree_balance *p_s_tb, int n_h) number_of_freeblk = tb->cur_blknum can be non-zero if a schedule occurs after empty blocks are acquired, and the balancing analysis is then restarted, amount_needed is the number needed by this level - (n_h) of the balancing analysis. + (h) of the balancing analysis. Note that for systems with many processes writing, it would be more layout optimal to calculate the total number needed by all @@ -800,54 +801,54 @@ static int get_empty_nodes(struct tree_balance *p_s_tb, int n_h) /* Initiate number_of_freeblk to the amount acquired prior to the restart of the analysis or 0 if not restarted, then subtract the amount needed - by all of the levels of the tree below n_h. */ - /* blknum includes S[n_h], so we subtract 1 in this calculation */ - for (n_counter = 0, n_number_of_freeblk = p_s_tb->cur_blknum; - n_counter < n_h; n_counter++) - n_number_of_freeblk -= - (p_s_tb->blknum[n_counter]) ? (p_s_tb->blknum[n_counter] - + by all of the levels of the tree below h. */ + /* blknum includes S[h], so we subtract 1 in this calculation */ + for (counter = 0, number_of_freeblk = tb->cur_blknum; + counter < h; counter++) + number_of_freeblk -= + (tb->blknum[counter]) ? (tb->blknum[counter] - 1) : 0; /* Allocate missing empty blocks. */ - /* if p_s_Sh == 0 then we are getting a new root */ - n_amount_needed = (p_s_Sh) ? (p_s_tb->blknum[n_h] - 1) : 1; + /* if Sh == 0 then we are getting a new root */ + amount_needed = (Sh) ? (tb->blknum[h] - 1) : 1; /* Amount_needed = the amount that we need more than the amount that we have. */ - if (n_amount_needed > n_number_of_freeblk) - n_amount_needed -= n_number_of_freeblk; + if (amount_needed > number_of_freeblk) + amount_needed -= number_of_freeblk; else /* If we have enough already then there is nothing to do. */ return CARRY_ON; /* No need to check quota - is not allocated for blocks used for formatted nodes */ - if (reiserfs_new_form_blocknrs(p_s_tb, a_n_blocknrs, - n_amount_needed) == NO_DISK_SPACE) + if (reiserfs_new_form_blocknrs(tb, blocknrs, + amount_needed) == NO_DISK_SPACE) return NO_DISK_SPACE; /* for each blocknumber we just got, get a buffer and stick it on FEB */ - for (p_n_blocknr = a_n_blocknrs, n_counter = 0; - n_counter < n_amount_needed; p_n_blocknr++, n_counter++) { + for (blocknr = blocknrs, counter = 0; + counter < amount_needed; blocknr++, counter++) { - RFALSE(!*p_n_blocknr, + RFALSE(!*blocknr, "PAP-8135: reiserfs_new_blocknrs failed when got new blocks"); - p_s_new_bh = sb_getblk(p_s_sb, *p_n_blocknr); - RFALSE(buffer_dirty(p_s_new_bh) || - buffer_journaled(p_s_new_bh) || - buffer_journal_dirty(p_s_new_bh), + new_bh = sb_getblk(sb, *blocknr); + RFALSE(buffer_dirty(new_bh) || + buffer_journaled(new_bh) || + buffer_journal_dirty(new_bh), "PAP-8140: journlaled or dirty buffer %b for the new block", - p_s_new_bh); + new_bh); /* Put empty buffers into the array. */ - RFALSE(p_s_tb->FEB[p_s_tb->cur_blknum], + RFALSE(tb->FEB[tb->cur_blknum], "PAP-8141: busy slot for new buffer"); - set_buffer_journal_new(p_s_new_bh); - p_s_tb->FEB[p_s_tb->cur_blknum++] = p_s_new_bh; + set_buffer_journal_new(new_bh); + tb->FEB[tb->cur_blknum++] = new_bh; } - if (n_retval == CARRY_ON && FILESYSTEM_CHANGED_TB(p_s_tb)) - n_retval = REPEAT_SEARCH; + if (retval == CARRY_ON && FILESYSTEM_CHANGED_TB(tb)) + retval = REPEAT_SEARCH; - return n_retval; + return retval; } /* Get free space of the left neighbor, which is stored in the parent @@ -895,35 +896,36 @@ static int get_rfree(struct tree_balance *tb, int h) } /* Check whether left neighbor is in memory. */ -static int is_left_neighbor_in_cache(struct tree_balance *p_s_tb, int n_h) +static int is_left_neighbor_in_cache(struct tree_balance *tb, int h) { - struct buffer_head *p_s_father, *left; - struct super_block *p_s_sb = p_s_tb->tb_sb; - b_blocknr_t n_left_neighbor_blocknr; - int n_left_neighbor_position; + struct buffer_head *father, *left; + struct super_block *sb = tb->tb_sb; + b_blocknr_t left_neighbor_blocknr; + int left_neighbor_position; - if (!p_s_tb->FL[n_h]) /* Father of the left neighbor does not exist. */ + /* Father of the left neighbor does not exist. */ + if (!tb->FL[h]) return 0; /* Calculate father of the node to be balanced. */ - p_s_father = PATH_H_PBUFFER(p_s_tb->tb_path, n_h + 1); + father = PATH_H_PBUFFER(tb->tb_path, h + 1); - RFALSE(!p_s_father || - !B_IS_IN_TREE(p_s_father) || - !B_IS_IN_TREE(p_s_tb->FL[n_h]) || - !buffer_uptodate(p_s_father) || - !buffer_uptodate(p_s_tb->FL[n_h]), + RFALSE(!father || + !B_IS_IN_TREE(father) || + !B_IS_IN_TREE(tb->FL[h]) || + !buffer_uptodate(father) || + !buffer_uptodate(tb->FL[h]), "vs-8165: F[h] (%b) or FL[h] (%b) is invalid", - p_s_father, p_s_tb->FL[n_h]); + father, tb->FL[h]); /* Get position of the pointer to the left neighbor into the left father. */ - n_left_neighbor_position = (p_s_father == p_s_tb->FL[n_h]) ? - p_s_tb->lkey[n_h] : B_NR_ITEMS(p_s_tb->FL[n_h]); + left_neighbor_position = (father == tb->FL[h]) ? + tb->lkey[h] : B_NR_ITEMS(tb->FL[h]); /* Get left neighbor block number. */ - n_left_neighbor_blocknr = - B_N_CHILD_NUM(p_s_tb->FL[n_h], n_left_neighbor_position); + left_neighbor_blocknr = + B_N_CHILD_NUM(tb->FL[h], left_neighbor_position); /* Look for the left neighbor in the cache. */ - if ((left = sb_find_get_block(p_s_sb, n_left_neighbor_blocknr))) { + if ((left = sb_find_get_block(sb, left_neighbor_blocknr))) { RFALSE(buffer_uptodate(left) && !B_IS_IN_TREE(left), "vs-8170: left neighbor (%b %z) is not in the tree", @@ -938,10 +940,10 @@ static int is_left_neighbor_in_cache(struct tree_balance *p_s_tb, int n_h) #define LEFT_PARENTS 'l' #define RIGHT_PARENTS 'r' -static void decrement_key(struct cpu_key *p_s_key) +static void decrement_key(struct cpu_key *key) { // call item specific function for this key - item_ops[cpu_key_k_type(p_s_key)]->decrement_key(p_s_key); + item_ops[cpu_key_k_type(key)]->decrement_key(key); } /* Calculate far left/right parent of the left/right neighbor of the current node, that @@ -952,77 +954,77 @@ static void decrement_key(struct cpu_key *p_s_key) SCHEDULE_OCCURRED - schedule occurred while the function worked; * CARRY_ON - schedule didn't occur while the function worked; */ -static int get_far_parent(struct tree_balance *p_s_tb, - int n_h, - struct buffer_head **pp_s_father, - struct buffer_head **pp_s_com_father, char c_lr_par) +static int get_far_parent(struct tree_balance *tb, + int h, + struct buffer_head **pfather, + struct buffer_head **pcom_father, char c_lr_par) { - struct buffer_head *p_s_parent; + struct buffer_head *parent; INITIALIZE_PATH(s_path_to_neighbor_father); - struct treepath *p_s_path = p_s_tb->tb_path; + struct treepath *path = tb->tb_path; struct cpu_key s_lr_father_key; - int n_counter, - n_position = INT_MAX, - n_first_last_position = 0, - n_path_offset = PATH_H_PATH_OFFSET(p_s_path, n_h); + int counter, + position = INT_MAX, + first_last_position = 0, + path_offset = PATH_H_PATH_OFFSET(path, h); - /* Starting from F[n_h] go upwards in the tree, and look for the common - ancestor of F[n_h], and its neighbor l/r, that should be obtained. */ + /* Starting from F[h] go upwards in the tree, and look for the common + ancestor of F[h], and its neighbor l/r, that should be obtained. */ - n_counter = n_path_offset; + counter = path_offset; - RFALSE(n_counter < FIRST_PATH_ELEMENT_OFFSET, + RFALSE(counter < FIRST_PATH_ELEMENT_OFFSET, "PAP-8180: invalid path length"); - for (; n_counter > FIRST_PATH_ELEMENT_OFFSET; n_counter--) { + for (; counter > FIRST_PATH_ELEMENT_OFFSET; counter--) { /* Check whether parent of the current buffer in the path is really parent in the tree. */ if (!B_IS_IN_TREE - (p_s_parent = PATH_OFFSET_PBUFFER(p_s_path, n_counter - 1))) + (parent = PATH_OFFSET_PBUFFER(path, counter - 1))) return REPEAT_SEARCH; /* Check whether position in the parent is correct. */ - if ((n_position = - PATH_OFFSET_POSITION(p_s_path, - n_counter - 1)) > - B_NR_ITEMS(p_s_parent)) + if ((position = + PATH_OFFSET_POSITION(path, + counter - 1)) > + B_NR_ITEMS(parent)) return REPEAT_SEARCH; /* Check whether parent at the path really points to the child. */ - if (B_N_CHILD_NUM(p_s_parent, n_position) != - PATH_OFFSET_PBUFFER(p_s_path, n_counter)->b_blocknr) + if (B_N_CHILD_NUM(parent, position) != + PATH_OFFSET_PBUFFER(path, counter)->b_blocknr) return REPEAT_SEARCH; /* Return delimiting key if position in the parent is not equal to first/last one. */ if (c_lr_par == RIGHT_PARENTS) - n_first_last_position = B_NR_ITEMS(p_s_parent); - if (n_position != n_first_last_position) { - *pp_s_com_father = p_s_parent; - get_bh(*pp_s_com_father); - /*(*pp_s_com_father = p_s_parent)->b_count++; */ + first_last_position = B_NR_ITEMS(parent); + if (position != first_last_position) { + *pcom_father = parent; + get_bh(*pcom_father); + /*(*pcom_father = parent)->b_count++; */ break; } } /* if we are in the root of the tree, then there is no common father */ - if (n_counter == FIRST_PATH_ELEMENT_OFFSET) { + if (counter == FIRST_PATH_ELEMENT_OFFSET) { /* Check whether first buffer in the path is the root of the tree. */ if (PATH_OFFSET_PBUFFER - (p_s_tb->tb_path, + (tb->tb_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr == - SB_ROOT_BLOCK(p_s_tb->tb_sb)) { - *pp_s_father = *pp_s_com_father = NULL; + SB_ROOT_BLOCK(tb->tb_sb)) { + *pfather = *pcom_father = NULL; return CARRY_ON; } return REPEAT_SEARCH; } - RFALSE(B_LEVEL(*pp_s_com_father) <= DISK_LEAF_NODE_LEVEL, + RFALSE(B_LEVEL(*pcom_father) <= DISK_LEAF_NODE_LEVEL, "PAP-8185: (%b %z) level too small", - *pp_s_com_father, *pp_s_com_father); + *pcom_father, *pcom_father); /* Check whether the common parent is locked. */ - if (buffer_locked(*pp_s_com_father)) { - __wait_on_buffer(*pp_s_com_father); - if (FILESYSTEM_CHANGED_TB(p_s_tb)) { - decrement_bcount(*pp_s_com_father); + if (buffer_locked(*pcom_father)) { + __wait_on_buffer(*pcom_father); + if (FILESYSTEM_CHANGED_TB(tb)) { + brelse(*pcom_father); return REPEAT_SEARCH; } } @@ -1032,128 +1034,131 @@ static int get_far_parent(struct tree_balance *p_s_tb, /* Form key to get parent of the left/right neighbor. */ le_key2cpu_key(&s_lr_father_key, - B_N_PDELIM_KEY(*pp_s_com_father, + B_N_PDELIM_KEY(*pcom_father, (c_lr_par == - LEFT_PARENTS) ? (p_s_tb->lkey[n_h - 1] = - n_position - - 1) : (p_s_tb->rkey[n_h - + LEFT_PARENTS) ? (tb->lkey[h - 1] = + position - + 1) : (tb->rkey[h - 1] = - n_position))); + position))); if (c_lr_par == LEFT_PARENTS) decrement_key(&s_lr_father_key); if (search_by_key - (p_s_tb->tb_sb, &s_lr_father_key, &s_path_to_neighbor_father, - n_h + 1) == IO_ERROR) + (tb->tb_sb, &s_lr_father_key, &s_path_to_neighbor_father, + h + 1) == IO_ERROR) // path is released return IO_ERROR; - if (FILESYSTEM_CHANGED_TB(p_s_tb)) { - decrement_counters_in_path(&s_path_to_neighbor_father); - decrement_bcount(*pp_s_com_father); + if (FILESYSTEM_CHANGED_TB(tb)) { + pathrelse(&s_path_to_neighbor_father); + brelse(*pcom_father); return REPEAT_SEARCH; } - *pp_s_father = PATH_PLAST_BUFFER(&s_path_to_neighbor_father); + *pfather = PATH_PLAST_BUFFER(&s_path_to_neighbor_father); - RFALSE(B_LEVEL(*pp_s_father) != n_h + 1, - "PAP-8190: (%b %z) level too small", *pp_s_father, *pp_s_father); + RFALSE(B_LEVEL(*pfather) != h + 1, + "PAP-8190: (%b %z) level too small", *pfather, *pfather); RFALSE(s_path_to_neighbor_father.path_length < FIRST_PATH_ELEMENT_OFFSET, "PAP-8192: path length is too small"); s_path_to_neighbor_father.path_length--; - decrement_counters_in_path(&s_path_to_neighbor_father); + pathrelse(&s_path_to_neighbor_father); return CARRY_ON; } -/* Get parents of neighbors of node in the path(S[n_path_offset]) and common parents of - * S[n_path_offset] and L[n_path_offset]/R[n_path_offset]: F[n_path_offset], FL[n_path_offset], - * FR[n_path_offset], CFL[n_path_offset], CFR[n_path_offset]. - * Calculate numbers of left and right delimiting keys position: lkey[n_path_offset], rkey[n_path_offset]. +/* Get parents of neighbors of node in the path(S[path_offset]) and common parents of + * S[path_offset] and L[path_offset]/R[path_offset]: F[path_offset], FL[path_offset], + * FR[path_offset], CFL[path_offset], CFR[path_offset]. + * Calculate numbers of left and right delimiting keys position: lkey[path_offset], rkey[path_offset]. * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; * CARRY_ON - schedule didn't occur while the function worked; */ -static int get_parents(struct tree_balance *p_s_tb, int n_h) +static int get_parents(struct tree_balance *tb, int h) { - struct treepath *p_s_path = p_s_tb->tb_path; - int n_position, - n_ret_value, - n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h); - struct buffer_head *p_s_curf, *p_s_curcf; + struct treepath *path = tb->tb_path; + int position, + ret, + path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h); + struct buffer_head *curf, *curcf; /* Current node is the root of the tree or will be root of the tree */ - if (n_path_offset <= FIRST_PATH_ELEMENT_OFFSET) { + if (path_offset <= FIRST_PATH_ELEMENT_OFFSET) { /* The root can not have parents. Release nodes which previously were obtained as parents of the current node neighbors. */ - decrement_bcount(p_s_tb->FL[n_h]); - decrement_bcount(p_s_tb->CFL[n_h]); - decrement_bcount(p_s_tb->FR[n_h]); - decrement_bcount(p_s_tb->CFR[n_h]); - p_s_tb->FL[n_h] = p_s_tb->CFL[n_h] = p_s_tb->FR[n_h] = - p_s_tb->CFR[n_h] = NULL; + brelse(tb->FL[h]); + brelse(tb->CFL[h]); + brelse(tb->FR[h]); + brelse(tb->CFR[h]); + tb->FL[h] = NULL; + tb->CFL[h] = NULL; + tb->FR[h] = NULL; + tb->CFR[h] = NULL; return CARRY_ON; } - /* Get parent FL[n_path_offset] of L[n_path_offset]. */ - if ((n_position = PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1))) { + /* Get parent FL[path_offset] of L[path_offset]. */ + position = PATH_OFFSET_POSITION(path, path_offset - 1); + if (position) { /* Current node is not the first child of its parent. */ - /*(p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2; */ - p_s_curf = p_s_curcf = - PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1); - get_bh(p_s_curf); - get_bh(p_s_curf); - p_s_tb->lkey[n_h] = n_position - 1; + curf = PATH_OFFSET_PBUFFER(path, path_offset - 1); + curcf = PATH_OFFSET_PBUFFER(path, path_offset - 1); + get_bh(curf); + get_bh(curf); + tb->lkey[h] = position - 1; } else { - /* Calculate current parent of L[n_path_offset], which is the left neighbor of the current node. - Calculate current common parent of L[n_path_offset] and the current node. Note that - CFL[n_path_offset] not equal FL[n_path_offset] and CFL[n_path_offset] not equal F[n_path_offset]. - Calculate lkey[n_path_offset]. */ - if ((n_ret_value = get_far_parent(p_s_tb, n_h + 1, &p_s_curf, - &p_s_curcf, + /* Calculate current parent of L[path_offset], which is the left neighbor of the current node. + Calculate current common parent of L[path_offset] and the current node. Note that + CFL[path_offset] not equal FL[path_offset] and CFL[path_offset] not equal F[path_offset]. + Calculate lkey[path_offset]. */ + if ((ret = get_far_parent(tb, h + 1, &curf, + &curcf, LEFT_PARENTS)) != CARRY_ON) - return n_ret_value; + return ret; } - decrement_bcount(p_s_tb->FL[n_h]); - p_s_tb->FL[n_h] = p_s_curf; /* New initialization of FL[n_h]. */ - decrement_bcount(p_s_tb->CFL[n_h]); - p_s_tb->CFL[n_h] = p_s_curcf; /* New initialization of CFL[n_h]. */ + brelse(tb->FL[h]); + tb->FL[h] = curf; /* New initialization of FL[h]. */ + brelse(tb->CFL[h]); + tb->CFL[h] = curcf; /* New initialization of CFL[h]. */ - RFALSE((p_s_curf && !B_IS_IN_TREE(p_s_curf)) || - (p_s_curcf && !B_IS_IN_TREE(p_s_curcf)), - "PAP-8195: FL (%b) or CFL (%b) is invalid", p_s_curf, p_s_curcf); + RFALSE((curf && !B_IS_IN_TREE(curf)) || + (curcf && !B_IS_IN_TREE(curcf)), + "PAP-8195: FL (%b) or CFL (%b) is invalid", curf, curcf); -/* Get parent FR[n_h] of R[n_h]. */ +/* Get parent FR[h] of R[h]. */ -/* Current node is the last child of F[n_h]. FR[n_h] != F[n_h]. */ - if (n_position == B_NR_ITEMS(PATH_H_PBUFFER(p_s_path, n_h + 1))) { -/* Calculate current parent of R[n_h], which is the right neighbor of F[n_h]. - Calculate current common parent of R[n_h] and current node. Note that CFR[n_h] - not equal FR[n_path_offset] and CFR[n_h] not equal F[n_h]. */ - if ((n_ret_value = - get_far_parent(p_s_tb, n_h + 1, &p_s_curf, &p_s_curcf, +/* Current node is the last child of F[h]. FR[h] != F[h]. */ + if (position == B_NR_ITEMS(PATH_H_PBUFFER(path, h + 1))) { +/* Calculate current parent of R[h], which is the right neighbor of F[h]. + Calculate current common parent of R[h] and current node. Note that CFR[h] + not equal FR[path_offset] and CFR[h] not equal F[h]. */ + if ((ret = + get_far_parent(tb, h + 1, &curf, &curcf, RIGHT_PARENTS)) != CARRY_ON) - return n_ret_value; + return ret; } else { -/* Current node is not the last child of its parent F[n_h]. */ - /*(p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2; */ - p_s_curf = p_s_curcf = - PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1); - get_bh(p_s_curf); - get_bh(p_s_curf); - p_s_tb->rkey[n_h] = n_position; +/* Current node is not the last child of its parent F[h]. */ + curf = PATH_OFFSET_PBUFFER(path, path_offset - 1); + curcf = PATH_OFFSET_PBUFFER(path, path_offset - 1); + get_bh(curf); + get_bh(curf); + tb->rkey[h] = position; } - decrement_bcount(p_s_tb->FR[n_h]); - p_s_tb->FR[n_h] = p_s_curf; /* New initialization of FR[n_path_offset]. */ + brelse(tb->FR[h]); + /* New initialization of FR[path_offset]. */ + tb->FR[h] = curf; - decrement_bcount(p_s_tb->CFR[n_h]); - p_s_tb->CFR[n_h] = p_s_curcf; /* New initialization of CFR[n_path_offset]. */ + brelse(tb->CFR[h]); + /* New initialization of CFR[path_offset]. */ + tb->CFR[h] = curcf; - RFALSE((p_s_curf && !B_IS_IN_TREE(p_s_curf)) || - (p_s_curcf && !B_IS_IN_TREE(p_s_curcf)), - "PAP-8205: FR (%b) or CFR (%b) is invalid", p_s_curf, p_s_curcf); + RFALSE((curf && !B_IS_IN_TREE(curf)) || + (curcf && !B_IS_IN_TREE(curcf)), + "PAP-8205: FR (%b) or CFR (%b) is invalid", curf, curcf); return CARRY_ON; } @@ -1203,7 +1208,7 @@ static inline int can_node_be_removed(int mode, int lfree, int sfree, int rfree, * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste; - * Returns: 1 - schedule occurred; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1217,7 +1222,7 @@ static int ip_check_balance(struct tree_balance *tb, int h) contains node being balanced. The mnemonic is that the attempted change in node space used level is levbytes bytes. */ - n_ret_value; + ret; int lfree, sfree, rfree /* free space in L, S and R */ ; @@ -1238,7 +1243,7 @@ static int ip_check_balance(struct tree_balance *tb, int h) /* we perform 8 calls to get_num_ver(). For each call we calculate five parameters. where 4th parameter is s1bytes and 5th - s2bytes */ - short snum012[40] = { 0, }; /* s0num, s1num, s2num for 8 cases + short snum012[40] = { 0, }; /* s0num, s1num, s2num for 8 cases 0,1 - do not shift and do not shift but bottle 2 - shift only whole item to left 3 - shift to left and bottle as much as possible @@ -1255,24 +1260,24 @@ static int ip_check_balance(struct tree_balance *tb, int h) /* Calculate balance parameters for creating new root. */ if (!Sh) { if (!h) - reiserfs_panic(tb->tb_sb, - "vs-8210: ip_check_balance: S[0] can not be 0"); - switch (n_ret_value = get_empty_nodes(tb, h)) { + reiserfs_panic(tb->tb_sb, "vs-8210", + "S[0] can not be 0"); + switch (ret = get_empty_nodes(tb, h)) { case CARRY_ON: set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); return NO_BALANCING_NEEDED; /* no balancing for higher levels needed */ case NO_DISK_SPACE: case REPEAT_SEARCH: - return n_ret_value; + return ret; default: - reiserfs_panic(tb->tb_sb, - "vs-8215: ip_check_balance: incorrect return value of get_empty_nodes"); + reiserfs_panic(tb->tb_sb, "vs-8215", "incorrect " + "return value of get_empty_nodes"); } } - if ((n_ret_value = get_parents(tb, h)) != CARRY_ON) /* get parents of S[h] neighbors. */ - return n_ret_value; + if ((ret = get_parents(tb, h)) != CARRY_ON) /* get parents of S[h] neighbors. */ + return ret; sfree = B_FREE_SPACE(Sh); @@ -1287,7 +1292,7 @@ static int ip_check_balance(struct tree_balance *tb, int h) create_virtual_node(tb, h); - /* + /* determine maximal number of items we can shift to the left neighbor (in tb structure) and the maximal number of bytes that can flow to the left neighbor from the left most liquid item that cannot be shifted from S[0] entirely (returned value) @@ -1348,13 +1353,13 @@ static int ip_check_balance(struct tree_balance *tb, int h) { int lpar, rpar, nset, lset, rset, lrset; - /* + /* * regular overflowing of the node */ - /* get_num_ver works in 2 modes (FLOW & NO_FLOW) + /* get_num_ver works in 2 modes (FLOW & NO_FLOW) lpar, rpar - number of items we can shift to left/right neighbor (including splitting item) - nset, lset, rset, lrset - shows, whether flowing items give better packing + nset, lset, rset, lrset - shows, whether flowing items give better packing */ #define FLOW 1 #define NO_FLOW 0 /* do not any splitting */ @@ -1544,7 +1549,7 @@ static int ip_check_balance(struct tree_balance *tb, int h) * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste; - * Returns: 1 - schedule occurred; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1559,7 +1564,7 @@ static int dc_check_balance_internal(struct tree_balance *tb, int h) /* Sh is the node whose balance is currently being checked, and Fh is its father. */ struct buffer_head *Sh, *Fh; - int maxsize, n_ret_value; + int maxsize, ret; int lfree, rfree /* free space in L and R */ ; Sh = PATH_H_PBUFFER(tb->tb_path, h); @@ -1584,8 +1589,8 @@ static int dc_check_balance_internal(struct tree_balance *tb, int h) return CARRY_ON; } - if ((n_ret_value = get_parents(tb, h)) != CARRY_ON) - return n_ret_value; + if ((ret = get_parents(tb, h)) != CARRY_ON) + return ret; /* get free space of neighbors */ rfree = get_rfree(tb, h); @@ -1727,7 +1732,7 @@ static int dc_check_balance_internal(struct tree_balance *tb, int h) * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste; - * Returns: 1 - schedule occurred; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1742,7 +1747,7 @@ static int dc_check_balance_leaf(struct tree_balance *tb, int h) attempted change in node space used level is levbytes bytes. */ int levbytes; /* the maximal item size */ - int maxsize, n_ret_value; + int maxsize, ret; /* S0 is the node whose balance is currently being checked, and F0 is its father. */ struct buffer_head *S0, *F0; @@ -1764,8 +1769,8 @@ static int dc_check_balance_leaf(struct tree_balance *tb, int h) return NO_BALANCING_NEEDED; } - if ((n_ret_value = get_parents(tb, h)) != CARRY_ON) - return n_ret_value; + if ((ret = get_parents(tb, h)) != CARRY_ON) + return ret; /* get free space of neighbors */ rfree = get_rfree(tb, h); @@ -1821,7 +1826,7 @@ static int dc_check_balance_leaf(struct tree_balance *tb, int h) * h current level of the node; * inum item number in S[h]; * mode d - delete, c - cut. - * Returns: 1 - schedule occurred; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1850,7 +1855,7 @@ static int dc_check_balance(struct tree_balance *tb, int h) * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste, d - delete, c - cut. - * Returns: 1 - schedule occurred; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1884,137 +1889,138 @@ static int check_balance(int mode, } /* Check whether parent at the path is the really parent of the current node.*/ -static int get_direct_parent(struct tree_balance *p_s_tb, int n_h) +static int get_direct_parent(struct tree_balance *tb, int h) { - struct buffer_head *p_s_bh; - struct treepath *p_s_path = p_s_tb->tb_path; - int n_position, - n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h); + struct buffer_head *bh; + struct treepath *path = tb->tb_path; + int position, + path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h); /* We are in the root or in the new root. */ - if (n_path_offset <= FIRST_PATH_ELEMENT_OFFSET) { + if (path_offset <= FIRST_PATH_ELEMENT_OFFSET) { - RFALSE(n_path_offset < FIRST_PATH_ELEMENT_OFFSET - 1, + RFALSE(path_offset < FIRST_PATH_ELEMENT_OFFSET - 1, "PAP-8260: invalid offset in the path"); - if (PATH_OFFSET_PBUFFER(p_s_path, FIRST_PATH_ELEMENT_OFFSET)-> - b_blocknr == SB_ROOT_BLOCK(p_s_tb->tb_sb)) { + if (PATH_OFFSET_PBUFFER(path, FIRST_PATH_ELEMENT_OFFSET)-> + b_blocknr == SB_ROOT_BLOCK(tb->tb_sb)) { /* Root is not changed. */ - PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1) = NULL; - PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1) = 0; + PATH_OFFSET_PBUFFER(path, path_offset - 1) = NULL; + PATH_OFFSET_POSITION(path, path_offset - 1) = 0; return CARRY_ON; } return REPEAT_SEARCH; /* Root is changed and we must recalculate the path. */ } if (!B_IS_IN_TREE - (p_s_bh = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))) + (bh = PATH_OFFSET_PBUFFER(path, path_offset - 1))) return REPEAT_SEARCH; /* Parent in the path is not in the tree. */ - if ((n_position = - PATH_OFFSET_POSITION(p_s_path, - n_path_offset - 1)) > B_NR_ITEMS(p_s_bh)) + if ((position = + PATH_OFFSET_POSITION(path, + path_offset - 1)) > B_NR_ITEMS(bh)) return REPEAT_SEARCH; - if (B_N_CHILD_NUM(p_s_bh, n_position) != - PATH_OFFSET_PBUFFER(p_s_path, n_path_offset)->b_blocknr) + if (B_N_CHILD_NUM(bh, position) != + PATH_OFFSET_PBUFFER(path, path_offset)->b_blocknr) /* Parent in the path is not parent of the current node in the tree. */ return REPEAT_SEARCH; - if (buffer_locked(p_s_bh)) { - __wait_on_buffer(p_s_bh); - if (FILESYSTEM_CHANGED_TB(p_s_tb)) + if (buffer_locked(bh)) { + __wait_on_buffer(bh); + if (FILESYSTEM_CHANGED_TB(tb)) return REPEAT_SEARCH; } return CARRY_ON; /* Parent in the path is unlocked and really parent of the current node. */ } -/* Using lnum[n_h] and rnum[n_h] we should determine what neighbors - * of S[n_h] we - * need in order to balance S[n_h], and get them if necessary. +/* Using lnum[h] and rnum[h] we should determine what neighbors + * of S[h] we + * need in order to balance S[h], and get them if necessary. * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; * CARRY_ON - schedule didn't occur while the function worked; */ -static int get_neighbors(struct tree_balance *p_s_tb, int n_h) +static int get_neighbors(struct tree_balance *tb, int h) { - int n_child_position, - n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h + 1); - unsigned long n_son_number; - struct super_block *p_s_sb = p_s_tb->tb_sb; - struct buffer_head *p_s_bh; + int child_position, + path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h + 1); + unsigned long son_number; + struct super_block *sb = tb->tb_sb; + struct buffer_head *bh; - PROC_INFO_INC(p_s_sb, get_neighbors[n_h]); + PROC_INFO_INC(sb, get_neighbors[h]); - if (p_s_tb->lnum[n_h]) { - /* We need left neighbor to balance S[n_h]. */ - PROC_INFO_INC(p_s_sb, need_l_neighbor[n_h]); - p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset); + if (tb->lnum[h]) { + /* We need left neighbor to balance S[h]. */ + PROC_INFO_INC(sb, need_l_neighbor[h]); + bh = PATH_OFFSET_PBUFFER(tb->tb_path, path_offset); - RFALSE(p_s_bh == p_s_tb->FL[n_h] && - !PATH_OFFSET_POSITION(p_s_tb->tb_path, n_path_offset), + RFALSE(bh == tb->FL[h] && + !PATH_OFFSET_POSITION(tb->tb_path, path_offset), "PAP-8270: invalid position in the parent"); - n_child_position = - (p_s_bh == - p_s_tb->FL[n_h]) ? p_s_tb->lkey[n_h] : B_NR_ITEMS(p_s_tb-> - FL[n_h]); - n_son_number = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position); - p_s_bh = sb_bread(p_s_sb, n_son_number); - if (!p_s_bh) + child_position = + (bh == + tb->FL[h]) ? tb->lkey[h] : B_NR_ITEMS(tb-> + FL[h]); + son_number = B_N_CHILD_NUM(tb->FL[h], child_position); + bh = sb_bread(sb, son_number); + if (!bh) return IO_ERROR; - if (FILESYSTEM_CHANGED_TB(p_s_tb)) { - decrement_bcount(p_s_bh); - PROC_INFO_INC(p_s_sb, get_neighbors_restart[n_h]); + if (FILESYSTEM_CHANGED_TB(tb)) { + brelse(bh); + PROC_INFO_INC(sb, get_neighbors_restart[h]); return REPEAT_SEARCH; } - RFALSE(!B_IS_IN_TREE(p_s_tb->FL[n_h]) || - n_child_position > B_NR_ITEMS(p_s_tb->FL[n_h]) || - B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position) != - p_s_bh->b_blocknr, "PAP-8275: invalid parent"); - RFALSE(!B_IS_IN_TREE(p_s_bh), "PAP-8280: invalid child"); - RFALSE(!n_h && - B_FREE_SPACE(p_s_bh) != - MAX_CHILD_SIZE(p_s_bh) - - dc_size(B_N_CHILD(p_s_tb->FL[0], n_child_position)), + RFALSE(!B_IS_IN_TREE(tb->FL[h]) || + child_position > B_NR_ITEMS(tb->FL[h]) || + B_N_CHILD_NUM(tb->FL[h], child_position) != + bh->b_blocknr, "PAP-8275: invalid parent"); + RFALSE(!B_IS_IN_TREE(bh), "PAP-8280: invalid child"); + RFALSE(!h && + B_FREE_SPACE(bh) != + MAX_CHILD_SIZE(bh) - + dc_size(B_N_CHILD(tb->FL[0], child_position)), "PAP-8290: invalid child size of left neighbor"); - decrement_bcount(p_s_tb->L[n_h]); - p_s_tb->L[n_h] = p_s_bh; + brelse(tb->L[h]); + tb->L[h] = bh; } - if (p_s_tb->rnum[n_h]) { /* We need right neighbor to balance S[n_path_offset]. */ - PROC_INFO_INC(p_s_sb, need_r_neighbor[n_h]); - p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset); + /* We need right neighbor to balance S[path_offset]. */ + if (tb->rnum[h]) { /* We need right neighbor to balance S[path_offset]. */ + PROC_INFO_INC(sb, need_r_neighbor[h]); + bh = PATH_OFFSET_PBUFFER(tb->tb_path, path_offset); - RFALSE(p_s_bh == p_s_tb->FR[n_h] && - PATH_OFFSET_POSITION(p_s_tb->tb_path, - n_path_offset) >= - B_NR_ITEMS(p_s_bh), + RFALSE(bh == tb->FR[h] && + PATH_OFFSET_POSITION(tb->tb_path, + path_offset) >= + B_NR_ITEMS(bh), "PAP-8295: invalid position in the parent"); - n_child_position = - (p_s_bh == p_s_tb->FR[n_h]) ? p_s_tb->rkey[n_h] + 1 : 0; - n_son_number = B_N_CHILD_NUM(p_s_tb->FR[n_h], n_child_position); - p_s_bh = sb_bread(p_s_sb, n_son_number); - if (!p_s_bh) + child_position = + (bh == tb->FR[h]) ? tb->rkey[h] + 1 : 0; + son_number = B_N_CHILD_NUM(tb->FR[h], child_position); + bh = sb_bread(sb, son_number); + if (!bh) return IO_ERROR; - if (FILESYSTEM_CHANGED_TB(p_s_tb)) { - decrement_bcount(p_s_bh); - PROC_INFO_INC(p_s_sb, get_neighbors_restart[n_h]); + if (FILESYSTEM_CHANGED_TB(tb)) { + brelse(bh); + PROC_INFO_INC(sb, get_neighbors_restart[h]); return REPEAT_SEARCH; } - decrement_bcount(p_s_tb->R[n_h]); - p_s_tb->R[n_h] = p_s_bh; + brelse(tb->R[h]); + tb->R[h] = bh; - RFALSE(!n_h - && B_FREE_SPACE(p_s_bh) != - MAX_CHILD_SIZE(p_s_bh) - - dc_size(B_N_CHILD(p_s_tb->FR[0], n_child_position)), + RFALSE(!h + && B_FREE_SPACE(bh) != + MAX_CHILD_SIZE(bh) - + dc_size(B_N_CHILD(tb->FR[0], child_position)), "PAP-8300: invalid child size of right neighbor (%d != %d - %d)", - B_FREE_SPACE(p_s_bh), MAX_CHILD_SIZE(p_s_bh), - dc_size(B_N_CHILD(p_s_tb->FR[0], n_child_position))); + B_FREE_SPACE(bh), MAX_CHILD_SIZE(bh), + dc_size(B_N_CHILD(tb->FR[0], child_position))); } return CARRY_ON; @@ -2088,52 +2094,46 @@ static int get_mem_for_virtual_node(struct tree_balance *tb) } #ifdef CONFIG_REISERFS_CHECK -static void tb_buffer_sanity_check(struct super_block *p_s_sb, - struct buffer_head *p_s_bh, +static void tb_buffer_sanity_check(struct super_block *sb, + struct buffer_head *bh, const char *descr, int level) { - if (p_s_bh) { - if (atomic_read(&(p_s_bh->b_count)) <= 0) { - - reiserfs_panic(p_s_sb, - "jmacd-1: tb_buffer_sanity_check(): negative or zero reference counter for buffer %s[%d] (%b)\n", - descr, level, p_s_bh); - } - - if (!buffer_uptodate(p_s_bh)) { - reiserfs_panic(p_s_sb, - "jmacd-2: tb_buffer_sanity_check(): buffer is not up to date %s[%d] (%b)\n", - descr, level, p_s_bh); - } - - if (!B_IS_IN_TREE(p_s_bh)) { - reiserfs_panic(p_s_sb, - "jmacd-3: tb_buffer_sanity_check(): buffer is not in tree %s[%d] (%b)\n", - descr, level, p_s_bh); - } - - if (p_s_bh->b_bdev != p_s_sb->s_bdev) { - reiserfs_panic(p_s_sb, - "jmacd-4: tb_buffer_sanity_check(): buffer has wrong device %s[%d] (%b)\n", - descr, level, p_s_bh); - } - - if (p_s_bh->b_size != p_s_sb->s_blocksize) { - reiserfs_panic(p_s_sb, - "jmacd-5: tb_buffer_sanity_check(): buffer has wrong blocksize %s[%d] (%b)\n", - descr, level, p_s_bh); - } - - if (p_s_bh->b_blocknr > SB_BLOCK_COUNT(p_s_sb)) { - reiserfs_panic(p_s_sb, - "jmacd-6: tb_buffer_sanity_check(): buffer block number too high %s[%d] (%b)\n", - descr, level, p_s_bh); - } + if (bh) { + if (atomic_read(&(bh->b_count)) <= 0) + + reiserfs_panic(sb, "jmacd-1", "negative or zero " + "reference counter for buffer %s[%d] " + "(%b)", descr, level, bh); + + if (!buffer_uptodate(bh)) + reiserfs_panic(sb, "jmacd-2", "buffer is not up " + "to date %s[%d] (%b)", + descr, level, bh); + + if (!B_IS_IN_TREE(bh)) + reiserfs_panic(sb, "jmacd-3", "buffer is not " + "in tree %s[%d] (%b)", + descr, level, bh); + + if (bh->b_bdev != sb->s_bdev) + reiserfs_panic(sb, "jmacd-4", "buffer has wrong " + "device %s[%d] (%b)", + descr, level, bh); + + if (bh->b_size != sb->s_blocksize) + reiserfs_panic(sb, "jmacd-5", "buffer has wrong " + "blocksize %s[%d] (%b)", + descr, level, bh); + + if (bh->b_blocknr > SB_BLOCK_COUNT(sb)) + reiserfs_panic(sb, "jmacd-6", "buffer block " + "number too high %s[%d] (%b)", + descr, level, bh); } } #else -static void tb_buffer_sanity_check(struct super_block *p_s_sb, - struct buffer_head *p_s_bh, +static void tb_buffer_sanity_check(struct super_block *sb, + struct buffer_head *bh, const char *descr, int level) {; } @@ -2144,7 +2144,7 @@ static int clear_all_dirty_bits(struct super_block *s, struct buffer_head *bh) return reiserfs_prepare_for_journal(s, bh, 0); } -static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb) +static int wait_tb_buffers_until_unlocked(struct tree_balance *tb) { struct buffer_head *locked; #ifdef CONFIG_REISERFS_CHECK @@ -2156,95 +2156,94 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb) locked = NULL; - for (i = p_s_tb->tb_path->path_length; + for (i = tb->tb_path->path_length; !locked && i > ILLEGAL_PATH_ELEMENT_OFFSET; i--) { - if (PATH_OFFSET_PBUFFER(p_s_tb->tb_path, i)) { + if (PATH_OFFSET_PBUFFER(tb->tb_path, i)) { /* if I understand correctly, we can only be sure the last buffer ** in the path is in the tree --clm */ #ifdef CONFIG_REISERFS_CHECK - if (PATH_PLAST_BUFFER(p_s_tb->tb_path) == - PATH_OFFSET_PBUFFER(p_s_tb->tb_path, i)) { - tb_buffer_sanity_check(p_s_tb->tb_sb, + if (PATH_PLAST_BUFFER(tb->tb_path) == + PATH_OFFSET_PBUFFER(tb->tb_path, i)) + tb_buffer_sanity_check(tb->tb_sb, PATH_OFFSET_PBUFFER - (p_s_tb->tb_path, + (tb->tb_path, i), "S", - p_s_tb->tb_path-> + tb->tb_path-> path_length - i); - } #endif - if (!clear_all_dirty_bits(p_s_tb->tb_sb, + if (!clear_all_dirty_bits(tb->tb_sb, PATH_OFFSET_PBUFFER - (p_s_tb->tb_path, + (tb->tb_path, i))) { locked = - PATH_OFFSET_PBUFFER(p_s_tb->tb_path, + PATH_OFFSET_PBUFFER(tb->tb_path, i); } } } - for (i = 0; !locked && i < MAX_HEIGHT && p_s_tb->insert_size[i]; + for (i = 0; !locked && i < MAX_HEIGHT && tb->insert_size[i]; i++) { - if (p_s_tb->lnum[i]) { + if (tb->lnum[i]) { - if (p_s_tb->L[i]) { - tb_buffer_sanity_check(p_s_tb->tb_sb, - p_s_tb->L[i], + if (tb->L[i]) { + tb_buffer_sanity_check(tb->tb_sb, + tb->L[i], "L", i); if (!clear_all_dirty_bits - (p_s_tb->tb_sb, p_s_tb->L[i])) - locked = p_s_tb->L[i]; + (tb->tb_sb, tb->L[i])) + locked = tb->L[i]; } - if (!locked && p_s_tb->FL[i]) { - tb_buffer_sanity_check(p_s_tb->tb_sb, - p_s_tb->FL[i], + if (!locked && tb->FL[i]) { + tb_buffer_sanity_check(tb->tb_sb, + tb->FL[i], "FL", i); if (!clear_all_dirty_bits - (p_s_tb->tb_sb, p_s_tb->FL[i])) - locked = p_s_tb->FL[i]; + (tb->tb_sb, tb->FL[i])) + locked = tb->FL[i]; } - if (!locked && p_s_tb->CFL[i]) { - tb_buffer_sanity_check(p_s_tb->tb_sb, - p_s_tb->CFL[i], + if (!locked && tb->CFL[i]) { + tb_buffer_sanity_check(tb->tb_sb, + tb->CFL[i], "CFL", i); if (!clear_all_dirty_bits - (p_s_tb->tb_sb, p_s_tb->CFL[i])) - locked = p_s_tb->CFL[i]; + (tb->tb_sb, tb->CFL[i])) + locked = tb->CFL[i]; } } - if (!locked && (p_s_tb->rnum[i])) { + if (!locked && (tb->rnum[i])) { - if (p_s_tb->R[i]) { - tb_buffer_sanity_check(p_s_tb->tb_sb, - p_s_tb->R[i], + if (tb->R[i]) { + tb_buffer_sanity_check(tb->tb_sb, + tb->R[i], "R", i); if (!clear_all_dirty_bits - (p_s_tb->tb_sb, p_s_tb->R[i])) - locked = p_s_tb->R[i]; + (tb->tb_sb, tb->R[i])) + locked = tb->R[i]; } - if (!locked && p_s_tb->FR[i]) { - tb_buffer_sanity_check(p_s_tb->tb_sb, - p_s_tb->FR[i], + if (!locked && tb->FR[i]) { + tb_buffer_sanity_check(tb->tb_sb, + tb->FR[i], "FR", i); if (!clear_all_dirty_bits - (p_s_tb->tb_sb, p_s_tb->FR[i])) - locked = p_s_tb->FR[i]; + (tb->tb_sb, tb->FR[i])) + locked = tb->FR[i]; } - if (!locked && p_s_tb->CFR[i]) { - tb_buffer_sanity_check(p_s_tb->tb_sb, - p_s_tb->CFR[i], + if (!locked && tb->CFR[i]) { + tb_buffer_sanity_check(tb->tb_sb, + tb->CFR[i], "CFR", i); if (!clear_all_dirty_bits - (p_s_tb->tb_sb, p_s_tb->CFR[i])) - locked = p_s_tb->CFR[i]; + (tb->tb_sb, tb->CFR[i])) + locked = tb->CFR[i]; } } } @@ -2257,10 +2256,10 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb) ** --clm */ for (i = 0; !locked && i < MAX_FEB_SIZE; i++) { - if (p_s_tb->FEB[i]) { + if (tb->FEB[i]) { if (!clear_all_dirty_bits - (p_s_tb->tb_sb, p_s_tb->FEB[i])) - locked = p_s_tb->FEB[i]; + (tb->tb_sb, tb->FEB[i])) + locked = tb->FEB[i]; } } @@ -2268,21 +2267,20 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb) #ifdef CONFIG_REISERFS_CHECK repeat_counter++; if ((repeat_counter % 10000) == 0) { - reiserfs_warning(p_s_tb->tb_sb, - "wait_tb_buffers_until_released(): too many " - "iterations waiting for buffer to unlock " + reiserfs_warning(tb->tb_sb, "reiserfs-8200", + "too many iterations waiting " + "for buffer to unlock " "(%b)", locked); /* Don't loop forever. Try to recover from possible error. */ - return (FILESYSTEM_CHANGED_TB(p_s_tb)) ? + return (FILESYSTEM_CHANGED_TB(tb)) ? REPEAT_SEARCH : CARRY_ON; } #endif __wait_on_buffer(locked); - if (FILESYSTEM_CHANGED_TB(p_s_tb)) { + if (FILESYSTEM_CHANGED_TB(tb)) return REPEAT_SEARCH; - } } } while (locked); @@ -2295,15 +2293,15 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb) * analyze what and where should be moved; * get sufficient number of new nodes; * Balancing will start only after all resources will be collected at a time. - * + * * When ported to SMP kernels, only at the last moment after all needed nodes * are collected in cache, will the resources be locked using the usual * textbook ordered lock acquisition algorithms. Note that ensuring that * this code neither write locks what it does not need to write lock nor locks out of order * will be a pain in the butt that could have been avoided. Grumble grumble. -Hans - * + * * fix is meant in the sense of render unchanging - * + * * Latency might be improved by first gathering a list of what buffers are needed * and then getting as many of them in parallel as possible? -Hans * @@ -2312,159 +2310,160 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb) * tb tree_balance structure; * inum item number in S[h]; * pos_in_item - comment this if you can - * ins_ih & ins_sd are used when inserting + * ins_ih item head of item being inserted + * data inserted item or data to be pasted * Returns: 1 - schedule occurred while the function worked; * 0 - schedule didn't occur while the function worked; - * -1 - if no_disk_space + * -1 - if no_disk_space */ -int fix_nodes(int n_op_mode, struct tree_balance *p_s_tb, struct item_head *p_s_ins_ih, // item head of item being inserted - const void *data // inserted item or data to be pasted - ) +int fix_nodes(int op_mode, struct tree_balance *tb, + struct item_head *ins_ih, const void *data) { - int n_ret_value, n_h, n_item_num = PATH_LAST_POSITION(p_s_tb->tb_path); - int n_pos_in_item; + int ret, h, item_num = PATH_LAST_POSITION(tb->tb_path); + int pos_in_item; /* we set wait_tb_buffers_run when we have to restore any dirty bits cleared ** during wait_tb_buffers_run */ int wait_tb_buffers_run = 0; - struct buffer_head *p_s_tbS0 = PATH_PLAST_BUFFER(p_s_tb->tb_path); + struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path); - ++REISERFS_SB(p_s_tb->tb_sb)->s_fix_nodes; + ++REISERFS_SB(tb->tb_sb)->s_fix_nodes; - n_pos_in_item = p_s_tb->tb_path->pos_in_item; + pos_in_item = tb->tb_path->pos_in_item; - p_s_tb->fs_gen = get_generation(p_s_tb->tb_sb); + tb->fs_gen = get_generation(tb->tb_sb); /* we prepare and log the super here so it will already be in the ** transaction when do_balance needs to change it. ** This way do_balance won't have to schedule when trying to prepare ** the super for logging */ - reiserfs_prepare_for_journal(p_s_tb->tb_sb, - SB_BUFFER_WITH_SB(p_s_tb->tb_sb), 1); - journal_mark_dirty(p_s_tb->transaction_handle, p_s_tb->tb_sb, - SB_BUFFER_WITH_SB(p_s_tb->tb_sb)); - if (FILESYSTEM_CHANGED_TB(p_s_tb)) + reiserfs_prepare_for_journal(tb->tb_sb, + SB_BUFFER_WITH_SB(tb->tb_sb), 1); + journal_mark_dirty(tb->transaction_handle, tb->tb_sb, + SB_BUFFER_WITH_SB(tb->tb_sb)); + if (FILESYSTEM_CHANGED_TB(tb)) return REPEAT_SEARCH; /* if it possible in indirect_to_direct conversion */ - if (buffer_locked(p_s_tbS0)) { - __wait_on_buffer(p_s_tbS0); - if (FILESYSTEM_CHANGED_TB(p_s_tb)) + if (buffer_locked(tbS0)) { + __wait_on_buffer(tbS0); + if (FILESYSTEM_CHANGED_TB(tb)) return REPEAT_SEARCH; } #ifdef CONFIG_REISERFS_CHECK if (cur_tb) { print_cur_tb("fix_nodes"); - reiserfs_panic(p_s_tb->tb_sb, - "PAP-8305: fix_nodes: there is pending do_balance"); + reiserfs_panic(tb->tb_sb, "PAP-8305", + "there is pending do_balance"); } - if (!buffer_uptodate(p_s_tbS0) || !B_IS_IN_TREE(p_s_tbS0)) { - reiserfs_panic(p_s_tb->tb_sb, - "PAP-8320: fix_nodes: S[0] (%b %z) is not uptodate " - "at the beginning of fix_nodes or not in tree (mode %c)", - p_s_tbS0, p_s_tbS0, n_op_mode); - } + if (!buffer_uptodate(tbS0) || !B_IS_IN_TREE(tbS0)) + reiserfs_panic(tb->tb_sb, "PAP-8320", "S[0] (%b %z) is " + "not uptodate at the beginning of fix_nodes " + "or not in tree (mode %c)", + tbS0, tbS0, op_mode); /* Check parameters. */ - switch (n_op_mode) { + switch (op_mode) { case M_INSERT: - if (n_item_num <= 0 || n_item_num > B_NR_ITEMS(p_s_tbS0)) - reiserfs_panic(p_s_tb->tb_sb, - "PAP-8330: fix_nodes: Incorrect item number %d (in S0 - %d) in case of insert", - n_item_num, B_NR_ITEMS(p_s_tbS0)); + if (item_num <= 0 || item_num > B_NR_ITEMS(tbS0)) + reiserfs_panic(tb->tb_sb, "PAP-8330", "Incorrect " + "item number %d (in S0 - %d) in case " + "of insert", item_num, + B_NR_ITEMS(tbS0)); break; case M_PASTE: case M_DELETE: case M_CUT: - if (n_item_num < 0 || n_item_num >= B_NR_ITEMS(p_s_tbS0)) { - print_block(p_s_tbS0, 0, -1, -1); - reiserfs_panic(p_s_tb->tb_sb, - "PAP-8335: fix_nodes: Incorrect item number(%d); mode = %c insert_size = %d\n", - n_item_num, n_op_mode, - p_s_tb->insert_size[0]); + if (item_num < 0 || item_num >= B_NR_ITEMS(tbS0)) { + print_block(tbS0, 0, -1, -1); + reiserfs_panic(tb->tb_sb, "PAP-8335", "Incorrect " + "item number(%d); mode = %c " + "insert_size = %d", + item_num, op_mode, + tb->insert_size[0]); } break; default: - reiserfs_panic(p_s_tb->tb_sb, - "PAP-8340: fix_nodes: Incorrect mode of operation"); + reiserfs_panic(tb->tb_sb, "PAP-8340", "Incorrect mode " + "of operation"); } #endif - if (get_mem_for_virtual_node(p_s_tb) == REPEAT_SEARCH) + if (get_mem_for_virtual_node(tb) == REPEAT_SEARCH) // FIXME: maybe -ENOMEM when tb->vn_buf == 0? Now just repeat return REPEAT_SEARCH; - /* Starting from the leaf level; for all levels n_h of the tree. */ - for (n_h = 0; n_h < MAX_HEIGHT && p_s_tb->insert_size[n_h]; n_h++) { - if ((n_ret_value = get_direct_parent(p_s_tb, n_h)) != CARRY_ON) { + /* Starting from the leaf level; for all levels h of the tree. */ + for (h = 0; h < MAX_HEIGHT && tb->insert_size[h]; h++) { + ret = get_direct_parent(tb, h); + if (ret != CARRY_ON) goto repeat; - } - if ((n_ret_value = - check_balance(n_op_mode, p_s_tb, n_h, n_item_num, - n_pos_in_item, p_s_ins_ih, - data)) != CARRY_ON) { - if (n_ret_value == NO_BALANCING_NEEDED) { + ret = check_balance(op_mode, tb, h, item_num, + pos_in_item, ins_ih, data); + if (ret != CARRY_ON) { + if (ret == NO_BALANCING_NEEDED) { /* No balancing for higher levels needed. */ - if ((n_ret_value = - get_neighbors(p_s_tb, n_h)) != CARRY_ON) { + ret = get_neighbors(tb, h); + if (ret != CARRY_ON) goto repeat; - } - if (n_h != MAX_HEIGHT - 1) - p_s_tb->insert_size[n_h + 1] = 0; + if (h != MAX_HEIGHT - 1) + tb->insert_size[h + 1] = 0; /* ok, analysis and resource gathering are complete */ break; } goto repeat; } - if ((n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON) { + ret = get_neighbors(tb, h); + if (ret != CARRY_ON) goto repeat; - } - if ((n_ret_value = get_empty_nodes(p_s_tb, n_h)) != CARRY_ON) { - goto repeat; /* No disk space, or schedule occurred and - analysis may be invalid and needs to be redone. */ - } + /* No disk space, or schedule occurred and analysis may be + * invalid and needs to be redone. */ + ret = get_empty_nodes(tb, h); + if (ret != CARRY_ON) + goto repeat; - if (!PATH_H_PBUFFER(p_s_tb->tb_path, n_h)) { + if (!PATH_H_PBUFFER(tb->tb_path, h)) { /* We have a positive insert size but no nodes exist on this level, this means that we are creating a new root. */ - RFALSE(p_s_tb->blknum[n_h] != 1, + RFALSE(tb->blknum[h] != 1, "PAP-8350: creating new empty root"); - if (n_h < MAX_HEIGHT - 1) - p_s_tb->insert_size[n_h + 1] = 0; - } else if (!PATH_H_PBUFFER(p_s_tb->tb_path, n_h + 1)) { - if (p_s_tb->blknum[n_h] > 1) { - /* The tree needs to be grown, so this node S[n_h] + if (h < MAX_HEIGHT - 1) + tb->insert_size[h + 1] = 0; + } else if (!PATH_H_PBUFFER(tb->tb_path, h + 1)) { + if (tb->blknum[h] > 1) { + /* The tree needs to be grown, so this node S[h] which is the root node is split into two nodes, - and a new node (S[n_h+1]) will be created to + and a new node (S[h+1]) will be created to become the root node. */ - RFALSE(n_h == MAX_HEIGHT - 1, + RFALSE(h == MAX_HEIGHT - 1, "PAP-8355: attempt to create too high of a tree"); - p_s_tb->insert_size[n_h + 1] = + tb->insert_size[h + 1] = (DC_SIZE + - KEY_SIZE) * (p_s_tb->blknum[n_h] - 1) + + KEY_SIZE) * (tb->blknum[h] - 1) + DC_SIZE; - } else if (n_h < MAX_HEIGHT - 1) - p_s_tb->insert_size[n_h + 1] = 0; + } else if (h < MAX_HEIGHT - 1) + tb->insert_size[h + 1] = 0; } else - p_s_tb->insert_size[n_h + 1] = - (DC_SIZE + KEY_SIZE) * (p_s_tb->blknum[n_h] - 1); + tb->insert_size[h + 1] = + (DC_SIZE + KEY_SIZE) * (tb->blknum[h] - 1); } - if ((n_ret_value = wait_tb_buffers_until_unlocked(p_s_tb)) == CARRY_ON) { - if (FILESYSTEM_CHANGED_TB(p_s_tb)) { + ret = wait_tb_buffers_until_unlocked(tb); + if (ret == CARRY_ON) { + if (FILESYSTEM_CHANGED_TB(tb)) { wait_tb_buffers_run = 1; - n_ret_value = REPEAT_SEARCH; + ret = REPEAT_SEARCH; goto repeat; } else { return CARRY_ON; @@ -2485,57 +2484,57 @@ int fix_nodes(int n_op_mode, struct tree_balance *p_s_tb, struct item_head *p_s_ /* Release path buffers. */ if (wait_tb_buffers_run) { - pathrelse_and_restore(p_s_tb->tb_sb, p_s_tb->tb_path); + pathrelse_and_restore(tb->tb_sb, tb->tb_path); } else { - pathrelse(p_s_tb->tb_path); + pathrelse(tb->tb_path); } /* brelse all resources collected for balancing */ for (i = 0; i < MAX_HEIGHT; i++) { if (wait_tb_buffers_run) { - reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, - p_s_tb->L[i]); - reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, - p_s_tb->R[i]); - reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, - p_s_tb->FL[i]); - reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, - p_s_tb->FR[i]); - reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, - p_s_tb-> + reiserfs_restore_prepared_buffer(tb->tb_sb, + tb->L[i]); + reiserfs_restore_prepared_buffer(tb->tb_sb, + tb->R[i]); + reiserfs_restore_prepared_buffer(tb->tb_sb, + tb->FL[i]); + reiserfs_restore_prepared_buffer(tb->tb_sb, + tb->FR[i]); + reiserfs_restore_prepared_buffer(tb->tb_sb, + tb-> CFL[i]); - reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, - p_s_tb-> + reiserfs_restore_prepared_buffer(tb->tb_sb, + tb-> CFR[i]); } - brelse(p_s_tb->L[i]); - p_s_tb->L[i] = NULL; - brelse(p_s_tb->R[i]); - p_s_tb->R[i] = NULL; - brelse(p_s_tb->FL[i]); - p_s_tb->FL[i] = NULL; - brelse(p_s_tb->FR[i]); - p_s_tb->FR[i] = NULL; - brelse(p_s_tb->CFL[i]); - p_s_tb->CFL[i] = NULL; - brelse(p_s_tb->CFR[i]); - p_s_tb->CFR[i] = NULL; + brelse(tb->L[i]); + brelse(tb->R[i]); + brelse(tb->FL[i]); + brelse(tb->FR[i]); + brelse(tb->CFL[i]); + brelse(tb->CFR[i]); + + tb->L[i] = NULL; + tb->R[i] = NULL; + tb->FL[i] = NULL; + tb->FR[i] = NULL; + tb->CFL[i] = NULL; + tb->CFR[i] = NULL; } if (wait_tb_buffers_run) { for (i = 0; i < MAX_FEB_SIZE; i++) { - if (p_s_tb->FEB[i]) { + if (tb->FEB[i]) reiserfs_restore_prepared_buffer - (p_s_tb->tb_sb, p_s_tb->FEB[i]); - } + (tb->tb_sb, tb->FEB[i]); } } - return n_ret_value; + return ret; } } -/* Anatoly will probably forgive me renaming p_s_tb to tb. I just +/* Anatoly will probably forgive me renaming tb to tb. I just wanted to make lines shorter */ void unfix_nodes(struct tree_balance *tb) { diff --git a/fs/reiserfs/hashes.c b/fs/reiserfs/hashes.c index e664ac16fad..6471c670743 100644 --- a/fs/reiserfs/hashes.c +++ b/fs/reiserfs/hashes.c @@ -7,7 +7,7 @@ * (see Applied Cryptography, 2nd edition, p448). * * Jeremy Fitzhardinge <jeremy@zip.com.au> 1998 - * + * * Jeremy has agreed to the contents of reiserfs/README. -Hans * Yura's function is added (04/07/2000) */ diff --git a/fs/reiserfs/ibalance.c b/fs/reiserfs/ibalance.c index de391a82b99..2074fd95046 100644 --- a/fs/reiserfs/ibalance.c +++ b/fs/reiserfs/ibalance.c @@ -105,8 +105,8 @@ static void internal_define_dest_src_infos(int shift_mode, break; default: - reiserfs_panic(tb->tb_sb, - "internal_define_dest_src_infos: shift type is unknown (%d)", + reiserfs_panic(tb->tb_sb, "ibalance-1", + "shift type is unknown (%d)", shift_mode); } } @@ -278,7 +278,7 @@ static void internal_delete_childs(struct buffer_info *cur_bi, int from, int n) /* copy cpy_num node pointers and cpy_num - 1 items from buffer src to buffer dest * last_first == FIRST_TO_LAST means, that we copy first items from src to tail of dest - * last_first == LAST_TO_FIRST means, that we copy last items from src to head of dest + * last_first == LAST_TO_FIRST means, that we copy last items from src to head of dest */ static void internal_copy_pointers_items(struct buffer_info *dest_bi, struct buffer_head *src, @@ -385,7 +385,7 @@ static void internal_move_pointers_items(struct buffer_info *dest_bi, if (last_first == FIRST_TO_LAST) { /* shift_left occurs */ first_pointer = 0; first_item = 0; - /* delete cpy_num - del_par pointers and keys starting for pointers with first_pointer, + /* delete cpy_num - del_par pointers and keys starting for pointers with first_pointer, for key - with first_item */ internal_delete_pointers_items(src_bi, first_pointer, first_item, cpy_num - del_par); @@ -453,7 +453,7 @@ static void internal_insert_key(struct buffer_info *dest_bi, int dest_position_b } } -/* Insert d_key'th (delimiting) key from buffer cfl to tail of dest. +/* Insert d_key'th (delimiting) key from buffer cfl to tail of dest. * Copy pointer_amount node pointers and pointer_amount - 1 items from buffer src to buffer dest. * Replace d_key'th key in buffer cfl. * Delete pointer_amount items and node pointers from buffer src. @@ -518,7 +518,7 @@ static void internal_shift1_left(struct tree_balance *tb, /* internal_move_pointers_items (tb->L[h], tb->S[h], FIRST_TO_LAST, pointer_amount, 1); */ } -/* Insert d_key'th (delimiting) key from buffer cfr to head of dest. +/* Insert d_key'th (delimiting) key from buffer cfr to head of dest. * Copy n node pointers and n - 1 items from buffer src to buffer dest. * Replace d_key'th key in buffer cfr. * Delete n items and node pointers from buffer src. @@ -702,8 +702,8 @@ static void balance_internal_when_delete(struct tree_balance *tb, return; } - reiserfs_panic(tb->tb_sb, - "balance_internal_when_delete: unexpected tb->lnum[%d]==%d or tb->rnum[%d]==%d", + reiserfs_panic(tb->tb_sb, "ibalance-2", + "unexpected tb->lnum[%d]==%d or tb->rnum[%d]==%d", h, tb->lnum[h], h, tb->rnum[h]); } @@ -749,7 +749,7 @@ int balance_internal(struct tree_balance *tb, /* tree_balance structure this means that new pointers and items must be inserted AFTER * child_pos } - else + else { it is the position of the leftmost pointer that must be deleted (together with its corresponding key to the left of the pointer) @@ -940,8 +940,8 @@ int balance_internal(struct tree_balance *tb, /* tree_balance structure struct block_head *blkh; if (tb->blknum[h] != 1) - reiserfs_panic(NULL, - "balance_internal: One new node required for creating the new root"); + reiserfs_panic(NULL, "ibalance-3", "One new node " + "required for creating the new root"); /* S[h] = empty buffer from the list FEB. */ tbSh = get_FEB(tb); blkh = B_BLK_HEAD(tbSh); diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 55fce92cdf1..6fd0f47e45d 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -53,7 +53,7 @@ void reiserfs_delete_inode(struct inode *inode) * after delete_object so that quota updates go into the same transaction as * stat data deletion */ if (!err) - DQUOT_FREE_INODE(inode); + vfs_dq_free_inode(inode); if (journal_end(&th, inode->i_sb, jbegin_count)) goto out; @@ -363,7 +363,7 @@ static int _get_block_create_0(struct inode *inode, sector_t block, } /* make sure we don't read more bytes than actually exist in ** the file. This can happen in odd cases where i_size isn't - ** correct, and when direct item padding results in a few + ** correct, and when direct item padding results in a few ** extra bytes at the end of the direct item */ if ((le_ih_k_offset(ih) + path.pos_in_item) > inode->i_size) @@ -438,15 +438,15 @@ static int reiserfs_bmap(struct inode *inode, sector_t block, ** -ENOENT instead of a valid buffer. block_prepare_write expects to ** be able to do i/o on the buffers returned, unless an error value ** is also returned. -** +** ** So, this allows block_prepare_write to be used for reading a single block ** in a page. Where it does not produce a valid page for holes, or past the ** end of the file. This turns out to be exactly what we need for reading ** tails for conversion. ** ** The point of the wrapper is forcing a certain value for create, even -** though the VFS layer is calling this function with create==1. If you -** don't want to send create == GET_BLOCK_NO_HOLE to reiserfs_get_block, +** though the VFS layer is calling this function with create==1. If you +** don't want to send create == GET_BLOCK_NO_HOLE to reiserfs_get_block, ** don't use this function. */ static int reiserfs_get_block_create_0(struct inode *inode, sector_t block, @@ -602,7 +602,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block, int done; int fs_gen; struct reiserfs_transaction_handle *th = NULL; - /* space reserved in transaction batch: + /* space reserved in transaction batch: . 3 balancings in direct->indirect conversion . 1 block involved into reiserfs_update_sd() XXX in practically impossible worst case direct2indirect() @@ -754,7 +754,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block, reiserfs_write_unlock(inode->i_sb); /* the item was found, so new blocks were not added to the file - ** there is no need to make sure the inode is updated with this + ** there is no need to make sure the inode is updated with this ** transaction */ return retval; @@ -841,10 +841,12 @@ int reiserfs_get_block(struct inode *inode, sector_t block, tail_offset); if (retval) { if (retval != -ENOSPC) - reiserfs_warning(inode->i_sb, - "clm-6004: convert tail failed inode %lu, error %d", - inode->i_ino, - retval); + reiserfs_error(inode->i_sb, + "clm-6004", + "convert tail failed " + "inode %lu, error %d", + inode->i_ino, + retval); if (allocated_block_nr) { /* the bitmap, the super, and the stat data == 3 */ if (!th) @@ -984,7 +986,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block, /* this loop could log more blocks than we had originally asked ** for. So, we have to allow the transaction to end if it is - ** too big or too full. Update the inode so things are + ** too big or too full. Update the inode so things are ** consistent if we crash before the function returns ** ** release the path so that anybody waiting on the path before @@ -995,7 +997,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block, if (retval) goto failure; } - /* inserting indirect pointers for a hole can take a + /* inserting indirect pointers for a hole can take a ** long time. reschedule if needed */ cond_resched(); @@ -1006,8 +1008,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block, goto failure; } if (retval == POSITION_FOUND) { - reiserfs_warning(inode->i_sb, - "vs-825: reiserfs_get_block: " + reiserfs_warning(inode->i_sb, "vs-825", "%K should not be found", &key); retval = -EEXIST; if (allocated_block_nr) @@ -1299,8 +1300,7 @@ static void update_stat_data(struct treepath *path, struct inode *inode, ih = PATH_PITEM_HEAD(path); if (!is_statdata_le_ih(ih)) - reiserfs_panic(inode->i_sb, - "vs-13065: update_stat_data: key %k, found item %h", + reiserfs_panic(inode->i_sb, "vs-13065", "key %k, found item %h", INODE_PKEY(inode), ih); if (stat_data_v1(ih)) { @@ -1332,10 +1332,9 @@ void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th, /* look for the object's stat data */ retval = search_item(inode->i_sb, &key, &path); if (retval == IO_ERROR) { - reiserfs_warning(inode->i_sb, - "vs-13050: reiserfs_update_sd: " - "i/o failure occurred trying to update %K stat data", - &key); + reiserfs_error(inode->i_sb, "vs-13050", + "i/o failure occurred trying to " + "update %K stat data", &key); return; } if (retval == ITEM_NOT_FOUND) { @@ -1345,9 +1344,9 @@ void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th, /*reiserfs_warning (inode->i_sb, "vs-13050: reiserfs_update_sd: i_nlink == 0, stat data not found"); */ return; } - reiserfs_warning(inode->i_sb, - "vs-13060: reiserfs_update_sd: " - "stat data of object %k (nlink == %d) not found (pos %d)", + reiserfs_warning(inode->i_sb, "vs-13060", + "stat data of object %k (nlink == %d) " + "not found (pos %d)", INODE_PKEY(inode), inode->i_nlink, pos); reiserfs_check_path(&path); @@ -1424,10 +1423,9 @@ void reiserfs_read_locked_inode(struct inode *inode, /* look for the object's stat data */ retval = search_item(inode->i_sb, &key, &path_to_sd); if (retval == IO_ERROR) { - reiserfs_warning(inode->i_sb, - "vs-13070: reiserfs_read_locked_inode: " - "i/o failure occurred trying to find stat data of %K", - &key); + reiserfs_error(inode->i_sb, "vs-13070", + "i/o failure occurred trying to find " + "stat data of %K", &key); reiserfs_make_bad_inode(inode); return; } @@ -1446,7 +1444,7 @@ void reiserfs_read_locked_inode(struct inode *inode, update sd on unlink all that is required is to check for nlink here. This bug was first found by Sizif when debugging SquidNG/Butterfly, forgotten, and found again after Philippe - Gramoulle <philippe.gramoulle@mmania.com> reproduced it. + Gramoulle <philippe.gramoulle@mmania.com> reproduced it. More logical fix would require changes in fs/inode.c:iput() to remove inode from hash-table _after_ fs cleaned disk stuff up and @@ -1457,8 +1455,7 @@ void reiserfs_read_locked_inode(struct inode *inode, during mount (fs/reiserfs/super.c:finish_unfinished()). */ if ((inode->i_nlink == 0) && !REISERFS_SB(inode->i_sb)->s_is_unlinked_ok) { - reiserfs_warning(inode->i_sb, - "vs-13075: reiserfs_read_locked_inode: " + reiserfs_warning(inode->i_sb, "vs-13075", "dead inode read from disk %K. " "This is likely to be race with knfsd. Ignore", &key); @@ -1555,7 +1552,7 @@ struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid, */ if (fh_type > fh_len) { if (fh_type != 6 || fh_len != 5) - reiserfs_warning(sb, + reiserfs_warning(sb, "reiserfs-13077", "nfsd/reiserfs, fhtype=%d, len=%d - odd", fh_type, fh_len); fh_type = 5; @@ -1622,7 +1619,7 @@ int reiserfs_write_inode(struct inode *inode, int do_sync) if (inode->i_sb->s_flags & MS_RDONLY) return -EROFS; /* memory pressure can sometimes initiate write_inode calls with sync == 1, - ** these cases are just when the system needs ram, not when the + ** these cases are just when the system needs ram, not when the ** inode needs to reach disk for safety, and they can safely be ** ignored because the altered inode has already been logged. */ @@ -1680,13 +1677,13 @@ static int reiserfs_new_directory(struct reiserfs_transaction_handle *th, /* look for place in the tree for new item */ retval = search_item(sb, &key, path); if (retval == IO_ERROR) { - reiserfs_warning(sb, "vs-13080: reiserfs_new_directory: " - "i/o failure occurred creating new directory"); + reiserfs_error(sb, "vs-13080", + "i/o failure occurred creating new directory"); return -EIO; } if (retval == ITEM_FOUND) { pathrelse(path); - reiserfs_warning(sb, "vs-13070: reiserfs_new_directory: " + reiserfs_warning(sb, "vs-13070", "object with this key exists (%k)", &(ih->ih_key)); return -EEXIST; @@ -1720,13 +1717,13 @@ static int reiserfs_new_symlink(struct reiserfs_transaction_handle *th, struct i /* look for place in the tree for new item */ retval = search_item(sb, &key, path); if (retval == IO_ERROR) { - reiserfs_warning(sb, "vs-13080: reiserfs_new_symlinik: " - "i/o failure occurred creating new symlink"); + reiserfs_error(sb, "vs-13080", + "i/o failure occurred creating new symlink"); return -EIO; } if (retval == ITEM_FOUND) { pathrelse(path); - reiserfs_warning(sb, "vs-13080: reiserfs_new_symlink: " + reiserfs_warning(sb, "vs-13080", "object with this key exists (%k)", &(ih->ih_key)); return -EEXIST; @@ -1739,7 +1736,7 @@ static int reiserfs_new_symlink(struct reiserfs_transaction_handle *th, struct i /* inserts the stat data into the tree, and then calls reiserfs_new_directory (to insert ".", ".." item if new object is directory) or reiserfs_new_symlink (to insert symlink body if new - object is symlink) or nothing (if new object is regular file) + object is symlink) or nothing (if new object is regular file) NOTE! uid and gid must already be set in the inode. If we return non-zero due to an error, we have to drop the quota previously allocated @@ -1747,10 +1744,11 @@ static int reiserfs_new_symlink(struct reiserfs_transaction_handle *th, struct i if we return non-zero, we also end the transaction. */ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, struct inode *dir, int mode, const char *symname, - /* 0 for regular, EMTRY_DIR_SIZE for dirs, + /* 0 for regular, EMTRY_DIR_SIZE for dirs, strlen (symname) for symlinks) */ loff_t i_size, struct dentry *dentry, - struct inode *inode) + struct inode *inode, + struct reiserfs_security_handle *security) { struct super_block *sb; struct reiserfs_iget_args args; @@ -1763,7 +1761,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, BUG_ON(!th->t_trans_id); - if (DQUOT_ALLOC_INODE(inode)) { + if (vfs_dq_alloc_inode(inode)) { err = -EDQUOT; goto out_end_trans; } @@ -1796,7 +1794,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, goto out_bad_inode; } if (old_format_only(sb)) - /* not a perfect generation count, as object ids can be reused, but + /* not a perfect generation count, as object ids can be reused, but ** this is as good as reiserfs can do right now. ** note that the private part of inode isn't filled in yet, we have ** to use the directory. @@ -1917,9 +1915,8 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, goto out_inserted_sd; } - /* XXX CHECK THIS */ if (reiserfs_posixacl(inode->i_sb)) { - retval = reiserfs_inherit_default_acl(dir, dentry, inode); + retval = reiserfs_inherit_default_acl(th, dir, dentry, inode); if (retval) { err = retval; reiserfs_check_path(&path_to_key); @@ -1927,10 +1924,23 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, goto out_inserted_sd; } } else if (inode->i_sb->s_flags & MS_POSIXACL) { - reiserfs_warning(inode->i_sb, "ACLs aren't enabled in the fs, " + reiserfs_warning(inode->i_sb, "jdm-13090", + "ACLs aren't enabled in the fs, " "but vfs thinks they are!"); - } else if (is_reiserfs_priv_object(dir)) { - reiserfs_mark_inode_private(inode); + } else if (IS_PRIVATE(dir)) + inode->i_flags |= S_PRIVATE; + + if (security->name) { + retval = reiserfs_security_write(th, inode, security); + if (retval) { + err = retval; + reiserfs_check_path(&path_to_key); + retval = journal_end(th, th->t_super, + th->t_blocks_allocated); + if (retval) + err = retval; + goto out_inserted_sd; + } } reiserfs_update_sd(th, inode); @@ -1947,12 +1957,12 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, INODE_PKEY(inode)->k_objectid = 0; /* Quota change must be inside a transaction for journaling */ - DQUOT_FREE_INODE(inode); + vfs_dq_free_inode(inode); out_end_trans: journal_end(th, th->t_super, th->t_blocks_allocated); /* Drop can be outside and it needs more credits so it's better to have it outside */ - DQUOT_DROP(inode); + vfs_dq_drop(inode); inode->i_flags |= S_NOQUOTA; make_bad_inode(inode); @@ -1960,19 +1970,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, inode->i_nlink = 0; th->t_trans_id = 0; /* so the caller can't use this handle later */ unlock_new_inode(inode); /* OK to do even if we hadn't locked it */ - - /* If we were inheriting an ACL, we need to release the lock so that - * iput doesn't deadlock in reiserfs_delete_xattrs. The locking - * code really needs to be reworked, but this will take care of it - * for now. -jeffm */ -#ifdef CONFIG_REISERFS_FS_POSIX_ACL - if (REISERFS_I(dir)->i_acl_default && !IS_ERR(REISERFS_I(dir)->i_acl_default)) { - reiserfs_write_unlock_xattrs(dir->i_sb); - iput(inode); - reiserfs_write_lock_xattrs(dir->i_sb); - } else -#endif - iput(inode); + iput(inode); return err; } @@ -1989,7 +1987,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, ** ** on failure, nonzero is returned, page_result and bh_result are untouched. */ -static int grab_tail_page(struct inode *p_s_inode, +static int grab_tail_page(struct inode *inode, struct page **page_result, struct buffer_head **bh_result) { @@ -1997,11 +1995,11 @@ static int grab_tail_page(struct inode *p_s_inode, /* we want the page with the last byte in the file, ** not the page that will hold the next byte for appending */ - unsigned long index = (p_s_inode->i_size - 1) >> PAGE_CACHE_SHIFT; + unsigned long index = (inode->i_size - 1) >> PAGE_CACHE_SHIFT; unsigned long pos = 0; unsigned long start = 0; - unsigned long blocksize = p_s_inode->i_sb->s_blocksize; - unsigned long offset = (p_s_inode->i_size) & (PAGE_CACHE_SIZE - 1); + unsigned long blocksize = inode->i_sb->s_blocksize; + unsigned long offset = (inode->i_size) & (PAGE_CACHE_SIZE - 1); struct buffer_head *bh; struct buffer_head *head; struct page *page; @@ -2015,7 +2013,7 @@ static int grab_tail_page(struct inode *p_s_inode, if ((offset & (blocksize - 1)) == 0) { return -ENOENT; } - page = grab_cache_page(p_s_inode->i_mapping, index); + page = grab_cache_page(inode->i_mapping, index); error = -ENOMEM; if (!page) { goto out; @@ -2044,10 +2042,8 @@ static int grab_tail_page(struct inode *p_s_inode, ** I've screwed up the code to find the buffer, or the code to ** call prepare_write */ - reiserfs_warning(p_s_inode->i_sb, - "clm-6000: error reading block %lu on dev %s", - bh->b_blocknr, - reiserfs_bdevname(p_s_inode->i_sb)); + reiserfs_error(inode->i_sb, "clm-6000", + "error reading block %lu", bh->b_blocknr); error = -EIO; goto unlock; } @@ -2069,57 +2065,58 @@ static int grab_tail_page(struct inode *p_s_inode, ** ** some code taken from block_truncate_page */ -int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) +int reiserfs_truncate_file(struct inode *inode, int update_timestamps) { struct reiserfs_transaction_handle th; /* we want the offset for the first byte after the end of the file */ - unsigned long offset = p_s_inode->i_size & (PAGE_CACHE_SIZE - 1); - unsigned blocksize = p_s_inode->i_sb->s_blocksize; + unsigned long offset = inode->i_size & (PAGE_CACHE_SIZE - 1); + unsigned blocksize = inode->i_sb->s_blocksize; unsigned length; struct page *page = NULL; int error; struct buffer_head *bh = NULL; int err2; - reiserfs_write_lock(p_s_inode->i_sb); + reiserfs_write_lock(inode->i_sb); - if (p_s_inode->i_size > 0) { - if ((error = grab_tail_page(p_s_inode, &page, &bh))) { - // -ENOENT means we truncated past the end of the file, + if (inode->i_size > 0) { + error = grab_tail_page(inode, &page, &bh); + if (error) { + // -ENOENT means we truncated past the end of the file, // and get_block_create_0 could not find a block to read in, // which is ok. if (error != -ENOENT) - reiserfs_warning(p_s_inode->i_sb, - "clm-6001: grab_tail_page failed %d", - error); + reiserfs_error(inode->i_sb, "clm-6001", + "grab_tail_page failed %d", + error); page = NULL; bh = NULL; } } - /* so, if page != NULL, we have a buffer head for the offset at - ** the end of the file. if the bh is mapped, and bh->b_blocknr != 0, - ** then we have an unformatted node. Otherwise, we have a direct item, - ** and no zeroing is required on disk. We zero after the truncate, - ** because the truncate might pack the item anyway + /* so, if page != NULL, we have a buffer head for the offset at + ** the end of the file. if the bh is mapped, and bh->b_blocknr != 0, + ** then we have an unformatted node. Otherwise, we have a direct item, + ** and no zeroing is required on disk. We zero after the truncate, + ** because the truncate might pack the item anyway ** (it will unmap bh if it packs). */ /* it is enough to reserve space in transaction for 2 balancings: one for "save" link adding and another for the first cut_from_item. 1 is for update_sd */ - error = journal_begin(&th, p_s_inode->i_sb, + error = journal_begin(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1); if (error) goto out; - reiserfs_update_inode_transaction(p_s_inode); + reiserfs_update_inode_transaction(inode); if (update_timestamps) /* we are doing real truncate: if the system crashes before the last transaction of truncating gets committed - on reboot the file either appears truncated properly or not truncated at all */ - add_save_link(&th, p_s_inode, 1); - err2 = reiserfs_do_truncate(&th, p_s_inode, page, update_timestamps); + add_save_link(&th, inode, 1); + err2 = reiserfs_do_truncate(&th, inode, page, update_timestamps); error = - journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1); + journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1); if (error) goto out; @@ -2130,7 +2127,7 @@ int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) } if (update_timestamps) { - error = remove_save_link(p_s_inode, 1 /* truncate */ ); + error = remove_save_link(inode, 1 /* truncate */); if (error) goto out; } @@ -2149,14 +2146,14 @@ int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) page_cache_release(page); } - reiserfs_write_unlock(p_s_inode->i_sb); + reiserfs_write_unlock(inode->i_sb); return 0; out: if (page) { unlock_page(page); page_cache_release(page); } - reiserfs_write_unlock(p_s_inode->i_sb); + reiserfs_write_unlock(inode->i_sb); return error; } @@ -2208,9 +2205,8 @@ static int map_block_for_writepage(struct inode *inode, /* we've found an unformatted node */ if (indirect_item_found(retval, ih)) { if (bytes_copied > 0) { - reiserfs_warning(inode->i_sb, - "clm-6002: bytes_copied %d", - bytes_copied); + reiserfs_warning(inode->i_sb, "clm-6002", + "bytes_copied %d", bytes_copied); } if (!get_block_num(item, pos_in_item)) { /* crap, we are writing to a hole */ @@ -2267,9 +2263,8 @@ static int map_block_for_writepage(struct inode *inode, goto research; } } else { - reiserfs_warning(inode->i_sb, - "clm-6003: bad item inode %lu, device %s", - inode->i_ino, reiserfs_bdevname(inode->i_sb)); + reiserfs_warning(inode->i_sb, "clm-6003", + "bad item inode %lu", inode->i_ino); retval = -EIO; goto out; } @@ -2312,8 +2307,8 @@ static int map_block_for_writepage(struct inode *inode, return retval; } -/* - * mason@suse.com: updated in 2.5.54 to follow the same general io +/* + * mason@suse.com: updated in 2.5.54 to follow the same general io * start/recovery path as __block_write_full_page, along with special * code to handle reiserfs tails. */ @@ -2453,7 +2448,7 @@ static int reiserfs_write_full_page(struct page *page, unlock_page(page); /* - * since any buffer might be the only dirty buffer on the page, + * since any buffer might be the only dirty buffer on the page, * the first submit_bh can bring the page out of writeback. * be careful with the buffers. */ @@ -2472,8 +2467,8 @@ static int reiserfs_write_full_page(struct page *page, if (nr == 0) { /* * if this page only had a direct item, it is very possible for - * no io to be required without there being an error. Or, - * someone else could have locked them and sent them down the + * no io to be required without there being an error. Or, + * someone else could have locked them and sent them down the * pipe without locking the page */ bh = head; @@ -2492,7 +2487,7 @@ static int reiserfs_write_full_page(struct page *page, fail: /* catches various errors, we need to make sure any valid dirty blocks - * get to the media. The page is currently locked and not marked for + * get to the media. The page is currently locked and not marked for * writeback */ ClearPageUptodate(page); @@ -3119,7 +3114,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) if (error) goto out; error = - DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; + vfs_dq_transfer(inode, attr) ? -EDQUOT : 0; if (error) { journal_end(&th, inode->i_sb, jbegin_count); diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index 830332021ed..0ccc3fdda7b 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c @@ -189,7 +189,7 @@ int reiserfs_unpack(struct inode *inode, struct file *filp) } /* we unpack by finding the page with the tail, and calling - ** reiserfs_prepare_write on that page. This will force a + ** reiserfs_prepare_write on that page. This will force a ** reiserfs_get_block to unpack the tail for us. */ index = inode->i_size >> PAGE_CACHE_SHIFT; diff --git a/fs/reiserfs/item_ops.c b/fs/reiserfs/item_ops.c index 9475557ab49..72cb1cc51b8 100644 --- a/fs/reiserfs/item_ops.c +++ b/fs/reiserfs/item_ops.c @@ -97,7 +97,8 @@ static int sd_unit_num(struct virtual_item *vi) static void sd_print_vi(struct virtual_item *vi) { - reiserfs_warning(NULL, "STATDATA, index %d, type 0x%x, %h", + reiserfs_warning(NULL, "reiserfs-16100", + "STATDATA, index %d, type 0x%x, %h", vi->vi_index, vi->vi_type, vi->vi_ih); } @@ -190,7 +191,8 @@ static int direct_unit_num(struct virtual_item *vi) static void direct_print_vi(struct virtual_item *vi) { - reiserfs_warning(NULL, "DIRECT, index %d, type 0x%x, %h", + reiserfs_warning(NULL, "reiserfs-16101", + "DIRECT, index %d, type 0x%x, %h", vi->vi_index, vi->vi_type, vi->vi_ih); } @@ -278,7 +280,7 @@ static void indirect_print_item(struct item_head *ih, char *item) unp = (__le32 *) item; if (ih_item_len(ih) % UNFM_P_SIZE) - reiserfs_warning(NULL, "indirect_print_item: invalid item len"); + reiserfs_warning(NULL, "reiserfs-16102", "invalid item len"); printk("%d pointers\n[ ", (int)I_UNFM_NUM(ih)); for (j = 0; j < I_UNFM_NUM(ih); j++) { @@ -334,7 +336,8 @@ static int indirect_unit_num(struct virtual_item *vi) static void indirect_print_vi(struct virtual_item *vi) { - reiserfs_warning(NULL, "INDIRECT, index %d, type 0x%x, %h", + reiserfs_warning(NULL, "reiserfs-16103", + "INDIRECT, index %d, type 0x%x, %h", vi->vi_index, vi->vi_type, vi->vi_ih); } @@ -359,7 +362,7 @@ static struct item_operations indirect_ops = { static int direntry_bytes_number(struct item_head *ih, int block_size) { - reiserfs_warning(NULL, "vs-16090: direntry_bytes_number: " + reiserfs_warning(NULL, "vs-16090", "bytes number is asked for direntry"); return 0; } @@ -514,8 +517,9 @@ static int direntry_create_vi(struct virtual_node *vn, ((is_affected && (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT)) ? insert_size : 0)) { - reiserfs_panic(NULL, - "vs-8025: set_entry_sizes: (mode==%c, insert_size==%d), invalid length of directory item", + reiserfs_panic(NULL, "vs-8025", "(mode==%c, " + "insert_size==%d), invalid length of " + "directory item", vn->vn_mode, insert_size); } } @@ -546,7 +550,8 @@ static int direntry_check_left(struct virtual_item *vi, int free, } if (entries == dir_u->entry_count) { - reiserfs_panic(NULL, "free space %d, entry_count %d\n", free, + reiserfs_panic(NULL, "item_ops-1", + "free space %d, entry_count %d", free, dir_u->entry_count); } @@ -614,7 +619,8 @@ static void direntry_print_vi(struct virtual_item *vi) int i; struct direntry_uarea *dir_u = vi->vi_uarea; - reiserfs_warning(NULL, "DIRENTRY, index %d, type 0x%x, %h, flags 0x%x", + reiserfs_warning(NULL, "reiserfs-16104", + "DIRENTRY, index %d, type 0x%x, %h, flags 0x%x", vi->vi_index, vi->vi_type, vi->vi_ih, dir_u->flags); printk("%d entries: ", dir_u->entry_count); for (i = 0; i < dir_u->entry_count; i++) @@ -642,43 +648,43 @@ static struct item_operations direntry_ops = { // static int errcatch_bytes_number(struct item_head *ih, int block_size) { - reiserfs_warning(NULL, - "green-16001: Invalid item type observed, run fsck ASAP"); + reiserfs_warning(NULL, "green-16001", + "Invalid item type observed, run fsck ASAP"); return 0; } static void errcatch_decrement_key(struct cpu_key *key) { - reiserfs_warning(NULL, - "green-16002: Invalid item type observed, run fsck ASAP"); + reiserfs_warning(NULL, "green-16002", + "Invalid item type observed, run fsck ASAP"); } static int errcatch_is_left_mergeable(struct reiserfs_key *key, unsigned long bsize) { - reiserfs_warning(NULL, - "green-16003: Invalid item type observed, run fsck ASAP"); + reiserfs_warning(NULL, "green-16003", + "Invalid item type observed, run fsck ASAP"); return 0; } static void errcatch_print_item(struct item_head *ih, char *item) { - reiserfs_warning(NULL, - "green-16004: Invalid item type observed, run fsck ASAP"); + reiserfs_warning(NULL, "green-16004", + "Invalid item type observed, run fsck ASAP"); } static void errcatch_check_item(struct item_head *ih, char *item) { - reiserfs_warning(NULL, - "green-16005: Invalid item type observed, run fsck ASAP"); + reiserfs_warning(NULL, "green-16005", + "Invalid item type observed, run fsck ASAP"); } static int errcatch_create_vi(struct virtual_node *vn, struct virtual_item *vi, int is_affected, int insert_size) { - reiserfs_warning(NULL, - "green-16006: Invalid item type observed, run fsck ASAP"); + reiserfs_warning(NULL, "green-16006", + "Invalid item type observed, run fsck ASAP"); return 0; // We might return -1 here as well, but it won't help as create_virtual_node() from where // this operation is called from is of return type void. } @@ -686,36 +692,36 @@ static int errcatch_create_vi(struct virtual_node *vn, static int errcatch_check_left(struct virtual_item *vi, int free, int start_skip, int end_skip) { - reiserfs_warning(NULL, - "green-16007: Invalid item type observed, run fsck ASAP"); + reiserfs_warning(NULL, "green-16007", + "Invalid item type observed, run fsck ASAP"); return -1; } static int errcatch_check_right(struct virtual_item *vi, int free) { - reiserfs_warning(NULL, - "green-16008: Invalid item type observed, run fsck ASAP"); + reiserfs_warning(NULL, "green-16008", + "Invalid item type observed, run fsck ASAP"); return -1; } static int errcatch_part_size(struct virtual_item *vi, int first, int count) { - reiserfs_warning(NULL, - "green-16009: Invalid item type observed, run fsck ASAP"); + reiserfs_warning(NULL, "green-16009", + "Invalid item type observed, run fsck ASAP"); return 0; } static int errcatch_unit_num(struct virtual_item *vi) { - reiserfs_warning(NULL, - "green-16010: Invalid item type observed, run fsck ASAP"); + reiserfs_warning(NULL, "green-16010", + "Invalid item type observed, run fsck ASAP"); return 0; } static void errcatch_print_vi(struct virtual_item *vi) { - reiserfs_warning(NULL, - "green-16011: Invalid item type observed, run fsck ASAP"); + reiserfs_warning(NULL, "green-16011", + "Invalid item type observed, run fsck ASAP"); } static struct item_operations errcatch_ops = { diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 9643c3bbeb3..77f5bb746bf 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -1,36 +1,36 @@ /* ** Write ahead logging implementation copyright Chris Mason 2000 ** -** The background commits make this code very interelated, and +** The background commits make this code very interelated, and ** overly complex. I need to rethink things a bit....The major players: ** -** journal_begin -- call with the number of blocks you expect to log. +** journal_begin -- call with the number of blocks you expect to log. ** If the current transaction is too -** old, it will block until the current transaction is +** old, it will block until the current transaction is ** finished, and then start a new one. -** Usually, your transaction will get joined in with +** Usually, your transaction will get joined in with ** previous ones for speed. ** -** journal_join -- same as journal_begin, but won't block on the current +** journal_join -- same as journal_begin, but won't block on the current ** transaction regardless of age. Don't ever call -** this. Ever. There are only two places it should be +** this. Ever. There are only two places it should be ** called from, and they are both inside this file. ** -** journal_mark_dirty -- adds blocks into this transaction. clears any flags +** journal_mark_dirty -- adds blocks into this transaction. clears any flags ** that might make them get sent to disk -** and then marks them BH_JDirty. Puts the buffer head -** into the current transaction hash. +** and then marks them BH_JDirty. Puts the buffer head +** into the current transaction hash. ** ** journal_end -- if the current transaction is batchable, it does nothing ** otherwise, it could do an async/synchronous commit, or -** a full flush of all log and real blocks in the +** a full flush of all log and real blocks in the ** transaction. ** -** flush_old_commits -- if the current transaction is too old, it is ended and -** commit blocks are sent to disk. Forces commit blocks -** to disk for all backgrounded commits that have been +** flush_old_commits -- if the current transaction is too old, it is ended and +** commit blocks are sent to disk. Forces commit blocks +** to disk for all backgrounded commits that have been ** around too long. -** -- Note, if you call this as an immediate flush from +** -- Note, if you call this as an immediate flush from ** from within kupdate, it will ignore the immediate flag */ @@ -97,7 +97,7 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall); static int can_dirty(struct reiserfs_journal_cnode *cn); static int journal_join(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, unsigned long nblocks); + struct super_block *sb, unsigned long nblocks); static int release_journal_dev(struct super_block *super, struct reiserfs_journal *journal); static int dirty_one_transaction(struct super_block *s, @@ -113,12 +113,12 @@ enum { }; static int do_journal_begin_r(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, + struct super_block *sb, unsigned long nblocks, int join); -static void init_journal_hash(struct super_block *p_s_sb) +static void init_journal_hash(struct super_block *sb) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); memset(journal->j_hash_table, 0, JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *)); } @@ -145,7 +145,7 @@ static void disable_barrier(struct super_block *s) } static struct reiserfs_bitmap_node *allocate_bitmap_node(struct super_block - *p_s_sb) + *sb) { struct reiserfs_bitmap_node *bn; static int id; @@ -154,7 +154,7 @@ static struct reiserfs_bitmap_node *allocate_bitmap_node(struct super_block if (!bn) { return NULL; } - bn->data = kzalloc(p_s_sb->s_blocksize, GFP_NOFS); + bn->data = kzalloc(sb->s_blocksize, GFP_NOFS); if (!bn->data) { kfree(bn); return NULL; @@ -164,9 +164,9 @@ static struct reiserfs_bitmap_node *allocate_bitmap_node(struct super_block return bn; } -static struct reiserfs_bitmap_node *get_bitmap_node(struct super_block *p_s_sb) +static struct reiserfs_bitmap_node *get_bitmap_node(struct super_block *sb) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); struct reiserfs_bitmap_node *bn = NULL; struct list_head *entry = journal->j_bitmap_nodes.next; @@ -176,21 +176,21 @@ static struct reiserfs_bitmap_node *get_bitmap_node(struct super_block *p_s_sb) if (entry != &journal->j_bitmap_nodes) { bn = list_entry(entry, struct reiserfs_bitmap_node, list); list_del(entry); - memset(bn->data, 0, p_s_sb->s_blocksize); + memset(bn->data, 0, sb->s_blocksize); journal->j_free_bitmap_nodes--; return bn; } - bn = allocate_bitmap_node(p_s_sb); + bn = allocate_bitmap_node(sb); if (!bn) { yield(); goto repeat; } return bn; } -static inline void free_bitmap_node(struct super_block *p_s_sb, +static inline void free_bitmap_node(struct super_block *sb, struct reiserfs_bitmap_node *bn) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); journal->j_used_bitmap_nodes--; if (journal->j_free_bitmap_nodes > REISERFS_MAX_BITMAP_NODES) { kfree(bn->data); @@ -201,46 +201,46 @@ static inline void free_bitmap_node(struct super_block *p_s_sb, } } -static void allocate_bitmap_nodes(struct super_block *p_s_sb) +static void allocate_bitmap_nodes(struct super_block *sb) { int i; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); struct reiserfs_bitmap_node *bn = NULL; for (i = 0; i < REISERFS_MIN_BITMAP_NODES; i++) { - bn = allocate_bitmap_node(p_s_sb); + bn = allocate_bitmap_node(sb); if (bn) { list_add(&bn->list, &journal->j_bitmap_nodes); journal->j_free_bitmap_nodes++; } else { - break; // this is ok, we'll try again when more are needed + break; /* this is ok, we'll try again when more are needed */ } } } -static int set_bit_in_list_bitmap(struct super_block *p_s_sb, +static int set_bit_in_list_bitmap(struct super_block *sb, b_blocknr_t block, struct reiserfs_list_bitmap *jb) { - unsigned int bmap_nr = block / (p_s_sb->s_blocksize << 3); - unsigned int bit_nr = block % (p_s_sb->s_blocksize << 3); + unsigned int bmap_nr = block / (sb->s_blocksize << 3); + unsigned int bit_nr = block % (sb->s_blocksize << 3); if (!jb->bitmaps[bmap_nr]) { - jb->bitmaps[bmap_nr] = get_bitmap_node(p_s_sb); + jb->bitmaps[bmap_nr] = get_bitmap_node(sb); } set_bit(bit_nr, (unsigned long *)jb->bitmaps[bmap_nr]->data); return 0; } -static void cleanup_bitmap_list(struct super_block *p_s_sb, +static void cleanup_bitmap_list(struct super_block *sb, struct reiserfs_list_bitmap *jb) { int i; if (jb->bitmaps == NULL) return; - for (i = 0; i < reiserfs_bmap_count(p_s_sb); i++) { + for (i = 0; i < reiserfs_bmap_count(sb); i++) { if (jb->bitmaps[i]) { - free_bitmap_node(p_s_sb, jb->bitmaps[i]); + free_bitmap_node(sb, jb->bitmaps[i]); jb->bitmaps[i] = NULL; } } @@ -249,7 +249,7 @@ static void cleanup_bitmap_list(struct super_block *p_s_sb, /* ** only call this on FS unmount. */ -static int free_list_bitmaps(struct super_block *p_s_sb, +static int free_list_bitmaps(struct super_block *sb, struct reiserfs_list_bitmap *jb_array) { int i; @@ -257,16 +257,16 @@ static int free_list_bitmaps(struct super_block *p_s_sb, for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) { jb = jb_array + i; jb->journal_list = NULL; - cleanup_bitmap_list(p_s_sb, jb); + cleanup_bitmap_list(sb, jb); vfree(jb->bitmaps); jb->bitmaps = NULL; } return 0; } -static int free_bitmap_nodes(struct super_block *p_s_sb) +static int free_bitmap_nodes(struct super_block *sb) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); struct list_head *next = journal->j_bitmap_nodes.next; struct reiserfs_bitmap_node *bn; @@ -283,10 +283,10 @@ static int free_bitmap_nodes(struct super_block *p_s_sb) } /* -** get memory for JOURNAL_NUM_BITMAPS worth of bitmaps. +** get memory for JOURNAL_NUM_BITMAPS worth of bitmaps. ** jb_array is the array to be filled in. */ -int reiserfs_allocate_list_bitmaps(struct super_block *p_s_sb, +int reiserfs_allocate_list_bitmaps(struct super_block *sb, struct reiserfs_list_bitmap *jb_array, unsigned int bmap_nr) { @@ -300,30 +300,30 @@ int reiserfs_allocate_list_bitmaps(struct super_block *p_s_sb, jb->journal_list = NULL; jb->bitmaps = vmalloc(mem); if (!jb->bitmaps) { - reiserfs_warning(p_s_sb, - "clm-2000, unable to allocate bitmaps for journal lists"); + reiserfs_warning(sb, "clm-2000", "unable to " + "allocate bitmaps for journal lists"); failed = 1; break; } memset(jb->bitmaps, 0, mem); } if (failed) { - free_list_bitmaps(p_s_sb, jb_array); + free_list_bitmaps(sb, jb_array); return -1; } return 0; } /* -** find an available list bitmap. If you can't find one, flush a commit list +** find an available list bitmap. If you can't find one, flush a commit list ** and try again */ -static struct reiserfs_list_bitmap *get_list_bitmap(struct super_block *p_s_sb, +static struct reiserfs_list_bitmap *get_list_bitmap(struct super_block *sb, struct reiserfs_journal_list *jl) { int i, j; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); struct reiserfs_list_bitmap *jb = NULL; for (j = 0; j < (JOURNAL_NUM_BITMAPS * 3); j++) { @@ -331,7 +331,7 @@ static struct reiserfs_list_bitmap *get_list_bitmap(struct super_block *p_s_sb, journal->j_list_bitmap_index = (i + 1) % JOURNAL_NUM_BITMAPS; jb = journal->j_list_bitmap + i; if (journal->j_list_bitmap[i].journal_list) { - flush_commit_list(p_s_sb, + flush_commit_list(sb, journal->j_list_bitmap[i]. journal_list, 1); if (!journal->j_list_bitmap[i].journal_list) { @@ -348,7 +348,7 @@ static struct reiserfs_list_bitmap *get_list_bitmap(struct super_block *p_s_sb, return jb; } -/* +/* ** allocates a new chunk of X nodes, and links them all together as a list. ** Uses the cnode->next and cnode->prev pointers ** returns NULL on failure @@ -376,14 +376,14 @@ static struct reiserfs_journal_cnode *allocate_cnodes(int num_cnodes) } /* -** pulls a cnode off the free list, or returns NULL on failure +** pulls a cnode off the free list, or returns NULL on failure */ -static struct reiserfs_journal_cnode *get_cnode(struct super_block *p_s_sb) +static struct reiserfs_journal_cnode *get_cnode(struct super_block *sb) { struct reiserfs_journal_cnode *cn; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); - reiserfs_check_lock_depth(p_s_sb, "get_cnode"); + reiserfs_check_lock_depth(sb, "get_cnode"); if (journal->j_cnode_free <= 0) { return NULL; @@ -403,14 +403,14 @@ static struct reiserfs_journal_cnode *get_cnode(struct super_block *p_s_sb) } /* -** returns a cnode to the free list +** returns a cnode to the free list */ -static void free_cnode(struct super_block *p_s_sb, +static void free_cnode(struct super_block *sb, struct reiserfs_journal_cnode *cn) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); - reiserfs_check_lock_depth(p_s_sb, "free_cnode"); + reiserfs_check_lock_depth(sb, "free_cnode"); journal->j_cnode_used--; journal->j_cnode_free++; @@ -436,8 +436,8 @@ void reiserfs_check_lock_depth(struct super_block *sb, char *caller) { #ifdef CONFIG_SMP if (current->lock_depth < 0) { - reiserfs_panic(sb, "%s called without kernel lock held", - caller); + reiserfs_panic(sb, "journal-1", "%s called without kernel " + "lock held", caller); } #else ; @@ -481,11 +481,11 @@ static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct ** reject it on the next call to reiserfs_in_journal ** */ -int reiserfs_in_journal(struct super_block *p_s_sb, +int reiserfs_in_journal(struct super_block *sb, unsigned int bmap_nr, int bit_nr, int search_all, b_blocknr_t * next_zero_bit) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); struct reiserfs_journal_cnode *cn; struct reiserfs_list_bitmap *jb; int i; @@ -493,14 +493,14 @@ int reiserfs_in_journal(struct super_block *p_s_sb, *next_zero_bit = 0; /* always start this at zero. */ - PROC_INFO_INC(p_s_sb, journal.in_journal); + PROC_INFO_INC(sb, journal.in_journal); /* If we aren't doing a search_all, this is a metablock, and it will be logged before use. ** if we crash before the transaction that freed it commits, this transaction won't ** have committed either, and the block will never be written */ if (search_all) { for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) { - PROC_INFO_INC(p_s_sb, journal.in_journal_bitmap); + PROC_INFO_INC(sb, journal.in_journal_bitmap); jb = journal->j_list_bitmap + i; if (jb->journal_list && jb->bitmaps[bmap_nr] && test_bit(bit_nr, @@ -510,28 +510,28 @@ int reiserfs_in_journal(struct super_block *p_s_sb, find_next_zero_bit((unsigned long *) (jb->bitmaps[bmap_nr]-> data), - p_s_sb->s_blocksize << 3, + sb->s_blocksize << 3, bit_nr + 1); return 1; } } } - bl = bmap_nr * (p_s_sb->s_blocksize << 3) + bit_nr; + bl = bmap_nr * (sb->s_blocksize << 3) + bit_nr; /* is it in any old transactions? */ if (search_all && (cn = - get_journal_hash_dev(p_s_sb, journal->j_list_hash_table, bl))) { + get_journal_hash_dev(sb, journal->j_list_hash_table, bl))) { return 1; } /* is it in the current transaction. This should never happen */ - if ((cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, bl))) { + if ((cn = get_journal_hash_dev(sb, journal->j_hash_table, bl))) { BUG(); return 1; } - PROC_INFO_INC(p_s_sb, journal.in_journal_reusable); + PROC_INFO_INC(sb, journal.in_journal_reusable); /* safe for reuse */ return 0; } @@ -553,16 +553,16 @@ static inline void insert_journal_hash(struct reiserfs_journal_cnode **table, } /* lock the current transaction */ -static inline void lock_journal(struct super_block *p_s_sb) +static inline void lock_journal(struct super_block *sb) { - PROC_INFO_INC(p_s_sb, journal.lock_journal); - mutex_lock(&SB_JOURNAL(p_s_sb)->j_mutex); + PROC_INFO_INC(sb, journal.lock_journal); + mutex_lock(&SB_JOURNAL(sb)->j_mutex); } /* unlock the current transaction */ -static inline void unlock_journal(struct super_block *p_s_sb) +static inline void unlock_journal(struct super_block *sb) { - mutex_unlock(&SB_JOURNAL(p_s_sb)->j_mutex); + mutex_unlock(&SB_JOURNAL(sb)->j_mutex); } static inline void get_journal_list(struct reiserfs_journal_list *jl) @@ -574,7 +574,7 @@ static inline void put_journal_list(struct super_block *s, struct reiserfs_journal_list *jl) { if (jl->j_refcount < 1) { - reiserfs_panic(s, "trans id %lu, refcount at %d", + reiserfs_panic(s, "journal-2", "trans id %u, refcount at %d", jl->j_trans_id, jl->j_refcount); } if (--jl->j_refcount == 0) @@ -586,20 +586,20 @@ static inline void put_journal_list(struct super_block *s, ** it gets called by flush_commit_list, and cleans up any data stored about blocks freed during a ** transaction. */ -static void cleanup_freed_for_journal_list(struct super_block *p_s_sb, +static void cleanup_freed_for_journal_list(struct super_block *sb, struct reiserfs_journal_list *jl) { struct reiserfs_list_bitmap *jb = jl->j_list_bitmap; if (jb) { - cleanup_bitmap_list(p_s_sb, jb); + cleanup_bitmap_list(sb, jb); } jl->j_list_bitmap->journal_list = NULL; jl->j_list_bitmap = NULL; } static int journal_list_still_alive(struct super_block *s, - unsigned long trans_id) + unsigned int trans_id) { struct reiserfs_journal *journal = SB_JOURNAL(s); struct list_head *entry = &journal->j_journal_list; @@ -644,8 +644,8 @@ static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate) char b[BDEVNAME_SIZE]; if (buffer_journaled(bh)) { - reiserfs_warning(NULL, - "clm-2084: pinned buffer %lu:%s sent to disk", + reiserfs_warning(NULL, "clm-2084", + "pinned buffer %lu:%s sent to disk", bh->b_blocknr, bdevname(bh->b_bdev, b)); } if (uptodate) @@ -933,9 +933,9 @@ static int flush_older_commits(struct super_block *s, struct reiserfs_journal_list *other_jl; struct reiserfs_journal_list *first_jl; struct list_head *entry; - unsigned long trans_id = jl->j_trans_id; - unsigned long other_trans_id; - unsigned long first_trans_id; + unsigned int trans_id = jl->j_trans_id; + unsigned int other_trans_id; + unsigned int first_trans_id; find_first: /* @@ -1014,7 +1014,7 @@ static int flush_commit_list(struct super_block *s, int i; b_blocknr_t bn; struct buffer_head *tbh = NULL; - unsigned long trans_id = jl->j_trans_id; + unsigned int trans_id = jl->j_trans_id; struct reiserfs_journal *journal = SB_JOURNAL(s); int barrier = 0; int retval = 0; @@ -1122,7 +1122,8 @@ static int flush_commit_list(struct super_block *s, sync_dirty_buffer(tbh); if (unlikely(!buffer_uptodate(tbh))) { #ifdef CONFIG_REISERFS_CHECK - reiserfs_warning(s, "journal-601, buffer write failed"); + reiserfs_warning(s, "journal-601", + "buffer write failed"); #endif retval = -EIO; } @@ -1154,14 +1155,14 @@ static int flush_commit_list(struct super_block *s, * up propagating the write error out to the filesystem. */ if (unlikely(!buffer_uptodate(jl->j_commit_bh))) { #ifdef CONFIG_REISERFS_CHECK - reiserfs_warning(s, "journal-615: buffer write failed"); + reiserfs_warning(s, "journal-615", "buffer write failed"); #endif retval = -EIO; } bforget(jl->j_commit_bh); if (journal->j_last_commit_id != 0 && (jl->j_trans_id - journal->j_last_commit_id) != 1) { - reiserfs_warning(s, "clm-2200: last commit %lu, current %lu", + reiserfs_warning(s, "clm-2200", "last commit %lu, current %lu", journal->j_last_commit_id, jl->j_trans_id); } journal->j_last_commit_id = jl->j_trans_id; @@ -1191,8 +1192,8 @@ static int flush_commit_list(struct super_block *s, } /* -** flush_journal_list frequently needs to find a newer transaction for a given block. This does that, or -** returns NULL if it can't find anything +** flush_journal_list frequently needs to find a newer transaction for a given block. This does that, or +** returns NULL if it can't find anything */ static struct reiserfs_journal_list *find_newer_jl_for_cn(struct reiserfs_journal_cnode @@ -1236,11 +1237,11 @@ static void remove_journal_hash(struct super_block *, ** journal list for this transaction. Aside from freeing the cnode, this also allows the ** block to be reallocated for data blocks if it had been deleted. */ -static void remove_all_from_journal_list(struct super_block *p_s_sb, +static void remove_all_from_journal_list(struct super_block *sb, struct reiserfs_journal_list *jl, int debug) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); struct reiserfs_journal_cnode *cn, *last; cn = jl->j_realblock; @@ -1250,18 +1251,18 @@ static void remove_all_from_journal_list(struct super_block *p_s_sb, while (cn) { if (cn->blocknr != 0) { if (debug) { - reiserfs_warning(p_s_sb, + reiserfs_warning(sb, "reiserfs-2201", "block %u, bh is %d, state %ld", cn->blocknr, cn->bh ? 1 : 0, cn->state); } cn->state = 0; - remove_journal_hash(p_s_sb, journal->j_list_hash_table, + remove_journal_hash(sb, journal->j_list_hash_table, jl, cn->blocknr, 1); } last = cn; cn = cn->next; - free_cnode(p_s_sb, last); + free_cnode(sb, last); } jl->j_realblock = NULL; } @@ -1273,12 +1274,12 @@ static void remove_all_from_journal_list(struct super_block *p_s_sb, ** called by flush_journal_list, before it calls remove_all_from_journal_list ** */ -static int _update_journal_header_block(struct super_block *p_s_sb, +static int _update_journal_header_block(struct super_block *sb, unsigned long offset, - unsigned long trans_id) + unsigned int trans_id) { struct reiserfs_journal_header *jh; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); if (reiserfs_is_journal_aborted(journal)) return -EIO; @@ -1288,8 +1289,8 @@ static int _update_journal_header_block(struct super_block *p_s_sb, wait_on_buffer((journal->j_header_bh)); if (unlikely(!buffer_uptodate(journal->j_header_bh))) { #ifdef CONFIG_REISERFS_CHECK - reiserfs_warning(p_s_sb, - "journal-699: buffer write failed"); + reiserfs_warning(sb, "journal-699", + "buffer write failed"); #endif return -EIO; } @@ -1302,49 +1303,49 @@ static int _update_journal_header_block(struct super_block *p_s_sb, jh->j_first_unflushed_offset = cpu_to_le32(offset); jh->j_mount_id = cpu_to_le32(journal->j_mount_id); - if (reiserfs_barrier_flush(p_s_sb)) { + if (reiserfs_barrier_flush(sb)) { int ret; lock_buffer(journal->j_header_bh); ret = submit_barrier_buffer(journal->j_header_bh); if (ret == -EOPNOTSUPP) { set_buffer_uptodate(journal->j_header_bh); - disable_barrier(p_s_sb); + disable_barrier(sb); goto sync; } wait_on_buffer(journal->j_header_bh); - check_barrier_completion(p_s_sb, journal->j_header_bh); + check_barrier_completion(sb, journal->j_header_bh); } else { sync: set_buffer_dirty(journal->j_header_bh); sync_dirty_buffer(journal->j_header_bh); } if (!buffer_uptodate(journal->j_header_bh)) { - reiserfs_warning(p_s_sb, - "journal-837: IO error during journal replay"); + reiserfs_warning(sb, "journal-837", + "IO error during journal replay"); return -EIO; } } return 0; } -static int update_journal_header_block(struct super_block *p_s_sb, +static int update_journal_header_block(struct super_block *sb, unsigned long offset, - unsigned long trans_id) + unsigned int trans_id) { - return _update_journal_header_block(p_s_sb, offset, trans_id); + return _update_journal_header_block(sb, offset, trans_id); } -/* -** flush any and all journal lists older than you are +/* +** flush any and all journal lists older than you are ** can only be called from flush_journal_list */ -static int flush_older_journal_lists(struct super_block *p_s_sb, +static int flush_older_journal_lists(struct super_block *sb, struct reiserfs_journal_list *jl) { struct list_head *entry; struct reiserfs_journal_list *other_jl; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); - unsigned long trans_id = jl->j_trans_id; + struct reiserfs_journal *journal = SB_JOURNAL(sb); + unsigned int trans_id = jl->j_trans_id; /* we know we are the only ones flushing things, no extra race * protection is required. @@ -1358,7 +1359,7 @@ static int flush_older_journal_lists(struct super_block *p_s_sb, if (other_jl->j_trans_id < trans_id) { BUG_ON(other_jl->j_refcount <= 0); /* do not flush all */ - flush_journal_list(p_s_sb, other_jl, 0); + flush_journal_list(sb, other_jl, 0); /* other_jl is now deleted from the list */ goto restart; @@ -1381,8 +1382,8 @@ static void del_from_work_list(struct super_block *s, ** always set flushall to 1, unless you are calling from inside ** flush_journal_list ** -** IMPORTANT. This can only be called while there are no journal writers, -** and the journal is locked. That means it can only be called from +** IMPORTANT. This can only be called while there are no journal writers, +** and the journal is locked. That means it can only be called from ** do_journal_end, or by journal_release */ static int flush_journal_list(struct super_block *s, @@ -1401,8 +1402,7 @@ static int flush_journal_list(struct super_block *s, BUG_ON(j_len_saved <= 0); if (atomic_read(&journal->j_wcount) != 0) { - reiserfs_warning(s, - "clm-2048: flush_journal_list called with wcount %d", + reiserfs_warning(s, "clm-2048", "called with wcount %d", atomic_read(&journal->j_wcount)); } BUG_ON(jl->j_trans_id == 0); @@ -1416,8 +1416,7 @@ static int flush_journal_list(struct super_block *s, count = 0; if (j_len_saved > journal->j_trans_max) { - reiserfs_panic(s, - "journal-715: flush_journal_list, length is %lu, trans id %lu\n", + reiserfs_panic(s, "journal-715", "length is %lu, trans id %lu", j_len_saved, jl->j_trans_id); return 0; } @@ -1430,7 +1429,7 @@ static int flush_journal_list(struct super_block *s, goto flush_older_and_return; } - /* start by putting the commit list on disk. This will also flush + /* start by putting the commit list on disk. This will also flush ** the commit lists of any olders transactions */ flush_commit_list(s, jl, 1); @@ -1445,12 +1444,12 @@ static int flush_journal_list(struct super_block *s, goto flush_older_and_return; } - /* loop through each cnode, see if we need to write it, - ** or wait on a more recent transaction, or just ignore it + /* loop through each cnode, see if we need to write it, + ** or wait on a more recent transaction, or just ignore it */ if (atomic_read(&(journal->j_wcount)) != 0) { - reiserfs_panic(s, - "journal-844: panic journal list is flushing, wcount is not 0\n"); + reiserfs_panic(s, "journal-844", "journal list is flushing, " + "wcount is not 0"); } cn = jl->j_realblock; while (cn) { @@ -1474,8 +1473,8 @@ static int flush_journal_list(struct super_block *s, if (!pjl && cn->bh) { saved_bh = cn->bh; - /* we do this to make sure nobody releases the buffer while - ** we are working with it + /* we do this to make sure nobody releases the buffer while + ** we are working with it */ get_bh(saved_bh); @@ -1498,8 +1497,8 @@ static int flush_journal_list(struct super_block *s, goto free_cnode; } - /* bh == NULL when the block got to disk on its own, OR, - ** the block got freed in a future transaction + /* bh == NULL when the block got to disk on its own, OR, + ** the block got freed in a future transaction */ if (saved_bh == NULL) { goto free_cnode; @@ -1510,8 +1509,8 @@ static int flush_journal_list(struct super_block *s, ** is not marked JDirty_wait */ if ((!was_jwait) && !buffer_locked(saved_bh)) { - reiserfs_warning(s, - "journal-813: BAD! buffer %llu %cdirty %cjwait, " + reiserfs_warning(s, "journal-813", + "BAD! buffer %llu %cdirty %cjwait, " "not in a newer tranasction", (unsigned long long)saved_bh-> b_blocknr, was_dirty ? ' ' : '!', @@ -1529,8 +1528,8 @@ static int flush_journal_list(struct super_block *s, unlock_buffer(saved_bh); count++; } else { - reiserfs_warning(s, - "clm-2082: Unable to flush buffer %llu in %s", + reiserfs_warning(s, "clm-2082", + "Unable to flush buffer %llu in %s", (unsigned long long)saved_bh-> b_blocknr, __func__); } @@ -1541,8 +1540,8 @@ static int flush_journal_list(struct super_block *s, /* we incremented this to keep others from taking the buffer head away */ put_bh(saved_bh); if (atomic_read(&(saved_bh->b_count)) < 0) { - reiserfs_warning(s, - "journal-945: saved_bh->b_count < 0"); + reiserfs_warning(s, "journal-945", + "saved_bh->b_count < 0"); } } } @@ -1551,18 +1550,18 @@ static int flush_journal_list(struct super_block *s, while (cn) { if (test_bit(BLOCK_NEEDS_FLUSH, &cn->state)) { if (!cn->bh) { - reiserfs_panic(s, - "journal-1011: cn->bh is NULL\n"); + reiserfs_panic(s, "journal-1011", + "cn->bh is NULL"); } wait_on_buffer(cn->bh); if (!cn->bh) { - reiserfs_panic(s, - "journal-1012: cn->bh is NULL\n"); + reiserfs_panic(s, "journal-1012", + "cn->bh is NULL"); } if (unlikely(!buffer_uptodate(cn->bh))) { #ifdef CONFIG_REISERFS_CHECK - reiserfs_warning(s, - "journal-949: buffer write failed\n"); + reiserfs_warning(s, "journal-949", + "buffer write failed"); #endif err = -EIO; } @@ -1587,7 +1586,7 @@ static int flush_journal_list(struct super_block *s, __func__); flush_older_and_return: - /* before we can update the journal header block, we _must_ flush all + /* before we can update the journal header block, we _must_ flush all ** real blocks from all older transactions to disk. This is because ** once the header block is updated, this transaction will not be ** replayed after a crash @@ -1597,7 +1596,7 @@ static int flush_journal_list(struct super_block *s, } err = journal->j_errno; - /* before we can remove everything from the hash tables for this + /* before we can remove everything from the hash tables for this ** transaction, we must make sure it can never be replayed ** ** since we are only called from do_journal_end, we know for sure there @@ -1623,7 +1622,7 @@ static int flush_journal_list(struct super_block *s, if (journal->j_last_flush_id != 0 && (jl->j_trans_id - journal->j_last_flush_id) != 1) { - reiserfs_warning(s, "clm-2201: last flush %lu, current %lu", + reiserfs_warning(s, "clm-2201", "last flush %lu, current %lu", journal->j_last_flush_id, jl->j_trans_id); } journal->j_last_flush_id = jl->j_trans_id; @@ -1758,13 +1757,13 @@ static int dirty_one_transaction(struct super_block *s, static int kupdate_transactions(struct super_block *s, struct reiserfs_journal_list *jl, struct reiserfs_journal_list **next_jl, - unsigned long *next_trans_id, + unsigned int *next_trans_id, int num_blocks, int num_trans) { int ret = 0; int written = 0; int transactions_flushed = 0; - unsigned long orig_trans_id = jl->j_trans_id; + unsigned int orig_trans_id = jl->j_trans_id; struct buffer_chunk chunk; struct list_head *entry; struct reiserfs_journal *journal = SB_JOURNAL(s); @@ -1833,7 +1832,7 @@ static int flush_used_journal_lists(struct super_block *s, int limit = 256; struct reiserfs_journal_list *tjl; struct reiserfs_journal_list *flush_jl; - unsigned long trans_id; + unsigned int trans_id; struct reiserfs_journal *journal = SB_JOURNAL(s); flush_jl = tjl = jl; @@ -1909,22 +1908,22 @@ void remove_journal_hash(struct super_block *sb, } } -static void free_journal_ram(struct super_block *p_s_sb) +static void free_journal_ram(struct super_block *sb) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); kfree(journal->j_current_jl); journal->j_num_lists--; vfree(journal->j_cnode_free_orig); - free_list_bitmaps(p_s_sb, journal->j_list_bitmap); - free_bitmap_nodes(p_s_sb); /* must be after free_list_bitmaps */ + free_list_bitmaps(sb, journal->j_list_bitmap); + free_bitmap_nodes(sb); /* must be after free_list_bitmaps */ if (journal->j_header_bh) { brelse(journal->j_header_bh); } /* j_header_bh is on the journal dev, make sure not to release the journal * dev until we brelse j_header_bh */ - release_journal_dev(p_s_sb, journal); + release_journal_dev(sb, journal); vfree(journal); } @@ -1933,27 +1932,27 @@ static void free_journal_ram(struct super_block *p_s_sb) ** of read_super() yet. Any other caller must keep error at 0. */ static int do_journal_release(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, int error) + struct super_block *sb, int error) { struct reiserfs_transaction_handle myth; int flushed = 0; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); /* we only want to flush out transactions if we were called with error == 0 */ - if (!error && !(p_s_sb->s_flags & MS_RDONLY)) { + if (!error && !(sb->s_flags & MS_RDONLY)) { /* end the current trans */ BUG_ON(!th->t_trans_id); - do_journal_end(th, p_s_sb, 10, FLUSH_ALL); + do_journal_end(th, sb, 10, FLUSH_ALL); /* make sure something gets logged to force our way into the flush code */ - if (!journal_join(&myth, p_s_sb, 1)) { - reiserfs_prepare_for_journal(p_s_sb, - SB_BUFFER_WITH_SB(p_s_sb), + if (!journal_join(&myth, sb, 1)) { + reiserfs_prepare_for_journal(sb, + SB_BUFFER_WITH_SB(sb), 1); - journal_mark_dirty(&myth, p_s_sb, - SB_BUFFER_WITH_SB(p_s_sb)); - do_journal_end(&myth, p_s_sb, 1, FLUSH_ALL); + journal_mark_dirty(&myth, sb, + SB_BUFFER_WITH_SB(sb)); + do_journal_end(&myth, sb, 1, FLUSH_ALL); flushed = 1; } } @@ -1961,26 +1960,26 @@ static int do_journal_release(struct reiserfs_transaction_handle *th, /* this also catches errors during the do_journal_end above */ if (!error && reiserfs_is_journal_aborted(journal)) { memset(&myth, 0, sizeof(myth)); - if (!journal_join_abort(&myth, p_s_sb, 1)) { - reiserfs_prepare_for_journal(p_s_sb, - SB_BUFFER_WITH_SB(p_s_sb), + if (!journal_join_abort(&myth, sb, 1)) { + reiserfs_prepare_for_journal(sb, + SB_BUFFER_WITH_SB(sb), 1); - journal_mark_dirty(&myth, p_s_sb, - SB_BUFFER_WITH_SB(p_s_sb)); - do_journal_end(&myth, p_s_sb, 1, FLUSH_ALL); + journal_mark_dirty(&myth, sb, + SB_BUFFER_WITH_SB(sb)); + do_journal_end(&myth, sb, 1, FLUSH_ALL); } } reiserfs_mounted_fs_count--; /* wait for all commits to finish */ - cancel_delayed_work(&SB_JOURNAL(p_s_sb)->j_work); + cancel_delayed_work(&SB_JOURNAL(sb)->j_work); flush_workqueue(commit_wq); if (!reiserfs_mounted_fs_count) { destroy_workqueue(commit_wq); commit_wq = NULL; } - free_journal_ram(p_s_sb); + free_journal_ram(sb); return 0; } @@ -1989,41 +1988,41 @@ static int do_journal_release(struct reiserfs_transaction_handle *th, ** call on unmount. flush all journal trans, release all alloc'd ram */ int journal_release(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb) + struct super_block *sb) { - return do_journal_release(th, p_s_sb, 0); + return do_journal_release(th, sb, 0); } /* ** only call from an error condition inside reiserfs_read_super! */ int journal_release_error(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb) + struct super_block *sb) { - return do_journal_release(th, p_s_sb, 1); + return do_journal_release(th, sb, 1); } /* compares description block with commit block. returns 1 if they differ, 0 if they are the same */ -static int journal_compare_desc_commit(struct super_block *p_s_sb, +static int journal_compare_desc_commit(struct super_block *sb, struct reiserfs_journal_desc *desc, struct reiserfs_journal_commit *commit) { if (get_commit_trans_id(commit) != get_desc_trans_id(desc) || get_commit_trans_len(commit) != get_desc_trans_len(desc) || - get_commit_trans_len(commit) > SB_JOURNAL(p_s_sb)->j_trans_max || + get_commit_trans_len(commit) > SB_JOURNAL(sb)->j_trans_max || get_commit_trans_len(commit) <= 0) { return 1; } return 0; } -/* returns 0 if it did not find a description block +/* returns 0 if it did not find a description block ** returns -1 if it found a corrupt commit block -** returns 1 if both desc and commit were valid +** returns 1 if both desc and commit were valid */ -static int journal_transaction_is_valid(struct super_block *p_s_sb, +static int journal_transaction_is_valid(struct super_block *sb, struct buffer_head *d_bh, - unsigned long *oldest_invalid_trans_id, + unsigned int *oldest_invalid_trans_id, unsigned long *newest_mount_id) { struct reiserfs_journal_desc *desc; @@ -2039,7 +2038,7 @@ static int journal_transaction_is_valid(struct super_block *p_s_sb, && !memcmp(get_journal_desc_magic(d_bh), JOURNAL_DESC_MAGIC, 8)) { if (oldest_invalid_trans_id && *oldest_invalid_trans_id && get_desc_trans_id(desc) > *oldest_invalid_trans_id) { - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-986: transaction " "is valid returning because trans_id %d is greater than " "oldest_invalid %lu", @@ -2049,7 +2048,7 @@ static int journal_transaction_is_valid(struct super_block *p_s_sb, } if (newest_mount_id && *newest_mount_id > get_desc_mount_id(desc)) { - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1087: transaction " "is valid returning because mount_id %d is less than " "newest_mount_id %lu", @@ -2057,36 +2056,37 @@ static int journal_transaction_is_valid(struct super_block *p_s_sb, *newest_mount_id); return -1; } - if (get_desc_trans_len(desc) > SB_JOURNAL(p_s_sb)->j_trans_max) { - reiserfs_warning(p_s_sb, - "journal-2018: Bad transaction length %d encountered, ignoring transaction", + if (get_desc_trans_len(desc) > SB_JOURNAL(sb)->j_trans_max) { + reiserfs_warning(sb, "journal-2018", + "Bad transaction length %d " + "encountered, ignoring transaction", get_desc_trans_len(desc)); return -1; } - offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb); + offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(sb); /* ok, we have a journal description block, lets see if the transaction was valid */ c_bh = - journal_bread(p_s_sb, - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + + journal_bread(sb, + SB_ONDISK_JOURNAL_1st_BLOCK(sb) + ((offset + get_desc_trans_len(desc) + - 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))); + 1) % SB_ONDISK_JOURNAL_SIZE(sb))); if (!c_bh) return 0; commit = (struct reiserfs_journal_commit *)c_bh->b_data; - if (journal_compare_desc_commit(p_s_sb, desc, commit)) { - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + if (journal_compare_desc_commit(sb, desc, commit)) { + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal_transaction_is_valid, commit offset %ld had bad " "time %d or length %d", c_bh->b_blocknr - - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), + SB_ONDISK_JOURNAL_1st_BLOCK(sb), get_commit_trans_id(commit), get_commit_trans_len(commit)); brelse(c_bh); if (oldest_invalid_trans_id) { *oldest_invalid_trans_id = get_desc_trans_id(desc); - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1004: " "transaction_is_valid setting oldest invalid trans_id " "to %d", @@ -2095,11 +2095,11 @@ static int journal_transaction_is_valid(struct super_block *p_s_sb, return -1; } brelse(c_bh); - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1006: found valid " "transaction start offset %llu, len %d id %d", d_bh->b_blocknr - - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), + SB_ONDISK_JOURNAL_1st_BLOCK(sb), get_desc_trans_len(desc), get_desc_trans_id(desc)); return 1; @@ -2121,63 +2121,63 @@ static void brelse_array(struct buffer_head **heads, int num) ** this either reads in a replays a transaction, or returns because the transaction ** is invalid, or too old. */ -static int journal_read_transaction(struct super_block *p_s_sb, +static int journal_read_transaction(struct super_block *sb, unsigned long cur_dblock, unsigned long oldest_start, - unsigned long oldest_trans_id, + unsigned int oldest_trans_id, unsigned long newest_mount_id) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); struct reiserfs_journal_desc *desc; struct reiserfs_journal_commit *commit; - unsigned long trans_id = 0; + unsigned int trans_id = 0; struct buffer_head *c_bh; struct buffer_head *d_bh; struct buffer_head **log_blocks = NULL; struct buffer_head **real_blocks = NULL; - unsigned long trans_offset; + unsigned int trans_offset; int i; int trans_half; - d_bh = journal_bread(p_s_sb, cur_dblock); + d_bh = journal_bread(sb, cur_dblock); if (!d_bh) return 1; desc = (struct reiserfs_journal_desc *)d_bh->b_data; - trans_offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb); - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1037: " + trans_offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(sb); + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1037: " "journal_read_transaction, offset %llu, len %d mount_id %d", - d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), + d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(sb), get_desc_trans_len(desc), get_desc_mount_id(desc)); if (get_desc_trans_id(desc) < oldest_trans_id) { - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1039: " + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1039: " "journal_read_trans skipping because %lu is too old", cur_dblock - - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)); + SB_ONDISK_JOURNAL_1st_BLOCK(sb)); brelse(d_bh); return 1; } if (get_desc_mount_id(desc) != newest_mount_id) { - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1146: " + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1146: " "journal_read_trans skipping because %d is != " "newest_mount_id %lu", get_desc_mount_id(desc), newest_mount_id); brelse(d_bh); return 1; } - c_bh = journal_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + + c_bh = journal_bread(sb, SB_ONDISK_JOURNAL_1st_BLOCK(sb) + ((trans_offset + get_desc_trans_len(desc) + 1) % - SB_ONDISK_JOURNAL_SIZE(p_s_sb))); + SB_ONDISK_JOURNAL_SIZE(sb))); if (!c_bh) { brelse(d_bh); return 1; } commit = (struct reiserfs_journal_commit *)c_bh->b_data; - if (journal_compare_desc_commit(p_s_sb, desc, commit)) { - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + if (journal_compare_desc_commit(sb, desc, commit)) { + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal_read_transaction, " "commit offset %llu had bad time %d or length %d", c_bh->b_blocknr - - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), + SB_ONDISK_JOURNAL_1st_BLOCK(sb), get_commit_trans_id(commit), get_commit_trans_len(commit)); brelse(c_bh); @@ -2195,38 +2195,41 @@ static int journal_read_transaction(struct super_block *p_s_sb, brelse(d_bh); kfree(log_blocks); kfree(real_blocks); - reiserfs_warning(p_s_sb, - "journal-1169: kmalloc failed, unable to mount FS"); + reiserfs_warning(sb, "journal-1169", + "kmalloc failed, unable to mount FS"); return -1; } /* get all the buffer heads */ - trans_half = journal_trans_half(p_s_sb->s_blocksize); + trans_half = journal_trans_half(sb->s_blocksize); for (i = 0; i < get_desc_trans_len(desc); i++) { log_blocks[i] = - journal_getblk(p_s_sb, - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + + journal_getblk(sb, + SB_ONDISK_JOURNAL_1st_BLOCK(sb) + (trans_offset + 1 + - i) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)); + i) % SB_ONDISK_JOURNAL_SIZE(sb)); if (i < trans_half) { real_blocks[i] = - sb_getblk(p_s_sb, + sb_getblk(sb, le32_to_cpu(desc->j_realblock[i])); } else { real_blocks[i] = - sb_getblk(p_s_sb, + sb_getblk(sb, le32_to_cpu(commit-> j_realblock[i - trans_half])); } - if (real_blocks[i]->b_blocknr > SB_BLOCK_COUNT(p_s_sb)) { - reiserfs_warning(p_s_sb, - "journal-1207: REPLAY FAILURE fsck required! Block to replay is outside of filesystem"); + if (real_blocks[i]->b_blocknr > SB_BLOCK_COUNT(sb)) { + reiserfs_warning(sb, "journal-1207", + "REPLAY FAILURE fsck required! " + "Block to replay is outside of " + "filesystem"); goto abort_replay; } /* make sure we don't try to replay onto log or reserved area */ if (is_block_in_log_or_reserved_area - (p_s_sb, real_blocks[i]->b_blocknr)) { - reiserfs_warning(p_s_sb, - "journal-1204: REPLAY FAILURE fsck required! Trying to replay onto a log block"); + (sb, real_blocks[i]->b_blocknr)) { + reiserfs_warning(sb, "journal-1204", + "REPLAY FAILURE fsck required! " + "Trying to replay onto a log block"); abort_replay: brelse_array(log_blocks, i); brelse_array(real_blocks, i); @@ -2242,8 +2245,9 @@ static int journal_read_transaction(struct super_block *p_s_sb, for (i = 0; i < get_desc_trans_len(desc); i++) { wait_on_buffer(log_blocks[i]); if (!buffer_uptodate(log_blocks[i])) { - reiserfs_warning(p_s_sb, - "journal-1212: REPLAY FAILURE fsck required! buffer write failed"); + reiserfs_warning(sb, "journal-1212", + "REPLAY FAILURE fsck required! " + "buffer write failed"); brelse_array(log_blocks + i, get_desc_trans_len(desc) - i); brelse_array(real_blocks, get_desc_trans_len(desc)); @@ -2266,8 +2270,9 @@ static int journal_read_transaction(struct super_block *p_s_sb, for (i = 0; i < get_desc_trans_len(desc); i++) { wait_on_buffer(real_blocks[i]); if (!buffer_uptodate(real_blocks[i])) { - reiserfs_warning(p_s_sb, - "journal-1226: REPLAY FAILURE, fsck required! buffer write failed"); + reiserfs_warning(sb, "journal-1226", + "REPLAY FAILURE, fsck required! " + "buffer write failed"); brelse_array(real_blocks + i, get_desc_trans_len(desc) - i); brelse(c_bh); @@ -2279,15 +2284,15 @@ static int journal_read_transaction(struct super_block *p_s_sb, brelse(real_blocks[i]); } cur_dblock = - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + + SB_ONDISK_JOURNAL_1st_BLOCK(sb) + ((trans_offset + get_desc_trans_len(desc) + - 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)); - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + 2) % SB_ONDISK_JOURNAL_SIZE(sb)); + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1095: setting journal " "start to offset %ld", - cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)); + cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(sb)); /* init starting values for the first transaction, in case this is the last transaction to be replayed. */ - journal->j_start = cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb); + journal->j_start = cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(sb); journal->j_last_flush_trans_id = trans_id; journal->j_trans_id = trans_id + 1; /* check for trans_id overflow */ @@ -2352,12 +2357,12 @@ static struct buffer_head *reiserfs_breada(struct block_device *dev, ** ** On exit, it sets things up so the first transaction will work correctly. */ -static int journal_read(struct super_block *p_s_sb) +static int journal_read(struct super_block *sb) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); struct reiserfs_journal_desc *desc; - unsigned long oldest_trans_id = 0; - unsigned long oldest_invalid_trans_id = 0; + unsigned int oldest_trans_id = 0; + unsigned int oldest_invalid_trans_id = 0; time_t start; unsigned long oldest_start = 0; unsigned long cur_dblock = 0; @@ -2370,46 +2375,46 @@ static int journal_read(struct super_block *p_s_sb) int ret; char b[BDEVNAME_SIZE]; - cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb); - reiserfs_info(p_s_sb, "checking transaction log (%s)\n", + cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(sb); + reiserfs_info(sb, "checking transaction log (%s)\n", bdevname(journal->j_dev_bd, b)); start = get_seconds(); - /* step 1, read in the journal header block. Check the transaction it says - ** is the first unflushed, and if that transaction is not valid, + /* step 1, read in the journal header block. Check the transaction it says + ** is the first unflushed, and if that transaction is not valid, ** replay is done */ - journal->j_header_bh = journal_bread(p_s_sb, - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) - + SB_ONDISK_JOURNAL_SIZE(p_s_sb)); + journal->j_header_bh = journal_bread(sb, + SB_ONDISK_JOURNAL_1st_BLOCK(sb) + + SB_ONDISK_JOURNAL_SIZE(sb)); if (!journal->j_header_bh) { return 1; } jh = (struct reiserfs_journal_header *)(journal->j_header_bh->b_data); if (le32_to_cpu(jh->j_first_unflushed_offset) < - SB_ONDISK_JOURNAL_SIZE(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(sb) && le32_to_cpu(jh->j_last_flush_trans_id) > 0) { oldest_start = - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + + SB_ONDISK_JOURNAL_1st_BLOCK(sb) + le32_to_cpu(jh->j_first_unflushed_offset); oldest_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) + 1; newest_mount_id = le32_to_cpu(jh->j_mount_id); - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1153: found in " "header: first_unflushed_offset %d, last_flushed_trans_id " "%lu", le32_to_cpu(jh->j_first_unflushed_offset), le32_to_cpu(jh->j_last_flush_trans_id)); valid_journal_header = 1; - /* now, we try to read the first unflushed offset. If it is not valid, - ** there is nothing more we can do, and it makes no sense to read + /* now, we try to read the first unflushed offset. If it is not valid, + ** there is nothing more we can do, and it makes no sense to read ** through the whole log. */ d_bh = - journal_bread(p_s_sb, - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + + journal_bread(sb, + SB_ONDISK_JOURNAL_1st_BLOCK(sb) + le32_to_cpu(jh->j_first_unflushed_offset)); - ret = journal_transaction_is_valid(p_s_sb, d_bh, NULL, NULL); + ret = journal_transaction_is_valid(sb, d_bh, NULL, NULL); if (!ret) { continue_replay = 0; } @@ -2417,9 +2422,9 @@ static int journal_read(struct super_block *p_s_sb) goto start_log_replay; } - if (continue_replay && bdev_read_only(p_s_sb->s_bdev)) { - reiserfs_warning(p_s_sb, - "clm-2076: device is readonly, unable to replay log"); + if (continue_replay && bdev_read_only(sb->s_bdev)) { + reiserfs_warning(sb, "clm-2076", + "device is readonly, unable to replay log"); return -1; } @@ -2428,17 +2433,17 @@ static int journal_read(struct super_block *p_s_sb) */ while (continue_replay && cur_dblock < - (SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + - SB_ONDISK_JOURNAL_SIZE(p_s_sb))) { + (SB_ONDISK_JOURNAL_1st_BLOCK(sb) + + SB_ONDISK_JOURNAL_SIZE(sb))) { /* Note that it is required for blocksize of primary fs device and journal device to be the same */ d_bh = reiserfs_breada(journal->j_dev_bd, cur_dblock, - p_s_sb->s_blocksize, - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + - SB_ONDISK_JOURNAL_SIZE(p_s_sb)); + sb->s_blocksize, + SB_ONDISK_JOURNAL_1st_BLOCK(sb) + + SB_ONDISK_JOURNAL_SIZE(sb)); ret = - journal_transaction_is_valid(p_s_sb, d_bh, + journal_transaction_is_valid(sb, d_bh, &oldest_invalid_trans_id, &newest_mount_id); if (ret == 1) { @@ -2447,26 +2452,26 @@ static int journal_read(struct super_block *p_s_sb) oldest_trans_id = get_desc_trans_id(desc); oldest_start = d_bh->b_blocknr; newest_mount_id = get_desc_mount_id(desc); - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1179: Setting " "oldest_start to offset %llu, trans_id %lu", oldest_start - SB_ONDISK_JOURNAL_1st_BLOCK - (p_s_sb), oldest_trans_id); + (sb), oldest_trans_id); } else if (oldest_trans_id > get_desc_trans_id(desc)) { /* one we just read was older */ oldest_trans_id = get_desc_trans_id(desc); oldest_start = d_bh->b_blocknr; - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1180: Resetting " "oldest_start to offset %lu, trans_id %lu", oldest_start - SB_ONDISK_JOURNAL_1st_BLOCK - (p_s_sb), oldest_trans_id); + (sb), oldest_trans_id); } if (newest_mount_id < get_desc_mount_id(desc)) { newest_mount_id = get_desc_mount_id(desc); - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1299: Setting " "newest_mount_id to %d", get_desc_mount_id(desc)); @@ -2481,17 +2486,17 @@ static int journal_read(struct super_block *p_s_sb) start_log_replay: cur_dblock = oldest_start; if (oldest_trans_id) { - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1206: Starting replay " "from offset %llu, trans_id %lu", - cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), + cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(sb), oldest_trans_id); } replay_count = 0; while (continue_replay && oldest_trans_id > 0) { ret = - journal_read_transaction(p_s_sb, cur_dblock, oldest_start, + journal_read_transaction(sb, cur_dblock, oldest_start, oldest_trans_id, newest_mount_id); if (ret < 0) { return ret; @@ -2499,14 +2504,14 @@ static int journal_read(struct super_block *p_s_sb) break; } cur_dblock = - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + journal->j_start; + SB_ONDISK_JOURNAL_1st_BLOCK(sb) + journal->j_start; replay_count++; if (cur_dblock == oldest_start) break; } if (oldest_trans_id == 0) { - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1225: No valid " "transactions found"); } /* j_start does not get set correctly if we don't replay any transactions. @@ -2526,16 +2531,16 @@ static int journal_read(struct super_block *p_s_sb) } else { journal->j_mount_id = newest_mount_id + 1; } - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1299: Setting " + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "journal-1299: Setting " "newest_mount_id to %lu", journal->j_mount_id); journal->j_first_unflushed_offset = journal->j_start; if (replay_count > 0) { - reiserfs_info(p_s_sb, + reiserfs_info(sb, "replayed %d transactions in %lu seconds\n", replay_count, get_seconds() - start); } - if (!bdev_read_only(p_s_sb->s_bdev) && - _update_journal_header_block(p_s_sb, journal->j_start, + if (!bdev_read_only(sb->s_bdev) && + _update_journal_header_block(sb, journal->j_start, journal->j_last_flush_trans_id)) { /* replay failed, caller must call free_journal_ram and abort ** the mount @@ -2560,9 +2565,9 @@ static struct reiserfs_journal_list *alloc_journal_list(struct super_block *s) return jl; } -static void journal_list_init(struct super_block *p_s_sb) +static void journal_list_init(struct super_block *sb) { - SB_JOURNAL(p_s_sb)->j_current_jl = alloc_journal_list(p_s_sb); + SB_JOURNAL(sb)->j_current_jl = alloc_journal_list(sb); } static int release_journal_dev(struct super_block *super, @@ -2580,9 +2585,8 @@ static int release_journal_dev(struct super_block *super, } if (result != 0) { - reiserfs_warning(super, - "sh-457: release_journal_dev: Cannot release journal device: %i", - result); + reiserfs_warning(super, "sh-457", + "Cannot release journal device: %i", result); } return result; } @@ -2612,7 +2616,7 @@ static int journal_init_dev(struct super_block *super, if (IS_ERR(journal->j_dev_bd)) { result = PTR_ERR(journal->j_dev_bd); journal->j_dev_bd = NULL; - reiserfs_warning(super, "sh-458: journal_init_dev: " + reiserfs_warning(super, "sh-458", "cannot init journal device '%s': %i", __bdevname(jdev, b), result); return result; @@ -2662,30 +2666,30 @@ static int journal_init_dev(struct super_block *super, */ #define REISERFS_STANDARD_BLKSIZE (4096) -static int check_advise_trans_params(struct super_block *p_s_sb, +static int check_advise_trans_params(struct super_block *sb, struct reiserfs_journal *journal) { if (journal->j_trans_max) { /* Non-default journal params. Do sanity check for them. */ int ratio = 1; - if (p_s_sb->s_blocksize < REISERFS_STANDARD_BLKSIZE) - ratio = REISERFS_STANDARD_BLKSIZE / p_s_sb->s_blocksize; + if (sb->s_blocksize < REISERFS_STANDARD_BLKSIZE) + ratio = REISERFS_STANDARD_BLKSIZE / sb->s_blocksize; if (journal->j_trans_max > JOURNAL_TRANS_MAX_DEFAULT / ratio || journal->j_trans_max < JOURNAL_TRANS_MIN_DEFAULT / ratio || - SB_ONDISK_JOURNAL_SIZE(p_s_sb) / journal->j_trans_max < + SB_ONDISK_JOURNAL_SIZE(sb) / journal->j_trans_max < JOURNAL_MIN_RATIO) { - reiserfs_warning(p_s_sb, - "sh-462: bad transaction max size (%u). FSCK?", - journal->j_trans_max); + reiserfs_warning(sb, "sh-462", + "bad transaction max size (%u). " + "FSCK?", journal->j_trans_max); return 1; } if (journal->j_max_batch != (journal->j_trans_max) * JOURNAL_MAX_BATCH_DEFAULT/JOURNAL_TRANS_MAX_DEFAULT) { - reiserfs_warning(p_s_sb, - "sh-463: bad transaction max batch (%u). FSCK?", - journal->j_max_batch); + reiserfs_warning(sb, "sh-463", + "bad transaction max batch (%u). " + "FSCK?", journal->j_max_batch); return 1; } } else { @@ -2693,9 +2697,11 @@ static int check_advise_trans_params(struct super_block *p_s_sb, The file system was created by old version of mkreiserfs, so some fields contain zeros, and we need to advise proper values for them */ - if (p_s_sb->s_blocksize != REISERFS_STANDARD_BLKSIZE) - reiserfs_panic(p_s_sb, "sh-464: bad blocksize (%u)", - p_s_sb->s_blocksize); + if (sb->s_blocksize != REISERFS_STANDARD_BLKSIZE) { + reiserfs_warning(sb, "sh-464", "bad blocksize (%u)", + sb->s_blocksize); + return 1; + } journal->j_trans_max = JOURNAL_TRANS_MAX_DEFAULT; journal->j_max_batch = JOURNAL_MAX_BATCH_DEFAULT; journal->j_max_commit_age = JOURNAL_MAX_COMMIT_AGE; @@ -2706,10 +2712,10 @@ static int check_advise_trans_params(struct super_block *p_s_sb, /* ** must be called once on fs mount. calls journal_read for you */ -int journal_init(struct super_block *p_s_sb, const char *j_dev_name, +int journal_init(struct super_block *sb, const char *j_dev_name, int old_format, unsigned int commit_max_age) { - int num_cnodes = SB_ONDISK_JOURNAL_SIZE(p_s_sb) * 2; + int num_cnodes = SB_ONDISK_JOURNAL_SIZE(sb) * 2; struct buffer_head *bhjh; struct reiserfs_super_block *rs; struct reiserfs_journal_header *jh; @@ -2717,10 +2723,10 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, struct reiserfs_journal_list *jl; char b[BDEVNAME_SIZE]; - journal = SB_JOURNAL(p_s_sb) = vmalloc(sizeof(struct reiserfs_journal)); + journal = SB_JOURNAL(sb) = vmalloc(sizeof(struct reiserfs_journal)); if (!journal) { - reiserfs_warning(p_s_sb, - "journal-1256: unable to get memory for journal structure"); + reiserfs_warning(sb, "journal-1256", + "unable to get memory for journal structure"); return 1; } memset(journal, 0, sizeof(struct reiserfs_journal)); @@ -2729,51 +2735,51 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, INIT_LIST_HEAD(&journal->j_working_list); INIT_LIST_HEAD(&journal->j_journal_list); journal->j_persistent_trans = 0; - if (reiserfs_allocate_list_bitmaps(p_s_sb, + if (reiserfs_allocate_list_bitmaps(sb, journal->j_list_bitmap, - reiserfs_bmap_count(p_s_sb))) + reiserfs_bmap_count(sb))) goto free_and_return; - allocate_bitmap_nodes(p_s_sb); + allocate_bitmap_nodes(sb); /* reserved for journal area support */ - SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) = (old_format ? + SB_JOURNAL_1st_RESERVED_BLOCK(sb) = (old_format ? REISERFS_OLD_DISK_OFFSET_IN_BYTES - / p_s_sb->s_blocksize + - reiserfs_bmap_count(p_s_sb) + + / sb->s_blocksize + + reiserfs_bmap_count(sb) + 1 : REISERFS_DISK_OFFSET_IN_BYTES / - p_s_sb->s_blocksize + 2); + sb->s_blocksize + 2); /* Sanity check to see is the standard journal fitting withing first bitmap (actual for small blocksizes) */ - if (!SB_ONDISK_JOURNAL_DEVICE(p_s_sb) && - (SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) + - SB_ONDISK_JOURNAL_SIZE(p_s_sb) > p_s_sb->s_blocksize * 8)) { - reiserfs_warning(p_s_sb, - "journal-1393: journal does not fit for area " - "addressed by first of bitmap blocks. It starts at " + if (!SB_ONDISK_JOURNAL_DEVICE(sb) && + (SB_JOURNAL_1st_RESERVED_BLOCK(sb) + + SB_ONDISK_JOURNAL_SIZE(sb) > sb->s_blocksize * 8)) { + reiserfs_warning(sb, "journal-1393", + "journal does not fit for area addressed " + "by first of bitmap blocks. It starts at " "%u and its size is %u. Block size %ld", - SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb), - SB_ONDISK_JOURNAL_SIZE(p_s_sb), - p_s_sb->s_blocksize); + SB_JOURNAL_1st_RESERVED_BLOCK(sb), + SB_ONDISK_JOURNAL_SIZE(sb), + sb->s_blocksize); goto free_and_return; } - if (journal_init_dev(p_s_sb, journal, j_dev_name) != 0) { - reiserfs_warning(p_s_sb, - "sh-462: unable to initialize jornal device"); + if (journal_init_dev(sb, journal, j_dev_name) != 0) { + reiserfs_warning(sb, "sh-462", + "unable to initialize jornal device"); goto free_and_return; } - rs = SB_DISK_SUPER_BLOCK(p_s_sb); + rs = SB_DISK_SUPER_BLOCK(sb); /* read journal header */ - bhjh = journal_bread(p_s_sb, - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + - SB_ONDISK_JOURNAL_SIZE(p_s_sb)); + bhjh = journal_bread(sb, + SB_ONDISK_JOURNAL_1st_BLOCK(sb) + + SB_ONDISK_JOURNAL_SIZE(sb)); if (!bhjh) { - reiserfs_warning(p_s_sb, - "sh-459: unable to read journal header"); + reiserfs_warning(sb, "sh-459", + "unable to read journal header"); goto free_and_return; } jh = (struct reiserfs_journal_header *)(bhjh->b_data); @@ -2782,10 +2788,10 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, if (is_reiserfs_jr(rs) && (le32_to_cpu(jh->jh_journal.jp_journal_magic) != sb_jp_journal_magic(rs))) { - reiserfs_warning(p_s_sb, - "sh-460: journal header magic %x " - "(device %s) does not match to magic found in super " - "block %x", jh->jh_journal.jp_journal_magic, + reiserfs_warning(sb, "sh-460", + "journal header magic %x (device %s) does " + "not match to magic found in super block %x", + jh->jh_journal.jp_journal_magic, bdevname(journal->j_dev_bd, b), sb_jp_journal_magic(rs)); brelse(bhjh); @@ -2798,7 +2804,7 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, le32_to_cpu(jh->jh_journal.jp_journal_max_commit_age); journal->j_max_trans_age = JOURNAL_MAX_TRANS_AGE; - if (check_advise_trans_params(p_s_sb, journal) != 0) + if (check_advise_trans_params(sb, journal) != 0) goto free_and_return; journal->j_default_max_commit_age = journal->j_max_commit_age; @@ -2807,12 +2813,12 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, journal->j_max_trans_age = commit_max_age; } - reiserfs_info(p_s_sb, "journal params: device %s, size %u, " + reiserfs_info(sb, "journal params: device %s, size %u, " "journal first block %u, max trans len %u, max batch %u, " "max commit age %u, max trans age %u\n", bdevname(journal->j_dev_bd, b), - SB_ONDISK_JOURNAL_SIZE(p_s_sb), - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), + SB_ONDISK_JOURNAL_SIZE(sb), + SB_ONDISK_JOURNAL_1st_BLOCK(sb), journal->j_trans_max, journal->j_max_batch, journal->j_max_commit_age, journal->j_max_trans_age); @@ -2820,7 +2826,7 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, brelse(bhjh); journal->j_list_bitmap_index = 0; - journal_list_init(p_s_sb); + journal_list_init(sb); memset(journal->j_list_hash_table, 0, JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *)); @@ -2852,7 +2858,7 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, journal->j_must_wait = 0; if (journal->j_cnode_free == 0) { - reiserfs_warning(p_s_sb, "journal-2004: Journal cnode memory " + reiserfs_warning(sb, "journal-2004", "Journal cnode memory " "allocation failed (%ld bytes). Journal is " "too large for available memory. Usually " "this is due to a journal that is too large.", @@ -2860,16 +2866,17 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, goto free_and_return; } - init_journal_hash(p_s_sb); + init_journal_hash(sb); jl = journal->j_current_jl; - jl->j_list_bitmap = get_list_bitmap(p_s_sb, jl); + jl->j_list_bitmap = get_list_bitmap(sb, jl); if (!jl->j_list_bitmap) { - reiserfs_warning(p_s_sb, - "journal-2005, get_list_bitmap failed for journal list 0"); + reiserfs_warning(sb, "journal-2005", + "get_list_bitmap failed for journal list 0"); goto free_and_return; } - if (journal_read(p_s_sb) < 0) { - reiserfs_warning(p_s_sb, "Replay Failure, unable to mount"); + if (journal_read(sb) < 0) { + reiserfs_warning(sb, "reiserfs-2006", + "Replay Failure, unable to mount"); goto free_and_return; } @@ -2878,10 +2885,10 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, commit_wq = create_workqueue("reiserfs"); INIT_DELAYED_WORK(&journal->j_work, flush_async_commits); - journal->j_work_sb = p_s_sb; + journal->j_work_sb = sb; return 0; free_and_return: - free_journal_ram(p_s_sb); + free_journal_ram(sb); return 1; } @@ -2912,7 +2919,7 @@ int journal_transaction_should_end(struct reiserfs_transaction_handle *th, return 0; } -/* this must be called inside a transaction, and requires the +/* this must be called inside a transaction, and requires the ** kernel_lock to be held */ void reiserfs_block_writes(struct reiserfs_transaction_handle *th) @@ -2970,7 +2977,7 @@ static void wake_queued_writers(struct super_block *s) wake_up(&journal->j_join_wait); } -static void let_transaction_grow(struct super_block *sb, unsigned long trans_id) +static void let_transaction_grow(struct super_block *sb, unsigned int trans_id) { struct reiserfs_journal *journal = SB_JOURNAL(sb); unsigned long bcount = journal->j_bcount; @@ -2997,43 +3004,43 @@ static void let_transaction_grow(struct super_block *sb, unsigned long trans_id) ** expect to use in nblocks. */ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, unsigned long nblocks, + struct super_block *sb, unsigned long nblocks, int join) { time_t now = get_seconds(); - int old_trans_id; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + unsigned int old_trans_id; + struct reiserfs_journal *journal = SB_JOURNAL(sb); struct reiserfs_transaction_handle myth; int sched_count = 0; int retval; - reiserfs_check_lock_depth(p_s_sb, "journal_begin"); + reiserfs_check_lock_depth(sb, "journal_begin"); BUG_ON(nblocks > journal->j_trans_max); - PROC_INFO_INC(p_s_sb, journal.journal_being); + PROC_INFO_INC(sb, journal.journal_being); /* set here for journal_join */ th->t_refcount = 1; - th->t_super = p_s_sb; + th->t_super = sb; relock: - lock_journal(p_s_sb); + lock_journal(sb); if (join != JBEGIN_ABORT && reiserfs_is_journal_aborted(journal)) { - unlock_journal(p_s_sb); + unlock_journal(sb); retval = journal->j_errno; goto out_fail; } journal->j_bcount++; if (test_bit(J_WRITERS_BLOCKED, &journal->j_state)) { - unlock_journal(p_s_sb); - reiserfs_wait_on_write_block(p_s_sb); - PROC_INFO_INC(p_s_sb, journal.journal_relock_writers); + unlock_journal(sb); + reiserfs_wait_on_write_block(sb); + PROC_INFO_INC(sb, journal.journal_relock_writers); goto relock; } now = get_seconds(); /* if there is no room in the journal OR - ** if this transaction is too old, and we weren't called joinable, wait for it to finish before beginning + ** if this transaction is too old, and we weren't called joinable, wait for it to finish before beginning ** we don't sleep if there aren't other writers */ @@ -3048,7 +3055,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, || (!join && journal->j_cnode_free < (journal->j_trans_max * 3))) { old_trans_id = journal->j_trans_id; - unlock_journal(p_s_sb); /* allow others to finish this transaction */ + unlock_journal(sb); /* allow others to finish this transaction */ if (!join && (journal->j_len_alloc + nblocks + 2) >= journal->j_max_batch && @@ -3056,7 +3063,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, (journal->j_len_alloc * 75)) { if (atomic_read(&journal->j_wcount) > 10) { sched_count++; - queue_log_writer(p_s_sb); + queue_log_writer(sb); goto relock; } } @@ -3066,25 +3073,25 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, if (atomic_read(&journal->j_jlock)) { while (journal->j_trans_id == old_trans_id && atomic_read(&journal->j_jlock)) { - queue_log_writer(p_s_sb); + queue_log_writer(sb); } goto relock; } - retval = journal_join(&myth, p_s_sb, 1); + retval = journal_join(&myth, sb, 1); if (retval) goto out_fail; /* someone might have ended the transaction while we joined */ if (old_trans_id != journal->j_trans_id) { - retval = do_journal_end(&myth, p_s_sb, 1, 0); + retval = do_journal_end(&myth, sb, 1, 0); } else { - retval = do_journal_end(&myth, p_s_sb, 1, COMMIT_NOW); + retval = do_journal_end(&myth, sb, 1, COMMIT_NOW); } if (retval) goto out_fail; - PROC_INFO_INC(p_s_sb, journal.journal_relock_wcount); + PROC_INFO_INC(sb, journal.journal_relock_wcount); goto relock; } /* we are the first writer, set trans_id */ @@ -3096,7 +3103,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, th->t_blocks_logged = 0; th->t_blocks_allocated = nblocks; th->t_trans_id = journal->j_trans_id; - unlock_journal(p_s_sb); + unlock_journal(sb); INIT_LIST_HEAD(&th->t_list); get_fs_excl(); return 0; @@ -3106,7 +3113,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, /* Re-set th->t_super, so we can properly keep track of how many * persistent transactions there are. We need to do this so if this * call is part of a failed restart_transaction, we can free it later */ - th->t_super = p_s_sb; + th->t_super = sb; return retval; } @@ -3157,7 +3164,7 @@ int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *th) } static int journal_join(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, unsigned long nblocks) + struct super_block *sb, unsigned long nblocks) { struct reiserfs_transaction_handle *cur_th = current->journal_info; @@ -3166,11 +3173,11 @@ static int journal_join(struct reiserfs_transaction_handle *th, */ th->t_handle_save = cur_th; BUG_ON(cur_th && cur_th->t_refcount > 1); - return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_JOIN); + return do_journal_begin_r(th, sb, nblocks, JBEGIN_JOIN); } int journal_join_abort(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, unsigned long nblocks) + struct super_block *sb, unsigned long nblocks) { struct reiserfs_transaction_handle *cur_th = current->journal_info; @@ -3179,11 +3186,11 @@ int journal_join_abort(struct reiserfs_transaction_handle *th, */ th->t_handle_save = cur_th; BUG_ON(cur_th && cur_th->t_refcount > 1); - return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_ABORT); + return do_journal_begin_r(th, sb, nblocks, JBEGIN_ABORT); } int journal_begin(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, unsigned long nblocks) + struct super_block *sb, unsigned long nblocks) { struct reiserfs_transaction_handle *cur_th = current->journal_info; int ret; @@ -3191,28 +3198,29 @@ int journal_begin(struct reiserfs_transaction_handle *th, th->t_handle_save = NULL; if (cur_th) { /* we are nesting into the current transaction */ - if (cur_th->t_super == p_s_sb) { + if (cur_th->t_super == sb) { BUG_ON(!cur_th->t_refcount); cur_th->t_refcount++; memcpy(th, cur_th, sizeof(*th)); if (th->t_refcount <= 1) - reiserfs_warning(p_s_sb, - "BAD: refcount <= 1, but journal_info != 0"); + reiserfs_warning(sb, "reiserfs-2005", + "BAD: refcount <= 1, but " + "journal_info != 0"); return 0; } else { /* we've ended up with a handle from a different filesystem. ** save it and restore on journal_end. This should never ** really happen... */ - reiserfs_warning(p_s_sb, - "clm-2100: nesting info a different FS"); + reiserfs_warning(sb, "clm-2100", + "nesting info a different FS"); th->t_handle_save = current->journal_info; current->journal_info = th; } } else { current->journal_info = th; } - ret = do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_REG); + ret = do_journal_begin_r(th, sb, nblocks, JBEGIN_REG); BUG_ON(current->journal_info != th); /* I guess this boils down to being the reciprocal of clm-2100 above. @@ -3232,32 +3240,32 @@ int journal_begin(struct reiserfs_transaction_handle *th, ** ** if it was dirty, cleans and files onto the clean list. I can't let it be dirty again until the ** transaction is committed. -** +** ** if j_len, is bigger than j_len_alloc, it pushes j_len_alloc to 10 + j_len. */ int journal_mark_dirty(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, struct buffer_head *bh) + struct super_block *sb, struct buffer_head *bh) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); struct reiserfs_journal_cnode *cn = NULL; int count_already_incd = 0; int prepared = 0; BUG_ON(!th->t_trans_id); - PROC_INFO_INC(p_s_sb, journal.mark_dirty); + PROC_INFO_INC(sb, journal.mark_dirty); if (th->t_trans_id != journal->j_trans_id) { - reiserfs_panic(th->t_super, - "journal-1577: handle trans id %ld != current trans id %ld\n", + reiserfs_panic(th->t_super, "journal-1577", + "handle trans id %ld != current trans id %ld", th->t_trans_id, journal->j_trans_id); } - p_s_sb->s_dirt = 1; + sb->s_dirt = 1; prepared = test_clear_buffer_journal_prepared(bh); clear_buffer_journal_restore_dirty(bh); /* already in this transaction, we are done */ if (buffer_journaled(bh)) { - PROC_INFO_INC(p_s_sb, journal.mark_dirty_already); + PROC_INFO_INC(sb, journal.mark_dirty_already); return 0; } @@ -3266,7 +3274,8 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th, ** could get to disk too early. NOT GOOD. */ if (!prepared || buffer_dirty(bh)) { - reiserfs_warning(p_s_sb, "journal-1777: buffer %llu bad state " + reiserfs_warning(sb, "journal-1777", + "buffer %llu bad state " "%cPREPARED %cLOCKED %cDIRTY %cJDIRTY_WAIT", (unsigned long long)bh->b_blocknr, prepared ? ' ' : '!', @@ -3276,23 +3285,23 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th, } if (atomic_read(&(journal->j_wcount)) <= 0) { - reiserfs_warning(p_s_sb, - "journal-1409: journal_mark_dirty returning because j_wcount was %d", + reiserfs_warning(sb, "journal-1409", + "returning because j_wcount was %d", atomic_read(&(journal->j_wcount))); return 1; } - /* this error means I've screwed up, and we've overflowed the transaction. + /* this error means I've screwed up, and we've overflowed the transaction. ** Nothing can be done here, except make the FS readonly or panic. */ if (journal->j_len >= journal->j_trans_max) { - reiserfs_panic(th->t_super, - "journal-1413: journal_mark_dirty: j_len (%lu) is too big\n", + reiserfs_panic(th->t_super, "journal-1413", + "j_len (%lu) is too big", journal->j_len); } if (buffer_journal_dirty(bh)) { count_already_incd = 1; - PROC_INFO_INC(p_s_sb, journal.mark_dirty_notjournal); + PROC_INFO_INC(sb, journal.mark_dirty_notjournal); clear_buffer_journal_dirty(bh); } @@ -3304,9 +3313,9 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th, /* now put this guy on the end */ if (!cn) { - cn = get_cnode(p_s_sb); + cn = get_cnode(sb); if (!cn) { - reiserfs_panic(p_s_sb, "get_cnode failed!\n"); + reiserfs_panic(sb, "journal-4", "get_cnode failed!"); } if (th->t_blocks_logged == th->t_blocks_allocated) { @@ -3318,7 +3327,7 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th, cn->bh = bh; cn->blocknr = bh->b_blocknr; - cn->sb = p_s_sb; + cn->sb = sb; cn->jlist = NULL; insert_journal_hash(journal->j_hash_table, cn); if (!count_already_incd) { @@ -3339,11 +3348,11 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th, } int journal_end(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, unsigned long nblocks) + struct super_block *sb, unsigned long nblocks) { if (!current->journal_info && th->t_refcount > 1) - reiserfs_warning(p_s_sb, "REISER-NESTING: th NULL, refcount %d", - th->t_refcount); + reiserfs_warning(sb, "REISER-NESTING", + "th NULL, refcount %d", th->t_refcount); if (!th->t_trans_id) { WARN_ON(1); @@ -3366,26 +3375,26 @@ int journal_end(struct reiserfs_transaction_handle *th, } return 0; } else { - return do_journal_end(th, p_s_sb, nblocks, 0); + return do_journal_end(th, sb, nblocks, 0); } } -/* removes from the current transaction, relsing and descrementing any counters. +/* removes from the current transaction, relsing and descrementing any counters. ** also files the removed buffer directly onto the clean list ** ** called by journal_mark_freed when a block has been deleted ** ** returns 1 if it cleaned and relsed the buffer. 0 otherwise */ -static int remove_from_transaction(struct super_block *p_s_sb, +static int remove_from_transaction(struct super_block *sb, b_blocknr_t blocknr, int already_cleaned) { struct buffer_head *bh; struct reiserfs_journal_cnode *cn; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); int ret = 0; - cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, blocknr); + cn = get_journal_hash_dev(sb, journal->j_hash_table, blocknr); if (!cn || !cn->bh) { return ret; } @@ -3403,7 +3412,7 @@ static int remove_from_transaction(struct super_block *p_s_sb, journal->j_last = cn->prev; } if (bh) - remove_journal_hash(p_s_sb, journal->j_hash_table, NULL, + remove_journal_hash(sb, journal->j_hash_table, NULL, bh->b_blocknr, 0); clear_buffer_journaled(bh); /* don't log this one */ @@ -3413,14 +3422,14 @@ static int remove_from_transaction(struct super_block *p_s_sb, clear_buffer_journal_test(bh); put_bh(bh); if (atomic_read(&(bh->b_count)) < 0) { - reiserfs_warning(p_s_sb, - "journal-1752: remove from trans, b_count < 0"); + reiserfs_warning(sb, "journal-1752", + "b_count < 0"); } ret = 1; } journal->j_len--; journal->j_len_alloc--; - free_cnode(p_s_sb, cn); + free_cnode(sb, cn); return ret; } @@ -3468,22 +3477,22 @@ static int can_dirty(struct reiserfs_journal_cnode *cn) } /* syncs the commit blocks, but does not force the real buffers to disk -** will wait until the current transaction is done/committed before returning +** will wait until the current transaction is done/committed before returning */ int journal_end_sync(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, unsigned long nblocks) + struct super_block *sb, unsigned long nblocks) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); BUG_ON(!th->t_trans_id); /* you can sync while nested, very, very bad */ BUG_ON(th->t_refcount > 1); if (journal->j_len == 0) { - reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), + reiserfs_prepare_for_journal(sb, SB_BUFFER_WITH_SB(sb), 1); - journal_mark_dirty(th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)); + journal_mark_dirty(th, sb, SB_BUFFER_WITH_SB(sb)); } - return do_journal_end(th, p_s_sb, nblocks, COMMIT_NOW | WAIT); + return do_journal_end(th, sb, nblocks, COMMIT_NOW | WAIT); } /* @@ -3493,7 +3502,7 @@ static void flush_async_commits(struct work_struct *work) { struct reiserfs_journal *journal = container_of(work, struct reiserfs_journal, j_work.work); - struct super_block *p_s_sb = journal->j_work_sb; + struct super_block *sb = journal->j_work_sb; struct reiserfs_journal_list *jl; struct list_head *entry; @@ -3502,7 +3511,7 @@ static void flush_async_commits(struct work_struct *work) /* last entry is the youngest, commit it and you get everything */ entry = journal->j_journal_list.prev; jl = JOURNAL_LIST_ENTRY(entry); - flush_commit_list(p_s_sb, jl, 1); + flush_commit_list(sb, jl, 1); } unlock_kernel(); } @@ -3511,11 +3520,11 @@ static void flush_async_commits(struct work_struct *work) ** flushes any old transactions to disk ** ends the current transaction if it is too old */ -int reiserfs_flush_old_commits(struct super_block *p_s_sb) +int reiserfs_flush_old_commits(struct super_block *sb) { time_t now; struct reiserfs_transaction_handle th; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); now = get_seconds(); /* safety check so we don't flush while we are replaying the log during @@ -3532,35 +3541,35 @@ int reiserfs_flush_old_commits(struct super_block *p_s_sb) journal->j_trans_start_time > 0 && journal->j_len > 0 && (now - journal->j_trans_start_time) > journal->j_max_trans_age) { - if (!journal_join(&th, p_s_sb, 1)) { - reiserfs_prepare_for_journal(p_s_sb, - SB_BUFFER_WITH_SB(p_s_sb), + if (!journal_join(&th, sb, 1)) { + reiserfs_prepare_for_journal(sb, + SB_BUFFER_WITH_SB(sb), 1); - journal_mark_dirty(&th, p_s_sb, - SB_BUFFER_WITH_SB(p_s_sb)); + journal_mark_dirty(&th, sb, + SB_BUFFER_WITH_SB(sb)); /* we're only being called from kreiserfsd, it makes no sense to do ** an async commit so that kreiserfsd can do it later */ - do_journal_end(&th, p_s_sb, 1, COMMIT_NOW | WAIT); + do_journal_end(&th, sb, 1, COMMIT_NOW | WAIT); } } - return p_s_sb->s_dirt; + return sb->s_dirt; } /* ** returns 0 if do_journal_end should return right away, returns 1 if do_journal_end should finish the commit -** -** if the current transaction is too old, but still has writers, this will wait on j_join_wait until all +** +** if the current transaction is too old, but still has writers, this will wait on j_join_wait until all ** the writers are done. By the time it wakes up, the transaction it was called has already ended, so it just ** flushes the commit list and returns 0. ** ** Won't batch when flush or commit_now is set. Also won't batch when others are waiting on j_join_wait. -** +** ** Note, we can't allow the journal_end to proceed while there are still writers in the log. */ static int check_journal_end(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, unsigned long nblocks, + struct super_block *sb, unsigned long nblocks, int flags) { @@ -3569,13 +3578,13 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, int commit_now = flags & COMMIT_NOW; int wait_on_commit = flags & WAIT; struct reiserfs_journal_list *jl; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); BUG_ON(!th->t_trans_id); if (th->t_trans_id != journal->j_trans_id) { - reiserfs_panic(th->t_super, - "journal-1577: handle trans id %ld != current trans id %ld\n", + reiserfs_panic(th->t_super, "journal-1577", + "handle trans id %ld != current trans id %ld", th->t_trans_id, journal->j_trans_id); } @@ -3584,7 +3593,7 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, atomic_dec(&(journal->j_wcount)); } - /* BUG, deal with case where j_len is 0, but people previously freed blocks need to be released + /* BUG, deal with case where j_len is 0, but people previously freed blocks need to be released ** will be dealt with by next transaction that actually writes something, but should be taken ** care of in this trans */ @@ -3593,7 +3602,7 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, /* if wcount > 0, and we are called to with flush or commit_now, ** we wait on j_join_wait. We will wake up when the last writer has ** finished the transaction, and started it on its way to the disk. - ** Then, we flush the commit or journal list, and just return 0 + ** Then, we flush the commit or journal list, and just return 0 ** because the rest of journal end was already done for this transaction. */ if (atomic_read(&(journal->j_wcount)) > 0) { @@ -3608,31 +3617,31 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, if (flush) { journal->j_next_full_flush = 1; } - unlock_journal(p_s_sb); + unlock_journal(sb); /* sleep while the current transaction is still j_jlocked */ while (journal->j_trans_id == trans_id) { if (atomic_read(&journal->j_jlock)) { - queue_log_writer(p_s_sb); + queue_log_writer(sb); } else { - lock_journal(p_s_sb); + lock_journal(sb); if (journal->j_trans_id == trans_id) { atomic_set(&(journal->j_jlock), 1); } - unlock_journal(p_s_sb); + unlock_journal(sb); } } BUG_ON(journal->j_trans_id == trans_id); if (commit_now - && journal_list_still_alive(p_s_sb, trans_id) + && journal_list_still_alive(sb, trans_id) && wait_on_commit) { - flush_commit_list(p_s_sb, jl, 1); + flush_commit_list(sb, jl, 1); } return 0; } - unlock_journal(p_s_sb); + unlock_journal(sb); return 0; } @@ -3649,13 +3658,13 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, && journal->j_len_alloc < journal->j_max_batch && journal->j_cnode_free > (journal->j_trans_max * 3)) { journal->j_bcount++; - unlock_journal(p_s_sb); + unlock_journal(sb); return 0; } - if (journal->j_start > SB_ONDISK_JOURNAL_SIZE(p_s_sb)) { - reiserfs_panic(p_s_sb, - "journal-003: journal_end: j_start (%ld) is too high\n", + if (journal->j_start > SB_ONDISK_JOURNAL_SIZE(sb)) { + reiserfs_panic(sb, "journal-003", + "j_start (%ld) is too high", journal->j_start); } return 1; @@ -3664,7 +3673,7 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, /* ** Does all the work that makes deleting blocks safe. ** when deleting a block mark BH_JNew, just remove it from the current transaction, clean it's buffer_head and move on. -** +** ** otherwise: ** set a bit for the block in the journal bitmap. That will prevent it from being allocated for unformatted nodes ** before this transaction has finished. @@ -3676,16 +3685,16 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, ** Then remove it from the current transaction, decrementing any counters and filing it on the clean list. */ int journal_mark_freed(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, b_blocknr_t blocknr) + struct super_block *sb, b_blocknr_t blocknr) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); struct reiserfs_journal_cnode *cn = NULL; struct buffer_head *bh = NULL; struct reiserfs_list_bitmap *jb = NULL; int cleaned = 0; BUG_ON(!th->t_trans_id); - cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, blocknr); + cn = get_journal_hash_dev(sb, journal->j_hash_table, blocknr); if (cn && cn->bh) { bh = cn->bh; get_bh(bh); @@ -3695,15 +3704,15 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th, clear_buffer_journal_new(bh); clear_prepared_bits(bh); reiserfs_clean_and_file_buffer(bh); - cleaned = remove_from_transaction(p_s_sb, blocknr, cleaned); + cleaned = remove_from_transaction(sb, blocknr, cleaned); } else { /* set the bit for this block in the journal bitmap for this transaction */ jb = journal->j_current_jl->j_list_bitmap; if (!jb) { - reiserfs_panic(p_s_sb, - "journal-1702: journal_mark_freed, journal_list_bitmap is NULL\n"); + reiserfs_panic(sb, "journal-1702", + "journal_list_bitmap is NULL"); } - set_bit_in_list_bitmap(p_s_sb, blocknr, jb); + set_bit_in_list_bitmap(sb, blocknr, jb); /* Note, the entire while loop is not allowed to schedule. */ @@ -3711,13 +3720,13 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th, clear_prepared_bits(bh); reiserfs_clean_and_file_buffer(bh); } - cleaned = remove_from_transaction(p_s_sb, blocknr, cleaned); + cleaned = remove_from_transaction(sb, blocknr, cleaned); /* find all older transactions with this block, make sure they don't try to write it out */ - cn = get_journal_hash_dev(p_s_sb, journal->j_list_hash_table, + cn = get_journal_hash_dev(sb, journal->j_list_hash_table, blocknr); while (cn) { - if (p_s_sb == cn->sb && blocknr == cn->blocknr) { + if (sb == cn->sb && blocknr == cn->blocknr) { set_bit(BLOCK_FREED, &cn->state); if (cn->bh) { if (!cleaned) { @@ -3733,8 +3742,9 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th, put_bh(cn->bh); if (atomic_read (&(cn->bh->b_count)) < 0) { - reiserfs_warning(p_s_sb, - "journal-2138: cn->bh->b_count < 0"); + reiserfs_warning(sb, + "journal-2138", + "cn->bh->b_count < 0"); } } if (cn->jlist) { /* since we are clearing the bh, we MUST dec nonzerolen */ @@ -3824,7 +3834,7 @@ static int __commit_trans_jl(struct inode *inode, unsigned long id, int reiserfs_commit_for_inode(struct inode *inode) { - unsigned long id = REISERFS_I(inode)->i_trans_id; + unsigned int id = REISERFS_I(inode)->i_trans_id; struct reiserfs_journal_list *jl = REISERFS_I(inode)->i_jl; /* for the whole inode, assume unset id means it was @@ -3839,18 +3849,18 @@ int reiserfs_commit_for_inode(struct inode *inode) return __commit_trans_jl(inode, id, jl); } -void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb, +void reiserfs_restore_prepared_buffer(struct super_block *sb, struct buffer_head *bh) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); - PROC_INFO_INC(p_s_sb, journal.restore_prepared); + struct reiserfs_journal *journal = SB_JOURNAL(sb); + PROC_INFO_INC(sb, journal.restore_prepared); if (!bh) { return; } if (test_clear_buffer_journal_restore_dirty(bh) && buffer_journal_dirty(bh)) { struct reiserfs_journal_cnode *cn; - cn = get_journal_hash_dev(p_s_sb, + cn = get_journal_hash_dev(sb, journal->j_list_hash_table, bh->b_blocknr); if (cn && can_dirty(cn)) { @@ -3867,12 +3877,12 @@ extern struct tree_balance *cur_tb; ** be written to disk while we are altering it. So, we must: ** clean it ** wait on it. -** +** */ -int reiserfs_prepare_for_journal(struct super_block *p_s_sb, +int reiserfs_prepare_for_journal(struct super_block *sb, struct buffer_head *bh, int wait) { - PROC_INFO_INC(p_s_sb, journal.prepare); + PROC_INFO_INC(sb, journal.prepare); if (!trylock_buffer(bh)) { if (!wait) @@ -3909,7 +3919,7 @@ static void flush_old_journal_lists(struct super_block *s) } } -/* +/* ** long and ugly. If flush, will not return until all commit ** blocks and all real buffers in the trans are on disk. ** If no_async, won't return until all commit blocks are on disk. @@ -3920,10 +3930,10 @@ static void flush_old_journal_lists(struct super_block *s) ** journal lists, etc just won't happen. */ static int do_journal_end(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb, unsigned long nblocks, + struct super_block *sb, unsigned long nblocks, int flags) { - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = SB_JOURNAL(sb); struct reiserfs_journal_cnode *cn, *next, *jl_cn; struct reiserfs_journal_cnode *last_cn = NULL; struct reiserfs_journal_desc *desc; @@ -3938,7 +3948,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, struct reiserfs_journal_list *jl, *temp_jl; struct list_head *entry, *safe; unsigned long jindex; - unsigned long commit_trans_id; + unsigned int commit_trans_id; int trans_half; BUG_ON(th->t_refcount > 1); @@ -3946,21 +3956,21 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, /* protect flush_older_commits from doing mistakes if the transaction ID counter gets overflowed. */ - if (th->t_trans_id == ~0UL) + if (th->t_trans_id == ~0U) flags |= FLUSH_ALL | COMMIT_NOW | WAIT; flush = flags & FLUSH_ALL; wait_on_commit = flags & WAIT; put_fs_excl(); current->journal_info = th->t_handle_save; - reiserfs_check_lock_depth(p_s_sb, "journal end"); + reiserfs_check_lock_depth(sb, "journal end"); if (journal->j_len == 0) { - reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), + reiserfs_prepare_for_journal(sb, SB_BUFFER_WITH_SB(sb), 1); - journal_mark_dirty(th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)); + journal_mark_dirty(th, sb, SB_BUFFER_WITH_SB(sb)); } - lock_journal(p_s_sb); + lock_journal(sb); if (journal->j_next_full_flush) { flags |= FLUSH_ALL; flush = 1; @@ -3970,13 +3980,13 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, wait_on_commit = 1; } - /* check_journal_end locks the journal, and unlocks if it does not return 1 + /* check_journal_end locks the journal, and unlocks if it does not return 1 ** it tells us if we should continue with the journal_end, or just return */ - if (!check_journal_end(th, p_s_sb, nblocks, flags)) { - p_s_sb->s_dirt = 1; - wake_queued_writers(p_s_sb); - reiserfs_async_progress_wait(p_s_sb); + if (!check_journal_end(th, sb, nblocks, flags)) { + sb->s_dirt = 1; + wake_queued_writers(sb); + reiserfs_async_progress_wait(sb); goto out; } @@ -4005,8 +4015,8 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, /* setup description block */ d_bh = - journal_getblk(p_s_sb, - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + + journal_getblk(sb, + SB_ONDISK_JOURNAL_1st_BLOCK(sb) + journal->j_start); set_buffer_uptodate(d_bh); desc = (struct reiserfs_journal_desc *)(d_bh)->b_data; @@ -4015,9 +4025,9 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, set_desc_trans_id(desc, journal->j_trans_id); /* setup commit block. Don't write (keep it clean too) this one until after everyone else is written */ - c_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + + c_bh = journal_getblk(sb, SB_ONDISK_JOURNAL_1st_BLOCK(sb) + ((journal->j_start + journal->j_len + - 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))); + 1) % SB_ONDISK_JOURNAL_SIZE(sb))); commit = (struct reiserfs_journal_commit *)c_bh->b_data; memset(c_bh->b_data, 0, c_bh->b_size); set_commit_trans_id(commit, journal->j_trans_id); @@ -4050,13 +4060,13 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, ** for each real block, add it to the journal list hash, ** copy into real block index array in the commit or desc block */ - trans_half = journal_trans_half(p_s_sb->s_blocksize); + trans_half = journal_trans_half(sb->s_blocksize); for (i = 0, cn = journal->j_first; cn; cn = cn->next, i++) { if (buffer_journaled(cn->bh)) { - jl_cn = get_cnode(p_s_sb); + jl_cn = get_cnode(sb); if (!jl_cn) { - reiserfs_panic(p_s_sb, - "journal-1676, get_cnode returned NULL\n"); + reiserfs_panic(sb, "journal-1676", + "get_cnode returned NULL"); } if (i == 0) { jl->j_realblock = jl_cn; @@ -4067,18 +4077,19 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, last_cn->next = jl_cn; } last_cn = jl_cn; - /* make sure the block we are trying to log is not a block + /* make sure the block we are trying to log is not a block of journal or reserved area */ if (is_block_in_log_or_reserved_area - (p_s_sb, cn->bh->b_blocknr)) { - reiserfs_panic(p_s_sb, - "journal-2332: Trying to log block %lu, which is a log block\n", + (sb, cn->bh->b_blocknr)) { + reiserfs_panic(sb, "journal-2332", + "Trying to log block %lu, " + "which is a log block", cn->bh->b_blocknr); } jl_cn->blocknr = cn->bh->b_blocknr; jl_cn->state = 0; - jl_cn->sb = p_s_sb; + jl_cn->sb = sb; jl_cn->bh = cn->bh; jl_cn->jlist = jl; insert_journal_hash(journal->j_list_hash_table, jl_cn); @@ -4119,11 +4130,11 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, char *addr; struct page *page; tmp_bh = - journal_getblk(p_s_sb, - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + + journal_getblk(sb, + SB_ONDISK_JOURNAL_1st_BLOCK(sb) + ((cur_write_start + jindex) % - SB_ONDISK_JOURNAL_SIZE(p_s_sb))); + SB_ONDISK_JOURNAL_SIZE(sb))); set_buffer_uptodate(tmp_bh); page = cn->bh->b_page; addr = kmap(page); @@ -4137,12 +4148,13 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, clear_buffer_journaled(cn->bh); } else { /* JDirty cleared sometime during transaction. don't log this one */ - reiserfs_warning(p_s_sb, - "journal-2048: do_journal_end: BAD, buffer in journal hash, but not JDirty!"); + reiserfs_warning(sb, "journal-2048", + "BAD, buffer in journal hash, " + "but not JDirty!"); brelse(cn->bh); } next = cn->next; - free_cnode(p_s_sb, cn); + free_cnode(sb, cn); cn = next; cond_resched(); } @@ -4152,7 +4164,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, ** so we dirty/relse c_bh in flush_commit_list, with commit_left <= 1. */ - journal->j_current_jl = alloc_journal_list(p_s_sb); + journal->j_current_jl = alloc_journal_list(sb); /* now it is safe to insert this transaction on the main list */ list_add_tail(&jl->j_list, &journal->j_journal_list); @@ -4163,7 +4175,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, old_start = journal->j_start; journal->j_start = (journal->j_start + journal->j_len + - 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb); + 2) % SB_ONDISK_JOURNAL_SIZE(sb); atomic_set(&(journal->j_wcount), 0); journal->j_bcount = 0; journal->j_last = NULL; @@ -4178,7 +4190,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, journal->j_len_alloc = 0; journal->j_next_full_flush = 0; journal->j_next_async_flush = 0; - init_journal_hash(p_s_sb); + init_journal_hash(sb); // make sure reiserfs_add_jh sees the new current_jl before we // write out the tails @@ -4207,14 +4219,14 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, ** queue don't wait for this proc to flush journal lists and such. */ if (flush) { - flush_commit_list(p_s_sb, jl, 1); - flush_journal_list(p_s_sb, jl, 1); + flush_commit_list(sb, jl, 1); + flush_journal_list(sb, jl, 1); } else if (!(jl->j_state & LIST_COMMIT_PENDING)) queue_delayed_work(commit_wq, &journal->j_work, HZ / 10); - /* if the next transaction has any chance of wrapping, flush - ** transactions that might get overwritten. If any journal lists are very - ** old flush them as well. + /* if the next transaction has any chance of wrapping, flush + ** transactions that might get overwritten. If any journal lists are very + ** old flush them as well. */ first_jl: list_for_each_safe(entry, safe, &journal->j_journal_list) { @@ -4222,11 +4234,11 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, if (journal->j_start <= temp_jl->j_start) { if ((journal->j_start + journal->j_trans_max + 1) >= temp_jl->j_start) { - flush_used_journal_lists(p_s_sb, temp_jl); + flush_used_journal_lists(sb, temp_jl); goto first_jl; } else if ((journal->j_start + journal->j_trans_max + 1) < - SB_ONDISK_JOURNAL_SIZE(p_s_sb)) { + SB_ONDISK_JOURNAL_SIZE(sb)) { /* if we don't cross into the next transaction and we don't * wrap, there is no way we can overlap any later transactions * break now @@ -4235,11 +4247,11 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, } } else if ((journal->j_start + journal->j_trans_max + 1) > - SB_ONDISK_JOURNAL_SIZE(p_s_sb)) { + SB_ONDISK_JOURNAL_SIZE(sb)) { if (((journal->j_start + journal->j_trans_max + 1) % - SB_ONDISK_JOURNAL_SIZE(p_s_sb)) >= + SB_ONDISK_JOURNAL_SIZE(sb)) >= temp_jl->j_start) { - flush_used_journal_lists(p_s_sb, temp_jl); + flush_used_journal_lists(sb, temp_jl); goto first_jl; } else { /* we don't overlap anything from out start to the end of the @@ -4250,46 +4262,47 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, } } } - flush_old_journal_lists(p_s_sb); + flush_old_journal_lists(sb); journal->j_current_jl->j_list_bitmap = - get_list_bitmap(p_s_sb, journal->j_current_jl); + get_list_bitmap(sb, journal->j_current_jl); if (!(journal->j_current_jl->j_list_bitmap)) { - reiserfs_panic(p_s_sb, - "journal-1996: do_journal_end, could not get a list bitmap\n"); + reiserfs_panic(sb, "journal-1996", + "could not get a list bitmap"); } atomic_set(&(journal->j_jlock), 0); - unlock_journal(p_s_sb); + unlock_journal(sb); /* wake up any body waiting to join. */ clear_bit(J_WRITERS_QUEUED, &journal->j_state); wake_up(&(journal->j_join_wait)); if (!flush && wait_on_commit && - journal_list_still_alive(p_s_sb, commit_trans_id)) { - flush_commit_list(p_s_sb, jl, 1); + journal_list_still_alive(sb, commit_trans_id)) { + flush_commit_list(sb, jl, 1); } out: - reiserfs_check_lock_depth(p_s_sb, "journal end2"); + reiserfs_check_lock_depth(sb, "journal end2"); memset(th, 0, sizeof(*th)); /* Re-set th->t_super, so we can properly keep track of how many * persistent transactions there are. We need to do this so if this * call is part of a failed restart_transaction, we can free it later */ - th->t_super = p_s_sb; + th->t_super = sb; return journal->j_errno; } -static void __reiserfs_journal_abort_hard(struct super_block *sb) +/* Send the file system read only and refuse new transactions */ +void reiserfs_abort_journal(struct super_block *sb, int errno) { struct reiserfs_journal *journal = SB_JOURNAL(sb); if (test_bit(J_ABORTED, &journal->j_state)) return; - printk(KERN_CRIT "REISERFS: Aborting journal for filesystem on %s\n", - reiserfs_bdevname(sb)); + if (!journal->j_errno) + journal->j_errno = errno; sb->s_flags |= MS_RDONLY; set_bit(J_ABORTED, &journal->j_state); @@ -4299,19 +4312,3 @@ static void __reiserfs_journal_abort_hard(struct super_block *sb) #endif } -static void __reiserfs_journal_abort_soft(struct super_block *sb, int errno) -{ - struct reiserfs_journal *journal = SB_JOURNAL(sb); - if (test_bit(J_ABORTED, &journal->j_state)) - return; - - if (!journal->j_errno) - journal->j_errno = errno; - - __reiserfs_journal_abort_hard(sb); -} - -void reiserfs_journal_abort(struct super_block *sb, int errno) -{ - __reiserfs_journal_abort_soft(sb, errno); -} diff --git a/fs/reiserfs/lbalance.c b/fs/reiserfs/lbalance.c index 6de060a6aa7..381750a155f 100644 --- a/fs/reiserfs/lbalance.c +++ b/fs/reiserfs/lbalance.c @@ -111,7 +111,7 @@ static void leaf_copy_dir_entries(struct buffer_info *dest_bi, item_num_in_dest = (last_first == FIRST_TO_LAST) ? (B_NR_ITEMS(dest) - 1) : 0; - leaf_paste_entries(dest_bi->bi_bh, item_num_in_dest, + leaf_paste_entries(dest_bi, item_num_in_dest, (last_first == FIRST_TO_LAST) ? I_ENTRY_COUNT(B_N_PITEM_HEAD(dest, item_num_in_dest)) @@ -119,8 +119,8 @@ static void leaf_copy_dir_entries(struct buffer_info *dest_bi, DEH_SIZE * copy_count + copy_records_len); } -/* Copy the first (if last_first == FIRST_TO_LAST) or last (last_first == LAST_TO_FIRST) item or - part of it or nothing (see the return 0 below) from SOURCE to the end +/* Copy the first (if last_first == FIRST_TO_LAST) or last (last_first == LAST_TO_FIRST) item or + part of it or nothing (see the return 0 below) from SOURCE to the end (if last_first) or beginning (!last_first) of the DEST */ /* returns 1 if anything was copied, else 0 */ static int leaf_copy_boundary_item(struct buffer_info *dest_bi, @@ -168,10 +168,11 @@ static int leaf_copy_boundary_item(struct buffer_info *dest_bi, if (bytes_or_entries == ih_item_len(ih) && is_indirect_le_ih(ih)) if (get_ih_free_space(ih)) - reiserfs_panic(NULL, - "vs-10020: leaf_copy_boundary_item: " - "last unformatted node must be filled entirely (%h)", - ih); + reiserfs_panic(sb_from_bi(dest_bi), + "vs-10020", + "last unformatted node " + "must be filled " + "entirely (%h)", ih); } #endif @@ -395,7 +396,7 @@ static void leaf_item_bottle(struct buffer_info *dest_bi, else { struct item_head n_ih; - /* copy part of the body of the item number 'item_num' of SOURCE to the end of the DEST + /* copy part of the body of the item number 'item_num' of SOURCE to the end of the DEST part defined by 'cpy_bytes'; create new item header; change old item_header (????); n_ih = new item_header; */ @@ -425,7 +426,7 @@ static void leaf_item_bottle(struct buffer_info *dest_bi, else { struct item_head n_ih; - /* copy part of the body of the item number 'item_num' of SOURCE to the begin of the DEST + /* copy part of the body of the item number 'item_num' of SOURCE to the begin of the DEST part defined by 'cpy_bytes'; create new item header; n_ih = new item_header; */ @@ -622,9 +623,8 @@ static void leaf_define_dest_src_infos(int shift_mode, struct tree_balance *tb, break; default: - reiserfs_panic(NULL, - "vs-10250: leaf_define_dest_src_infos: shift type is unknown (%d)", - shift_mode); + reiserfs_panic(sb_from_bi(src_bi), "vs-10250", + "shift type is unknown (%d)", shift_mode); } RFALSE(!src_bi->bi_bh || !dest_bi->bi_bh, "vs-10260: mode==%d, source (%p) or dest (%p) buffer is initialized incorrectly", @@ -674,9 +674,9 @@ int leaf_shift_left(struct tree_balance *tb, int shift_num, int shift_bytes) #ifdef CONFIG_REISERFS_CHECK if (tb->tb_mode == M_PASTE || tb->tb_mode == M_INSERT) { print_cur_tb("vs-10275"); - reiserfs_panic(tb->tb_sb, - "vs-10275: leaf_shift_left: balance condition corrupted (%c)", - tb->tb_mode); + reiserfs_panic(tb->tb_sb, "vs-10275", + "balance condition corrupted " + "(%c)", tb->tb_mode); } #endif @@ -724,7 +724,7 @@ int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes) static void leaf_delete_items_entirely(struct buffer_info *bi, int first, int del_num); /* If del_bytes == -1, starting from position 'first' delete del_num items in whole in buffer CUR. - If not. + If not. If last_first == 0. Starting from position 'first' delete del_num-1 items in whole. Delete part of body of the first item. Part defined by del_bytes. Don't delete first item header If last_first == 1. Starting from position 'first+1' delete del_num-1 items in whole. Delete part of body of @@ -783,7 +783,7 @@ void leaf_delete_items(struct buffer_info *cur_bi, int last_first, /* len = body len of item */ len = ih_item_len(ih); - /* delete the part of the last item of the bh + /* delete the part of the last item of the bh do not delete item header */ leaf_cut_from_buffer(cur_bi, B_NR_ITEMS(bh) - 1, @@ -865,7 +865,7 @@ void leaf_insert_into_buf(struct buffer_info *bi, int before, } } -/* paste paste_size bytes to affected_item_num-th item. +/* paste paste_size bytes to affected_item_num-th item. When item is a directory, this only prepare space for new entries */ void leaf_paste_in_buffer(struct buffer_info *bi, int affected_item_num, int pos_in_item, int paste_size, @@ -889,9 +889,12 @@ void leaf_paste_in_buffer(struct buffer_info *bi, int affected_item_num, #ifdef CONFIG_REISERFS_CHECK if (zeros_number > paste_size) { + struct super_block *sb = NULL; + if (bi && bi->tb) + sb = bi->tb->tb_sb; print_cur_tb("10177"); - reiserfs_panic(NULL, - "vs-10177: leaf_paste_in_buffer: ero number == %d, paste_size == %d", + reiserfs_panic(sb, "vs-10177", + "zeros_number == %d, paste_size == %d", zeros_number, paste_size); } #endif /* CONFIG_REISERFS_CHECK */ @@ -1019,7 +1022,7 @@ static int leaf_cut_entries(struct buffer_head *bh, /* when cut item is part of regular file pos_in_item - first byte that must be cut cut_size - number of bytes to be cut beginning from pos_in_item - + when cut item is part of directory pos_in_item - number of first deleted entry cut_size - count of deleted entries @@ -1191,7 +1194,7 @@ static void leaf_delete_items_entirely(struct buffer_info *bi, } /* paste new_entry_count entries (new_dehs, records) into position before to item_num-th item */ -void leaf_paste_entries(struct buffer_head *bh, +void leaf_paste_entries(struct buffer_info *bi, int item_num, int before, int new_entry_count, @@ -1203,6 +1206,7 @@ void leaf_paste_entries(struct buffer_head *bh, struct reiserfs_de_head *deh; char *insert_point; int i, old_entry_num; + struct buffer_head *bh = bi->bi_bh; if (new_entry_count == 0) return; @@ -1271,7 +1275,7 @@ void leaf_paste_entries(struct buffer_head *bh, /* change item key if necessary (when we paste before 0-th entry */ if (!before) { set_le_ih_k_offset(ih, deh_offset(new_dehs)); -/* memcpy (&ih->ih_key.k_offset, +/* memcpy (&ih->ih_key.k_offset, &new_dehs->deh_offset, SHORT_KEY_SIZE);*/ } #ifdef CONFIG_REISERFS_CHECK @@ -1287,13 +1291,17 @@ void leaf_paste_entries(struct buffer_head *bh, prev = (i != 0) ? deh_location(&(deh[i - 1])) : 0; if (prev && prev <= deh_location(&(deh[i]))) - reiserfs_warning(NULL, - "vs-10240: leaf_paste_entries: directory item (%h) corrupted (prev %a, cur(%d) %a)", - ih, deh + i - 1, i, deh + i); + reiserfs_error(sb_from_bi(bi), "vs-10240", + "directory item (%h) " + "corrupted (prev %a, " + "cur(%d) %a)", + ih, deh + i - 1, i, deh + i); if (next && next >= deh_location(&(deh[i]))) - reiserfs_warning(NULL, - "vs-10250: leaf_paste_entries: directory item (%h) corrupted (cur(%d) %a, next %a)", - ih, i, deh + i, deh + i + 1); + reiserfs_error(sb_from_bi(bi), "vs-10250", + "directory item (%h) " + "corrupted (cur(%d) %a, " + "next %a)", + ih, i, deh + i, deh + i + 1); } } #endif diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 738967f6c8e..efd4d720718 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -106,7 +106,7 @@ key of the first directory entry in it. This function first calls search_by_key, then, if item whose first entry matches is not found it looks for the entry inside directory item found by search_by_key. Fills the path to the entry, and to the -entry position in the item +entry position in the item */ @@ -120,8 +120,8 @@ int search_by_entry_key(struct super_block *sb, const struct cpu_key *key, switch (retval) { case ITEM_NOT_FOUND: if (!PATH_LAST_POSITION(path)) { - reiserfs_warning(sb, - "vs-7000: search_by_entry_key: search_by_key returned item position == 0"); + reiserfs_error(sb, "vs-7000", "search_by_key " + "returned item position == 0"); pathrelse(path); return IO_ERROR; } @@ -135,8 +135,7 @@ int search_by_entry_key(struct super_block *sb, const struct cpu_key *key, default: pathrelse(path); - reiserfs_warning(sb, - "vs-7002: search_by_entry_key: no path to here"); + reiserfs_error(sb, "vs-7002", "no path to here"); return IO_ERROR; } @@ -146,10 +145,9 @@ int search_by_entry_key(struct super_block *sb, const struct cpu_key *key, if (!is_direntry_le_ih(de->de_ih) || COMP_SHORT_KEYS(&(de->de_ih->ih_key), key)) { print_block(de->de_bh, 0, -1, -1); - reiserfs_panic(sb, - "vs-7005: search_by_entry_key: found item %h is not directory item or " - "does not belong to the same directory as key %K", - de->de_ih, key); + reiserfs_panic(sb, "vs-7005", "found item %h is not directory " + "item or does not belong to the same directory " + "as key %K", de->de_ih, key); } #endif /* CONFIG_REISERFS_CHECK */ @@ -300,8 +298,7 @@ static int reiserfs_find_entry(struct inode *dir, const char *name, int namelen, search_by_entry_key(dir->i_sb, &key_to_search, path_to_entry, de); if (retval == IO_ERROR) { - reiserfs_warning(dir->i_sb, "zam-7001: io error in %s", - __func__); + reiserfs_error(dir->i_sb, "zam-7001", "io error"); return IO_ERROR; } @@ -361,9 +358,10 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry, return ERR_PTR(-EACCES); } - /* Propogate the priv_object flag so we know we're in the priv tree */ - if (is_reiserfs_priv_object(dir)) - reiserfs_mark_inode_private(inode); + /* Propagate the private flag so we know we're + * in the priv tree */ + if (IS_PRIVATE(dir)) + inode->i_flags |= S_PRIVATE; } reiserfs_write_unlock(dir->i_sb); if (retval == IO_ERROR) { @@ -373,7 +371,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry, return d_splice_alias(inode, dentry); } -/* +/* ** looks up the dentry of the parent directory for child. ** taken from ext2_get_parent */ @@ -403,7 +401,7 @@ struct dentry *reiserfs_get_parent(struct dentry *child) return d_obtain_alias(inode); } -/* add entry to the directory (entry can be hidden). +/* add entry to the directory (entry can be hidden). insert definition of when hidden directories are used here -Hans @@ -484,10 +482,9 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th, } if (retval != NAME_FOUND) { - reiserfs_warning(dir->i_sb, - "zam-7002:%s: \"reiserfs_find_entry\" " - "has returned unexpected value (%d)", - __func__, retval); + reiserfs_error(dir->i_sb, "zam-7002", + "reiserfs_find_entry() returned " + "unexpected value (%d)", retval); } return -EEXIST; @@ -498,8 +495,9 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th, MAX_GENERATION_NUMBER + 1); if (gen_number > MAX_GENERATION_NUMBER) { /* there is no free generation number */ - reiserfs_warning(dir->i_sb, - "reiserfs_add_entry: Congratulations! we have got hash function screwed up"); + reiserfs_warning(dir->i_sb, "reiserfs-7010", + "Congratulations! we have got hash function " + "screwed up"); if (buffer != small_buf) kfree(buffer); pathrelse(&path); @@ -515,10 +513,9 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th, if (gen_number != 0) { /* we need to re-search for the insertion point */ if (search_by_entry_key(dir->i_sb, &entry_key, &path, &de) != NAME_NOT_FOUND) { - reiserfs_warning(dir->i_sb, - "vs-7032: reiserfs_add_entry: " - "entry with this key (%K) already exists", - &entry_key); + reiserfs_warning(dir->i_sb, "vs-7032", + "entry with this key (%K) already " + "exists", &entry_key); if (buffer != small_buf) kfree(buffer); @@ -555,15 +552,15 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th, */ static int drop_new_inode(struct inode *inode) { - DQUOT_DROP(inode); + vfs_dq_drop(inode); make_bad_inode(inode); inode->i_flags |= S_NOQUOTA; iput(inode); return 0; } -/* utility function that does setup for reiserfs_new_inode. -** DQUOT_INIT needs lots of credits so it's better to have it +/* utility function that does setup for reiserfs_new_inode. +** vfs_dq_init needs lots of credits so it's better to have it ** outside of a transaction, so we had to pull some bits of ** reiserfs_new_inode out into this func. */ @@ -586,7 +583,7 @@ static int new_inode_init(struct inode *inode, struct inode *dir, int mode) } else { inode->i_gid = current_fsgid(); } - DQUOT_INIT(inode); + vfs_dq_init(inode); return 0; } @@ -601,20 +598,22 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode, 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); struct reiserfs_transaction_handle th; - int locked; + struct reiserfs_security_handle security; if (!(inode = new_inode(dir->i_sb))) { return -ENOMEM; } new_inode_init(inode, dir, mode); - locked = reiserfs_cache_default_acl(dir); - + jbegin_count += reiserfs_cache_default_acl(dir); + retval = reiserfs_security_init(dir, inode, &security); + if (retval < 0) { + drop_new_inode(inode); + return retval; + } + jbegin_count += retval; reiserfs_write_lock(dir->i_sb); - if (locked) - reiserfs_write_lock_xattrs(dir->i_sb); - retval = journal_begin(&th, dir->i_sb, jbegin_count); if (retval) { drop_new_inode(inode); @@ -623,15 +622,10 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode, retval = reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry, - inode); + inode, &security); if (retval) goto out_failed; - if (locked) { - reiserfs_write_unlock_xattrs(dir->i_sb); - locked = 0; - } - inode->i_op = &reiserfs_file_inode_operations; inode->i_fop = &reiserfs_file_operations; inode->i_mapping->a_ops = &reiserfs_address_space_operations; @@ -658,8 +652,6 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode, retval = journal_end(&th, dir->i_sb, jbegin_count); out_failed: - if (locked) - reiserfs_write_unlock_xattrs(dir->i_sb); reiserfs_write_unlock(dir->i_sb); return retval; } @@ -670,12 +662,12 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int retval; struct inode *inode; struct reiserfs_transaction_handle th; + struct reiserfs_security_handle security; /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); - int locked; if (!new_valid_dev(rdev)) return -EINVAL; @@ -685,13 +677,15 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode, } new_inode_init(inode, dir, mode); - locked = reiserfs_cache_default_acl(dir); - + jbegin_count += reiserfs_cache_default_acl(dir); + retval = reiserfs_security_init(dir, inode, &security); + if (retval < 0) { + drop_new_inode(inode); + return retval; + } + jbegin_count += retval; reiserfs_write_lock(dir->i_sb); - if (locked) - reiserfs_write_lock_xattrs(dir->i_sb); - retval = journal_begin(&th, dir->i_sb, jbegin_count); if (retval) { drop_new_inode(inode); @@ -700,16 +694,11 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode, retval = reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry, - inode); + inode, &security); if (retval) { goto out_failed; } - if (locked) { - reiserfs_write_unlock_xattrs(dir->i_sb); - locked = 0; - } - inode->i_op = &reiserfs_special_inode_operations; init_special_inode(inode, inode->i_mode, rdev); @@ -739,8 +728,6 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode, retval = journal_end(&th, dir->i_sb, jbegin_count); out_failed: - if (locked) - reiserfs_write_unlock_xattrs(dir->i_sb); reiserfs_write_unlock(dir->i_sb); return retval; } @@ -750,12 +737,12 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) int retval; struct inode *inode; struct reiserfs_transaction_handle th; + struct reiserfs_security_handle security; /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); - int locked; #ifdef DISPLACE_NEW_PACKING_LOCALITIES /* set flag that new packing locality created and new blocks for the content * of that directory are not displaced yet */ @@ -767,11 +754,14 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) } new_inode_init(inode, dir, mode); - locked = reiserfs_cache_default_acl(dir); - + jbegin_count += reiserfs_cache_default_acl(dir); + retval = reiserfs_security_init(dir, inode, &security); + if (retval < 0) { + drop_new_inode(inode); + return retval; + } + jbegin_count += retval; reiserfs_write_lock(dir->i_sb); - if (locked) - reiserfs_write_lock_xattrs(dir->i_sb); retval = journal_begin(&th, dir->i_sb, jbegin_count); if (retval) { @@ -787,17 +777,12 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) retval = reiserfs_new_inode(&th, dir, mode, NULL /*symlink */ , old_format_only(dir->i_sb) ? EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE, - dentry, inode); + dentry, inode, &security); if (retval) { dir->i_nlink--; goto out_failed; } - if (locked) { - reiserfs_write_unlock_xattrs(dir->i_sb); - locked = 0; - } - reiserfs_update_inode_transaction(inode); reiserfs_update_inode_transaction(dir); @@ -827,8 +812,6 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) unlock_new_inode(inode); retval = journal_end(&th, dir->i_sb, jbegin_count); out_failed: - if (locked) - reiserfs_write_unlock_xattrs(dir->i_sb); reiserfs_write_unlock(dir->i_sb); return retval; } @@ -837,7 +820,7 @@ static inline int reiserfs_empty_dir(struct inode *inode) { /* we can cheat because an old format dir cannot have ** EMPTY_DIR_SIZE, and a new format dir cannot have - ** EMPTY_DIR_SIZE_V1. So, if the inode is either size, + ** EMPTY_DIR_SIZE_V1. So, if the inode is either size, ** regardless of disk format version, the directory is empty. */ if (inode->i_size != EMPTY_DIR_SIZE && @@ -903,8 +886,9 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry) goto end_rmdir; if (inode->i_nlink != 2 && inode->i_nlink != 1) - reiserfs_warning(inode->i_sb, "%s: empty directory has nlink " - "!= 2 (%d)", __func__, inode->i_nlink); + reiserfs_error(inode->i_sb, "reiserfs-7040", + "empty directory has nlink != 2 (%d)", + inode->i_nlink); clear_nlink(inode); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; @@ -980,10 +964,9 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry) } if (!inode->i_nlink) { - reiserfs_warning(inode->i_sb, "%s: deleting nonexistent file " - "(%s:%lu), %d", __func__, - reiserfs_bdevname(inode->i_sb), inode->i_ino, - inode->i_nlink); + reiserfs_warning(inode->i_sb, "reiserfs-7042", + "deleting nonexistent file (%lu), %d", + inode->i_ino, inode->i_nlink); inode->i_nlink = 1; } @@ -1037,6 +1020,7 @@ static int reiserfs_symlink(struct inode *parent_dir, char *name; int item_len; struct reiserfs_transaction_handle th; + struct reiserfs_security_handle security; int mode = S_IFLNK | S_IRWXUGO; /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ int jbegin_count = @@ -1049,6 +1033,13 @@ static int reiserfs_symlink(struct inode *parent_dir, } new_inode_init(inode, parent_dir, mode); + retval = reiserfs_security_init(parent_dir, inode, &security); + if (retval < 0) { + drop_new_inode(inode); + return retval; + } + jbegin_count += retval; + reiserfs_write_lock(parent_dir->i_sb); item_len = ROUND_UP(strlen(symname)); if (item_len > MAX_DIRECT_ITEM_LEN(parent_dir->i_sb->s_blocksize)) { @@ -1066,8 +1057,6 @@ static int reiserfs_symlink(struct inode *parent_dir, memcpy(name, symname, strlen(symname)); padd_item(name, item_len, strlen(symname)); - /* We would inherit the default ACL here, but symlinks don't get ACLs */ - retval = journal_begin(&th, parent_dir->i_sb, jbegin_count); if (retval) { drop_new_inode(inode); @@ -1077,7 +1066,7 @@ static int reiserfs_symlink(struct inode *parent_dir, retval = reiserfs_new_inode(&th, parent_dir, mode, name, strlen(symname), - dentry, inode); + dentry, inode, &security); kfree(name); if (retval) { /* reiserfs_new_inode iputs for us */ goto out_failed; @@ -1173,7 +1162,7 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir, return retval; } -// de contains information pointing to an entry which +/* de contains information pointing to an entry which */ static int de_still_valid(const char *name, int len, struct reiserfs_dir_entry *de) { @@ -1196,15 +1185,14 @@ static int entry_points_to_object(const char *name, int len, if (inode) { if (!de_visible(de->de_deh + de->de_entry_num)) - reiserfs_panic(NULL, - "vs-7042: entry_points_to_object: entry must be visible"); + reiserfs_panic(inode->i_sb, "vs-7042", + "entry must be visible"); return (de->de_objectid == inode->i_ino) ? 1 : 0; } /* this must be added hidden entry */ if (de_visible(de->de_deh + de->de_entry_num)) - reiserfs_panic(NULL, - "vs-7043: entry_points_to_object: entry must be visible"); + reiserfs_panic(NULL, "vs-7043", "entry must be visible"); return 1; } @@ -1218,10 +1206,10 @@ static void set_ino_in_dir_entry(struct reiserfs_dir_entry *de, de->de_deh[de->de_entry_num].deh_objectid = key->k_objectid; } -/* +/* * process, that is going to call fix_nodes/do_balance must hold only * one path. If it holds 2 or more, it can get into endless waiting in - * get_empty_nodes or its clones + * get_empty_nodes or its clones */ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) @@ -1275,7 +1263,7 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, old_inode_mode = old_inode->i_mode; if (S_ISDIR(old_inode_mode)) { - // make sure, that directory being renamed has correct ".." + // make sure, that directory being renamed has correct ".." // and that its new parent directory has not too many links // already @@ -1286,8 +1274,8 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, } } - /* directory is renamed, its parent directory will be changed, - ** so find ".." entry + /* directory is renamed, its parent directory will be changed, + ** so find ".." entry */ dot_dot_de.de_gen_number_bit_string = NULL; retval = @@ -1318,8 +1306,8 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, new_dentry->d_name.len, old_inode, 0); if (retval == -EEXIST) { if (!new_dentry_inode) { - reiserfs_panic(old_dir->i_sb, - "vs-7050: new entry is found, new inode == 0\n"); + reiserfs_panic(old_dir->i_sb, "vs-7050", + "new entry is found, new inode == 0"); } } else if (retval) { int err = journal_end(&th, old_dir->i_sb, jbegin_count); @@ -1397,9 +1385,9 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, this stuff, yes? Then, having gathered everything into RAM we should lock the buffers, yes? -Hans */ - /* probably. our rename needs to hold more - ** than one path at once. The seals would - ** have to be written to deal with multi-path + /* probably. our rename needs to hold more + ** than one path at once. The seals would + ** have to be written to deal with multi-path ** issues -chris */ /* sanity checking before doing the rename - avoid races many @@ -1477,7 +1465,7 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, } if (S_ISDIR(old_inode_mode)) { - // adjust ".." of renamed directory + /* adjust ".." of renamed directory */ set_ino_in_dir_entry(&dot_dot_de, INODE_PKEY(new_dir)); journal_mark_dirty(&th, new_dir->i_sb, dot_dot_de.de_bh); @@ -1499,8 +1487,8 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (reiserfs_cut_from_item (&th, &old_entry_path, &(old_de.de_entry_key), old_dir, NULL, 0) < 0) - reiserfs_warning(old_dir->i_sb, - "vs-7060: reiserfs_rename: couldn't not cut old name. Fsck later?"); + reiserfs_error(old_dir->i_sb, "vs-7060", + "couldn't not cut old name. Fsck later?"); old_dir->i_size -= DEH_SIZE + old_de.de_entrylen; diff --git a/fs/reiserfs/objectid.c b/fs/reiserfs/objectid.c index ea0cf8c28a9..3a6de810bd6 100644 --- a/fs/reiserfs/objectid.c +++ b/fs/reiserfs/objectid.c @@ -18,8 +18,7 @@ static void check_objectid_map(struct super_block *s, __le32 * map) { if (le32_to_cpu(map[0]) != 1) - reiserfs_panic(s, - "vs-15010: check_objectid_map: map corrupted: %lx", + reiserfs_panic(s, "vs-15010", "map corrupted: %lx", (long unsigned int)le32_to_cpu(map[0])); // FIXME: add something else here @@ -61,7 +60,7 @@ __u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th) /* comment needed -Hans */ unused_objectid = le32_to_cpu(map[1]); if (unused_objectid == U32_MAX) { - reiserfs_warning(s, "%s: no more object ids", __func__); + reiserfs_warning(s, "reiserfs-15100", "no more object ids"); reiserfs_restore_prepared_buffer(s, SB_BUFFER_WITH_SB(s)); return 0; } @@ -160,9 +159,8 @@ void reiserfs_release_objectid(struct reiserfs_transaction_handle *th, i += 2; } - reiserfs_warning(s, - "vs-15011: reiserfs_release_objectid: tried to free free object id (%lu)", - (long unsigned)objectid_to_release); + reiserfs_error(s, "vs-15011", "tried to free free object id (%lu)", + (long unsigned)objectid_to_release); } int reiserfs_convert_objectid_map_v1(struct super_block *s) @@ -182,7 +180,7 @@ int reiserfs_convert_objectid_map_v1(struct super_block *s) if (cur_size > new_size) { /* mark everyone used that was listed as free at the end of the objectid - ** map + ** map */ objectid_map[new_size - 1] = objectid_map[cur_size - 1]; set_sb_oid_cursize(disk_sb, new_size); diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c index 740bb8c0c1a..536eacaeb71 100644 --- a/fs/reiserfs/prints.c +++ b/fs/reiserfs/prints.c @@ -157,19 +157,16 @@ static void sprintf_disk_child(char *buf, struct disk_child *dc) dc_size(dc)); } -static char *is_there_reiserfs_struct(char *fmt, int *what, int *skip) +static char *is_there_reiserfs_struct(char *fmt, int *what) { char *k = fmt; - *skip = 0; - while ((k = strchr(k, '%')) != NULL) { if (k[1] == 'k' || k[1] == 'K' || k[1] == 'h' || k[1] == 't' || k[1] == 'z' || k[1] == 'b' || k[1] == 'y' || k[1] == 'a') { *what = k[1]; break; } - (*skip)++; k++; } return k; @@ -181,30 +178,29 @@ static char *is_there_reiserfs_struct(char *fmt, int *what, int *skip) appropriative printk. With this reiserfs_warning you can use format specification for complex structures like you used to do with printfs for integers, doubles and pointers. For instance, to print - out key structure you have to write just: - reiserfs_warning ("bad key %k", key); - instead of - printk ("bad key %lu %lu %lu %lu", key->k_dir_id, key->k_objectid, - key->k_offset, key->k_uniqueness); + out key structure you have to write just: + reiserfs_warning ("bad key %k", key); + instead of + printk ("bad key %lu %lu %lu %lu", key->k_dir_id, key->k_objectid, + key->k_offset, key->k_uniqueness); */ - +static DEFINE_SPINLOCK(error_lock); static void prepare_error_buf(const char *fmt, va_list args) { char *fmt1 = fmt_buf; char *k; char *p = error_buf; - int i, j, what, skip; + int what; + + spin_lock(&error_lock); strcpy(fmt1, fmt); - while ((k = is_there_reiserfs_struct(fmt1, &what, &skip)) != NULL) { + while ((k = is_there_reiserfs_struct(fmt1, &what)) != NULL) { *k = 0; p += vsprintf(p, fmt1, args); - for (i = 0; i < skip; i++) - j = va_arg(args, int); - switch (what) { case 'k': sprintf_le_key(p, va_arg(args, struct reiserfs_key *)); @@ -243,15 +239,16 @@ static void prepare_error_buf(const char *fmt, va_list args) fmt1 = k + 2; } vsprintf(p, fmt1, args); + spin_unlock(&error_lock); } /* in addition to usual conversion specifiers this accepts reiserfs - specific conversion specifiers: - %k to print little endian key, - %K to print cpu key, + specific conversion specifiers: + %k to print little endian key, + %K to print cpu key, %h to print item_head, - %t to print directory entry + %t to print directory entry %z to print block head (arg must be struct buffer_head * %b to print buffer_head */ @@ -264,14 +261,17 @@ static void prepare_error_buf(const char *fmt, va_list args) va_end( args );\ } -void reiserfs_warning(struct super_block *sb, const char *fmt, ...) +void __reiserfs_warning(struct super_block *sb, const char *id, + const char *function, const char *fmt, ...) { do_reiserfs_warning(fmt); if (sb) - printk(KERN_WARNING "ReiserFS: %s: warning: %s\n", - reiserfs_bdevname(sb), error_buf); + printk(KERN_WARNING "REISERFS warning (device %s): %s%s%s: " + "%s\n", sb->s_id, id ? id : "", id ? " " : "", + function, error_buf); else - printk(KERN_WARNING "ReiserFS: warning: %s\n", error_buf); + printk(KERN_WARNING "REISERFS warning: %s%s%s: %s\n", + id ? id : "", id ? " " : "", function, error_buf); } /* No newline.. reiserfs_info calls can be followed by printk's */ @@ -279,10 +279,10 @@ void reiserfs_info(struct super_block *sb, const char *fmt, ...) { do_reiserfs_warning(fmt); if (sb) - printk(KERN_NOTICE "ReiserFS: %s: %s", - reiserfs_bdevname(sb), error_buf); + printk(KERN_NOTICE "REISERFS (device %s): %s", + sb->s_id, error_buf); else - printk(KERN_NOTICE "ReiserFS: %s", error_buf); + printk(KERN_NOTICE "REISERFS %s:", error_buf); } /* No newline.. reiserfs_printk calls can be followed by printk's */ @@ -297,10 +297,10 @@ void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...) #ifdef CONFIG_REISERFS_CHECK do_reiserfs_warning(fmt); if (s) - printk(KERN_DEBUG "ReiserFS: %s: %s\n", - reiserfs_bdevname(s), error_buf); + printk(KERN_DEBUG "REISERFS debug (device %s): %s\n", + s->s_id, error_buf); else - printk(KERN_DEBUG "ReiserFS: %s\n", error_buf); + printk(KERN_DEBUG "REISERFS debug: %s\n", error_buf); #endif } @@ -314,17 +314,17 @@ void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...) maintainer-errorid. Don't bother with reusing errorids, there are lots of numbers out there. - Example: - + Example: + reiserfs_panic( p_sb, "reiser-29: reiserfs_new_blocknrs: " "one of search_start or rn(%d) is equal to MAX_B_NUM," - "which means that we are optimizing location based on the bogus location of a temp buffer (%p).", + "which means that we are optimizing location based on the bogus location of a temp buffer (%p).", rn, bh ); Regular panic()s sometimes clear the screen before the message can - be read, thus the need for the while loop. + be read, thus the need for the while loop. Numbering scheme for panic used by Vladimir and Anatoly( Hans completely ignores this scheme, and considers it pointless complexity): @@ -353,14 +353,46 @@ void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...) extern struct tree_balance *cur_tb; #endif -void reiserfs_panic(struct super_block *sb, const char *fmt, ...) +void __reiserfs_panic(struct super_block *sb, const char *id, + const char *function, const char *fmt, ...) { do_reiserfs_warning(fmt); +#ifdef CONFIG_REISERFS_CHECK dump_stack(); +#endif + if (sb) + panic(KERN_WARNING "REISERFS panic (device %s): %s%s%s: %s\n", + sb->s_id, id ? id : "", id ? " " : "", + function, error_buf); + else + panic(KERN_WARNING "REISERFS panic: %s%s%s: %s\n", + id ? id : "", id ? " " : "", function, error_buf); +} + +void __reiserfs_error(struct super_block *sb, const char *id, + const char *function, const char *fmt, ...) +{ + do_reiserfs_warning(fmt); - panic(KERN_EMERG "REISERFS: panic (device %s): %s\n", - reiserfs_bdevname(sb), error_buf); + BUG_ON(sb == NULL); + + if (reiserfs_error_panic(sb)) + __reiserfs_panic(sb, id, function, error_buf); + + if (id && id[0]) + printk(KERN_CRIT "REISERFS error (device %s): %s %s: %s\n", + sb->s_id, id, function, error_buf); + else + printk(KERN_CRIT "REISERFS error (device %s): %s: %s\n", + sb->s_id, function, error_buf); + + if (sb->s_flags & MS_RDONLY) + return; + + reiserfs_info(sb, "Remounting filesystem read-only\n"); + sb->s_flags |= MS_RDONLY; + reiserfs_abort_journal(sb, -EIO); } void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...) @@ -368,18 +400,18 @@ void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...) do_reiserfs_warning(fmt); if (reiserfs_error_panic(sb)) { - panic(KERN_CRIT "REISERFS: panic (device %s): %s\n", - reiserfs_bdevname(sb), error_buf); + panic(KERN_CRIT "REISERFS panic (device %s): %s\n", sb->s_id, + error_buf); } - if (sb->s_flags & MS_RDONLY) + if (reiserfs_is_journal_aborted(SB_JOURNAL(sb))) return; - printk(KERN_CRIT "REISERFS: abort (device %s): %s\n", - reiserfs_bdevname(sb), error_buf); + printk(KERN_CRIT "REISERFS abort (device %s): %s\n", sb->s_id, + error_buf); sb->s_flags |= MS_RDONLY; - reiserfs_journal_abort(sb, errno); + reiserfs_abort_journal(sb, errno); } /* this prints internal nodes (4 keys/items in line) (dc_number, @@ -681,12 +713,10 @@ static void check_leaf_block_head(struct buffer_head *bh) blkh = B_BLK_HEAD(bh); nr = blkh_nr_item(blkh); if (nr > (bh->b_size - BLKH_SIZE) / IH_SIZE) - reiserfs_panic(NULL, - "vs-6010: check_leaf_block_head: invalid item number %z", + reiserfs_panic(NULL, "vs-6010", "invalid item number %z", bh); if (blkh_free_space(blkh) > bh->b_size - BLKH_SIZE - IH_SIZE * nr) - reiserfs_panic(NULL, - "vs-6020: check_leaf_block_head: invalid free space %z", + reiserfs_panic(NULL, "vs-6020", "invalid free space %z", bh); } @@ -697,21 +727,15 @@ static void check_internal_block_head(struct buffer_head *bh) blkh = B_BLK_HEAD(bh); if (!(B_LEVEL(bh) > DISK_LEAF_NODE_LEVEL && B_LEVEL(bh) <= MAX_HEIGHT)) - reiserfs_panic(NULL, - "vs-6025: check_internal_block_head: invalid level %z", - bh); + reiserfs_panic(NULL, "vs-6025", "invalid level %z", bh); if (B_NR_ITEMS(bh) > (bh->b_size - BLKH_SIZE) / IH_SIZE) - reiserfs_panic(NULL, - "vs-6030: check_internal_block_head: invalid item number %z", - bh); + reiserfs_panic(NULL, "vs-6030", "invalid item number %z", bh); if (B_FREE_SPACE(bh) != bh->b_size - BLKH_SIZE - KEY_SIZE * B_NR_ITEMS(bh) - DC_SIZE * (B_NR_ITEMS(bh) + 1)) - reiserfs_panic(NULL, - "vs-6040: check_internal_block_head: invalid free space %z", - bh); + reiserfs_panic(NULL, "vs-6040", "invalid free space %z", bh); } diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c index 37173fa07d1..9229e5514a4 100644 --- a/fs/reiserfs/procfs.c +++ b/fs/reiserfs/procfs.c @@ -321,7 +321,7 @@ static int show_journal(struct seq_file *m, struct super_block *sb) /* incore fields */ "j_1st_reserved_block: \t%i\n" "j_state: \t%li\n" - "j_trans_id: \t%lu\n" + "j_trans_id: \t%u\n" "j_mount_id: \t%lu\n" "j_start: \t%lu\n" "j_len: \t%lu\n" @@ -329,7 +329,7 @@ static int show_journal(struct seq_file *m, struct super_block *sb) "j_wcount: \t%i\n" "j_bcount: \t%lu\n" "j_first_unflushed_offset: \t%lu\n" - "j_last_flush_trans_id: \t%lu\n" + "j_last_flush_trans_id: \t%u\n" "j_trans_start_time: \t%li\n" "j_list_bitmap_index: \t%i\n" "j_must_wait: \t%i\n" @@ -492,7 +492,6 @@ int reiserfs_proc_info_init(struct super_block *sb) spin_lock_init(&__PINFO(sb).lock); REISERFS_SB(sb)->procdir = proc_mkdir(b, proc_info_root); if (REISERFS_SB(sb)->procdir) { - REISERFS_SB(sb)->procdir->owner = THIS_MODULE; REISERFS_SB(sb)->procdir->data = sb; add_file(sb, "version", show_version); add_file(sb, "super", show_super); @@ -503,7 +502,7 @@ int reiserfs_proc_info_init(struct super_block *sb) add_file(sb, "journal", show_journal); return 0; } - reiserfs_warning(sb, "reiserfs: cannot create /proc/%s/%s", + reiserfs_warning(sb, "cannot create /proc/%s/%s", proc_info_root_name, b); return 1; } @@ -556,11 +555,8 @@ int reiserfs_proc_info_global_init(void) { if (proc_info_root == NULL) { proc_info_root = proc_mkdir(proc_info_root_name, NULL); - if (proc_info_root) { - proc_info_root->owner = THIS_MODULE; - } else { - reiserfs_warning(NULL, - "reiserfs: cannot create /proc/%s", + if (!proc_info_root) { + reiserfs_warning(NULL, "cannot create /proc/%s", proc_info_root_name); return 1; } @@ -634,7 +630,7 @@ int reiserfs_global_version_in_proc(char *buffer, char **start, * */ -/* +/* * Make Linus happy. * Local variables: * c-indentation-style: "K&R" diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c index f71c3948ede..238e9d9b31e 100644 --- a/fs/reiserfs/resize.c +++ b/fs/reiserfs/resize.c @@ -1,8 +1,8 @@ -/* +/* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ -/* +/* * Written by Alexander Zarochentcev. * * The kernel part of the (on-line) reiserfs resizer. @@ -101,7 +101,7 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) memcpy(jbitmap[i].bitmaps, jb->bitmaps, copy_size); /* just in case vfree schedules on us, copy the new - ** pointer into the journal struct before freeing the + ** pointer into the journal struct before freeing the ** old one */ node_tmp = jb->bitmaps; diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index abbc64dcc8d..d036ee5b1c8 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -23,7 +23,6 @@ * get_rkey * key_in_buffer * decrement_bcount - * decrement_counters_in_path * reiserfs_check_path * pathrelse_and_restore * pathrelse @@ -57,28 +56,28 @@ #include <linux/quotaops.h> /* Does the buffer contain a disk block which is in the tree. */ -inline int B_IS_IN_TREE(const struct buffer_head *p_s_bh) +inline int B_IS_IN_TREE(const struct buffer_head *bh) { - RFALSE(B_LEVEL(p_s_bh) > MAX_HEIGHT, - "PAP-1010: block (%b) has too big level (%z)", p_s_bh, p_s_bh); + RFALSE(B_LEVEL(bh) > MAX_HEIGHT, + "PAP-1010: block (%b) has too big level (%z)", bh, bh); - return (B_LEVEL(p_s_bh) != FREE_LEVEL); + return (B_LEVEL(bh) != FREE_LEVEL); } // // to gets item head in le form // -inline void copy_item_head(struct item_head *p_v_to, - const struct item_head *p_v_from) +inline void copy_item_head(struct item_head *to, + const struct item_head *from) { - memcpy(p_v_to, p_v_from, IH_SIZE); + memcpy(to, from, IH_SIZE); } /* k1 is pointer to on-disk structure which is stored in little-endian form. k2 is pointer to cpu variable. For key of items of the same object this returns 0. - Returns: -1 if key1 < key2 + Returns: -1 if key1 < key2 0 if key1 == key2 1 if key1 > key2 */ inline int comp_short_keys(const struct reiserfs_key *le_key, @@ -136,15 +135,15 @@ static inline int comp_keys(const struct reiserfs_key *le_key, inline int comp_short_le_keys(const struct reiserfs_key *key1, const struct reiserfs_key *key2) { - __u32 *p_s_1_u32, *p_s_2_u32; - int n_key_length = REISERFS_SHORT_KEY_LEN; + __u32 *k1_u32, *k2_u32; + int key_length = REISERFS_SHORT_KEY_LEN; - p_s_1_u32 = (__u32 *) key1; - p_s_2_u32 = (__u32 *) key2; - for (; n_key_length--; ++p_s_1_u32, ++p_s_2_u32) { - if (le32_to_cpu(*p_s_1_u32) < le32_to_cpu(*p_s_2_u32)) + k1_u32 = (__u32 *) key1; + k2_u32 = (__u32 *) key2; + for (; key_length--; ++k1_u32, ++k2_u32) { + if (le32_to_cpu(*k1_u32) < le32_to_cpu(*k2_u32)) return -1; - if (le32_to_cpu(*p_s_1_u32) > le32_to_cpu(*p_s_2_u32)) + if (le32_to_cpu(*k1_u32) > le32_to_cpu(*k2_u32)) return 1; } return 0; @@ -175,52 +174,51 @@ inline int comp_le_keys(const struct reiserfs_key *k1, * Binary search toolkit function * * Search for an item in the array by the item key * * Returns: 1 if found, 0 if not found; * - * *p_n_pos = number of the searched element if found, else the * - * number of the first element that is larger than p_v_key. * + * *pos = number of the searched element if found, else the * + * number of the first element that is larger than key. * **************************************************************************/ -/* For those not familiar with binary search: n_lbound is the leftmost item that it - could be, n_rbound the rightmost item that it could be. We examine the item - halfway between n_lbound and n_rbound, and that tells us either that we can increase - n_lbound, or decrease n_rbound, or that we have found it, or if n_lbound <= n_rbound that +/* For those not familiar with binary search: lbound is the leftmost item that it + could be, rbound the rightmost item that it could be. We examine the item + halfway between lbound and rbound, and that tells us either that we can increase + lbound, or decrease rbound, or that we have found it, or if lbound <= rbound that there are no possible items, and we have not found it. With each examination we cut the number of possible items it could be by one more than half rounded down, or we find it. */ -static inline int bin_search(const void *p_v_key, /* Key to search for. */ - const void *p_v_base, /* First item in the array. */ - int p_n_num, /* Number of items in the array. */ - int p_n_width, /* Item size in the array. - searched. Lest the reader be - confused, note that this is crafted - as a general function, and when it - is applied specifically to the array - of item headers in a node, p_n_width - is actually the item header size not - the item size. */ - int *p_n_pos /* Number of the searched for element. */ +static inline int bin_search(const void *key, /* Key to search for. */ + const void *base, /* First item in the array. */ + int num, /* Number of items in the array. */ + int width, /* Item size in the array. + searched. Lest the reader be + confused, note that this is crafted + as a general function, and when it + is applied specifically to the array + of item headers in a node, width + is actually the item header size not + the item size. */ + int *pos /* Number of the searched for element. */ ) { - int n_rbound, n_lbound, n_j; + int rbound, lbound, j; - for (n_j = ((n_rbound = p_n_num - 1) + (n_lbound = 0)) / 2; - n_lbound <= n_rbound; n_j = (n_rbound + n_lbound) / 2) + for (j = ((rbound = num - 1) + (lbound = 0)) / 2; + lbound <= rbound; j = (rbound + lbound) / 2) switch (comp_keys - ((struct reiserfs_key *)((char *)p_v_base + - n_j * p_n_width), - (struct cpu_key *)p_v_key)) { + ((struct reiserfs_key *)((char *)base + j * width), + (struct cpu_key *)key)) { case -1: - n_lbound = n_j + 1; + lbound = j + 1; continue; case 1: - n_rbound = n_j - 1; + rbound = j - 1; continue; case 0: - *p_n_pos = n_j; + *pos = j; return ITEM_FOUND; /* Key found in the array. */ } /* bin_search did not find given key, it returns position of key, that is minimal and greater than the given one. */ - *p_n_pos = n_lbound; + *pos = lbound; return ITEM_NOT_FOUND; } @@ -243,90 +241,88 @@ static const struct reiserfs_key MAX_KEY = { of the path, and going upwards. We must check the path's validity at each step. If the key is not in the path, there is no delimiting key in the tree (buffer is first or last buffer in tree), and in this case we return a special key, either MIN_KEY or MAX_KEY. */ -static inline const struct reiserfs_key *get_lkey(const struct treepath - *p_s_chk_path, - const struct super_block - *p_s_sb) +static inline const struct reiserfs_key *get_lkey(const struct treepath *chk_path, + const struct super_block *sb) { - int n_position, n_path_offset = p_s_chk_path->path_length; - struct buffer_head *p_s_parent; + int position, path_offset = chk_path->path_length; + struct buffer_head *parent; - RFALSE(n_path_offset < FIRST_PATH_ELEMENT_OFFSET, + RFALSE(path_offset < FIRST_PATH_ELEMENT_OFFSET, "PAP-5010: invalid offset in the path"); /* While not higher in path than first element. */ - while (n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET) { + while (path_offset-- > FIRST_PATH_ELEMENT_OFFSET) { RFALSE(!buffer_uptodate - (PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)), + (PATH_OFFSET_PBUFFER(chk_path, path_offset)), "PAP-5020: parent is not uptodate"); /* Parent at the path is not in the tree now. */ if (!B_IS_IN_TREE - (p_s_parent = - PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset))) + (parent = + PATH_OFFSET_PBUFFER(chk_path, path_offset))) return &MAX_KEY; /* Check whether position in the parent is correct. */ - if ((n_position = - PATH_OFFSET_POSITION(p_s_chk_path, - n_path_offset)) > - B_NR_ITEMS(p_s_parent)) + if ((position = + PATH_OFFSET_POSITION(chk_path, + path_offset)) > + B_NR_ITEMS(parent)) return &MAX_KEY; /* Check whether parent at the path really points to the child. */ - if (B_N_CHILD_NUM(p_s_parent, n_position) != - PATH_OFFSET_PBUFFER(p_s_chk_path, - n_path_offset + 1)->b_blocknr) + if (B_N_CHILD_NUM(parent, position) != + PATH_OFFSET_PBUFFER(chk_path, + path_offset + 1)->b_blocknr) return &MAX_KEY; /* Return delimiting key if position in the parent is not equal to zero. */ - if (n_position) - return B_N_PDELIM_KEY(p_s_parent, n_position - 1); + if (position) + return B_N_PDELIM_KEY(parent, position - 1); } /* Return MIN_KEY if we are in the root of the buffer tree. */ - if (PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)-> - b_blocknr == SB_ROOT_BLOCK(p_s_sb)) + if (PATH_OFFSET_PBUFFER(chk_path, FIRST_PATH_ELEMENT_OFFSET)-> + b_blocknr == SB_ROOT_BLOCK(sb)) return &MIN_KEY; return &MAX_KEY; } /* Get delimiting key of the buffer at the path and its right neighbor. */ -inline const struct reiserfs_key *get_rkey(const struct treepath *p_s_chk_path, - const struct super_block *p_s_sb) +inline const struct reiserfs_key *get_rkey(const struct treepath *chk_path, + const struct super_block *sb) { - int n_position, n_path_offset = p_s_chk_path->path_length; - struct buffer_head *p_s_parent; + int position, path_offset = chk_path->path_length; + struct buffer_head *parent; - RFALSE(n_path_offset < FIRST_PATH_ELEMENT_OFFSET, + RFALSE(path_offset < FIRST_PATH_ELEMENT_OFFSET, "PAP-5030: invalid offset in the path"); - while (n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET) { + while (path_offset-- > FIRST_PATH_ELEMENT_OFFSET) { RFALSE(!buffer_uptodate - (PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)), + (PATH_OFFSET_PBUFFER(chk_path, path_offset)), "PAP-5040: parent is not uptodate"); /* Parent at the path is not in the tree now. */ if (!B_IS_IN_TREE - (p_s_parent = - PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset))) + (parent = + PATH_OFFSET_PBUFFER(chk_path, path_offset))) return &MIN_KEY; /* Check whether position in the parent is correct. */ - if ((n_position = - PATH_OFFSET_POSITION(p_s_chk_path, - n_path_offset)) > - B_NR_ITEMS(p_s_parent)) + if ((position = + PATH_OFFSET_POSITION(chk_path, + path_offset)) > + B_NR_ITEMS(parent)) return &MIN_KEY; /* Check whether parent at the path really points to the child. */ - if (B_N_CHILD_NUM(p_s_parent, n_position) != - PATH_OFFSET_PBUFFER(p_s_chk_path, - n_path_offset + 1)->b_blocknr) + if (B_N_CHILD_NUM(parent, position) != + PATH_OFFSET_PBUFFER(chk_path, + path_offset + 1)->b_blocknr) return &MIN_KEY; /* Return delimiting key if position in the parent is not the last one. */ - if (n_position != B_NR_ITEMS(p_s_parent)) - return B_N_PDELIM_KEY(p_s_parent, n_position); + if (position != B_NR_ITEMS(parent)) + return B_N_PDELIM_KEY(parent, position); } /* Return MAX_KEY if we are in the root of the buffer tree. */ - if (PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)-> - b_blocknr == SB_ROOT_BLOCK(p_s_sb)) + if (PATH_OFFSET_PBUFFER(chk_path, FIRST_PATH_ELEMENT_OFFSET)-> + b_blocknr == SB_ROOT_BLOCK(sb)) return &MAX_KEY; return &MIN_KEY; } @@ -336,60 +332,29 @@ inline const struct reiserfs_key *get_rkey(const struct treepath *p_s_chk_path, the path. These delimiting keys are stored at least one level above that buffer in the tree. If the buffer is the first or last node in the tree order then one of the delimiting keys may be absent, and in this case get_lkey and get_rkey return a special key which is MIN_KEY or MAX_KEY. */ -static inline int key_in_buffer(struct treepath *p_s_chk_path, /* Path which should be checked. */ - const struct cpu_key *p_s_key, /* Key which should be checked. */ - struct super_block *p_s_sb /* Super block pointer. */ +static inline int key_in_buffer(struct treepath *chk_path, /* Path which should be checked. */ + const struct cpu_key *key, /* Key which should be checked. */ + struct super_block *sb ) { - RFALSE(!p_s_key || p_s_chk_path->path_length < FIRST_PATH_ELEMENT_OFFSET - || p_s_chk_path->path_length > MAX_HEIGHT, + RFALSE(!key || chk_path->path_length < FIRST_PATH_ELEMENT_OFFSET + || chk_path->path_length > MAX_HEIGHT, "PAP-5050: pointer to the key(%p) is NULL or invalid path length(%d)", - p_s_key, p_s_chk_path->path_length); - RFALSE(!PATH_PLAST_BUFFER(p_s_chk_path)->b_bdev, + key, chk_path->path_length); + RFALSE(!PATH_PLAST_BUFFER(chk_path)->b_bdev, "PAP-5060: device must not be NODEV"); - if (comp_keys(get_lkey(p_s_chk_path, p_s_sb), p_s_key) == 1) + if (comp_keys(get_lkey(chk_path, sb), key) == 1) /* left delimiting key is bigger, that the key we look for */ return 0; - // if ( comp_keys(p_s_key, get_rkey(p_s_chk_path, p_s_sb)) != -1 ) - if (comp_keys(get_rkey(p_s_chk_path, p_s_sb), p_s_key) != 1) - /* p_s_key must be less than right delimitiing key */ + /* if ( comp_keys(key, get_rkey(chk_path, sb)) != -1 ) */ + if (comp_keys(get_rkey(chk_path, sb), key) != 1) + /* key must be less than right delimitiing key */ return 0; return 1; } -inline void decrement_bcount(struct buffer_head *p_s_bh) -{ - if (p_s_bh) { - if (atomic_read(&(p_s_bh->b_count))) { - put_bh(p_s_bh); - return; - } - reiserfs_panic(NULL, - "PAP-5070: decrement_bcount: trying to free free buffer %b", - p_s_bh); - } -} - -/* Decrement b_count field of the all buffers in the path. */ -void decrement_counters_in_path(struct treepath *p_s_search_path) -{ - int n_path_offset = p_s_search_path->path_length; - - RFALSE(n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET || - n_path_offset > EXTENDED_MAX_HEIGHT - 1, - "PAP-5080: invalid path offset of %d", n_path_offset); - - while (n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) { - struct buffer_head *bh; - - bh = PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--); - decrement_bcount(bh); - } - p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET; -} - int reiserfs_check_path(struct treepath *p) { RFALSE(p->path_length != ILLEGAL_PATH_ELEMENT_OFFSET, @@ -397,40 +362,38 @@ int reiserfs_check_path(struct treepath *p) return 0; } -/* Release all buffers in the path. Restore dirty bits clean -** when preparing the buffer for the log -** -** only called from fix_nodes() -*/ -void pathrelse_and_restore(struct super_block *s, struct treepath *p_s_search_path) +/* Drop the reference to each buffer in a path and restore + * dirty bits clean when preparing the buffer for the log. + * This version should only be called from fix_nodes() */ +void pathrelse_and_restore(struct super_block *sb, + struct treepath *search_path) { - int n_path_offset = p_s_search_path->path_length; + int path_offset = search_path->path_length; - RFALSE(n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET, + RFALSE(path_offset < ILLEGAL_PATH_ELEMENT_OFFSET, "clm-4000: invalid path offset"); - while (n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) { - reiserfs_restore_prepared_buffer(s, - PATH_OFFSET_PBUFFER - (p_s_search_path, - n_path_offset)); - brelse(PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--)); + while (path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) { + struct buffer_head *bh; + bh = PATH_OFFSET_PBUFFER(search_path, path_offset--); + reiserfs_restore_prepared_buffer(sb, bh); + brelse(bh); } - p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET; + search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET; } -/* Release all buffers in the path. */ -void pathrelse(struct treepath *p_s_search_path) +/* Drop the reference to each buffer in a path */ +void pathrelse(struct treepath *search_path) { - int n_path_offset = p_s_search_path->path_length; + int path_offset = search_path->path_length; - RFALSE(n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET, + RFALSE(path_offset < ILLEGAL_PATH_ELEMENT_OFFSET, "PAP-5090: invalid path offset"); - while (n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) - brelse(PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--)); + while (path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) + brelse(PATH_OFFSET_PBUFFER(search_path, path_offset--)); - p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET; + search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET; } static int is_leaf(char *buf, int blocksize, struct buffer_head *bh) @@ -444,23 +407,24 @@ static int is_leaf(char *buf, int blocksize, struct buffer_head *bh) blkh = (struct block_head *)buf; if (blkh_level(blkh) != DISK_LEAF_NODE_LEVEL) { - reiserfs_warning(NULL, - "is_leaf: this should be caught earlier"); + reiserfs_warning(NULL, "reiserfs-5080", + "this should be caught earlier"); return 0; } nr = blkh_nr_item(blkh); if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN))) { /* item number is too big or too small */ - reiserfs_warning(NULL, "is_leaf: nr_item seems wrong: %z", bh); + reiserfs_warning(NULL, "reiserfs-5081", + "nr_item seems wrong: %z", bh); return 0; } ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1; used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location(ih)); if (used_space != blocksize - blkh_free_space(blkh)) { /* free space does not match to calculated amount of use space */ - reiserfs_warning(NULL, "is_leaf: free space seems wrong: %z", - bh); + reiserfs_warning(NULL, "reiserfs-5082", + "free space seems wrong: %z", bh); return 0; } // FIXME: it is_leaf will hit performance too much - we may have @@ -471,29 +435,29 @@ static int is_leaf(char *buf, int blocksize, struct buffer_head *bh) prev_location = blocksize; for (i = 0; i < nr; i++, ih++) { if (le_ih_k_type(ih) == TYPE_ANY) { - reiserfs_warning(NULL, - "is_leaf: wrong item type for item %h", + reiserfs_warning(NULL, "reiserfs-5083", + "wrong item type for item %h", ih); return 0; } if (ih_location(ih) >= blocksize || ih_location(ih) < IH_SIZE * nr) { - reiserfs_warning(NULL, - "is_leaf: item location seems wrong: %h", + reiserfs_warning(NULL, "reiserfs-5084", + "item location seems wrong: %h", ih); return 0; } if (ih_item_len(ih) < 1 || ih_item_len(ih) > MAX_ITEM_LEN(blocksize)) { - reiserfs_warning(NULL, - "is_leaf: item length seems wrong: %h", + reiserfs_warning(NULL, "reiserfs-5085", + "item length seems wrong: %h", ih); return 0; } if (prev_location - ih_location(ih) != ih_item_len(ih)) { - reiserfs_warning(NULL, - "is_leaf: item location seems wrong (second one): %h", - ih); + reiserfs_warning(NULL, "reiserfs-5086", + "item location seems wrong " + "(second one): %h", ih); return 0; } prev_location = ih_location(ih); @@ -514,24 +478,23 @@ static int is_internal(char *buf, int blocksize, struct buffer_head *bh) nr = blkh_level(blkh); if (nr <= DISK_LEAF_NODE_LEVEL || nr > MAX_HEIGHT) { /* this level is not possible for internal nodes */ - reiserfs_warning(NULL, - "is_internal: this should be caught earlier"); + reiserfs_warning(NULL, "reiserfs-5087", + "this should be caught earlier"); return 0; } nr = blkh_nr_item(blkh); if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE)) { /* for internal which is not root we might check min number of keys */ - reiserfs_warning(NULL, - "is_internal: number of key seems wrong: %z", - bh); + reiserfs_warning(NULL, "reiserfs-5088", + "number of key seems wrong: %z", bh); return 0; } used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1); if (used_space != blocksize - blkh_free_space(blkh)) { - reiserfs_warning(NULL, - "is_internal: free space seems wrong: %z", bh); + reiserfs_warning(NULL, "reiserfs-5089", + "free space seems wrong: %z", bh); return 0; } // one may imagine much more checks @@ -543,8 +506,8 @@ static int is_internal(char *buf, int blocksize, struct buffer_head *bh) static int is_tree_node(struct buffer_head *bh, int level) { if (B_LEVEL(bh) != level) { - reiserfs_warning(NULL, - "is_tree_node: node level %d does not match to the expected one %d", + reiserfs_warning(NULL, "reiserfs-5090", "node level %d does " + "not match to the expected one %d", B_LEVEL(bh), level); return 0; } @@ -580,10 +543,10 @@ static void search_by_key_reada(struct super_block *s, /************************************************************************** * Algorithm SearchByKey * * look for item in the Disk S+Tree by its key * - * Input: p_s_sb - super block * - * p_s_key - pointer to the key to search * + * Input: sb - super block * + * key - pointer to the key to search * * Output: ITEM_FOUND, ITEM_NOT_FOUND or IO_ERROR * - * p_s_search_path - path from the root to the needed leaf * + * search_path - path from the root to the needed leaf * **************************************************************************/ /* This function fills up the path from the root to the leaf as it @@ -600,22 +563,22 @@ static void search_by_key_reada(struct super_block *s, correctness of the top of the path but need not be checked for the correctness of the bottom of the path */ /* The function is NOT SCHEDULE-SAFE! */ -int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* Key to search. */ - struct treepath *p_s_search_path,/* This structure was +int search_by_key(struct super_block *sb, const struct cpu_key *key, /* Key to search. */ + struct treepath *search_path,/* This structure was allocated and initialized by the calling function. It is filled up by this function. */ - int n_stop_level /* How far down the tree to search. To + int stop_level /* How far down the tree to search. To stop at leaf level - set to DISK_LEAF_NODE_LEVEL */ ) { - b_blocknr_t n_block_number; + b_blocknr_t block_number; int expected_level; - struct buffer_head *p_s_bh; - struct path_element *p_s_last_element; - int n_node_level, n_retval; + struct buffer_head *bh; + struct path_element *last_element; + int node_level, retval; int right_neighbor_of_leaf_node; int fs_gen; struct buffer_head *reada_bh[SEARCH_BY_KEY_READA]; @@ -623,80 +586,79 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* int reada_count = 0; #ifdef CONFIG_REISERFS_CHECK - int n_repeat_counter = 0; + int repeat_counter = 0; #endif - PROC_INFO_INC(p_s_sb, search_by_key); + PROC_INFO_INC(sb, search_by_key); /* As we add each node to a path we increase its count. This means that we must be careful to release all nodes in a path before we either discard the path struct or re-use the path struct, as we do here. */ - decrement_counters_in_path(p_s_search_path); + pathrelse(search_path); right_neighbor_of_leaf_node = 0; /* With each iteration of this loop we search through the items in the current node, and calculate the next current node(next path element) for the next iteration of this loop.. */ - n_block_number = SB_ROOT_BLOCK(p_s_sb); + block_number = SB_ROOT_BLOCK(sb); expected_level = -1; while (1) { #ifdef CONFIG_REISERFS_CHECK - if (!(++n_repeat_counter % 50000)) - reiserfs_warning(p_s_sb, "PAP-5100: search_by_key: %s:" - "there were %d iterations of while loop " - "looking for key %K", - current->comm, n_repeat_counter, - p_s_key); + if (!(++repeat_counter % 50000)) + reiserfs_warning(sb, "PAP-5100", + "%s: there were %d iterations of " + "while loop looking for key %K", + current->comm, repeat_counter, + key); #endif /* prep path to have another element added to it. */ - p_s_last_element = - PATH_OFFSET_PELEMENT(p_s_search_path, - ++p_s_search_path->path_length); - fs_gen = get_generation(p_s_sb); + last_element = + PATH_OFFSET_PELEMENT(search_path, + ++search_path->path_length); + fs_gen = get_generation(sb); /* Read the next tree node, and set the last element in the path to have a pointer to it. */ - if ((p_s_bh = p_s_last_element->pe_buffer = - sb_getblk(p_s_sb, n_block_number))) { - if (!buffer_uptodate(p_s_bh) && reada_count > 1) { - search_by_key_reada(p_s_sb, reada_bh, + if ((bh = last_element->pe_buffer = + sb_getblk(sb, block_number))) { + if (!buffer_uptodate(bh) && reada_count > 1) + search_by_key_reada(sb, reada_bh, reada_blocks, reada_count); - } - ll_rw_block(READ, 1, &p_s_bh); - wait_on_buffer(p_s_bh); - if (!buffer_uptodate(p_s_bh)) + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) goto io_error; } else { io_error: - p_s_search_path->path_length--; - pathrelse(p_s_search_path); + search_path->path_length--; + pathrelse(search_path); return IO_ERROR; } reada_count = 0; if (expected_level == -1) - expected_level = SB_TREE_HEIGHT(p_s_sb); + expected_level = SB_TREE_HEIGHT(sb); expected_level--; /* It is possible that schedule occurred. We must check whether the key to search is still in the tree rooted from the current buffer. If not then repeat search from the root. */ - if (fs_changed(fs_gen, p_s_sb) && - (!B_IS_IN_TREE(p_s_bh) || - B_LEVEL(p_s_bh) != expected_level || - !key_in_buffer(p_s_search_path, p_s_key, p_s_sb))) { - PROC_INFO_INC(p_s_sb, search_by_key_fs_changed); - PROC_INFO_INC(p_s_sb, search_by_key_restarted); - PROC_INFO_INC(p_s_sb, + if (fs_changed(fs_gen, sb) && + (!B_IS_IN_TREE(bh) || + B_LEVEL(bh) != expected_level || + !key_in_buffer(search_path, key, sb))) { + PROC_INFO_INC(sb, search_by_key_fs_changed); + PROC_INFO_INC(sb, search_by_key_restarted); + PROC_INFO_INC(sb, sbk_restarted[expected_level - 1]); - decrement_counters_in_path(p_s_search_path); + pathrelse(search_path); /* Get the root block number so that we can repeat the search starting from the root. */ - n_block_number = SB_ROOT_BLOCK(p_s_sb); + block_number = SB_ROOT_BLOCK(sb); expected_level = -1; right_neighbor_of_leaf_node = 0; @@ -704,53 +666,53 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* continue; } - /* only check that the key is in the buffer if p_s_key is not + /* only check that the key is in the buffer if key is not equal to the MAX_KEY. Latter case is only possible in "finish_unfinished()" processing during mount. */ - RFALSE(comp_keys(&MAX_KEY, p_s_key) && - !key_in_buffer(p_s_search_path, p_s_key, p_s_sb), + RFALSE(comp_keys(&MAX_KEY, key) && + !key_in_buffer(search_path, key, sb), "PAP-5130: key is not in the buffer"); #ifdef CONFIG_REISERFS_CHECK if (cur_tb) { print_cur_tb("5140"); - reiserfs_panic(p_s_sb, - "PAP-5140: search_by_key: schedule occurred in do_balance!"); + reiserfs_panic(sb, "PAP-5140", + "schedule occurred in do_balance!"); } #endif // make sure, that the node contents look like a node of // certain level - if (!is_tree_node(p_s_bh, expected_level)) { - reiserfs_warning(p_s_sb, "vs-5150: search_by_key: " - "invalid format found in block %ld. Fsck?", - p_s_bh->b_blocknr); - pathrelse(p_s_search_path); + if (!is_tree_node(bh, expected_level)) { + reiserfs_error(sb, "vs-5150", + "invalid format found in block %ld. " + "Fsck?", bh->b_blocknr); + pathrelse(search_path); return IO_ERROR; } /* ok, we have acquired next formatted node in the tree */ - n_node_level = B_LEVEL(p_s_bh); + node_level = B_LEVEL(bh); - PROC_INFO_BH_STAT(p_s_sb, p_s_bh, n_node_level - 1); + PROC_INFO_BH_STAT(sb, bh, node_level - 1); - RFALSE(n_node_level < n_stop_level, + RFALSE(node_level < stop_level, "vs-5152: tree level (%d) is less than stop level (%d)", - n_node_level, n_stop_level); + node_level, stop_level); - n_retval = bin_search(p_s_key, B_N_PITEM_HEAD(p_s_bh, 0), - B_NR_ITEMS(p_s_bh), - (n_node_level == + retval = bin_search(key, B_N_PITEM_HEAD(bh, 0), + B_NR_ITEMS(bh), + (node_level == DISK_LEAF_NODE_LEVEL) ? IH_SIZE : KEY_SIZE, - &(p_s_last_element->pe_position)); - if (n_node_level == n_stop_level) { - return n_retval; + &(last_element->pe_position)); + if (node_level == stop_level) { + return retval; } /* we are not in the stop level */ - if (n_retval == ITEM_FOUND) + if (retval == ITEM_FOUND) /* item has been found, so we choose the pointer which is to the right of the found one */ - p_s_last_element->pe_position++; + last_element->pe_position++; /* if item was not found we choose the position which is to the left of the found item. This requires no code, @@ -759,24 +721,24 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* /* So we have chosen a position in the current node which is an internal node. Now we calculate child block number by position in the node. */ - n_block_number = - B_N_CHILD_NUM(p_s_bh, p_s_last_element->pe_position); + block_number = + B_N_CHILD_NUM(bh, last_element->pe_position); /* if we are going to read leaf nodes, try for read ahead as well */ - if ((p_s_search_path->reada & PATH_READA) && - n_node_level == DISK_LEAF_NODE_LEVEL + 1) { - int pos = p_s_last_element->pe_position; - int limit = B_NR_ITEMS(p_s_bh); + if ((search_path->reada & PATH_READA) && + node_level == DISK_LEAF_NODE_LEVEL + 1) { + int pos = last_element->pe_position; + int limit = B_NR_ITEMS(bh); struct reiserfs_key *le_key; - if (p_s_search_path->reada & PATH_READA_BACK) + if (search_path->reada & PATH_READA_BACK) limit = 0; while (reada_count < SEARCH_BY_KEY_READA) { if (pos == limit) break; reada_blocks[reada_count++] = - B_N_CHILD_NUM(p_s_bh, pos); - if (p_s_search_path->reada & PATH_READA_BACK) + B_N_CHILD_NUM(bh, pos); + if (search_path->reada & PATH_READA_BACK) pos--; else pos++; @@ -784,9 +746,9 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* /* * check to make sure we're in the same object */ - le_key = B_N_PDELIM_KEY(p_s_bh, pos); + le_key = B_N_PDELIM_KEY(bh, pos); if (le32_to_cpu(le_key->k_objectid) != - p_s_key->on_disk_key.k_objectid) { + key->on_disk_key.k_objectid) { break; } } @@ -795,11 +757,11 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* } /* Form the path to an item and position in this item which contains - file byte defined by p_s_key. If there is no such item + file byte defined by key. If there is no such item corresponding to the key, we point the path to the item with - maximal key less than p_s_key, and *p_n_pos_in_item is set to one + maximal key less than key, and *pos_in_item is set to one past the last entry/byte in the item. If searching for entry in a - directory item, and it is not found, *p_n_pos_in_item is set to one + directory item, and it is not found, *pos_in_item is set to one entry more than the entry with maximal key which is less than the sought key. @@ -810,48 +772,48 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* units of directory entries. */ /* The function is NOT SCHEDULE-SAFE! */ -int search_for_position_by_key(struct super_block *p_s_sb, /* Pointer to the super block. */ +int search_for_position_by_key(struct super_block *sb, /* Pointer to the super block. */ const struct cpu_key *p_cpu_key, /* Key to search (cpu variable) */ - struct treepath *p_s_search_path /* Filled up by this function. */ + struct treepath *search_path /* Filled up by this function. */ ) { struct item_head *p_le_ih; /* pointer to on-disk structure */ - int n_blk_size; + int blk_size; loff_t item_offset, offset; struct reiserfs_dir_entry de; int retval; /* If searching for directory entry. */ if (is_direntry_cpu_key(p_cpu_key)) - return search_by_entry_key(p_s_sb, p_cpu_key, p_s_search_path, + return search_by_entry_key(sb, p_cpu_key, search_path, &de); /* If not searching for directory entry. */ /* If item is found. */ - retval = search_item(p_s_sb, p_cpu_key, p_s_search_path); + retval = search_item(sb, p_cpu_key, search_path); if (retval == IO_ERROR) return retval; if (retval == ITEM_FOUND) { RFALSE(!ih_item_len (B_N_PITEM_HEAD - (PATH_PLAST_BUFFER(p_s_search_path), - PATH_LAST_POSITION(p_s_search_path))), + (PATH_PLAST_BUFFER(search_path), + PATH_LAST_POSITION(search_path))), "PAP-5165: item length equals zero"); - pos_in_item(p_s_search_path) = 0; + pos_in_item(search_path) = 0; return POSITION_FOUND; } - RFALSE(!PATH_LAST_POSITION(p_s_search_path), + RFALSE(!PATH_LAST_POSITION(search_path), "PAP-5170: position equals zero"); /* Item is not found. Set path to the previous item. */ p_le_ih = - B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_search_path), - --PATH_LAST_POSITION(p_s_search_path)); - n_blk_size = p_s_sb->s_blocksize; + B_N_PITEM_HEAD(PATH_PLAST_BUFFER(search_path), + --PATH_LAST_POSITION(search_path)); + blk_size = sb->s_blocksize; if (comp_short_keys(&(p_le_ih->ih_key), p_cpu_key)) { return FILE_NOT_FOUND; @@ -863,10 +825,10 @@ int search_for_position_by_key(struct super_block *p_s_sb, /* Pointer to the sup /* Needed byte is contained in the item pointed to by the path. */ if (item_offset <= offset && - item_offset + op_bytes_number(p_le_ih, n_blk_size) > offset) { - pos_in_item(p_s_search_path) = offset - item_offset; + item_offset + op_bytes_number(p_le_ih, blk_size) > offset) { + pos_in_item(search_path) = offset - item_offset; if (is_indirect_le_ih(p_le_ih)) { - pos_in_item(p_s_search_path) /= n_blk_size; + pos_in_item(search_path) /= blk_size; } return POSITION_FOUND; } @@ -874,30 +836,30 @@ int search_for_position_by_key(struct super_block *p_s_sb, /* Pointer to the sup /* Needed byte is not contained in the item pointed to by the path. Set pos_in_item out of the item. */ if (is_indirect_le_ih(p_le_ih)) - pos_in_item(p_s_search_path) = + pos_in_item(search_path) = ih_item_len(p_le_ih) / UNFM_P_SIZE; else - pos_in_item(p_s_search_path) = ih_item_len(p_le_ih); + pos_in_item(search_path) = ih_item_len(p_le_ih); return POSITION_NOT_FOUND; } /* Compare given item and item pointed to by the path. */ -int comp_items(const struct item_head *stored_ih, const struct treepath *p_s_path) +int comp_items(const struct item_head *stored_ih, const struct treepath *path) { - struct buffer_head *p_s_bh; + struct buffer_head *bh = PATH_PLAST_BUFFER(path); struct item_head *ih; /* Last buffer at the path is not in the tree. */ - if (!B_IS_IN_TREE(p_s_bh = PATH_PLAST_BUFFER(p_s_path))) + if (!B_IS_IN_TREE(bh)) return 1; /* Last path position is invalid. */ - if (PATH_LAST_POSITION(p_s_path) >= B_NR_ITEMS(p_s_bh)) + if (PATH_LAST_POSITION(path) >= B_NR_ITEMS(bh)) return 1; /* we need only to know, whether it is the same item */ - ih = get_ih(p_s_path); + ih = get_ih(path); return memcmp(stored_ih, ih, IH_SIZE); } @@ -924,9 +886,9 @@ static inline int prepare_for_direct_item(struct treepath *path, } // new file gets truncated if (get_inode_item_key_version(inode) == KEY_FORMAT_3_6) { - // + // round_len = ROUND_UP(new_file_length); - /* this was n_new_file_length < le_ih ... */ + /* this was new_file_length < le_ih ... */ if (round_len < le_ih_k_offset(le_ih)) { *cut_size = -(IH_SIZE + ih_item_len(le_ih)); return M_DELETE; /* Delete this item. */ @@ -986,96 +948,95 @@ static inline int prepare_for_direntry_item(struct treepath *path, In case of file truncate calculate whether this item must be deleted/truncated or last unformatted node of this item will be converted to a direct item. This function returns a determination of what balance mode the calling function should employ. */ -static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, struct inode *inode, struct treepath *p_s_path, const struct cpu_key *p_s_item_key, int *p_n_removed, /* Number of unformatted nodes which were removed +static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, struct inode *inode, struct treepath *path, const struct cpu_key *item_key, int *removed, /* Number of unformatted nodes which were removed from end of the file. */ - int *p_n_cut_size, unsigned long long n_new_file_length /* MAX_KEY_OFFSET in case of delete. */ + int *cut_size, unsigned long long new_file_length /* MAX_KEY_OFFSET in case of delete. */ ) { - struct super_block *p_s_sb = inode->i_sb; - struct item_head *p_le_ih = PATH_PITEM_HEAD(p_s_path); - struct buffer_head *p_s_bh = PATH_PLAST_BUFFER(p_s_path); + struct super_block *sb = inode->i_sb; + struct item_head *p_le_ih = PATH_PITEM_HEAD(path); + struct buffer_head *bh = PATH_PLAST_BUFFER(path); BUG_ON(!th->t_trans_id); /* Stat_data item. */ if (is_statdata_le_ih(p_le_ih)) { - RFALSE(n_new_file_length != max_reiserfs_offset(inode), + RFALSE(new_file_length != max_reiserfs_offset(inode), "PAP-5210: mode must be M_DELETE"); - *p_n_cut_size = -(IH_SIZE + ih_item_len(p_le_ih)); + *cut_size = -(IH_SIZE + ih_item_len(p_le_ih)); return M_DELETE; } /* Directory item. */ if (is_direntry_le_ih(p_le_ih)) - return prepare_for_direntry_item(p_s_path, p_le_ih, inode, - n_new_file_length, - p_n_cut_size); + return prepare_for_direntry_item(path, p_le_ih, inode, + new_file_length, + cut_size); /* Direct item. */ if (is_direct_le_ih(p_le_ih)) - return prepare_for_direct_item(p_s_path, p_le_ih, inode, - n_new_file_length, p_n_cut_size); + return prepare_for_direct_item(path, p_le_ih, inode, + new_file_length, cut_size); /* Case of an indirect item. */ { - int blk_size = p_s_sb->s_blocksize; + int blk_size = sb->s_blocksize; struct item_head s_ih; int need_re_search; int delete = 0; int result = M_CUT; int pos = 0; - if ( n_new_file_length == max_reiserfs_offset (inode) ) { + if ( new_file_length == max_reiserfs_offset (inode) ) { /* prepare_for_delete_or_cut() is called by * reiserfs_delete_item() */ - n_new_file_length = 0; + new_file_length = 0; delete = 1; } do { need_re_search = 0; - *p_n_cut_size = 0; - p_s_bh = PATH_PLAST_BUFFER(p_s_path); - copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path)); + *cut_size = 0; + bh = PATH_PLAST_BUFFER(path); + copy_item_head(&s_ih, PATH_PITEM_HEAD(path)); pos = I_UNFM_NUM(&s_ih); - while (le_ih_k_offset (&s_ih) + (pos - 1) * blk_size > n_new_file_length) { + while (le_ih_k_offset (&s_ih) + (pos - 1) * blk_size > new_file_length) { __le32 *unfm; __u32 block; /* Each unformatted block deletion may involve one additional * bitmap block into the transaction, thereby the initial * journal space reservation might not be enough. */ - if (!delete && (*p_n_cut_size) != 0 && - reiserfs_transaction_free_space(th) < JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD) { + if (!delete && (*cut_size) != 0 && + reiserfs_transaction_free_space(th) < JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD) break; - } - unfm = (__le32 *)B_I_PITEM(p_s_bh, &s_ih) + pos - 1; + unfm = (__le32 *)B_I_PITEM(bh, &s_ih) + pos - 1; block = get_block_num(unfm, 0); if (block != 0) { - reiserfs_prepare_for_journal(p_s_sb, p_s_bh, 1); + reiserfs_prepare_for_journal(sb, bh, 1); put_block_num(unfm, 0, 0); - journal_mark_dirty (th, p_s_sb, p_s_bh); + journal_mark_dirty(th, sb, bh); reiserfs_free_block(th, inode, block, 1); } cond_resched(); - if (item_moved (&s_ih, p_s_path)) { + if (item_moved (&s_ih, path)) { need_re_search = 1; break; } pos --; - (*p_n_removed) ++; - (*p_n_cut_size) -= UNFM_P_SIZE; + (*removed)++; + (*cut_size) -= UNFM_P_SIZE; if (pos == 0) { - (*p_n_cut_size) -= IH_SIZE; + (*cut_size) -= IH_SIZE; result = M_DELETE; break; } @@ -1083,12 +1044,12 @@ static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, st /* a trick. If the buffer has been logged, this will do nothing. If ** we've broken the loop without logging it, it will restore the ** buffer */ - reiserfs_restore_prepared_buffer(p_s_sb, p_s_bh); + reiserfs_restore_prepared_buffer(sb, bh); } while (need_re_search && - search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_FOUND); - pos_in_item(p_s_path) = pos * UNFM_P_SIZE; + search_for_position_by_key(sb, item_key, path) == POSITION_FOUND); + pos_in_item(path) = pos * UNFM_P_SIZE; - if (*p_n_cut_size == 0) { + if (*cut_size == 0) { /* Nothing were cut. maybe convert last unformatted node to the * direct item? */ result = M_CONVERT; @@ -1098,45 +1059,45 @@ static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, st } /* Calculate number of bytes which will be deleted or cut during balance */ -static int calc_deleted_bytes_number(struct tree_balance *p_s_tb, char c_mode) +static int calc_deleted_bytes_number(struct tree_balance *tb, char mode) { - int n_del_size; - struct item_head *p_le_ih = PATH_PITEM_HEAD(p_s_tb->tb_path); + int del_size; + struct item_head *p_le_ih = PATH_PITEM_HEAD(tb->tb_path); if (is_statdata_le_ih(p_le_ih)) return 0; - n_del_size = - (c_mode == - M_DELETE) ? ih_item_len(p_le_ih) : -p_s_tb->insert_size[0]; + del_size = + (mode == + M_DELETE) ? ih_item_len(p_le_ih) : -tb->insert_size[0]; if (is_direntry_le_ih(p_le_ih)) { - // return EMPTY_DIR_SIZE; /* We delete emty directoris only. */ - // we can't use EMPTY_DIR_SIZE, as old format dirs have a different - // empty size. ick. FIXME, is this right? - // - return n_del_size; + /* return EMPTY_DIR_SIZE; We delete emty directoris only. + * we can't use EMPTY_DIR_SIZE, as old format dirs have a different + * empty size. ick. FIXME, is this right? */ + return del_size; } if (is_indirect_le_ih(p_le_ih)) - n_del_size = (n_del_size / UNFM_P_SIZE) * (PATH_PLAST_BUFFER(p_s_tb->tb_path)->b_size); // - get_ih_free_space (p_le_ih); - return n_del_size; + del_size = (del_size / UNFM_P_SIZE) * + (PATH_PLAST_BUFFER(tb->tb_path)->b_size); + return del_size; } static void init_tb_struct(struct reiserfs_transaction_handle *th, - struct tree_balance *p_s_tb, - struct super_block *p_s_sb, - struct treepath *p_s_path, int n_size) + struct tree_balance *tb, + struct super_block *sb, + struct treepath *path, int size) { BUG_ON(!th->t_trans_id); - memset(p_s_tb, '\0', sizeof(struct tree_balance)); - p_s_tb->transaction_handle = th; - p_s_tb->tb_sb = p_s_sb; - p_s_tb->tb_path = p_s_path; - PATH_OFFSET_PBUFFER(p_s_path, ILLEGAL_PATH_ELEMENT_OFFSET) = NULL; - PATH_OFFSET_POSITION(p_s_path, ILLEGAL_PATH_ELEMENT_OFFSET) = 0; - p_s_tb->insert_size[0] = n_size; + memset(tb, '\0', sizeof(struct tree_balance)); + tb->transaction_handle = th; + tb->tb_sb = sb; + tb->tb_path = path; + PATH_OFFSET_PBUFFER(path, ILLEGAL_PATH_ELEMENT_OFFSET) = NULL; + PATH_OFFSET_POSITION(path, ILLEGAL_PATH_ELEMENT_OFFSET) = 0; + tb->insert_size[0] = size; } void padd_item(char *item, int total_length, int length) @@ -1175,73 +1136,77 @@ char head2type(struct item_head *ih) } #endif -/* Delete object item. */ -int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_path, /* Path to the deleted item. */ - const struct cpu_key *p_s_item_key, /* Key to search for the deleted item. */ - struct inode *p_s_inode, /* inode is here just to update i_blocks and quotas */ - struct buffer_head *p_s_un_bh) -{ /* NULL or unformatted node pointer. */ - struct super_block *p_s_sb = p_s_inode->i_sb; +/* Delete object item. + * th - active transaction handle + * path - path to the deleted item + * item_key - key to search for the deleted item + * indode - used for updating i_blocks and quotas + * un_bh - NULL or unformatted node pointer + */ +int reiserfs_delete_item(struct reiserfs_transaction_handle *th, + struct treepath *path, const struct cpu_key *item_key, + struct inode *inode, struct buffer_head *un_bh) +{ + struct super_block *sb = inode->i_sb; struct tree_balance s_del_balance; struct item_head s_ih; struct item_head *q_ih; int quota_cut_bytes; - int n_ret_value, n_del_size, n_removed; + int ret_value, del_size, removed; #ifdef CONFIG_REISERFS_CHECK - char c_mode; - int n_iter = 0; + char mode; + int iter = 0; #endif BUG_ON(!th->t_trans_id); - init_tb_struct(th, &s_del_balance, p_s_sb, p_s_path, + init_tb_struct(th, &s_del_balance, sb, path, 0 /*size is unknown */ ); while (1) { - n_removed = 0; + removed = 0; #ifdef CONFIG_REISERFS_CHECK - n_iter++; - c_mode = + iter++; + mode = #endif - prepare_for_delete_or_cut(th, p_s_inode, p_s_path, - p_s_item_key, &n_removed, - &n_del_size, - max_reiserfs_offset(p_s_inode)); + prepare_for_delete_or_cut(th, inode, path, + item_key, &removed, + &del_size, + max_reiserfs_offset(inode)); - RFALSE(c_mode != M_DELETE, "PAP-5320: mode must be M_DELETE"); + RFALSE(mode != M_DELETE, "PAP-5320: mode must be M_DELETE"); - copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path)); - s_del_balance.insert_size[0] = n_del_size; + copy_item_head(&s_ih, PATH_PITEM_HEAD(path)); + s_del_balance.insert_size[0] = del_size; - n_ret_value = fix_nodes(M_DELETE, &s_del_balance, NULL, NULL); - if (n_ret_value != REPEAT_SEARCH) + ret_value = fix_nodes(M_DELETE, &s_del_balance, NULL, NULL); + if (ret_value != REPEAT_SEARCH) break; - PROC_INFO_INC(p_s_sb, delete_item_restarted); + PROC_INFO_INC(sb, delete_item_restarted); // file system changed, repeat search - n_ret_value = - search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path); - if (n_ret_value == IO_ERROR) + ret_value = + search_for_position_by_key(sb, item_key, path); + if (ret_value == IO_ERROR) break; - if (n_ret_value == FILE_NOT_FOUND) { - reiserfs_warning(p_s_sb, - "vs-5340: reiserfs_delete_item: " + if (ret_value == FILE_NOT_FOUND) { + reiserfs_warning(sb, "vs-5340", "no items of the file %K found", - p_s_item_key); + item_key); break; } } /* while (1) */ - if (n_ret_value != CARRY_ON) { + if (ret_value != CARRY_ON) { unfix_nodes(&s_del_balance); return 0; } // reiserfs_delete_item returns item length when success - n_ret_value = calc_deleted_bytes_number(&s_del_balance, M_DELETE); - q_ih = get_ih(p_s_path); + ret_value = calc_deleted_bytes_number(&s_del_balance, M_DELETE); + q_ih = get_ih(path); quota_cut_bytes = ih_item_len(q_ih); /* hack so the quota code doesn't have to guess if the file @@ -1250,15 +1215,15 @@ int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct treepath ** split into multiple items, and we only want to decrement for ** the unfm node once */ - if (!S_ISLNK(p_s_inode->i_mode) && is_direct_le_ih(q_ih)) { - if ((le_ih_k_offset(q_ih) & (p_s_sb->s_blocksize - 1)) == 1) { - quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE; + if (!S_ISLNK(inode->i_mode) && is_direct_le_ih(q_ih)) { + if ((le_ih_k_offset(q_ih) & (sb->s_blocksize - 1)) == 1) { + quota_cut_bytes = sb->s_blocksize + UNFM_P_SIZE; } else { quota_cut_bytes = 0; } } - if (p_s_un_bh) { + if (un_bh) { int off; char *data; @@ -1276,31 +1241,31 @@ int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct treepath ** The unformatted node must be dirtied later on. We can't be ** sure here if the entire tail has been deleted yet. ** - ** p_s_un_bh is from the page cache (all unformatted nodes are + ** un_bh is from the page cache (all unformatted nodes are ** from the page cache) and might be a highmem page. So, we - ** can't use p_s_un_bh->b_data. + ** can't use un_bh->b_data. ** -clm */ - data = kmap_atomic(p_s_un_bh->b_page, KM_USER0); + data = kmap_atomic(un_bh->b_page, KM_USER0); off = ((le_ih_k_offset(&s_ih) - 1) & (PAGE_CACHE_SIZE - 1)); memcpy(data + off, - B_I_PITEM(PATH_PLAST_BUFFER(p_s_path), &s_ih), - n_ret_value); + B_I_PITEM(PATH_PLAST_BUFFER(path), &s_ih), + ret_value); kunmap_atomic(data, KM_USER0); } /* Perform balancing after all resources have been collected at once. */ do_balance(&s_del_balance, NULL, NULL, M_DELETE); #ifdef REISERQUOTA_DEBUG - reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, + reiserfs_debug(sb, REISERFS_DEBUG_CODE, "reiserquota delete_item(): freeing %u, id=%u type=%c", - quota_cut_bytes, p_s_inode->i_uid, head2type(&s_ih)); + quota_cut_bytes, inode->i_uid, head2type(&s_ih)); #endif - DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes); + vfs_dq_free_space_nodirty(inode, quota_cut_bytes); /* Return deleted body length */ - return n_ret_value; + return ret_value; } /* Summary Of Mechanisms For Handling Collisions Between Processes: @@ -1338,10 +1303,9 @@ void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th, while (1) { retval = search_item(th->t_super, &cpu_key, &path); if (retval == IO_ERROR) { - reiserfs_warning(th->t_super, - "vs-5350: reiserfs_delete_solid_item: " - "i/o failure occurred trying to delete %K", - &cpu_key); + reiserfs_error(th->t_super, "vs-5350", + "i/o failure occurred trying " + "to delete %K", &cpu_key); break; } if (retval != ITEM_FOUND) { @@ -1355,9 +1319,8 @@ void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th, GET_GENERATION_NUMBER(le_key_k_offset (le_key_version(key), key)) == 1)) - reiserfs_warning(th->t_super, - "vs-5355: reiserfs_delete_solid_item: %k not found", - key); + reiserfs_warning(th->t_super, "vs-5355", + "%k not found", key); break; } if (!tb_init) { @@ -1383,14 +1346,13 @@ void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th, quota_cut_bytes, inode->i_uid, key2type(key)); #endif - DQUOT_FREE_SPACE_NODIRTY(inode, + vfs_dq_free_space_nodirty(inode, quota_cut_bytes); } break; } // IO_ERROR, NO_DISK_SPACE, etc - reiserfs_warning(th->t_super, - "vs-5360: reiserfs_delete_solid_item: " + reiserfs_warning(th->t_super, "vs-5360", "could not delete %K due to fix_nodes failure", &cpu_key); unfix_nodes(&tb); @@ -1462,36 +1424,37 @@ static void unmap_buffers(struct page *page, loff_t pos) } static int maybe_indirect_to_direct(struct reiserfs_transaction_handle *th, - struct inode *p_s_inode, + struct inode *inode, struct page *page, - struct treepath *p_s_path, - const struct cpu_key *p_s_item_key, - loff_t n_new_file_size, char *p_c_mode) + struct treepath *path, + const struct cpu_key *item_key, + loff_t new_file_size, char *mode) { - struct super_block *p_s_sb = p_s_inode->i_sb; - int n_block_size = p_s_sb->s_blocksize; + struct super_block *sb = inode->i_sb; + int block_size = sb->s_blocksize; int cut_bytes; BUG_ON(!th->t_trans_id); - BUG_ON(n_new_file_size != p_s_inode->i_size); + BUG_ON(new_file_size != inode->i_size); /* the page being sent in could be NULL if there was an i/o error ** reading in the last block. The user will hit problems trying to ** read the file, but for now we just skip the indirect2direct */ - if (atomic_read(&p_s_inode->i_count) > 1 || - !tail_has_to_be_packed(p_s_inode) || - !page || (REISERFS_I(p_s_inode)->i_flags & i_nopack_mask)) { - // leave tail in an unformatted node - *p_c_mode = M_SKIP_BALANCING; + if (atomic_read(&inode->i_count) > 1 || + !tail_has_to_be_packed(inode) || + !page || (REISERFS_I(inode)->i_flags & i_nopack_mask)) { + /* leave tail in an unformatted node */ + *mode = M_SKIP_BALANCING; cut_bytes = - n_block_size - (n_new_file_size & (n_block_size - 1)); - pathrelse(p_s_path); + block_size - (new_file_size & (block_size - 1)); + pathrelse(path); return cut_bytes; } - /* Permorm the conversion to a direct_item. */ - /*return indirect_to_direct (p_s_inode, p_s_path, p_s_item_key, n_new_file_size, p_c_mode); */ - return indirect2direct(th, p_s_inode, page, p_s_path, p_s_item_key, - n_new_file_size, p_c_mode); + /* Perform the conversion to a direct_item. */ + /* return indirect_to_direct(inode, path, item_key, + new_file_size, mode); */ + return indirect2direct(th, inode, page, path, item_key, + new_file_size, mode); } /* we did indirect_to_direct conversion. And we have inserted direct @@ -1515,8 +1478,8 @@ static void indirect_to_direct_roll_back(struct reiserfs_transaction_handle *th, /* look for the last byte of the tail */ if (search_for_position_by_key(inode->i_sb, &tail_key, path) == POSITION_NOT_FOUND) - reiserfs_panic(inode->i_sb, - "vs-5615: indirect_to_direct_roll_back: found invalid item"); + reiserfs_panic(inode->i_sb, "vs-5615", + "found invalid item"); RFALSE(path->pos_in_item != ih_item_len(PATH_PITEM_HEAD(path)) - 1, "vs-5616: appended bytes found"); @@ -1533,38 +1496,39 @@ static void indirect_to_direct_roll_back(struct reiserfs_transaction_handle *th, set_cpu_key_k_offset(&tail_key, cpu_key_k_offset(&tail_key) - removed); } - reiserfs_warning(inode->i_sb, - "indirect_to_direct_roll_back: indirect_to_direct conversion has been rolled back due to lack of disk space"); + reiserfs_warning(inode->i_sb, "reiserfs-5091", "indirect_to_direct " + "conversion has been rolled back due to " + "lack of disk space"); //mark_file_without_tail (inode); mark_inode_dirty(inode); } /* (Truncate or cut entry) or delete object item. Returns < 0 on failure */ int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th, - struct treepath *p_s_path, - struct cpu_key *p_s_item_key, - struct inode *p_s_inode, - struct page *page, loff_t n_new_file_size) + struct treepath *path, + struct cpu_key *item_key, + struct inode *inode, + struct page *page, loff_t new_file_size) { - struct super_block *p_s_sb = p_s_inode->i_sb; + struct super_block *sb = inode->i_sb; /* Every function which is going to call do_balance must first create a tree_balance structure. Then it must fill up this structure by using the init_tb_struct and fix_nodes functions. After that we can make tree balancing. */ struct tree_balance s_cut_balance; struct item_head *p_le_ih; - int n_cut_size = 0, /* Amount to be cut. */ - n_ret_value = CARRY_ON, n_removed = 0, /* Number of the removed unformatted nodes. */ - n_is_inode_locked = 0; - char c_mode; /* Mode of the balance. */ + int cut_size = 0, /* Amount to be cut. */ + ret_value = CARRY_ON, removed = 0, /* Number of the removed unformatted nodes. */ + is_inode_locked = 0; + char mode; /* Mode of the balance. */ int retval2 = -1; int quota_cut_bytes; loff_t tail_pos = 0; BUG_ON(!th->t_trans_id); - init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path, - n_cut_size); + init_tb_struct(th, &s_cut_balance, inode->i_sb, path, + cut_size); /* Repeat this loop until we either cut the item without needing to balance, or we fix_nodes without schedule occurring */ @@ -1574,144 +1538,142 @@ int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th, free unformatted nodes which are pointed to by the cut pointers. */ - c_mode = - prepare_for_delete_or_cut(th, p_s_inode, p_s_path, - p_s_item_key, &n_removed, - &n_cut_size, n_new_file_size); - if (c_mode == M_CONVERT) { + mode = + prepare_for_delete_or_cut(th, inode, path, + item_key, &removed, + &cut_size, new_file_size); + if (mode == M_CONVERT) { /* convert last unformatted node to direct item or leave tail in the unformatted node */ - RFALSE(n_ret_value != CARRY_ON, + RFALSE(ret_value != CARRY_ON, "PAP-5570: can not convert twice"); - n_ret_value = - maybe_indirect_to_direct(th, p_s_inode, page, - p_s_path, p_s_item_key, - n_new_file_size, &c_mode); - if (c_mode == M_SKIP_BALANCING) + ret_value = + maybe_indirect_to_direct(th, inode, page, + path, item_key, + new_file_size, &mode); + if (mode == M_SKIP_BALANCING) /* tail has been left in the unformatted node */ - return n_ret_value; + return ret_value; - n_is_inode_locked = 1; + is_inode_locked = 1; /* removing of last unformatted node will change value we have to return to truncate. Save it */ - retval2 = n_ret_value; - /*retval2 = p_s_sb->s_blocksize - (n_new_file_size & (p_s_sb->s_blocksize - 1)); */ + retval2 = ret_value; + /*retval2 = sb->s_blocksize - (new_file_size & (sb->s_blocksize - 1)); */ /* So, we have performed the first part of the conversion: inserting the new direct item. Now we are removing the last unformatted node pointer. Set key to search for it. */ - set_cpu_key_k_type(p_s_item_key, TYPE_INDIRECT); - p_s_item_key->key_length = 4; - n_new_file_size -= - (n_new_file_size & (p_s_sb->s_blocksize - 1)); - tail_pos = n_new_file_size; - set_cpu_key_k_offset(p_s_item_key, n_new_file_size + 1); + set_cpu_key_k_type(item_key, TYPE_INDIRECT); + item_key->key_length = 4; + new_file_size -= + (new_file_size & (sb->s_blocksize - 1)); + tail_pos = new_file_size; + set_cpu_key_k_offset(item_key, new_file_size + 1); if (search_for_position_by_key - (p_s_sb, p_s_item_key, - p_s_path) == POSITION_NOT_FOUND) { - print_block(PATH_PLAST_BUFFER(p_s_path), 3, - PATH_LAST_POSITION(p_s_path) - 1, - PATH_LAST_POSITION(p_s_path) + 1); - reiserfs_panic(p_s_sb, - "PAP-5580: reiserfs_cut_from_item: item to convert does not exist (%K)", - p_s_item_key); + (sb, item_key, + path) == POSITION_NOT_FOUND) { + print_block(PATH_PLAST_BUFFER(path), 3, + PATH_LAST_POSITION(path) - 1, + PATH_LAST_POSITION(path) + 1); + reiserfs_panic(sb, "PAP-5580", "item to " + "convert does not exist (%K)", + item_key); } continue; } - if (n_cut_size == 0) { - pathrelse(p_s_path); + if (cut_size == 0) { + pathrelse(path); return 0; } - s_cut_balance.insert_size[0] = n_cut_size; + s_cut_balance.insert_size[0] = cut_size; - n_ret_value = fix_nodes(c_mode, &s_cut_balance, NULL, NULL); - if (n_ret_value != REPEAT_SEARCH) + ret_value = fix_nodes(mode, &s_cut_balance, NULL, NULL); + if (ret_value != REPEAT_SEARCH) break; - PROC_INFO_INC(p_s_sb, cut_from_item_restarted); + PROC_INFO_INC(sb, cut_from_item_restarted); - n_ret_value = - search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path); - if (n_ret_value == POSITION_FOUND) + ret_value = + search_for_position_by_key(sb, item_key, path); + if (ret_value == POSITION_FOUND) continue; - reiserfs_warning(p_s_sb, - "PAP-5610: reiserfs_cut_from_item: item %K not found", - p_s_item_key); + reiserfs_warning(sb, "PAP-5610", "item %K not found", + item_key); unfix_nodes(&s_cut_balance); - return (n_ret_value == IO_ERROR) ? -EIO : -ENOENT; + return (ret_value == IO_ERROR) ? -EIO : -ENOENT; } /* while */ // check fix_nodes results (IO_ERROR or NO_DISK_SPACE) - if (n_ret_value != CARRY_ON) { - if (n_is_inode_locked) { + if (ret_value != CARRY_ON) { + if (is_inode_locked) { // FIXME: this seems to be not needed: we are always able // to cut item - indirect_to_direct_roll_back(th, p_s_inode, p_s_path); + indirect_to_direct_roll_back(th, inode, path); } - if (n_ret_value == NO_DISK_SPACE) - reiserfs_warning(p_s_sb, "NO_DISK_SPACE"); + if (ret_value == NO_DISK_SPACE) + reiserfs_warning(sb, "reiserfs-5092", + "NO_DISK_SPACE"); unfix_nodes(&s_cut_balance); return -EIO; } /* go ahead and perform balancing */ - RFALSE(c_mode == M_PASTE || c_mode == M_INSERT, "invalid mode"); + RFALSE(mode == M_PASTE || mode == M_INSERT, "invalid mode"); /* Calculate number of bytes that need to be cut from the item. */ quota_cut_bytes = - (c_mode == - M_DELETE) ? ih_item_len(get_ih(p_s_path)) : -s_cut_balance. + (mode == + M_DELETE) ? ih_item_len(get_ih(path)) : -s_cut_balance. insert_size[0]; if (retval2 == -1) - n_ret_value = calc_deleted_bytes_number(&s_cut_balance, c_mode); + ret_value = calc_deleted_bytes_number(&s_cut_balance, mode); else - n_ret_value = retval2; + ret_value = retval2; /* For direct items, we only change the quota when deleting the last ** item. */ p_le_ih = PATH_PITEM_HEAD(s_cut_balance.tb_path); - if (!S_ISLNK(p_s_inode->i_mode) && is_direct_le_ih(p_le_ih)) { - if (c_mode == M_DELETE && - (le_ih_k_offset(p_le_ih) & (p_s_sb->s_blocksize - 1)) == + if (!S_ISLNK(inode->i_mode) && is_direct_le_ih(p_le_ih)) { + if (mode == M_DELETE && + (le_ih_k_offset(p_le_ih) & (sb->s_blocksize - 1)) == 1) { // FIXME: this is to keep 3.5 happy - REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX; - quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE; + REISERFS_I(inode)->i_first_direct_byte = U32_MAX; + quota_cut_bytes = sb->s_blocksize + UNFM_P_SIZE; } else { quota_cut_bytes = 0; } } #ifdef CONFIG_REISERFS_CHECK - if (n_is_inode_locked) { + if (is_inode_locked) { struct item_head *le_ih = PATH_PITEM_HEAD(s_cut_balance.tb_path); /* we are going to complete indirect2direct conversion. Make sure, that we exactly remove last unformatted node pointer of the item */ if (!is_indirect_le_ih(le_ih)) - reiserfs_panic(p_s_sb, - "vs-5652: reiserfs_cut_from_item: " + reiserfs_panic(sb, "vs-5652", "item must be indirect %h", le_ih); - if (c_mode == M_DELETE && ih_item_len(le_ih) != UNFM_P_SIZE) - reiserfs_panic(p_s_sb, - "vs-5653: reiserfs_cut_from_item: " - "completing indirect2direct conversion indirect item %h " - "being deleted must be of 4 byte long", - le_ih); + if (mode == M_DELETE && ih_item_len(le_ih) != UNFM_P_SIZE) + reiserfs_panic(sb, "vs-5653", "completing " + "indirect2direct conversion indirect " + "item %h being deleted must be of " + "4 byte long", le_ih); - if (c_mode == M_CUT + if (mode == M_CUT && s_cut_balance.insert_size[0] != -UNFM_P_SIZE) { - reiserfs_panic(p_s_sb, - "vs-5654: reiserfs_cut_from_item: " - "can not complete indirect2direct conversion of %h (CUT, insert_size==%d)", + reiserfs_panic(sb, "vs-5654", "can not complete " + "indirect2direct conversion of %h " + "(CUT, insert_size==%d)", le_ih, s_cut_balance.insert_size[0]); } /* it would be useful to make sure, that right neighboring @@ -1719,23 +1681,23 @@ int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th, } #endif - do_balance(&s_cut_balance, NULL, NULL, c_mode); - if (n_is_inode_locked) { + do_balance(&s_cut_balance, NULL, NULL, mode); + if (is_inode_locked) { /* we've done an indirect->direct conversion. when the data block ** was freed, it was removed from the list of blocks that must ** be flushed before the transaction commits, make sure to ** unmap and invalidate it */ unmap_buffers(page, tail_pos); - REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask; + REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; } #ifdef REISERQUOTA_DEBUG - reiserfs_debug(p_s_inode->i_sb, REISERFS_DEBUG_CODE, + reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota cut_from_item(): freeing %u id=%u type=%c", - quota_cut_bytes, p_s_inode->i_uid, '?'); + quota_cut_bytes, inode->i_uid, '?'); #endif - DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes); - return n_ret_value; + vfs_dq_free_space_nodirty(inode, quota_cut_bytes); + return ret_value; } static void truncate_directory(struct reiserfs_transaction_handle *th, @@ -1743,8 +1705,7 @@ static void truncate_directory(struct reiserfs_transaction_handle *th, { BUG_ON(!th->t_trans_id); if (inode->i_nlink) - reiserfs_warning(inode->i_sb, - "vs-5655: truncate_directory: link count != 0"); + reiserfs_error(inode->i_sb, "vs-5655", "link count != 0"); set_le_key_k_offset(KEY_FORMAT_3_5, INODE_PKEY(inode), DOT_OFFSET); set_le_key_k_type(KEY_FORMAT_3_5, INODE_PKEY(inode), TYPE_DIRENTRY); @@ -1756,8 +1717,8 @@ static void truncate_directory(struct reiserfs_transaction_handle *th, /* Truncate file to the new size. Note, this must be called with a transaction already started */ -int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, /* ->i_size contains new - size */ +int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, + struct inode *inode, /* ->i_size contains new size */ struct page *page, /* up to date for last block */ int update_timestamps /* when it is called by file_release to convert @@ -1768,47 +1729,45 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p INITIALIZE_PATH(s_search_path); /* Path to the current object item. */ struct item_head *p_le_ih; /* Pointer to an item header. */ struct cpu_key s_item_key; /* Key to search for a previous file item. */ - loff_t n_file_size, /* Old file size. */ - n_new_file_size; /* New file size. */ - int n_deleted; /* Number of deleted or truncated bytes. */ + loff_t file_size, /* Old file size. */ + new_file_size; /* New file size. */ + int deleted; /* Number of deleted or truncated bytes. */ int retval; int err = 0; BUG_ON(!th->t_trans_id); if (! - (S_ISREG(p_s_inode->i_mode) || S_ISDIR(p_s_inode->i_mode) - || S_ISLNK(p_s_inode->i_mode))) + (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) + || S_ISLNK(inode->i_mode))) return 0; - if (S_ISDIR(p_s_inode->i_mode)) { + if (S_ISDIR(inode->i_mode)) { // deletion of directory - no need to update timestamps - truncate_directory(th, p_s_inode); + truncate_directory(th, inode); return 0; } /* Get new file size. */ - n_new_file_size = p_s_inode->i_size; + new_file_size = inode->i_size; // FIXME: note, that key type is unimportant here - make_cpu_key(&s_item_key, p_s_inode, max_reiserfs_offset(p_s_inode), + make_cpu_key(&s_item_key, inode, max_reiserfs_offset(inode), TYPE_DIRECT, 3); retval = - search_for_position_by_key(p_s_inode->i_sb, &s_item_key, + search_for_position_by_key(inode->i_sb, &s_item_key, &s_search_path); if (retval == IO_ERROR) { - reiserfs_warning(p_s_inode->i_sb, - "vs-5657: reiserfs_do_truncate: " - "i/o failure occurred trying to truncate %K", - &s_item_key); + reiserfs_error(inode->i_sb, "vs-5657", + "i/o failure occurred trying to truncate %K", + &s_item_key); err = -EIO; goto out; } if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) { - reiserfs_warning(p_s_inode->i_sb, - "PAP-5660: reiserfs_do_truncate: " - "wrong result %d of search for %K", retval, - &s_item_key); + reiserfs_error(inode->i_sb, "PAP-5660", + "wrong result %d of search for %K", retval, + &s_item_key); err = -EIO; goto out; @@ -1819,56 +1778,56 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p /* Get real file size (total length of all file items) */ p_le_ih = PATH_PITEM_HEAD(&s_search_path); if (is_statdata_le_ih(p_le_ih)) - n_file_size = 0; + file_size = 0; else { loff_t offset = le_ih_k_offset(p_le_ih); int bytes = - op_bytes_number(p_le_ih, p_s_inode->i_sb->s_blocksize); + op_bytes_number(p_le_ih, inode->i_sb->s_blocksize); /* this may mismatch with real file size: if last direct item had no padding zeros and last unformatted node had no free space, this file would have this file size */ - n_file_size = offset + bytes - 1; + file_size = offset + bytes - 1; } /* * are we doing a full truncate or delete, if so * kick in the reada code */ - if (n_new_file_size == 0) + if (new_file_size == 0) s_search_path.reada = PATH_READA | PATH_READA_BACK; - if (n_file_size == 0 || n_file_size < n_new_file_size) { + if (file_size == 0 || file_size < new_file_size) { goto update_and_out; } /* Update key to search for the last file item. */ - set_cpu_key_k_offset(&s_item_key, n_file_size); + set_cpu_key_k_offset(&s_item_key, file_size); do { /* Cut or delete file item. */ - n_deleted = + deleted = reiserfs_cut_from_item(th, &s_search_path, &s_item_key, - p_s_inode, page, n_new_file_size); - if (n_deleted < 0) { - reiserfs_warning(p_s_inode->i_sb, - "vs-5665: reiserfs_do_truncate: reiserfs_cut_from_item failed"); + inode, page, new_file_size); + if (deleted < 0) { + reiserfs_warning(inode->i_sb, "vs-5665", + "reiserfs_cut_from_item failed"); reiserfs_check_path(&s_search_path); return 0; } - RFALSE(n_deleted > n_file_size, + RFALSE(deleted > file_size, "PAP-5670: reiserfs_cut_from_item: too many bytes deleted: deleted %d, file_size %lu, item_key %K", - n_deleted, n_file_size, &s_item_key); + deleted, file_size, &s_item_key); /* Change key to search the last file item. */ - n_file_size -= n_deleted; + file_size -= deleted; - set_cpu_key_k_offset(&s_item_key, n_file_size); + set_cpu_key_k_offset(&s_item_key, file_size); /* While there are bytes to truncate and previous file item is presented in the tree. */ /* - ** This loop could take a really long time, and could log + ** This loop could take a really long time, and could log ** many more blocks than a transaction can hold. So, we do a polite ** journal end here, and if the transaction needs ending, we make ** sure the file is consistent before ending the current trans @@ -1877,37 +1836,38 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p if (journal_transaction_should_end(th, 0) || reiserfs_transaction_free_space(th) <= JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD) { int orig_len_alloc = th->t_blocks_allocated; - decrement_counters_in_path(&s_search_path); + pathrelse(&s_search_path); if (update_timestamps) { - p_s_inode->i_mtime = p_s_inode->i_ctime = - CURRENT_TIME_SEC; + inode->i_mtime = CURRENT_TIME_SEC; + inode->i_ctime = CURRENT_TIME_SEC; } - reiserfs_update_sd(th, p_s_inode); + reiserfs_update_sd(th, inode); - err = journal_end(th, p_s_inode->i_sb, orig_len_alloc); + err = journal_end(th, inode->i_sb, orig_len_alloc); if (err) goto out; - err = journal_begin(th, p_s_inode->i_sb, + err = journal_begin(th, inode->i_sb, JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD + JOURNAL_PER_BALANCE_CNT * 4) ; if (err) goto out; - reiserfs_update_inode_transaction(p_s_inode); + reiserfs_update_inode_transaction(inode); } - } while (n_file_size > ROUND_UP(n_new_file_size) && - search_for_position_by_key(p_s_inode->i_sb, &s_item_key, + } while (file_size > ROUND_UP(new_file_size) && + search_for_position_by_key(inode->i_sb, &s_item_key, &s_search_path) == POSITION_FOUND); - RFALSE(n_file_size > ROUND_UP(n_new_file_size), + RFALSE(file_size > ROUND_UP(new_file_size), "PAP-5680: truncate did not finish: new_file_size %Ld, current %Ld, oid %d", - n_new_file_size, n_file_size, s_item_key.on_disk_key.k_objectid); + new_file_size, file_size, s_item_key.on_disk_key.k_objectid); update_and_out: if (update_timestamps) { // this is truncate, not file closing - p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME_SEC; + inode->i_mtime = CURRENT_TIME_SEC; + inode->i_ctime = CURRENT_TIME_SEC; } - reiserfs_update_sd(th, p_s_inode); + reiserfs_update_sd(th, inode); out: pathrelse(&s_search_path); @@ -1917,7 +1877,7 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p #ifdef CONFIG_REISERFS_CHECK // this makes sure, that we __append__, not overwrite or add holes static void check_research_for_paste(struct treepath *path, - const struct cpu_key *p_s_key) + const struct cpu_key *key) { struct item_head *found_ih = get_ih(path); @@ -1925,36 +1885,36 @@ static void check_research_for_paste(struct treepath *path, if (le_ih_k_offset(found_ih) + op_bytes_number(found_ih, get_last_bh(path)->b_size) != - cpu_key_k_offset(p_s_key) + cpu_key_k_offset(key) || op_bytes_number(found_ih, get_last_bh(path)->b_size) != pos_in_item(path)) - reiserfs_panic(NULL, - "PAP-5720: check_research_for_paste: " - "found direct item %h or position (%d) does not match to key %K", - found_ih, pos_in_item(path), p_s_key); + reiserfs_panic(NULL, "PAP-5720", "found direct item " + "%h or position (%d) does not match " + "to key %K", found_ih, + pos_in_item(path), key); } if (is_indirect_le_ih(found_ih)) { if (le_ih_k_offset(found_ih) + op_bytes_number(found_ih, get_last_bh(path)->b_size) != - cpu_key_k_offset(p_s_key) + cpu_key_k_offset(key) || I_UNFM_NUM(found_ih) != pos_in_item(path) || get_ih_free_space(found_ih) != 0) - reiserfs_panic(NULL, - "PAP-5730: check_research_for_paste: " - "found indirect item (%h) or position (%d) does not match to key (%K)", - found_ih, pos_in_item(path), p_s_key); + reiserfs_panic(NULL, "PAP-5730", "found indirect " + "item (%h) or position (%d) does not " + "match to key (%K)", + found_ih, pos_in_item(path), key); } } #endif /* config reiserfs check */ /* Paste bytes to the existing item. Returns bytes number pasted into the item. */ -int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_search_path, /* Path to the pasted item. */ - const struct cpu_key *p_s_key, /* Key to search for the needed item. */ +int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct treepath *search_path, /* Path to the pasted item. */ + const struct cpu_key *key, /* Key to search for the needed item. */ struct inode *inode, /* Inode item belongs to */ - const char *p_c_body, /* Pointer to the bytes to paste. */ - int n_pasted_size) + const char *body, /* Pointer to the bytes to paste. */ + int pasted_size) { /* Size of pasted bytes. */ struct tree_balance s_paste_balance; int retval; @@ -1967,18 +1927,18 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct tree #ifdef REISERQUOTA_DEBUG reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota paste_into_item(): allocating %u id=%u type=%c", - n_pasted_size, inode->i_uid, - key2type(&(p_s_key->on_disk_key))); + pasted_size, inode->i_uid, + key2type(&(key->on_disk_key))); #endif - if (DQUOT_ALLOC_SPACE_NODIRTY(inode, n_pasted_size)) { - pathrelse(p_s_search_path); + if (vfs_dq_alloc_space_nodirty(inode, pasted_size)) { + pathrelse(search_path); return -EDQUOT; } - init_tb_struct(th, &s_paste_balance, th->t_super, p_s_search_path, - n_pasted_size); + init_tb_struct(th, &s_paste_balance, th->t_super, search_path, + pasted_size); #ifdef DISPLACE_NEW_PACKING_LOCALITIES - s_paste_balance.key = p_s_key->on_disk_key; + s_paste_balance.key = key->on_disk_key; #endif /* DQUOT_* can schedule, must check before the fix_nodes */ @@ -1988,33 +1948,33 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct tree while ((retval = fix_nodes(M_PASTE, &s_paste_balance, NULL, - p_c_body)) == REPEAT_SEARCH) { + body)) == REPEAT_SEARCH) { search_again: /* file system changed while we were in the fix_nodes */ PROC_INFO_INC(th->t_super, paste_into_item_restarted); retval = - search_for_position_by_key(th->t_super, p_s_key, - p_s_search_path); + search_for_position_by_key(th->t_super, key, + search_path); if (retval == IO_ERROR) { retval = -EIO; goto error_out; } if (retval == POSITION_FOUND) { - reiserfs_warning(inode->i_sb, - "PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists", - p_s_key); + reiserfs_warning(inode->i_sb, "PAP-5710", + "entry or pasted byte (%K) exists", + key); retval = -EEXIST; goto error_out; } #ifdef CONFIG_REISERFS_CHECK - check_research_for_paste(p_s_search_path, p_s_key); + check_research_for_paste(search_path, key); #endif } /* Perform balancing after all resources are collected by fix_nodes, and accessing them will not risk triggering schedule. */ if (retval == CARRY_ON) { - do_balance(&s_paste_balance, NULL /*ih */ , p_c_body, M_PASTE); + do_balance(&s_paste_balance, NULL /*ih */ , body, M_PASTE); return 0; } retval = (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO; @@ -2024,18 +1984,24 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct tree #ifdef REISERQUOTA_DEBUG reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota paste_into_item(): freeing %u id=%u type=%c", - n_pasted_size, inode->i_uid, - key2type(&(p_s_key->on_disk_key))); + pasted_size, inode->i_uid, + key2type(&(key->on_disk_key))); #endif - DQUOT_FREE_SPACE_NODIRTY(inode, n_pasted_size); + vfs_dq_free_space_nodirty(inode, pasted_size); return retval; } -/* Insert new item into the buffer at the path. */ -int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_path, /* Path to the inserteded item. */ - const struct cpu_key *key, struct item_head *p_s_ih, /* Pointer to the item header to insert. */ - struct inode *inode, const char *p_c_body) -{ /* Pointer to the bytes to insert. */ +/* Insert new item into the buffer at the path. + * th - active transaction handle + * path - path to the inserted item + * ih - pointer to the item header to insert + * body - pointer to the bytes to insert + */ +int reiserfs_insert_item(struct reiserfs_transaction_handle *th, + struct treepath *path, const struct cpu_key *key, + struct item_head *ih, struct inode *inode, + const char *body) +{ struct tree_balance s_ins_balance; int retval; int fs_gen = 0; @@ -2045,28 +2011,27 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath if (inode) { /* Do we count quotas for item? */ fs_gen = get_generation(inode->i_sb); - quota_bytes = ih_item_len(p_s_ih); + quota_bytes = ih_item_len(ih); /* hack so the quota code doesn't have to guess if the file has ** a tail, links are always tails, so there's no guessing needed */ - if (!S_ISLNK(inode->i_mode) && is_direct_le_ih(p_s_ih)) { + if (!S_ISLNK(inode->i_mode) && is_direct_le_ih(ih)) quota_bytes = inode->i_sb->s_blocksize + UNFM_P_SIZE; - } #ifdef REISERQUOTA_DEBUG reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota insert_item(): allocating %u id=%u type=%c", - quota_bytes, inode->i_uid, head2type(p_s_ih)); + quota_bytes, inode->i_uid, head2type(ih)); #endif /* We can't dirty inode here. It would be immediately written but * appropriate stat item isn't inserted yet... */ - if (DQUOT_ALLOC_SPACE_NODIRTY(inode, quota_bytes)) { - pathrelse(p_s_path); + if (vfs_dq_alloc_space_nodirty(inode, quota_bytes)) { + pathrelse(path); return -EDQUOT; } } - init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path, - IH_SIZE + ih_item_len(p_s_ih)); + init_tb_struct(th, &s_ins_balance, th->t_super, path, + IH_SIZE + ih_item_len(ih)); #ifdef DISPLACE_NEW_PACKING_LOCALITIES s_ins_balance.key = key->on_disk_key; #endif @@ -2076,19 +2041,18 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath } while ((retval = - fix_nodes(M_INSERT, &s_ins_balance, p_s_ih, - p_c_body)) == REPEAT_SEARCH) { + fix_nodes(M_INSERT, &s_ins_balance, ih, + body)) == REPEAT_SEARCH) { search_again: /* file system changed while we were in the fix_nodes */ PROC_INFO_INC(th->t_super, insert_item_restarted); - retval = search_item(th->t_super, key, p_s_path); + retval = search_item(th->t_super, key, path); if (retval == IO_ERROR) { retval = -EIO; goto error_out; } if (retval == ITEM_FOUND) { - reiserfs_warning(th->t_super, - "PAP-5760: reiserfs_insert_item: " + reiserfs_warning(th->t_super, "PAP-5760", "key %K already exists in the tree", key); retval = -EEXIST; @@ -2098,7 +2062,7 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath /* make balancing after all resources will be collected at a time */ if (retval == CARRY_ON) { - do_balance(&s_ins_balance, p_s_ih, p_c_body, M_INSERT); + do_balance(&s_ins_balance, ih, body, M_INSERT); return 0; } @@ -2109,9 +2073,9 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath #ifdef REISERQUOTA_DEBUG reiserfs_debug(th->t_super, REISERFS_DEBUG_CODE, "reiserquota insert_item(): freeing %u id=%u type=%c", - quota_bytes, inode->i_uid, head2type(p_s_ih)); + quota_bytes, inode->i_uid, head2type(ih)); #endif if (inode) - DQUOT_FREE_SPACE_NODIRTY(inode, quota_bytes); + vfs_dq_free_space_nodirty(inode, quota_bytes); return retval; } diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index f3c820b7582..972250c6289 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -183,9 +183,9 @@ static int finish_unfinished(struct super_block *s) if (REISERFS_SB(s)->s_qf_names[i]) { int ret = reiserfs_quota_on_mount(s, i); if (ret < 0) - reiserfs_warning(s, - "reiserfs: cannot turn on journaled quota: error %d", - ret); + reiserfs_warning(s, "reiserfs-2500", + "cannot turn on journaled " + "quota: error %d", ret); } } #endif @@ -195,17 +195,16 @@ static int finish_unfinished(struct super_block *s) while (!retval) { retval = search_item(s, &max_cpu_key, &path); if (retval != ITEM_NOT_FOUND) { - reiserfs_warning(s, - "vs-2140: finish_unfinished: search_by_key returned %d", - retval); + reiserfs_error(s, "vs-2140", + "search_by_key returned %d", retval); break; } bh = get_last_bh(&path); item_pos = get_item_pos(&path); if (item_pos != B_NR_ITEMS(bh)) { - reiserfs_warning(s, - "vs-2060: finish_unfinished: wrong position found"); + reiserfs_warning(s, "vs-2060", + "wrong position found"); break; } item_pos--; @@ -235,8 +234,7 @@ static int finish_unfinished(struct super_block *s) if (!inode) { /* the unlink almost completed, it just did not manage to remove "save" link and release objectid */ - reiserfs_warning(s, - "vs-2180: finish_unfinished: iget failed for %K", + reiserfs_warning(s, "vs-2180", "iget failed for %K", &obj_key); retval = remove_save_link_only(s, &save_link_key, 1); continue; @@ -244,21 +242,22 @@ static int finish_unfinished(struct super_block *s) if (!truncate && inode->i_nlink) { /* file is not unlinked */ - reiserfs_warning(s, - "vs-2185: finish_unfinished: file %K is not unlinked", + reiserfs_warning(s, "vs-2185", + "file %K is not unlinked", &obj_key); retval = remove_save_link_only(s, &save_link_key, 0); continue; } - DQUOT_INIT(inode); + vfs_dq_init(inode); if (truncate && S_ISDIR(inode->i_mode)) { /* We got a truncate request for a dir which is impossible. The only imaginable way is to execute unfinished truncate request then boot into old kernel, remove the file and create dir with the same key. */ - reiserfs_warning(s, - "green-2101: impossible truncate on a directory %k. Please report", + reiserfs_warning(s, "green-2101", + "impossible truncate on a " + "directory %k. Please report", INODE_PKEY(inode)); retval = remove_save_link_only(s, &save_link_key, 0); truncate = 0; @@ -288,9 +287,10 @@ static int finish_unfinished(struct super_block *s) /* removal gets completed in iput */ retval = 0; } else { - reiserfs_warning(s, "Dead loop in " - "finish_unfinished detected, " - "just remove save link\n"); + reiserfs_warning(s, "super-2189", "Dead loop " + "in finish_unfinished " + "detected, just remove " + "save link\n"); retval = remove_save_link_only(s, &save_link_key, 0); } @@ -360,8 +360,9 @@ void add_save_link(struct reiserfs_transaction_handle *th, } else { /* truncate */ if (S_ISDIR(inode->i_mode)) - reiserfs_warning(inode->i_sb, - "green-2102: Adding a truncate savelink for a directory %k! Please report", + reiserfs_warning(inode->i_sb, "green-2102", + "Adding a truncate savelink for " + "a directory %k! Please report", INODE_PKEY(inode)); set_cpu_key_k_offset(&key, 1); set_cpu_key_k_type(&key, TYPE_INDIRECT); @@ -376,9 +377,9 @@ void add_save_link(struct reiserfs_transaction_handle *th, retval = search_item(inode->i_sb, &key, &path); if (retval != ITEM_NOT_FOUND) { if (retval != -ENOSPC) - reiserfs_warning(inode->i_sb, "vs-2100: add_save_link:" - "search_by_key (%K) returned %d", &key, - retval); + reiserfs_error(inode->i_sb, "vs-2100", + "search_by_key (%K) returned %d", &key, + retval); pathrelse(&path); return; } @@ -391,9 +392,8 @@ void add_save_link(struct reiserfs_transaction_handle *th, reiserfs_insert_item(th, &path, &key, &ih, NULL, (char *)&link); if (retval) { if (retval != -ENOSPC) - reiserfs_warning(inode->i_sb, - "vs-2120: add_save_link: insert_item returned %d", - retval); + reiserfs_error(inode->i_sb, "vs-2120", + "insert_item returned %d", retval); } else { if (truncate) REISERFS_I(inode)->i_flags |= @@ -492,8 +492,7 @@ static void reiserfs_put_super(struct super_block *s) print_statistics(s); if (REISERFS_SB(s)->reserved_blocks != 0) { - reiserfs_warning(s, - "green-2005: reiserfs_put_super: reserved blocks left %d", + reiserfs_warning(s, "green-2005", "reserved blocks left %d", REISERFS_SB(s)->reserved_blocks); } @@ -559,8 +558,8 @@ static void reiserfs_dirty_inode(struct inode *inode) int err = 0; if (inode->i_sb->s_flags & MS_RDONLY) { - reiserfs_warning(inode->i_sb, - "clm-6006: writing inode %lu on readonly FS", + reiserfs_warning(inode->i_sb, "clm-6006", + "writing inode %lu on readonly FS", inode->i_ino); return; } @@ -629,8 +628,6 @@ static const struct super_operations reiserfs_sops = { #ifdef CONFIG_QUOTA #define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group") -static int reiserfs_dquot_initialize(struct inode *, int); -static int reiserfs_dquot_drop(struct inode *); static int reiserfs_write_dquot(struct dquot *); static int reiserfs_acquire_dquot(struct dquot *); static int reiserfs_release_dquot(struct dquot *); @@ -639,8 +636,8 @@ static int reiserfs_write_info(struct super_block *, int); static int reiserfs_quota_on(struct super_block *, int, int, char *, int); static struct dquot_operations reiserfs_quota_operations = { - .initialize = reiserfs_dquot_initialize, - .drop = reiserfs_dquot_drop, + .initialize = dquot_initialize, + .drop = dquot_drop, .alloc_space = dquot_alloc_space, .alloc_inode = dquot_alloc_inode, .free_space = dquot_free_space, @@ -759,7 +756,7 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts, char **opt_arg, unsigned long *bit_flags) { char *p; - /* foo=bar, + /* foo=bar, ^ ^ ^ | | +-- option_end | +-- arg_start @@ -794,13 +791,15 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts, if (bit_flags) { if (opt->clrmask == (1 << REISERFS_UNSUPPORTED_OPT)) - reiserfs_warning(s, "%s not supported.", + reiserfs_warning(s, "super-6500", + "%s not supported.\n", p); else *bit_flags &= ~opt->clrmask; if (opt->setmask == (1 << REISERFS_UNSUPPORTED_OPT)) - reiserfs_warning(s, "%s not supported.", + reiserfs_warning(s, "super-6501", + "%s not supported.\n", p); else *bit_flags |= opt->setmask; @@ -809,7 +808,8 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts, } } if (!opt->option_name) { - reiserfs_warning(s, "unknown mount option \"%s\"", p); + reiserfs_warning(s, "super-6502", + "unknown mount option \"%s\"", p); return -1; } @@ -817,8 +817,9 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts, switch (*p) { case '=': if (!opt->arg_required) { - reiserfs_warning(s, - "the option \"%s\" does not require an argument", + reiserfs_warning(s, "super-6503", + "the option \"%s\" does not " + "require an argument\n", opt->option_name); return -1; } @@ -826,14 +827,15 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts, case 0: if (opt->arg_required) { - reiserfs_warning(s, - "the option \"%s\" requires an argument", - opt->option_name); + reiserfs_warning(s, "super-6504", + "the option \"%s\" requires an " + "argument\n", opt->option_name); return -1; } break; default: - reiserfs_warning(s, "head of option \"%s\" is only correct", + reiserfs_warning(s, "super-6505", + "head of option \"%s\" is only correct\n", opt->option_name); return -1; } @@ -845,7 +847,8 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts, && !(opt->arg_required & (1 << REISERFS_OPT_ALLOWEMPTY)) && !strlen(p)) { /* this catches "option=," if not allowed */ - reiserfs_warning(s, "empty argument for \"%s\"", + reiserfs_warning(s, "super-6506", + "empty argument for \"%s\"\n", opt->option_name); return -1; } @@ -867,7 +870,8 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts, } } - reiserfs_warning(s, "bad value \"%s\" for option \"%s\"", p, + reiserfs_warning(s, "super-6506", + "bad value \"%s\" for option \"%s\"\n", p, opt->option_name); return -1; } @@ -957,9 +961,9 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin *blocks = simple_strtoul(arg, &p, 0); if (*p != '\0') { /* NNN does not look like a number */ - reiserfs_warning(s, - "reiserfs_parse_options: bad value %s", - arg); + reiserfs_warning(s, "super-6507", + "bad value %s for " + "-oresize\n", arg); return 0; } } @@ -970,8 +974,8 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin unsigned long val = simple_strtoul(arg, &p, 0); /* commit=NNN (time in seconds) */ if (*p != '\0' || val >= (unsigned int)-1) { - reiserfs_warning(s, - "reiserfs_parse_options: bad value %s", + reiserfs_warning(s, "super-6508", + "bad value %s for -ocommit\n", arg); return 0; } @@ -979,16 +983,18 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin } if (c == 'w') { - reiserfs_warning(s, "reiserfs: nolargeio option is no longer supported"); + reiserfs_warning(s, "super-6509", "nolargeio option " + "is no longer supported"); return 0; } if (c == 'j') { if (arg && *arg && jdev_name) { if (*jdev_name) { //Hm, already assigned? - reiserfs_warning(s, - "reiserfs_parse_options: journal device was already specified to be %s", - *jdev_name); + reiserfs_warning(s, "super-6510", + "journal device was " + "already specified to " + "be %s", *jdev_name); return 0; } *jdev_name = arg; @@ -1000,29 +1006,35 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin if (sb_any_quota_loaded(s) && (!*arg != !REISERFS_SB(s)->s_qf_names[qtype])) { - reiserfs_warning(s, - "reiserfs_parse_options: cannot change journaled quota options when quota turned on."); + reiserfs_warning(s, "super-6511", + "cannot change journaled " + "quota options when quota " + "turned on."); return 0; } if (*arg) { /* Some filename specified? */ if (REISERFS_SB(s)->s_qf_names[qtype] && strcmp(REISERFS_SB(s)->s_qf_names[qtype], arg)) { - reiserfs_warning(s, - "reiserfs_parse_options: %s quota file already specified.", + reiserfs_warning(s, "super-6512", + "%s quota file " + "already specified.", QTYPE2NAME(qtype)); return 0; } if (strchr(arg, '/')) { - reiserfs_warning(s, - "reiserfs_parse_options: quotafile must be on filesystem root."); + reiserfs_warning(s, "super-6513", + "quotafile must be " + "on filesystem root."); return 0; } qf_names[qtype] = kmalloc(strlen(arg) + 1, GFP_KERNEL); if (!qf_names[qtype]) { - reiserfs_warning(s, - "reiserfs_parse_options: not enough memory for storing quotafile name."); + reiserfs_warning(s, "reiserfs-2502", + "not enough memory " + "for storing " + "quotafile name."); return 0; } strcpy(qf_names[qtype], arg); @@ -1040,21 +1052,24 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin else if (!strcmp(arg, "vfsv0")) *qfmt = QFMT_VFS_V0; else { - reiserfs_warning(s, - "reiserfs_parse_options: unknown quota format specified."); + reiserfs_warning(s, "super-6514", + "unknown quota format " + "specified."); return 0; } if (sb_any_quota_loaded(s) && *qfmt != REISERFS_SB(s)->s_jquota_fmt) { - reiserfs_warning(s, - "reiserfs_parse_options: cannot change journaled quota options when quota turned on."); + reiserfs_warning(s, "super-6515", + "cannot change journaled " + "quota options when quota " + "turned on."); return 0; } } #else if (c == 'u' || c == 'g' || c == 'f') { - reiserfs_warning(s, - "reiserfs_parse_options: journaled quota options not supported."); + reiserfs_warning(s, "reiserfs-2503", "journaled " + "quota options not supported."); return 0; } #endif @@ -1063,15 +1078,15 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin #ifdef CONFIG_QUOTA if (!REISERFS_SB(s)->s_jquota_fmt && !*qfmt && (qf_names[USRQUOTA] || qf_names[GRPQUOTA])) { - reiserfs_warning(s, - "reiserfs_parse_options: journaled quota format not specified."); + reiserfs_warning(s, "super-6515", + "journaled quota format not specified."); return 0; } /* This checking is not precise wrt the quota type but for our purposes it is sufficient */ if (!(*mount_options & (1 << REISERFS_QUOTA)) && sb_any_quota_loaded(s)) { - reiserfs_warning(s, - "reiserfs_parse_options: quota options must be present when quota is turned on."); + reiserfs_warning(s, "super-6516", "quota options must " + "be present when quota is turned on."); return 0; } #endif @@ -1131,14 +1146,15 @@ static void handle_attrs(struct super_block *s) if (reiserfs_attrs(s)) { if (old_format_only(s)) { - reiserfs_warning(s, - "reiserfs: cannot support attributes on 3.5.x disk format"); + reiserfs_warning(s, "super-6517", "cannot support " + "attributes on 3.5.x disk format"); REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_ATTRS); return; } if (!(le32_to_cpu(rs->s_flags) & reiserfs_attrs_cleared)) { - reiserfs_warning(s, - "reiserfs: cannot support attributes until flag is set in super-block"); + reiserfs_warning(s, "super-6518", "cannot support " + "attributes until flag is set in " + "super-block"); REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_ATTRS); } } @@ -1280,6 +1296,8 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) REISERFS_SB(s)->s_mount_state = sb_umount_state(rs); s->s_flags &= ~MS_RDONLY; set_sb_umount_state(rs, REISERFS_ERROR_FS); + if (!old_format_only(s)) + set_sb_mnt_count(rs, sb_mnt_count(rs) + 1); /* mark_buffer_dirty (SB_BUFFER_WITH_SB (s), 1); */ journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); REISERFS_SB(s)->s_mount_state = REISERFS_VALID_FS; @@ -1314,7 +1332,7 @@ static int read_super_block(struct super_block *s, int offset) bh = sb_bread(s, offset / s->s_blocksize); if (!bh) { - reiserfs_warning(s, "sh-2006: read_super_block: " + reiserfs_warning(s, "sh-2006", "bread failed (dev %s, block %lu, size %lu)", reiserfs_bdevname(s), offset / s->s_blocksize, s->s_blocksize); @@ -1328,15 +1346,15 @@ static int read_super_block(struct super_block *s, int offset) } // // ok, reiserfs signature (old or new) found in at the given offset - // + // fs_blocksize = sb_blocksize(rs); brelse(bh); sb_set_blocksize(s, fs_blocksize); bh = sb_bread(s, offset / s->s_blocksize); if (!bh) { - reiserfs_warning(s, "sh-2007: read_super_block: " - "bread failed (dev %s, block %lu, size %lu)\n", + reiserfs_warning(s, "sh-2007", + "bread failed (dev %s, block %lu, size %lu)", reiserfs_bdevname(s), offset / s->s_blocksize, s->s_blocksize); return 1; @@ -1344,8 +1362,8 @@ static int read_super_block(struct super_block *s, int offset) rs = (struct reiserfs_super_block *)bh->b_data; if (sb_blocksize(rs) != s->s_blocksize) { - reiserfs_warning(s, "sh-2011: read_super_block: " - "can't find a reiserfs filesystem on (dev %s, block %Lu, size %lu)\n", + reiserfs_warning(s, "sh-2011", "can't find a reiserfs " + "filesystem on (dev %s, block %Lu, size %lu)", reiserfs_bdevname(s), (unsigned long long)bh->b_blocknr, s->s_blocksize); @@ -1355,9 +1373,10 @@ static int read_super_block(struct super_block *s, int offset) if (rs->s_v1.s_root_block == cpu_to_le32(-1)) { brelse(bh); - reiserfs_warning(s, - "Unfinished reiserfsck --rebuild-tree run detected. Please run\n" - "reiserfsck --rebuild-tree and wait for a completion. If that fails\n" + reiserfs_warning(s, "super-6519", "Unfinished reiserfsck " + "--rebuild-tree run detected. Please run\n" + "reiserfsck --rebuild-tree and wait for a " + "completion. If that fails\n" "get newer reiserfsprogs package"); return 1; } @@ -1369,18 +1388,15 @@ static int read_super_block(struct super_block *s, int offset) /* magic is of non-standard journal filesystem, look at s_version to find which format is in use */ if (sb_version(rs) == REISERFS_VERSION_2) - reiserfs_warning(s, - "read_super_block: found reiserfs format \"3.6\"" - " with non-standard journal"); + reiserfs_info(s, "found reiserfs format \"3.6\"" + " with non-standard journal\n"); else if (sb_version(rs) == REISERFS_VERSION_1) - reiserfs_warning(s, - "read_super_block: found reiserfs format \"3.5\"" - " with non-standard journal"); + reiserfs_info(s, "found reiserfs format \"3.5\"" + " with non-standard journal\n"); else { - reiserfs_warning(s, - "sh-2012: read_super_block: found unknown " - "format \"%u\" of reiserfs with non-standard magic", - sb_version(rs)); + reiserfs_warning(s, "sh-2012", "found unknown " + "format \"%u\" of reiserfs with " + "non-standard magic", sb_version(rs)); return 1; } } else @@ -1410,8 +1426,7 @@ static int reread_meta_blocks(struct super_block *s) ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s))); wait_on_buffer(SB_BUFFER_WITH_SB(s)); if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) { - reiserfs_warning(s, - "reread_meta_blocks, error reading the super"); + reiserfs_warning(s, "reiserfs-2504", "error reading the super"); return 1; } @@ -1454,8 +1469,8 @@ static __u32 find_hash_out(struct super_block *s) if (reiserfs_rupasov_hash(s)) { hash = YURA_HASH; } - reiserfs_warning(s, "FS seems to be empty, autodetect " - "is using the default hash"); + reiserfs_info(s, "FS seems to be empty, autodetect " + "is using the default hash\n"); break; } r5hash = GET_HASH_VALUE(r5_hash(de.de_name, de.de_namelen)); @@ -1475,10 +1490,10 @@ static __u32 find_hash_out(struct super_block *s) && (yurahash == GET_HASH_VALUE(deh_offset (&(de.de_deh[de.de_entry_num])))))) { - reiserfs_warning(s, - "Unable to automatically detect hash function. " - "Please mount with -o hash={tea,rupasov,r5}", - reiserfs_bdevname(s)); + reiserfs_warning(s, "reiserfs-2506", "Unable to " + "automatically detect hash function. " + "Please mount with -o " + "hash={tea,rupasov,r5}"); hash = UNSET_HASH; break; } @@ -1492,7 +1507,8 @@ static __u32 find_hash_out(struct super_block *s) (deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash) hash = R5_HASH; else { - reiserfs_warning(s, "Unrecognised hash function"); + reiserfs_warning(s, "reiserfs-2506", + "Unrecognised hash function"); hash = UNSET_HASH; } } while (0); @@ -1516,21 +1532,24 @@ static int what_hash(struct super_block *s) code = find_hash_out(s); if (code != UNSET_HASH && reiserfs_hash_detect(s)) { - /* detection has found the hash, and we must check against the - ** mount options + /* detection has found the hash, and we must check against the + ** mount options */ if (reiserfs_rupasov_hash(s) && code != YURA_HASH) { - reiserfs_warning(s, "Error, %s hash detected, " + reiserfs_warning(s, "reiserfs-2507", + "Error, %s hash detected, " "unable to force rupasov hash", reiserfs_hashname(code)); code = UNSET_HASH; } else if (reiserfs_tea_hash(s) && code != TEA_HASH) { - reiserfs_warning(s, "Error, %s hash detected, " + reiserfs_warning(s, "reiserfs-2508", + "Error, %s hash detected, " "unable to force tea hash", reiserfs_hashname(code)); code = UNSET_HASH; } else if (reiserfs_r5_hash(s) && code != R5_HASH) { - reiserfs_warning(s, "Error, %s hash detected, " + reiserfs_warning(s, "reiserfs-2509", + "Error, %s hash detected, " "unable to force r5 hash", reiserfs_hashname(code)); code = UNSET_HASH; @@ -1546,7 +1565,7 @@ static int what_hash(struct super_block *s) } } - /* if we are mounted RW, and we have a new valid hash code, update + /* if we are mounted RW, and we have a new valid hash code, update ** the super */ if (code != UNSET_HASH && @@ -1589,9 +1608,9 @@ static int function2code(hashf_t func) return 0; } -#define SWARN(silent, s, ...) \ +#define SWARN(silent, s, id, ...) \ if (!(silent)) \ - reiserfs_warning (s, __VA_ARGS__) + reiserfs_warning(s, id, __VA_ARGS__) static int reiserfs_fill_super(struct super_block *s, void *data, int silent) { @@ -1625,10 +1644,6 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) REISERFS_SB(s)->s_alloc_options.preallocmin = 0; /* Preallocate by 16 blocks (17-1) at once */ REISERFS_SB(s)->s_alloc_options.preallocsize = 17; -#ifdef CONFIG_REISERFS_FS_XATTR - /* Initialize the rwsem for xattr dir */ - init_rwsem(&REISERFS_SB(s)->xattr_dir_sem); -#endif /* setup default block allocator options */ reiserfs_init_alloc_options(s); @@ -1643,8 +1658,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) #endif if (blocks) { - SWARN(silent, s, "jmacd-7: reiserfs_fill_super: resize option " - "for remount only"); + SWARN(silent, s, "jmacd-7", "resize option for remount only"); goto error; } @@ -1653,8 +1667,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) old_format = 1; /* try new format (64-th 1k block), which can contain reiserfs super block */ else if (read_super_block(s, REISERFS_DISK_OFFSET_IN_BYTES)) { - SWARN(silent, s, - "sh-2021: reiserfs_fill_super: can not find reiserfs on %s", + SWARN(silent, s, "sh-2021", "can not find reiserfs on %s", reiserfs_bdevname(s)); goto error; } @@ -1666,13 +1679,12 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) if (s->s_bdev && s->s_bdev->bd_inode && i_size_read(s->s_bdev->bd_inode) < sb_block_count(rs) * sb_blocksize(rs)) { - SWARN(silent, s, - "Filesystem on %s cannot be mounted because it is bigger than the device", - reiserfs_bdevname(s)); - SWARN(silent, s, - "You may need to run fsck or increase size of your LVM partition"); - SWARN(silent, s, - "Or may be you forgot to reboot after fdisk when it told you to"); + SWARN(silent, s, "", "Filesystem cannot be " + "mounted because it is bigger than the device"); + SWARN(silent, s, "", "You may need to run fsck " + "or increase size of your LVM partition"); + SWARN(silent, s, "", "Or may be you forgot to " + "reboot after fdisk when it told you to"); goto error; } @@ -1680,14 +1692,13 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) sbi->s_mount_state = REISERFS_VALID_FS; if ((errval = reiserfs_init_bitmap_cache(s))) { - SWARN(silent, s, - "jmacd-8: reiserfs_fill_super: unable to read bitmap"); + SWARN(silent, s, "jmacd-8", "unable to read bitmap"); goto error; } errval = -EINVAL; #ifdef CONFIG_REISERFS_CHECK - SWARN(silent, s, "CONFIG_REISERFS_CHECK is set ON"); - SWARN(silent, s, "- it is slow mode for debugging."); + SWARN(silent, s, "", "CONFIG_REISERFS_CHECK is set ON"); + SWARN(silent, s, "", "- it is slow mode for debugging."); #endif /* make data=ordered the default */ @@ -1708,8 +1719,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) } // set_device_ro(s->s_dev, 1) ; if (journal_init(s, jdev_name, old_format, commit_max_age)) { - SWARN(silent, s, - "sh-2022: reiserfs_fill_super: unable to initialize journal space"); + SWARN(silent, s, "sh-2022", + "unable to initialize journal space"); goto error; } else { jinit_done = 1; /* once this is set, journal_release must be called @@ -1717,8 +1728,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) */ } if (reread_meta_blocks(s)) { - SWARN(silent, s, - "jmacd-9: reiserfs_fill_super: unable to reread meta blocks after journal init"); + SWARN(silent, s, "jmacd-9", + "unable to reread meta blocks after journal init"); goto error; } @@ -1726,8 +1737,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) goto error; if (bdev_read_only(s->s_bdev) && !(s->s_flags & MS_RDONLY)) { - SWARN(silent, s, - "clm-7000: Detected readonly device, marking FS readonly"); + SWARN(silent, s, "clm-7000", + "Detected readonly device, marking FS readonly"); s->s_flags |= MS_RDONLY; } args.objectid = REISERFS_ROOT_OBJECTID; @@ -1736,8 +1747,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) iget5_locked(s, REISERFS_ROOT_OBJECTID, reiserfs_find_actor, reiserfs_init_locked_inode, (void *)(&args)); if (!root_inode) { - SWARN(silent, s, - "jmacd-10: reiserfs_fill_super: get root inode failed"); + SWARN(silent, s, "jmacd-10", "get root inode failed"); goto error; } @@ -1786,7 +1796,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) * avoiding corruption. -jeffm */ if (bmap_would_wrap(reiserfs_bmap_count(s)) && sb_bmap_nr(rs) != 0) { - reiserfs_warning(s, "super-2030: This file system " + reiserfs_warning(s, "super-2030", "This file system " "claims to use %u bitmap blocks in " "its super block, but requires %u. " "Clearing to zero.", sb_bmap_nr(rs), @@ -1819,7 +1829,9 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) } else if (!silent) { reiserfs_info(s, "using 3.5.x disk format\n"); } - } + } else + set_sb_mnt_count(rs, sb_mnt_count(rs) + 1); + journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); errval = journal_end(&th, s, 1); @@ -1896,58 +1908,6 @@ static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf) } #ifdef CONFIG_QUOTA -static int reiserfs_dquot_initialize(struct inode *inode, int type) -{ - struct reiserfs_transaction_handle th; - int ret, err; - - /* We may create quota structure so we need to reserve enough blocks */ - reiserfs_write_lock(inode->i_sb); - ret = - journal_begin(&th, inode->i_sb, - 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb)); - if (ret) - goto out; - ret = dquot_initialize(inode, type); - err = - journal_end(&th, inode->i_sb, - 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb)); - if (!ret && err) - ret = err; - out: - reiserfs_write_unlock(inode->i_sb); - return ret; -} - -static int reiserfs_dquot_drop(struct inode *inode) -{ - struct reiserfs_transaction_handle th; - int ret, err; - - /* We may delete quota structure so we need to reserve enough blocks */ - reiserfs_write_lock(inode->i_sb); - ret = - journal_begin(&th, inode->i_sb, - 2 * REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)); - if (ret) { - /* - * We call dquot_drop() anyway to at least release references - * to quota structures so that umount does not hang. - */ - dquot_drop(inode); - goto out; - } - ret = dquot_drop(inode); - err = - journal_end(&th, inode->i_sb, - 2 * REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)); - if (!ret && err) - ret = err; - out: - reiserfs_write_unlock(inode->i_sb); - return ret; -} - static int reiserfs_write_dquot(struct dquot *dquot) { struct reiserfs_transaction_handle th; @@ -2085,8 +2045,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) { err = reiserfs_unpack(inode, NULL); if (err) { - reiserfs_warning(sb, - "reiserfs: Unpacking tail of quota file failed" + reiserfs_warning(sb, "super-6520", + "Unpacking tail of quota file failed" " (%d). Cannot turn on quotas.", err); err = -EINVAL; goto out; @@ -2097,8 +2057,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, if (REISERFS_SB(sb)->s_qf_names[type]) { /* Quotafile not of fs root? */ if (path.dentry->d_parent != sb->s_root) - reiserfs_warning(sb, - "reiserfs: Quota file not on filesystem root. " + reiserfs_warning(sb, "super-6521", + "Quota file not on filesystem root. " "Journalled quota will not work."); } @@ -2249,9 +2209,6 @@ static int __init init_reiserfs_fs(void) return ret; } - if ((ret = reiserfs_xattr_register_handlers())) - goto failed_reiserfs_xattr_register_handlers; - reiserfs_proc_info_global_init(); reiserfs_proc_register_global("version", reiserfs_global_version_in_proc); @@ -2262,9 +2219,6 @@ static int __init init_reiserfs_fs(void) return 0; } - reiserfs_xattr_unregister_handlers(); - - failed_reiserfs_xattr_register_handlers: reiserfs_proc_unregister_global("version"); reiserfs_proc_info_global_done(); destroy_inodecache(); @@ -2274,7 +2228,6 @@ static int __init init_reiserfs_fs(void) static void __exit exit_reiserfs_fs(void) { - reiserfs_xattr_unregister_handlers(); reiserfs_proc_unregister_global("version"); reiserfs_proc_info_global_done(); unregister_filesystem(&reiserfs_fs_type); diff --git a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c index f8121a1147e..d7f6e51bef2 100644 --- a/fs/reiserfs/tail_conversion.c +++ b/fs/reiserfs/tail_conversion.c @@ -26,7 +26,7 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode, converted item. */ struct item_head ind_ih; /* new indirect item to be inserted or key of unfm pointer to be pasted */ - int n_blk_size, n_retval; /* returned value for reiserfs_insert_item and clones */ + int blk_size, retval; /* returned value for reiserfs_insert_item and clones */ unp_t unfm_ptr; /* Handle on an unformatted node that will be inserted in the tree. */ @@ -35,7 +35,7 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode, REISERFS_SB(sb)->s_direct2indirect++; - n_blk_size = sb->s_blocksize; + blk_size = sb->s_blocksize; /* and key to search for append or insert pointer to the new unformatted node. */ @@ -46,11 +46,11 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode, /* Set the key to search for the place for new unfm pointer */ make_cpu_key(&end_key, inode, tail_offset, TYPE_INDIRECT, 4); - // FIXME: we could avoid this + /* FIXME: we could avoid this */ if (search_for_position_by_key(sb, &end_key, path) == POSITION_FOUND) { - reiserfs_warning(sb, "PAP-14030: direct2indirect: " - "pasted or inserted byte exists in the tree %K. " - "Use fsck to repair.", &end_key); + reiserfs_error(sb, "PAP-14030", + "pasted or inserted byte exists in " + "the tree %K. Use fsck to repair.", &end_key); pathrelse(path); return -EIO; } @@ -64,17 +64,17 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode, set_ih_free_space(&ind_ih, 0); /* delete at nearest future */ put_ih_item_len(&ind_ih, UNFM_P_SIZE); PATH_LAST_POSITION(path)++; - n_retval = + retval = reiserfs_insert_item(th, path, &end_key, &ind_ih, inode, (char *)&unfm_ptr); } else { /* Paste into last indirect item of an object. */ - n_retval = reiserfs_paste_into_item(th, path, &end_key, inode, + retval = reiserfs_paste_into_item(th, path, &end_key, inode, (char *)&unfm_ptr, UNFM_P_SIZE); } - if (n_retval) { - return n_retval; + if (retval) { + return retval; } // note: from here there are two keys which have matching first // three key components. They only differ by the fourth one. @@ -92,14 +92,13 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode, last item of the file */ if (search_for_position_by_key(sb, &end_key, path) == POSITION_FOUND) - reiserfs_panic(sb, - "PAP-14050: direct2indirect: " + reiserfs_panic(sb, "PAP-14050", "direct item (%K) not found", &end_key); p_le_ih = PATH_PITEM_HEAD(path); RFALSE(!is_direct_le_ih(p_le_ih), "vs-14055: direct item expected(%K), found %h", &end_key, p_le_ih); - tail_size = (le_ih_k_offset(p_le_ih) & (n_blk_size - 1)) + tail_size = (le_ih_k_offset(p_le_ih) & (blk_size - 1)) + ih_item_len(p_le_ih) - 1; /* we only send the unbh pointer if the buffer is not up to date. @@ -114,11 +113,11 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode, } else { up_to_date_bh = unbh; } - n_retval = reiserfs_delete_item(th, path, &end_key, inode, + retval = reiserfs_delete_item(th, path, &end_key, inode, up_to_date_bh); - total_tail += n_retval; - if (tail_size == n_retval) + total_tail += retval; + if (tail_size == retval) // done: file does not have direct items anymore break; @@ -130,7 +129,7 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode, unsigned pgoff = (tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1); char *kaddr = kmap_atomic(up_to_date_bh->b_page, KM_USER0); - memset(kaddr + pgoff, 0, n_blk_size - total_tail); + memset(kaddr + pgoff, 0, blk_size - total_tail); kunmap_atomic(kaddr, KM_USER0); } @@ -171,14 +170,18 @@ void reiserfs_unmap_buffer(struct buffer_head *bh) what we expect from it (number of cut bytes). But when tail remains in the unformatted node, we set mode to SKIP_BALANCING and unlock inode */ -int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, struct page *page, struct treepath *p_s_path, /* path to the indirect item. */ - const struct cpu_key *p_s_item_key, /* Key to look for unformatted node pointer to be cut. */ +int indirect2direct(struct reiserfs_transaction_handle *th, + struct inode *inode, struct page *page, + struct treepath *path, /* path to the indirect item. */ + const struct cpu_key *item_key, /* Key to look for + * unformatted node + * pointer to be cut. */ loff_t n_new_file_size, /* New file size. */ - char *p_c_mode) + char *mode) { - struct super_block *p_s_sb = p_s_inode->i_sb; + struct super_block *sb = inode->i_sb; struct item_head s_ih; - unsigned long n_block_size = p_s_sb->s_blocksize; + unsigned long block_size = sb->s_blocksize; char *tail; int tail_len, round_tail_len; loff_t pos, pos1; /* position of first byte of the tail */ @@ -186,22 +189,22 @@ int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_in BUG_ON(!th->t_trans_id); - REISERFS_SB(p_s_sb)->s_indirect2direct++; + REISERFS_SB(sb)->s_indirect2direct++; - *p_c_mode = M_SKIP_BALANCING; + *mode = M_SKIP_BALANCING; /* store item head path points to. */ - copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path)); + copy_item_head(&s_ih, PATH_PITEM_HEAD(path)); - tail_len = (n_new_file_size & (n_block_size - 1)); - if (get_inode_sd_version(p_s_inode) == STAT_DATA_V2) + tail_len = (n_new_file_size & (block_size - 1)); + if (get_inode_sd_version(inode) == STAT_DATA_V2) round_tail_len = ROUND_UP(tail_len); else round_tail_len = tail_len; pos = le_ih_k_offset(&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE - - 1) * p_s_sb->s_blocksize; + 1) * sb->s_blocksize; pos1 = pos; // we are protected by i_mutex. The tail can not disapper, not @@ -210,27 +213,26 @@ int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_in tail = (char *)kmap(page); /* this can schedule */ - if (path_changed(&s_ih, p_s_path)) { + if (path_changed(&s_ih, path)) { /* re-search indirect item */ - if (search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) + if (search_for_position_by_key(sb, item_key, path) == POSITION_NOT_FOUND) - reiserfs_panic(p_s_sb, - "PAP-5520: indirect2direct: " + reiserfs_panic(sb, "PAP-5520", "item to be converted %K does not exist", - p_s_item_key); - copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path)); + item_key); + copy_item_head(&s_ih, PATH_PITEM_HEAD(path)); #ifdef CONFIG_REISERFS_CHECK pos = le_ih_k_offset(&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE - - 1) * p_s_sb->s_blocksize; + 1) * sb->s_blocksize; if (pos != pos1) - reiserfs_panic(p_s_sb, "vs-5530: indirect2direct: " - "tail position changed while we were reading it"); + reiserfs_panic(sb, "vs-5530", "tail position " + "changed while we were reading it"); #endif } /* Set direct item header to insert. */ - make_le_item_head(&s_ih, NULL, get_inode_item_key_version(p_s_inode), + make_le_item_head(&s_ih, NULL, get_inode_item_key_version(inode), pos1 + 1, TYPE_DIRECT, round_tail_len, 0xffff /*ih_free_space */ ); @@ -240,13 +242,13 @@ int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_in */ tail = tail + (pos & (PAGE_CACHE_SIZE - 1)); - PATH_LAST_POSITION(p_s_path)++; + PATH_LAST_POSITION(path)++; - key = *p_s_item_key; + key = *item_key; set_cpu_key_k_type(&key, TYPE_DIRECT); key.key_length = 4; /* Insert tail as new direct item in the tree */ - if (reiserfs_insert_item(th, p_s_path, &key, &s_ih, p_s_inode, + if (reiserfs_insert_item(th, path, &key, &s_ih, inode, tail ? tail : NULL) < 0) { /* No disk memory. So we can not convert last unformatted node to the direct item. In this case we used to adjust @@ -255,12 +257,12 @@ int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_in unformatted node. For now i_size is considered as guard for going out of file size */ kunmap(page); - return n_block_size - round_tail_len; + return block_size - round_tail_len; } kunmap(page); /* make sure to get the i_blocks changes from reiserfs_insert_item */ - reiserfs_update_sd(th, p_s_inode); + reiserfs_update_sd(th, inode); // note: we have now the same as in above direct2indirect // conversion: there are two keys which have matching first three @@ -268,11 +270,11 @@ int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_in /* We have inserted new direct item and must remove last unformatted node. */ - *p_c_mode = M_CUT; + *mode = M_CUT; /* we store position of first direct item in the in-core inode */ - //mark_file_with_tail (p_s_inode, pos1 + 1); - REISERFS_I(p_s_inode)->i_first_direct_byte = pos1 + 1; + /* mark_file_with_tail (inode, pos1 + 1); */ + REISERFS_I(inode)->i_first_direct_byte = pos1 + 1; - return n_block_size - round_tail_len; + return block_size - round_tail_len; } diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index ad92461cbfc..f83f52bae39 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -27,6 +27,10 @@ * these are special cases for filesystem ACLs, they are interpreted by the * kernel, in addition, they are negatively and positively cached and attached * to the inode so that unnecessary lookups are avoided. + * + * Locking works like so: + * Directory components (xattr root, xattr dir) are protectd by their i_mutex. + * The xattrs themselves are protected by the xattr_sem. */ #include <linux/reiserfs_fs.h> @@ -44,328 +48,334 @@ #include <net/checksum.h> #include <linux/smp_lock.h> #include <linux/stat.h> +#include <linux/quotaops.h> -#define FL_READONLY 128 -#define FL_DIR_SEM_HELD 256 #define PRIVROOT_NAME ".reiserfs_priv" #define XAROOT_NAME "xattrs" -static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char - *prefix); -/* Returns the dentry referring to the root of the extended attribute - * directory tree. If it has already been retrieved, it is used. If it - * hasn't been created and the flags indicate creation is allowed, we - * attempt to create it. On error, we return a pointer-encoded error. - */ -static struct dentry *get_xa_root(struct super_block *sb, int flags) +/* Helpers for inode ops. We do this so that we don't have all the VFS + * overhead and also for proper i_mutex annotation. + * dir->i_mutex must be held for all of them. */ +#ifdef CONFIG_REISERFS_FS_XATTR +static int xattr_create(struct inode *dir, struct dentry *dentry, int mode) { - struct dentry *privroot = dget(REISERFS_SB(sb)->priv_root); - struct dentry *xaroot; + BUG_ON(!mutex_is_locked(&dir->i_mutex)); + vfs_dq_init(dir); + return dir->i_op->create(dir, dentry, mode, NULL); +} +#endif - /* This needs to be created at mount-time */ - if (!privroot) - return ERR_PTR(-ENODATA); +static int xattr_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + BUG_ON(!mutex_is_locked(&dir->i_mutex)); + vfs_dq_init(dir); + return dir->i_op->mkdir(dir, dentry, mode); +} - mutex_lock_nested(&privroot->d_inode->i_mutex, I_MUTEX_XATTR); - if (REISERFS_SB(sb)->xattr_root) { - xaroot = dget(REISERFS_SB(sb)->xattr_root); - goto out; - } +/* We use I_MUTEX_CHILD here to silence lockdep. It's safe because xattr + * mutation ops aren't called during rename or splace, which are the + * only other users of I_MUTEX_CHILD. It violates the ordering, but that's + * better than allocating another subclass just for this code. */ +static int xattr_unlink(struct inode *dir, struct dentry *dentry) +{ + int error; + BUG_ON(!mutex_is_locked(&dir->i_mutex)); + vfs_dq_init(dir); - xaroot = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME)); - if (IS_ERR(xaroot)) { - goto out; - } else if (!xaroot->d_inode) { + mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); + error = dir->i_op->unlink(dir, dentry); + mutex_unlock(&dentry->d_inode->i_mutex); + + if (!error) + d_delete(dentry); + return error; +} + +static int xattr_rmdir(struct inode *dir, struct dentry *dentry) +{ + int error; + BUG_ON(!mutex_is_locked(&dir->i_mutex)); + vfs_dq_init(dir); + + mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); + dentry_unhash(dentry); + error = dir->i_op->rmdir(dir, dentry); + if (!error) + dentry->d_inode->i_flags |= S_DEAD; + mutex_unlock(&dentry->d_inode->i_mutex); + if (!error) + d_delete(dentry); + dput(dentry); + + return error; +} + +#define xattr_may_create(flags) (!flags || flags & XATTR_CREATE) + +/* Returns and possibly creates the xattr dir. */ +static struct dentry *lookup_or_create_dir(struct dentry *parent, + const char *name, int flags) +{ + struct dentry *dentry; + BUG_ON(!parent); + + dentry = lookup_one_len(name, parent, strlen(name)); + if (IS_ERR(dentry)) + return dentry; + else if (!dentry->d_inode) { int err = -ENODATA; - if (flags == 0 || flags & XATTR_CREATE) - err = privroot->d_inode->i_op->mkdir(privroot->d_inode, - xaroot, 0700); + + if (xattr_may_create(flags)) { + mutex_lock_nested(&parent->d_inode->i_mutex, + I_MUTEX_XATTR); + err = xattr_mkdir(parent->d_inode, dentry, 0700); + mutex_unlock(&parent->d_inode->i_mutex); + } + if (err) { - dput(xaroot); - xaroot = ERR_PTR(err); - goto out; + dput(dentry); + dentry = ERR_PTR(err); } } - REISERFS_SB(sb)->xattr_root = dget(xaroot); - out: - mutex_unlock(&privroot->d_inode->i_mutex); - dput(privroot); - return xaroot; + return dentry; +} + +static struct dentry *open_xa_root(struct super_block *sb, int flags) +{ + struct dentry *privroot = REISERFS_SB(sb)->priv_root; + if (!privroot) + return ERR_PTR(-ENODATA); + return lookup_or_create_dir(privroot, XAROOT_NAME, flags); } -/* Opens the directory corresponding to the inode's extended attribute store. - * If flags allow, the tree to the directory may be created. If creation is - * prohibited, -ENODATA is returned. */ static struct dentry *open_xa_dir(const struct inode *inode, int flags) { struct dentry *xaroot, *xadir; char namebuf[17]; - xaroot = get_xa_root(inode->i_sb, flags); + xaroot = open_xa_root(inode->i_sb, flags); if (IS_ERR(xaroot)) return xaroot; - /* ok, we have xaroot open */ snprintf(namebuf, sizeof(namebuf), "%X.%X", le32_to_cpu(INODE_PKEY(inode)->k_objectid), inode->i_generation); - xadir = lookup_one_len(namebuf, xaroot, strlen(namebuf)); - if (IS_ERR(xadir)) { - dput(xaroot); - return xadir; - } - - if (!xadir->d_inode) { - int err; - if (flags == 0 || flags & XATTR_CREATE) { - /* Although there is nothing else trying to create this directory, - * another directory with the same hash may be created, so we need - * to protect against that */ - err = - xaroot->d_inode->i_op->mkdir(xaroot->d_inode, xadir, - 0700); - if (err) { - dput(xaroot); - dput(xadir); - return ERR_PTR(err); - } - } - if (!xadir->d_inode) { - dput(xaroot); - dput(xadir); - return ERR_PTR(-ENODATA); - } - } + xadir = lookup_or_create_dir(xaroot, namebuf, flags); dput(xaroot); return xadir; + } -/* Returns a dentry corresponding to a specific extended attribute file - * for the inode. If flags allow, the file is created. Otherwise, a - * valid or negative dentry, or an error is returned. */ -static struct dentry *get_xa_file_dentry(const struct inode *inode, - const char *name, int flags) -{ - struct dentry *xadir, *xafile; - int err = 0; +/* The following are side effects of other operations that aren't explicitly + * modifying extended attributes. This includes operations such as permissions + * or ownership changes, object deletions, etc. */ +struct reiserfs_dentry_buf { + struct dentry *xadir; + int count; + struct dentry *dentries[8]; +}; - xadir = open_xa_dir(inode, flags); - if (IS_ERR(xadir)) { - return ERR_CAST(xadir); - } else if (!xadir->d_inode) { - dput(xadir); - return ERR_PTR(-ENODATA); - } +static int +fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset, + u64 ino, unsigned int d_type) +{ + struct reiserfs_dentry_buf *dbuf = buf; + struct dentry *dentry; - xafile = lookup_one_len(name, xadir, strlen(name)); - if (IS_ERR(xafile)) { - dput(xadir); - return ERR_CAST(xafile); - } + if (dbuf->count == ARRAY_SIZE(dbuf->dentries)) + return -ENOSPC; - if (xafile->d_inode) { /* file exists */ - if (flags & XATTR_CREATE) { - err = -EEXIST; - dput(xafile); - goto out; - } - } else if (flags & XATTR_REPLACE || flags & FL_READONLY) { - goto out; - } else { - /* inode->i_mutex is down, so nothing else can try to create - * the same xattr */ - err = xadir->d_inode->i_op->create(xadir->d_inode, xafile, - 0700 | S_IFREG, NULL); + if (name[0] == '.' && (name[1] == '\0' || + (name[1] == '.' && name[2] == '\0'))) + return 0; - if (err) { - dput(xafile); - goto out; - } + dentry = lookup_one_len(name, dbuf->xadir, namelen); + if (IS_ERR(dentry)) { + return PTR_ERR(dentry); + } else if (!dentry->d_inode) { + /* A directory entry exists, but no file? */ + reiserfs_error(dentry->d_sb, "xattr-20003", + "Corrupted directory: xattr %s listed but " + "not found for file %s.\n", + dentry->d_name.name, dbuf->xadir->d_name.name); + dput(dentry); + return -EIO; } - out: - dput(xadir); - if (err) - xafile = ERR_PTR(err); - else if (!xafile->d_inode) { - dput(xafile); - xafile = ERR_PTR(-ENODATA); - } - return xafile; + dbuf->dentries[dbuf->count++] = dentry; + return 0; } -/* - * this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but - * we need to drop the path before calling the filldir struct. That - * would be a big performance hit to the non-xattr case, so I've copied - * the whole thing for now. --clm - * - * the big difference is that I go backwards through the directory, - * and don't mess with f->f_pos, but the idea is the same. Do some - * action on each and every entry in the directory. - * - * we're called with i_mutex held, so there are no worries about the directory - * changing underneath us. - */ -static int __xattr_readdir(struct inode *inode, void *dirent, filldir_t filldir) +static void +cleanup_dentry_buf(struct reiserfs_dentry_buf *buf) { - struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */ - INITIALIZE_PATH(path_to_entry); - struct buffer_head *bh; - int entry_num; - struct item_head *ih, tmp_ih; - int search_res; - char *local_buf; - loff_t next_pos; - char small_buf[32]; /* avoid kmalloc if we can */ - struct reiserfs_de_head *deh; - int d_reclen; - char *d_name; - off_t d_off; - ino_t d_ino; - struct reiserfs_dir_entry de; - - /* form key for search the next directory entry using f_pos field of - file structure */ - next_pos = max_reiserfs_offset(inode); - - while (1) { - research: - if (next_pos <= DOT_DOT_OFFSET) - break; - make_cpu_key(&pos_key, inode, next_pos, TYPE_DIRENTRY, 3); - - search_res = - search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry, - &de); - if (search_res == IO_ERROR) { - // FIXME: we could just skip part of directory which could - // not be read - pathrelse(&path_to_entry); - return -EIO; - } + int i; + for (i = 0; i < buf->count; i++) + if (buf->dentries[i]) + dput(buf->dentries[i]); +} + +static int reiserfs_for_each_xattr(struct inode *inode, + int (*action)(struct dentry *, void *), + void *data) +{ + struct dentry *dir; + int i, err = 0; + loff_t pos = 0; + struct reiserfs_dentry_buf buf = { + .count = 0, + }; - if (search_res == NAME_NOT_FOUND) - de.de_entry_num--; + /* Skip out, an xattr has no xattrs associated with it */ + if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) + return 0; - set_de_name_and_namelen(&de); - entry_num = de.de_entry_num; - deh = &(de.de_deh[entry_num]); + dir = open_xa_dir(inode, XATTR_REPLACE); + if (IS_ERR(dir)) { + err = PTR_ERR(dir); + goto out; + } else if (!dir->d_inode) { + err = 0; + goto out_dir; + } - bh = de.de_bh; - ih = de.de_ih; + mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); + buf.xadir = dir; + err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos); + while ((err == 0 || err == -ENOSPC) && buf.count) { + err = 0; - if (!is_direntry_le_ih(ih)) { - reiserfs_warning(inode->i_sb, "not direntry %h", ih); - break; - } - copy_item_head(&tmp_ih, ih); + for (i = 0; i < buf.count && buf.dentries[i]; i++) { + int lerr = 0; + struct dentry *dentry = buf.dentries[i]; - /* we must have found item, that is item of this directory, */ - RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key), - "vs-9000: found item %h does not match to dir we readdir %K", - ih, &pos_key); + if (err == 0 && !S_ISDIR(dentry->d_inode->i_mode)) + lerr = action(dentry, data); - if (deh_offset(deh) <= DOT_DOT_OFFSET) { - break; + dput(dentry); + buf.dentries[i] = NULL; + err = lerr ?: err; } + buf.count = 0; + if (!err) + err = reiserfs_readdir_dentry(dir, &buf, + fill_with_dentries, &pos); + } + mutex_unlock(&dir->d_inode->i_mutex); - /* look for the previous entry in the directory */ - next_pos = deh_offset(deh) - 1; - - if (!de_visible(deh)) - /* it is hidden entry */ - continue; + /* Clean up after a failed readdir */ + cleanup_dentry_buf(&buf); - d_reclen = entry_length(bh, ih, entry_num); - d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh); - d_off = deh_offset(deh); - d_ino = deh_objectid(deh); + if (!err) { + /* We start a transaction here to avoid a ABBA situation + * between the xattr root's i_mutex and the journal lock. + * This doesn't incur much additional overhead since the + * new transaction will just nest inside the + * outer transaction. */ + int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 + + 4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); + struct reiserfs_transaction_handle th; + err = journal_begin(&th, inode->i_sb, blocks); + if (!err) { + int jerror; + mutex_lock_nested(&dir->d_parent->d_inode->i_mutex, + I_MUTEX_XATTR); + err = action(dir, data); + jerror = journal_end(&th, inode->i_sb, blocks); + mutex_unlock(&dir->d_parent->d_inode->i_mutex); + err = jerror ?: err; + } + } +out_dir: + dput(dir); +out: + /* -ENODATA isn't an error */ + if (err == -ENODATA) + err = 0; + return err; +} - if (!d_name[d_reclen - 1]) - d_reclen = strlen(d_name); +static int delete_one_xattr(struct dentry *dentry, void *data) +{ + struct inode *dir = dentry->d_parent->d_inode; - if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)) { - /* too big to send back to VFS */ - continue; - } + /* This is the xattr dir, handle specially. */ + if (S_ISDIR(dentry->d_inode->i_mode)) + return xattr_rmdir(dir, dentry); - /* Ignore the .reiserfs_priv entry */ - if (reiserfs_xattrs(inode->i_sb) && - !old_format_only(inode->i_sb) && - deh_objectid(deh) == - le32_to_cpu(INODE_PKEY - (REISERFS_SB(inode->i_sb)->priv_root->d_inode)-> - k_objectid)) - continue; - - if (d_reclen <= 32) { - local_buf = small_buf; - } else { - local_buf = kmalloc(d_reclen, GFP_NOFS); - if (!local_buf) { - pathrelse(&path_to_entry); - return -ENOMEM; - } - if (item_moved(&tmp_ih, &path_to_entry)) { - kfree(local_buf); + return xattr_unlink(dir, dentry); +} - /* sigh, must retry. Do this same offset again */ - next_pos = d_off; - goto research; - } - } +static int chown_one_xattr(struct dentry *dentry, void *data) +{ + struct iattr *attrs = data; + return reiserfs_setattr(dentry, attrs); +} - // Note, that we copy name to user space via temporary - // buffer (local_buf) because filldir will block if - // user space buffer is swapped out. At that time - // entry can move to somewhere else - memcpy(local_buf, d_name, d_reclen); - - /* the filldir function might need to start transactions, - * or do who knows what. Release the path now that we've - * copied all the important stuff out of the deh - */ - pathrelse(&path_to_entry); - - if (filldir(dirent, local_buf, d_reclen, d_off, d_ino, - DT_UNKNOWN) < 0) { - if (local_buf != small_buf) { - kfree(local_buf); - } - goto end; - } - if (local_buf != small_buf) { - kfree(local_buf); - } - } /* while */ +/* No i_mutex, but the inode is unconnected. */ +int reiserfs_delete_xattrs(struct inode *inode) +{ + int err = reiserfs_for_each_xattr(inode, delete_one_xattr, NULL); + if (err) + reiserfs_warning(inode->i_sb, "jdm-20004", + "Couldn't delete all xattrs (%d)\n", err); + return err; +} - end: - pathrelse(&path_to_entry); - return 0; +/* inode->i_mutex: down */ +int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) +{ + int err = reiserfs_for_each_xattr(inode, chown_one_xattr, attrs); + if (err) + reiserfs_warning(inode->i_sb, "jdm-20007", + "Couldn't chown all xattrs (%d)\n", err); + return err; } -/* - * this could be done with dedicated readdir ops for the xattr files, - * but I want to get something working asap - * this is stolen from vfs_readdir - * - */ -static -int xattr_readdir(struct inode *inode, filldir_t filler, void *buf) +#ifdef CONFIG_REISERFS_FS_XATTR +/* Returns a dentry corresponding to a specific extended attribute file + * for the inode. If flags allow, the file is created. Otherwise, a + * valid or negative dentry, or an error is returned. */ +static struct dentry *xattr_lookup(struct inode *inode, const char *name, + int flags) { - int res = -ENOENT; - mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR); - if (!IS_DEADDIR(inode)) { - lock_kernel(); - res = __xattr_readdir(inode, buf, filler); - unlock_kernel(); + struct dentry *xadir, *xafile; + int err = 0; + + xadir = open_xa_dir(inode, flags); + if (IS_ERR(xadir)) + return ERR_CAST(xadir); + + xafile = lookup_one_len(name, xadir, strlen(name)); + if (IS_ERR(xafile)) { + err = PTR_ERR(xafile); + goto out; } - mutex_unlock(&inode->i_mutex); - return res; + + if (xafile->d_inode && (flags & XATTR_CREATE)) + err = -EEXIST; + + if (!xafile->d_inode) { + err = -ENODATA; + if (xattr_may_create(flags)) { + mutex_lock_nested(&xadir->d_inode->i_mutex, + I_MUTEX_XATTR); + err = xattr_create(xadir->d_inode, xafile, + 0700|S_IFREG); + mutex_unlock(&xadir->d_inode->i_mutex); + } + } + + if (err) + dput(xafile); +out: + dput(xadir); + if (err) + return ERR_PTR(err); + return xafile; } /* Internal operations on file data */ @@ -375,14 +385,14 @@ static inline void reiserfs_put_page(struct page *page) page_cache_release(page); } -static struct page *reiserfs_get_page(struct inode *dir, unsigned long n) +static struct page *reiserfs_get_page(struct inode *dir, size_t n) { struct address_space *mapping = dir->i_mapping; struct page *page; /* We can deadlock if we try to free dentries, and an unlink/rmdir has just occured - GFP_NOFS avoids this */ mapping_set_gfp_mask(mapping, GFP_NOFS); - page = read_mapping_page(mapping, n, NULL); + page = read_mapping_page(mapping, n >> PAGE_CACHE_SHIFT, NULL); if (!IS_ERR(page)) { kmap(page); if (PageError(page)) @@ -405,6 +415,45 @@ int reiserfs_commit_write(struct file *f, struct page *page, int reiserfs_prepare_write(struct file *f, struct page *page, unsigned from, unsigned to); +static void update_ctime(struct inode *inode) +{ + struct timespec now = current_fs_time(inode->i_sb); + if (hlist_unhashed(&inode->i_hash) || !inode->i_nlink || + timespec_equal(&inode->i_ctime, &now)) + return; + + inode->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); +} + +static int lookup_and_delete_xattr(struct inode *inode, const char *name) +{ + int err = 0; + struct dentry *dentry, *xadir; + + xadir = open_xa_dir(inode, XATTR_REPLACE); + if (IS_ERR(xadir)) + return PTR_ERR(xadir); + + dentry = lookup_one_len(name, xadir, strlen(name)); + if (IS_ERR(dentry)) { + err = PTR_ERR(dentry); + goto out_dput; + } + + if (dentry->d_inode) { + mutex_lock_nested(&xadir->d_inode->i_mutex, I_MUTEX_XATTR); + err = xattr_unlink(xadir->d_inode, dentry); + mutex_unlock(&xadir->d_inode->i_mutex); + update_ctime(inode); + } + + dput(dentry); +out_dput: + dput(xadir); + return err; +} + /* Generic extended attribute operations that can be used by xa plugins */ @@ -412,58 +461,32 @@ int reiserfs_prepare_write(struct file *f, struct page *page, * inode->i_mutex: down */ int -reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, - size_t buffer_size, int flags) +reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th, + struct inode *inode, const char *name, + const void *buffer, size_t buffer_size, int flags) { int err = 0; struct dentry *dentry; struct page *page; char *data; - struct address_space *mapping; size_t file_pos = 0; size_t buffer_pos = 0; - struct inode *xinode; - struct iattr newattrs; + size_t new_size; __u32 xahash = 0; if (get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; - /* Empty xattrs are ok, they're just empty files, no hash */ - if (buffer && buffer_size) - xahash = xattr_hash(buffer, buffer_size); + if (!buffer) + return lookup_and_delete_xattr(inode, name); - open_file: - dentry = get_xa_file_dentry(inode, name, flags); - if (IS_ERR(dentry)) { - err = PTR_ERR(dentry); - goto out; - } - - xinode = dentry->d_inode; - REISERFS_I(inode)->i_flags |= i_has_xattr_dir; + dentry = xattr_lookup(inode, name, flags); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); - /* we need to copy it off.. */ - if (xinode->i_nlink > 1) { - dput(dentry); - err = reiserfs_xattr_del(inode, name); - if (err < 0) - goto out; - /* We just killed the old one, we're not replacing anymore */ - if (flags & XATTR_REPLACE) - flags &= ~XATTR_REPLACE; - goto open_file; - } + down_write(&REISERFS_I(inode)->i_xattr_sem); - /* Resize it so we're ok to write there */ - newattrs.ia_size = buffer_size; - newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - mutex_lock_nested(&xinode->i_mutex, I_MUTEX_XATTR); - err = notify_change(dentry, &newattrs); - if (err) - goto out_filp; - - mapping = xinode->i_mapping; + xahash = xattr_hash(buffer, buffer_size); while (buffer_pos < buffer_size || buffer_pos == 0) { size_t chunk; size_t skip = 0; @@ -473,10 +496,10 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, else chunk = buffer_size - buffer_pos; - page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT); + page = reiserfs_get_page(dentry->d_inode, file_pos); if (IS_ERR(page)) { err = PTR_ERR(page); - goto out_filp; + goto out_unlock; } lock_page(page); @@ -510,28 +533,61 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, break; } - /* We can't mark the inode dirty if it's not hashed. This is the case - * when we're inheriting the default ACL. If we dirty it, the inode - * gets marked dirty, but won't (ever) make it onto the dirty list until - * it's synced explicitly to clear I_DIRTY. This is bad. */ - if (!hlist_unhashed(&inode->i_hash)) { - inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); + new_size = buffer_size + sizeof(struct reiserfs_xattr_header); + if (!err && new_size < i_size_read(dentry->d_inode)) { + struct iattr newattrs = { + .ia_ctime = current_fs_time(inode->i_sb), + .ia_size = buffer_size, + .ia_valid = ATTR_SIZE | ATTR_CTIME, + }; + mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR); + down_write(&dentry->d_inode->i_alloc_sem); + err = reiserfs_setattr(dentry, &newattrs); + up_write(&dentry->d_inode->i_alloc_sem); + mutex_unlock(&dentry->d_inode->i_mutex); + } else + update_ctime(inode); +out_unlock: + up_write(&REISERFS_I(inode)->i_xattr_sem); + dput(dentry); + return err; +} + +/* We need to start a transaction to maintain lock ordering */ +int reiserfs_xattr_set(struct inode *inode, const char *name, + const void *buffer, size_t buffer_size, int flags) +{ + + struct reiserfs_transaction_handle th; + int error, error2; + size_t jbegin_count = reiserfs_xattr_nblocks(inode, buffer_size); + + if (!(flags & XATTR_REPLACE)) + jbegin_count += reiserfs_xattr_jcreate_nblocks(inode); + + reiserfs_write_lock(inode->i_sb); + error = journal_begin(&th, inode->i_sb, jbegin_count); + if (error) { + reiserfs_write_unlock(inode->i_sb); + return error; } - out_filp: - mutex_unlock(&xinode->i_mutex); - dput(dentry); + error = reiserfs_xattr_set_handle(&th, inode, name, + buffer, buffer_size, flags); - out: - return err; + error2 = journal_end(&th, inode->i_sb, jbegin_count); + if (error == 0) + error = error2; + reiserfs_write_unlock(inode->i_sb); + + return error; } /* * inode->i_mutex: down */ int -reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, +reiserfs_xattr_get(struct inode *inode, const char *name, void *buffer, size_t buffer_size) { ssize_t err = 0; @@ -540,7 +596,6 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, size_t file_pos = 0; size_t buffer_pos = 0; struct page *page; - struct inode *xinode; __u32 hash = 0; if (name == NULL) @@ -551,25 +606,25 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, if (get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; - dentry = get_xa_file_dentry(inode, name, FL_READONLY); + dentry = xattr_lookup(inode, name, XATTR_REPLACE); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); goto out; } - xinode = dentry->d_inode; - isize = xinode->i_size; - REISERFS_I(inode)->i_flags |= i_has_xattr_dir; + down_read(&REISERFS_I(inode)->i_xattr_sem); + + isize = i_size_read(dentry->d_inode); /* Just return the size needed */ if (buffer == NULL) { err = isize - sizeof(struct reiserfs_xattr_header); - goto out_dput; + goto out_unlock; } if (buffer_size < isize - sizeof(struct reiserfs_xattr_header)) { err = -ERANGE; - goto out_dput; + goto out_unlock; } while (file_pos < isize) { @@ -581,10 +636,10 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, else chunk = isize - file_pos; - page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT); + page = reiserfs_get_page(dentry->d_inode, file_pos); if (IS_ERR(page)) { err = PTR_ERR(page); - goto out_dput; + goto out_unlock; } lock_page(page); @@ -598,12 +653,12 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) { unlock_page(page); reiserfs_put_page(page); - reiserfs_warning(inode->i_sb, + reiserfs_warning(inode->i_sb, "jdm-20001", "Invalid magic for xattr (%s) " "associated with %k", name, INODE_PKEY(inode)); err = -EIO; - goto out_dput; + goto out_unlock; } hash = le32_to_cpu(rxh->h_hash); } @@ -618,256 +673,83 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) != hash) { - reiserfs_warning(inode->i_sb, + reiserfs_warning(inode->i_sb, "jdm-20002", "Invalid hash for xattr (%s) associated " "with %k", name, INODE_PKEY(inode)); err = -EIO; } - out_dput: +out_unlock: + up_read(&REISERFS_I(inode)->i_xattr_sem); dput(dentry); - out: +out: return err; } -static int -__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen) -{ - struct dentry *dentry; - struct inode *dir = xadir->d_inode; - int err = 0; - - dentry = lookup_one_len(name, xadir, namelen); - if (IS_ERR(dentry)) { - err = PTR_ERR(dentry); - goto out; - } else if (!dentry->d_inode) { - err = -ENODATA; - goto out_file; - } - - /* Skip directories.. */ - if (S_ISDIR(dentry->d_inode->i_mode)) - goto out_file; - - if (!is_reiserfs_priv_object(dentry->d_inode)) { - reiserfs_warning(dir->i_sb, "OID %08x [%.*s/%.*s] doesn't have " - "priv flag set [parent is %sset].", - le32_to_cpu(INODE_PKEY(dentry->d_inode)-> - k_objectid), xadir->d_name.len, - xadir->d_name.name, namelen, name, - is_reiserfs_priv_object(xadir-> - d_inode) ? "" : - "not "); - dput(dentry); - return -EIO; - } - - err = dir->i_op->unlink(dir, dentry); - if (!err) - d_delete(dentry); - - out_file: - dput(dentry); - - out: - return err; -} - -int reiserfs_xattr_del(struct inode *inode, const char *name) -{ - struct dentry *dir; - int err; - - dir = open_xa_dir(inode, FL_READONLY); - if (IS_ERR(dir)) { - err = PTR_ERR(dir); - goto out; - } - - err = __reiserfs_xattr_del(dir, name, strlen(name)); - dput(dir); - - if (!err) { - inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); - } - - out: - return err; -} - -/* The following are side effects of other operations that aren't explicitly - * modifying extended attributes. This includes operations such as permissions - * or ownership changes, object deletions, etc. */ - -static int -reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, - loff_t offset, u64 ino, unsigned int d_type) -{ - struct dentry *xadir = (struct dentry *)buf; - - return __reiserfs_xattr_del(xadir, name, namelen); - -} - -/* This is called w/ inode->i_mutex downed */ -int reiserfs_delete_xattrs(struct inode *inode) -{ - struct dentry *dir, *root; - int err = 0; - - /* Skip out, an xattr has no xattrs associated with it */ - if (is_reiserfs_priv_object(inode) || - get_inode_sd_version(inode) == STAT_DATA_V1 || - !reiserfs_xattrs(inode->i_sb)) { - return 0; - } - reiserfs_read_lock_xattrs(inode->i_sb); - dir = open_xa_dir(inode, FL_READONLY); - reiserfs_read_unlock_xattrs(inode->i_sb); - if (IS_ERR(dir)) { - err = PTR_ERR(dir); - goto out; - } else if (!dir->d_inode) { - dput(dir); - return 0; - } - - lock_kernel(); - err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir); - if (err) { - unlock_kernel(); - goto out_dir; - } - - /* Leftovers besides . and .. -- that's not good. */ - if (dir->d_inode->i_nlink <= 2) { - root = get_xa_root(inode->i_sb, XATTR_REPLACE); - reiserfs_write_lock_xattrs(inode->i_sb); - err = vfs_rmdir(root->d_inode, dir); - reiserfs_write_unlock_xattrs(inode->i_sb); - dput(root); - } else { - reiserfs_warning(inode->i_sb, - "Couldn't remove all entries in directory"); - } - unlock_kernel(); - - out_dir: - dput(dir); - - out: - if (!err) - REISERFS_I(inode)->i_flags = - REISERFS_I(inode)->i_flags & ~i_has_xattr_dir; - return err; -} - -struct reiserfs_chown_buf { - struct inode *inode; - struct dentry *xadir; - struct iattr *attrs; +/* Actual operations that are exported to VFS-land */ +struct xattr_handler *reiserfs_xattr_handlers[] = { + &reiserfs_xattr_user_handler, + &reiserfs_xattr_trusted_handler, +#ifdef CONFIG_REISERFS_FS_SECURITY + &reiserfs_xattr_security_handler, +#endif +#ifdef CONFIG_REISERFS_FS_POSIX_ACL + &reiserfs_posix_acl_access_handler, + &reiserfs_posix_acl_default_handler, +#endif + NULL }; -/* XXX: If there is a better way to do this, I'd love to hear about it */ -static int -reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, - loff_t offset, u64 ino, unsigned int d_type) -{ - struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; - struct dentry *xafile, *xadir = chown_buf->xadir; - struct iattr *attrs = chown_buf->attrs; - int err = 0; - - xafile = lookup_one_len(name, xadir, namelen); - if (IS_ERR(xafile)) - return PTR_ERR(xafile); - else if (!xafile->d_inode) { - dput(xafile); - return -ENODATA; - } - - if (!S_ISDIR(xafile->d_inode->i_mode)) - err = notify_change(xafile, attrs); - dput(xafile); - - return err; -} +/* + * In order to implement different sets of xattr operations for each xattr + * prefix with the generic xattr API, a filesystem should create a + * null-terminated array of struct xattr_handler (one for each prefix) and + * hang a pointer to it off of the s_xattr field of the superblock. + * + * The generic_fooxattr() functions will use this list to dispatch xattr + * operations to the correct xattr_handler. + */ +#define for_each_xattr_handler(handlers, handler) \ + for ((handler) = *(handlers)++; \ + (handler) != NULL; \ + (handler) = *(handlers)++) -int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) +/* This is the implementation for the xattr plugin infrastructure */ +static inline struct xattr_handler * +find_xattr_handler_prefix(struct xattr_handler **handlers, + const char *name) { - struct dentry *dir; - int err = 0; - struct reiserfs_chown_buf buf; - unsigned int ia_valid = attrs->ia_valid; + struct xattr_handler *xah; - /* Skip out, an xattr has no xattrs associated with it */ - if (is_reiserfs_priv_object(inode) || - get_inode_sd_version(inode) == STAT_DATA_V1 || - !reiserfs_xattrs(inode->i_sb)) { - return 0; - } - reiserfs_read_lock_xattrs(inode->i_sb); - dir = open_xa_dir(inode, FL_READONLY); - reiserfs_read_unlock_xattrs(inode->i_sb); - if (IS_ERR(dir)) { - if (PTR_ERR(dir) != -ENODATA) - err = PTR_ERR(dir); - goto out; - } else if (!dir->d_inode) { - dput(dir); - goto out; - } + if (!handlers) + return NULL; - lock_kernel(); - - attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME); - buf.xadir = dir; - buf.attrs = attrs; - buf.inode = inode; - - err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf); - if (err) { - unlock_kernel(); - goto out_dir; + for_each_xattr_handler(handlers, xah) { + if (strncmp(xah->prefix, name, strlen(xah->prefix)) == 0) + break; } - err = notify_change(dir, attrs); - unlock_kernel(); - - out_dir: - dput(dir); - - out: - attrs->ia_valid = ia_valid; - return err; + return xah; } -/* Actual operations that are exported to VFS-land */ /* * Inode operation getxattr() - * Preliminary locking: we down dentry->d_inode->i_mutex */ ssize_t reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer, size_t size) { - struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); - int err; + struct inode *inode = dentry->d_inode; + struct xattr_handler *handler; - if (!xah || !reiserfs_xattrs(dentry->d_sb) || - get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) + handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name); + + if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; - reiserfs_read_lock_xattr_i(dentry->d_inode); - reiserfs_read_lock_xattrs(dentry->d_sb); - err = xah->get(dentry->d_inode, name, buffer, size); - reiserfs_read_unlock_xattrs(dentry->d_sb); - reiserfs_read_unlock_xattr_i(dentry->d_inode); - return err; + return handler->get(inode, name, buffer, size); } /* @@ -879,27 +761,15 @@ int reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); - int err; - int lock; + struct inode *inode = dentry->d_inode; + struct xattr_handler *handler; - if (!xah || !reiserfs_xattrs(dentry->d_sb) || - get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) + handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name); + + if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; - reiserfs_write_lock_xattr_i(dentry->d_inode); - lock = !has_xattr_dir(dentry->d_inode); - if (lock) - reiserfs_write_lock_xattrs(dentry->d_sb); - else - reiserfs_read_lock_xattrs(dentry->d_sb); - err = xah->set(dentry->d_inode, name, value, size, flags); - if (lock) - reiserfs_write_unlock_xattrs(dentry->d_sb); - else - reiserfs_read_unlock_xattrs(dentry->d_sb); - reiserfs_write_unlock_xattr_i(dentry->d_inode); - return err; + return handler->set(inode, name, value, size, flags); } /* @@ -909,86 +779,66 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value, */ int reiserfs_removexattr(struct dentry *dentry, const char *name) { - int err; - struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); + struct inode *inode = dentry->d_inode; + struct xattr_handler *handler; + handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name); - if (!xah || !reiserfs_xattrs(dentry->d_sb) || - get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) + if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; - reiserfs_write_lock_xattr_i(dentry->d_inode); - reiserfs_read_lock_xattrs(dentry->d_sb); - - /* Deletion pre-operation */ - if (xah->del) { - err = xah->del(dentry->d_inode, name); - if (err) - goto out; - } - - err = reiserfs_xattr_del(dentry->d_inode, name); - - dentry->d_inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(dentry->d_inode); - - out: - reiserfs_read_unlock_xattrs(dentry->d_sb); - reiserfs_write_unlock_xattr_i(dentry->d_inode); - return err; + return handler->set(inode, name, NULL, 0, XATTR_REPLACE); } -/* This is what filldir will use: - * r_pos will always contain the amount of space required for the entire - * list. If r_pos becomes larger than r_size, we need more space and we - * return an error indicating this. If r_pos is less than r_size, then we've - * filled the buffer successfully and we return success */ -struct reiserfs_listxattr_buf { - int r_pos; - int r_size; - char *r_buf; - struct inode *r_inode; +struct listxattr_buf { + size_t size; + size_t pos; + char *buf; + struct inode *inode; }; -static int -reiserfs_listxattr_filler(void *buf, const char *name, int namelen, - loff_t offset, u64 ino, unsigned int d_type) +static int listxattr_filler(void *buf, const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) { - struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf; - int len = 0; - if (name[0] != '.' - || (namelen != 1 && (name[1] != '.' || namelen != 2))) { - struct reiserfs_xattr_handler *xah = - find_xattr_handler_prefix(name); - if (!xah) - return 0; /* Unsupported xattr name, skip it */ - - /* We call ->list() twice because the operation isn't required to just - * return the name back - we want to make sure we have enough space */ - len += xah->list(b->r_inode, name, namelen, NULL); - - if (len) { - if (b->r_pos + len + 1 <= b->r_size) { - char *p = b->r_buf + b->r_pos; - p += xah->list(b->r_inode, name, namelen, p); - *p++ = '\0'; - } - b->r_pos += len + 1; + struct listxattr_buf *b = (struct listxattr_buf *)buf; + size_t size; + if (name[0] != '.' || + (namelen != 1 && (name[1] != '.' || namelen != 2))) { + struct xattr_handler *handler; + handler = find_xattr_handler_prefix(b->inode->i_sb->s_xattr, + name); + if (!handler) /* Unsupported xattr name */ + return 0; + if (b->buf) { + size = handler->list(b->inode, b->buf + b->pos, + b->size, name, namelen); + if (size > b->size) + return -ERANGE; + } else { + size = handler->list(b->inode, NULL, 0, name, namelen); } - } + b->pos += size; + } return 0; } /* * Inode operation listxattr() * - * Preliminary locking: we down dentry->d_inode->i_mutex + * We totally ignore the generic listxattr here because it would be stupid + * not to. Since the xattrs are organized in a directory, we can just + * readdir to find them. */ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) { struct dentry *dir; int err = 0; - struct reiserfs_listxattr_buf buf; + loff_t pos = 0; + struct listxattr_buf buf = { + .inode = dentry->d_inode, + .buf = buffer, + .size = buffer ? size : 0, + }; if (!dentry->d_inode) return -EINVAL; @@ -997,130 +847,104 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) return -EOPNOTSUPP; - reiserfs_read_lock_xattr_i(dentry->d_inode); - reiserfs_read_lock_xattrs(dentry->d_sb); - dir = open_xa_dir(dentry->d_inode, FL_READONLY); - reiserfs_read_unlock_xattrs(dentry->d_sb); + dir = open_xa_dir(dentry->d_inode, XATTR_REPLACE); if (IS_ERR(dir)) { err = PTR_ERR(dir); if (err == -ENODATA) - err = 0; /* Not an error if there aren't any xattrs */ + err = 0; /* Not an error if there aren't any xattrs */ goto out; } - buf.r_buf = buffer; - buf.r_size = buffer ? size : 0; - buf.r_pos = 0; - buf.r_inode = dentry->d_inode; + mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); + err = reiserfs_readdir_dentry(dir, &buf, listxattr_filler, &pos); + mutex_unlock(&dir->d_inode->i_mutex); - REISERFS_I(dentry->d_inode)->i_flags |= i_has_xattr_dir; - - err = xattr_readdir(dir->d_inode, reiserfs_listxattr_filler, &buf); - if (err) - goto out_dir; - - if (buf.r_pos > buf.r_size && buffer != NULL) - err = -ERANGE; - else - err = buf.r_pos; + if (!err) + err = buf.pos; - out_dir: dput(dir); - - out: - reiserfs_read_unlock_xattr_i(dentry->d_inode); +out: return err; } -/* This is the implementation for the xattr plugin infrastructure */ -static LIST_HEAD(xattr_handlers); -static DEFINE_RWLOCK(handler_lock); - -static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char - *prefix) +static int reiserfs_check_acl(struct inode *inode, int mask) { - struct reiserfs_xattr_handler *xah = NULL; - struct list_head *p; + struct posix_acl *acl; + int error = -EAGAIN; /* do regular unix permission checks by default */ - read_lock(&handler_lock); - list_for_each(p, &xattr_handlers) { - xah = list_entry(p, struct reiserfs_xattr_handler, handlers); - if (strncmp(xah->prefix, prefix, strlen(xah->prefix)) == 0) - break; - xah = NULL; + acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); + + if (acl) { + if (!IS_ERR(acl)) { + error = posix_acl_permission(inode, acl, mask); + posix_acl_release(acl); + } else if (PTR_ERR(acl) != -ENODATA) + error = PTR_ERR(acl); } - read_unlock(&handler_lock); - return xah; + return error; } -static void __unregister_handlers(void) +int reiserfs_permission(struct inode *inode, int mask) { - struct reiserfs_xattr_handler *xah; - struct list_head *p, *tmp; - - list_for_each_safe(p, tmp, &xattr_handlers) { - xah = list_entry(p, struct reiserfs_xattr_handler, handlers); - if (xah->exit) - xah->exit(); - - list_del_init(p); - } - INIT_LIST_HEAD(&xattr_handlers); + /* + * We don't do permission checks on the internal objects. + * Permissions are determined by the "owning" object. + */ + if (IS_PRIVATE(inode)) + return 0; + /* + * Stat data v1 doesn't support ACLs. + */ + if (get_inode_sd_version(inode) == STAT_DATA_V1) + return generic_permission(inode, mask, NULL); + else + return generic_permission(inode, mask, reiserfs_check_acl); } -int __init reiserfs_xattr_register_handlers(void) +static int create_privroot(struct dentry *dentry) { - int err = 0; - struct reiserfs_xattr_handler *xah; - struct list_head *p; - - write_lock(&handler_lock); - - /* If we're already initialized, nothing to do */ - if (!list_empty(&xattr_handlers)) { - write_unlock(&handler_lock); - return 0; - } - - /* Add the handlers */ - list_add_tail(&user_handler.handlers, &xattr_handlers); - list_add_tail(&trusted_handler.handlers, &xattr_handlers); -#ifdef CONFIG_REISERFS_FS_SECURITY - list_add_tail(&security_handler.handlers, &xattr_handlers); -#endif -#ifdef CONFIG_REISERFS_FS_POSIX_ACL - list_add_tail(&posix_acl_access_handler.handlers, &xattr_handlers); - list_add_tail(&posix_acl_default_handler.handlers, &xattr_handlers); -#endif - - /* Run initializers, if available */ - list_for_each(p, &xattr_handlers) { - xah = list_entry(p, struct reiserfs_xattr_handler, handlers); - if (xah->init) { - err = xah->init(); - if (err) { - list_del_init(p); - break; - } - } + int err; + struct inode *inode = dentry->d_parent->d_inode; + mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR); + err = xattr_mkdir(inode, dentry, 0700); + mutex_unlock(&inode->i_mutex); + if (err) { + dput(dentry); + dentry = NULL; } - /* Clean up other handlers, if any failed */ - if (err) - __unregister_handlers(); + if (dentry && dentry->d_inode) + reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr " + "storage.\n", PRIVROOT_NAME); - write_unlock(&handler_lock); return err; } -void reiserfs_xattr_unregister_handlers(void) +static int xattr_mount_check(struct super_block *s) { - write_lock(&handler_lock); - __unregister_handlers(); - write_unlock(&handler_lock); + /* We need generation numbers to ensure that the oid mapping is correct + * v3.5 filesystems don't have them. */ + if (old_format_only(s)) { + if (reiserfs_xattrs_optional(s)) { + /* Old format filesystem, but optional xattrs have + * been enabled. Error out. */ + reiserfs_warning(s, "jdm-2005", + "xattrs/ACLs not supported " + "on pre-v3.6 format filesystems. " + "Failing mount."); + return -EOPNOTSUPP; + } + } + + return 0; } +#else +int __init reiserfs_xattr_register_handlers(void) { return 0; } +void reiserfs_xattr_unregister_handlers(void) {} +#endif + /* This will catch lookups from the fs root to .reiserfs_priv */ static int xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name) @@ -1136,7 +960,7 @@ xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name) return 1; } -static struct dentry_operations xattr_lookup_poison_ops = { +static const struct dentry_operations xattr_lookup_poison_ops = { .d_compare = xattr_lookup_poison, }; @@ -1147,48 +971,23 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags) { int err = 0; - /* We need generation numbers to ensure that the oid mapping is correct - * v3.5 filesystems don't have them. */ - if (!old_format_only(s)) { - set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); - } else if (reiserfs_xattrs_optional(s)) { - /* Old format filesystem, but optional xattrs have been enabled - * at mount time. Error out. */ - reiserfs_warning(s, "xattrs/ACLs not supported on pre v3.6 " - "format filesystem. Failing mount."); - err = -EOPNOTSUPP; +#ifdef CONFIG_REISERFS_FS_XATTR + err = xattr_mount_check(s); + if (err) goto error; - } else { - /* Old format filesystem, but no optional xattrs have been enabled. This - * means we silently disable xattrs on the filesystem. */ - clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); - } +#endif /* If we don't have the privroot located yet - go find it */ - if (reiserfs_xattrs(s) && !REISERFS_SB(s)->priv_root) { + if (!REISERFS_SB(s)->priv_root) { struct dentry *dentry; dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, strlen(PRIVROOT_NAME)); if (!IS_ERR(dentry)) { - if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) { - struct inode *inode = dentry->d_parent->d_inode; - mutex_lock_nested(&inode->i_mutex, - I_MUTEX_XATTR); - err = inode->i_op->mkdir(inode, dentry, 0700); - mutex_unlock(&inode->i_mutex); - if (err) { - dput(dentry); - dentry = NULL; - } - - if (dentry && dentry->d_inode) - reiserfs_warning(s, - "Created %s on %s - reserved for " - "xattr storage.", - PRIVROOT_NAME, - reiserfs_bdevname - (inode->i_sb)); - } else if (!dentry->d_inode) { +#ifdef CONFIG_REISERFS_FS_XATTR + if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) + err = create_privroot(dentry); +#endif + if (!dentry->d_inode) { dput(dentry); dentry = NULL; } @@ -1197,73 +996,41 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags) if (!err && dentry) { s->s_root->d_op = &xattr_lookup_poison_ops; - reiserfs_mark_inode_private(dentry->d_inode); + dentry->d_inode->i_flags |= S_PRIVATE; REISERFS_SB(s)->priv_root = dentry; - } else if (!(mount_flags & MS_RDONLY)) { /* xattrs are unavailable */ - /* If we're read-only it just means that the dir hasn't been - * created. Not an error -- just no xattrs on the fs. We'll - * check again if we go read-write */ - reiserfs_warning(s, "xattrs/ACLs enabled and couldn't " - "find/create .reiserfs_priv. Failing mount."); +#ifdef CONFIG_REISERFS_FS_XATTR + /* xattrs are unavailable */ + } else if (!(mount_flags & MS_RDONLY)) { + /* If we're read-only it just means that the dir + * hasn't been created. Not an error -- just no + * xattrs on the fs. We'll check again if we + * go read-write */ + reiserfs_warning(s, "jdm-20006", + "xattrs/ACLs enabled and couldn't " + "find/create .reiserfs_priv. " + "Failing mount."); err = -EOPNOTSUPP; +#endif } } - error: - /* This is only nonzero if there was an error initializing the xattr - * directory or if there is a condition where we don't support them. */ +#ifdef CONFIG_REISERFS_FS_XATTR + if (!err) + s->s_xattr = reiserfs_xattr_handlers; + +error: if (err) { - clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt)); clear_bit(REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt)); } +#endif /* The super_block MS_POSIXACL must mirror the (no)acl mount option. */ s->s_flags = s->s_flags & ~MS_POSIXACL; +#ifdef CONFIG_REISERFS_FS_POSIX_ACL if (reiserfs_posixacl(s)) s->s_flags |= MS_POSIXACL; +#endif return err; } - -static int reiserfs_check_acl(struct inode *inode, int mask) -{ - struct posix_acl *acl; - int error = -EAGAIN; /* do regular unix permission checks by default */ - - reiserfs_read_lock_xattr_i(inode); - reiserfs_read_lock_xattrs(inode->i_sb); - - acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); - - reiserfs_read_unlock_xattrs(inode->i_sb); - reiserfs_read_unlock_xattr_i(inode); - - if (acl) { - if (!IS_ERR(acl)) { - error = posix_acl_permission(inode, acl, mask); - posix_acl_release(acl); - } else if (PTR_ERR(acl) != -ENODATA) - error = PTR_ERR(acl); - } - - return error; -} - -int reiserfs_permission(struct inode *inode, int mask) -{ - /* - * We don't do permission checks on the internal objects. - * Permissions are determined by the "owning" object. - */ - if (is_reiserfs_priv_object(inode)) - return 0; - - /* - * Stat data v1 doesn't support ACLs. - */ - if (get_inode_sd_version(inode) == STAT_DATA_V1) - return generic_permission(inode, mask, NULL); - else - return generic_permission(inode, mask, reiserfs_check_acl); -} diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index b7e4fa4539d..d423416d93d 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -10,15 +10,17 @@ #include <linux/reiserfs_acl.h> #include <asm/uaccess.h> -static int reiserfs_set_acl(struct inode *inode, int type, +static int reiserfs_set_acl(struct reiserfs_transaction_handle *th, + struct inode *inode, int type, struct posix_acl *acl); static int xattr_set_acl(struct inode *inode, int type, const void *value, size_t size) { struct posix_acl *acl; - int error; - + int error, error2; + struct reiserfs_transaction_handle th; + size_t jcreate_blocks; if (!reiserfs_posixacl(inode->i_sb)) return -EOPNOTSUPP; if (!is_owner_or_cap(inode)) @@ -36,7 +38,21 @@ xattr_set_acl(struct inode *inode, int type, const void *value, size_t size) } else acl = NULL; - error = reiserfs_set_acl(inode, type, acl); + /* Pessimism: We can't assume that anything from the xattr root up + * has been created. */ + + jcreate_blocks = reiserfs_xattr_jcreate_nblocks(inode) + + reiserfs_xattr_nblocks(inode, size) * 2; + + reiserfs_write_lock(inode->i_sb); + error = journal_begin(&th, inode->i_sb, jcreate_blocks); + if (error == 0) { + error = reiserfs_set_acl(&th, inode, type, acl); + error2 = journal_end(&th, inode->i_sb, jcreate_blocks); + if (error2) + error = error2; + } + reiserfs_write_unlock(inode->i_sb); release_and_out: posix_acl_release(acl); @@ -172,6 +188,29 @@ static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size) return ERR_PTR(-EINVAL); } +static inline void iset_acl(struct inode *inode, struct posix_acl **i_acl, + struct posix_acl *acl) +{ + spin_lock(&inode->i_lock); + if (*i_acl != ERR_PTR(-ENODATA)) + posix_acl_release(*i_acl); + *i_acl = posix_acl_dup(acl); + spin_unlock(&inode->i_lock); +} + +static inline struct posix_acl *iget_acl(struct inode *inode, + struct posix_acl **i_acl) +{ + struct posix_acl *acl = ERR_PTR(-ENODATA); + + spin_lock(&inode->i_lock); + if (*i_acl != ERR_PTR(-ENODATA)) + acl = posix_acl_dup(*i_acl); + spin_unlock(&inode->i_lock); + + return acl; +} + /* * Inode operation get_posix_acl(). * @@ -199,11 +238,11 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) return ERR_PTR(-EINVAL); } - if (IS_ERR(*p_acl)) { - if (PTR_ERR(*p_acl) == -ENODATA) - return NULL; - } else if (*p_acl != NULL) - return posix_acl_dup(*p_acl); + acl = iget_acl(inode, p_acl); + if (acl && !IS_ERR(acl)) + return acl; + else if (PTR_ERR(acl) == -ENODATA) + return NULL; size = reiserfs_xattr_get(inode, name, NULL, 0); if (size < 0) { @@ -229,7 +268,7 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) } else { acl = posix_acl_from_disk(value, retval); if (!IS_ERR(acl)) - *p_acl = posix_acl_dup(acl); + iset_acl(inode, p_acl, acl); } kfree(value); @@ -243,12 +282,13 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) * BKL held [before 2.5.x] */ static int -reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) +reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, + int type, struct posix_acl *acl) { char *name; void *value = NULL; struct posix_acl **p_acl; - size_t size; + size_t size = 0; int error; struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); @@ -285,31 +325,28 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) value = posix_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); - error = reiserfs_xattr_set(inode, name, value, size, 0); - } else { - error = reiserfs_xattr_del(inode, name); - if (error == -ENODATA) { - /* This may seem odd here, but it means that the ACL was set - * with a value representable with mode bits. If there was - * an ACL before, reiserfs_xattr_del already dirtied the inode. - */ + } + + error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0); + + /* + * Ensure that the inode gets dirtied if we're only using + * the mode bits and an old ACL didn't exist. We don't need + * to check if the inode is hashed here since we won't get + * called by reiserfs_inherit_default_acl(). + */ + if (error == -ENODATA) { + error = 0; + if (type == ACL_TYPE_ACCESS) { + inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); - error = 0; } } kfree(value); - if (!error) { - /* Release the old one */ - if (!IS_ERR(*p_acl) && *p_acl) - posix_acl_release(*p_acl); - - if (acl == NULL) - *p_acl = ERR_PTR(-ENODATA); - else - *p_acl = posix_acl_dup(acl); - } + if (!error) + iset_acl(inode, p_acl, acl); return error; } @@ -317,7 +354,8 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) /* dir->i_mutex: locked, * inode is new and not released into the wild yet */ int -reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, +reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, + struct inode *dir, struct dentry *dentry, struct inode *inode) { struct posix_acl *acl; @@ -335,8 +373,8 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This * would be useless since permissions are ignored, and a pain because * it introduces locking cycles */ - if (is_reiserfs_priv_object(dir)) { - reiserfs_mark_inode_private(inode); + if (IS_PRIVATE(dir)) { + inode->i_flags |= S_PRIVATE; goto apply_umask; } @@ -354,7 +392,8 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, /* Copy the default ACL to the default ACL of a new directory */ if (S_ISDIR(inode->i_mode)) { - err = reiserfs_set_acl(inode, ACL_TYPE_DEFAULT, acl); + err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT, + acl); if (err) goto cleanup; } @@ -375,9 +414,9 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, /* If we need an ACL.. */ if (need_acl > 0) { - err = - reiserfs_set_acl(inode, ACL_TYPE_ACCESS, - acl_copy); + err = reiserfs_set_acl(th, inode, + ACL_TYPE_ACCESS, + acl_copy); if (err) goto cleanup_copy; } @@ -395,25 +434,45 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, return err; } -/* Looks up and caches the result of the default ACL. - * We do this so that we don't need to carry the xattr_sem into - * reiserfs_new_inode if we don't need to */ +/* This is used to cache the default acl before a new object is created. + * The biggest reason for this is to get an idea of how many blocks will + * actually be required for the create operation if we must inherit an ACL. + * An ACL write can add up to 3 object creations and an additional file write + * so we'd prefer not to reserve that many blocks in the journal if we can. + * It also has the advantage of not loading the ACL with a transaction open, + * this may seem silly, but if the owner of the directory is doing the + * creation, the ACL may not be loaded since the permissions wouldn't require + * it. + * We return the number of blocks required for the transaction. + */ int reiserfs_cache_default_acl(struct inode *inode) { - int ret = 0; - if (reiserfs_posixacl(inode->i_sb) && !is_reiserfs_priv_object(inode)) { - struct posix_acl *acl; - reiserfs_read_lock_xattr_i(inode); - reiserfs_read_lock_xattrs(inode->i_sb); - acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT); - reiserfs_read_unlock_xattrs(inode->i_sb); - reiserfs_read_unlock_xattr_i(inode); - ret = (acl && !IS_ERR(acl)); - if (ret) - posix_acl_release(acl); + struct posix_acl *acl; + int nblocks = 0; + + if (IS_PRIVATE(inode)) + return 0; + + acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT); + + if (acl && !IS_ERR(acl)) { + int size = reiserfs_acl_size(acl->a_count); + + /* Other xattrs can be created during inode creation. We don't + * want to claim too many blocks, so we check to see if we + * we need to create the tree to the xattrs, and then we + * just want two files. */ + nblocks = reiserfs_xattr_jcreate_nblocks(inode); + nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); + + REISERFS_I(inode)->i_flags |= i_has_xattr_dir; + + /* We need to account for writes + bitmaps for two files */ + nblocks += reiserfs_xattr_nblocks(inode, size) * 4; + posix_acl_release(acl); } - return ret; + return nblocks; } int reiserfs_acl_chmod(struct inode *inode) @@ -429,9 +488,7 @@ int reiserfs_acl_chmod(struct inode *inode) return 0; } - reiserfs_read_lock_xattrs(inode->i_sb); acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); - reiserfs_read_unlock_xattrs(inode->i_sb); if (!acl) return 0; if (IS_ERR(acl)) @@ -442,18 +499,20 @@ int reiserfs_acl_chmod(struct inode *inode) return -ENOMEM; error = posix_acl_chmod_masq(clone, inode->i_mode); if (!error) { - int lock = !has_xattr_dir(inode); - reiserfs_write_lock_xattr_i(inode); - if (lock) - reiserfs_write_lock_xattrs(inode->i_sb); - else - reiserfs_read_lock_xattrs(inode->i_sb); - error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone); - if (lock) - reiserfs_write_unlock_xattrs(inode->i_sb); - else - reiserfs_read_unlock_xattrs(inode->i_sb); - reiserfs_write_unlock_xattr_i(inode); + struct reiserfs_transaction_handle th; + size_t size = reiserfs_xattr_nblocks(inode, + reiserfs_acl_size(clone->a_count)); + reiserfs_write_lock(inode->i_sb); + error = journal_begin(&th, inode->i_sb, size * 2); + if (!error) { + int error2; + error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS, + clone); + error2 = journal_end(&th, inode->i_sb, size * 2); + if (error2) + error = error2; + } + reiserfs_write_unlock(inode->i_sb); } posix_acl_release(clone); return error; @@ -477,38 +536,22 @@ posix_acl_access_set(struct inode *inode, const char *name, return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); } -static int posix_acl_access_del(struct inode *inode, const char *name) +static size_t posix_acl_access_list(struct inode *inode, char *list, + size_t list_size, const char *name, + size_t name_len) { - struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); - struct posix_acl **acl = &reiserfs_i->i_acl_access; - if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1) - return -EINVAL; - if (!IS_ERR(*acl) && *acl) { - posix_acl_release(*acl); - *acl = ERR_PTR(-ENODATA); - } - - return 0; -} - -static int -posix_acl_access_list(struct inode *inode, const char *name, int namelen, - char *out) -{ - int len = namelen; + const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); if (!reiserfs_posixacl(inode->i_sb)) return 0; - if (out) - memcpy(out, name, len); - - return len; + if (list && size <= list_size) + memcpy(list, POSIX_ACL_XATTR_ACCESS, size); + return size; } -struct reiserfs_xattr_handler posix_acl_access_handler = { +struct xattr_handler reiserfs_posix_acl_access_handler = { .prefix = POSIX_ACL_XATTR_ACCESS, .get = posix_acl_access_get, .set = posix_acl_access_set, - .del = posix_acl_access_del, .list = posix_acl_access_list, }; @@ -530,37 +573,21 @@ posix_acl_default_set(struct inode *inode, const char *name, return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); } -static int posix_acl_default_del(struct inode *inode, const char *name) +static size_t posix_acl_default_list(struct inode *inode, char *list, + size_t list_size, const char *name, + size_t name_len) { - struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); - struct posix_acl **acl = &reiserfs_i->i_acl_default; - if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1) - return -EINVAL; - if (!IS_ERR(*acl) && *acl) { - posix_acl_release(*acl); - *acl = ERR_PTR(-ENODATA); - } - - return 0; -} - -static int -posix_acl_default_list(struct inode *inode, const char *name, int namelen, - char *out) -{ - int len = namelen; + const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); if (!reiserfs_posixacl(inode->i_sb)) return 0; - if (out) - memcpy(out, name, len); - - return len; + if (list && size <= list_size) + memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); + return size; } -struct reiserfs_xattr_handler posix_acl_default_handler = { +struct xattr_handler reiserfs_posix_acl_default_handler = { .prefix = POSIX_ACL_XATTR_DEFAULT, .get = posix_acl_default_get, .set = posix_acl_default_set, - .del = posix_acl_default_del, .list = posix_acl_default_list, }; diff --git a/fs/reiserfs/xattr_security.c b/fs/reiserfs/xattr_security.c index 056008db137..4d3c20e787c 100644 --- a/fs/reiserfs/xattr_security.c +++ b/fs/reiserfs/xattr_security.c @@ -4,6 +4,7 @@ #include <linux/pagemap.h> #include <linux/xattr.h> #include <linux/reiserfs_xattr.h> +#include <linux/security.h> #include <asm/uaccess.h> static int @@ -12,7 +13,7 @@ security_get(struct inode *inode, const char *name, void *buffer, size_t size) if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX)) return -EINVAL; - if (is_reiserfs_priv_object(inode)) + if (IS_PRIVATE(inode)) return -EPERM; return reiserfs_xattr_get(inode, name, buffer, size); @@ -25,41 +26,84 @@ security_set(struct inode *inode, const char *name, const void *buffer, if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX)) return -EINVAL; - if (is_reiserfs_priv_object(inode)) + if (IS_PRIVATE(inode)) return -EPERM; return reiserfs_xattr_set(inode, name, buffer, size, flags); } -static int security_del(struct inode *inode, const char *name) +static size_t security_list(struct inode *inode, char *list, size_t list_len, + const char *name, size_t namelen) { - if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX)) - return -EINVAL; + const size_t len = namelen + 1; - if (is_reiserfs_priv_object(inode)) - return -EPERM; + if (IS_PRIVATE(inode)) + return 0; + + if (list && len <= list_len) { + memcpy(list, name, namelen); + list[namelen] = '\0'; + } - return 0; + return len; } -static int -security_list(struct inode *inode, const char *name, int namelen, char *out) +/* Initializes the security context for a new inode and returns the number + * of blocks needed for the transaction. If successful, reiserfs_security + * must be released using reiserfs_security_free when the caller is done. */ +int reiserfs_security_init(struct inode *dir, struct inode *inode, + struct reiserfs_security_handle *sec) { - int len = namelen; + int blocks = 0; + int error = security_inode_init_security(inode, dir, &sec->name, + &sec->value, &sec->length); + if (error) { + if (error == -EOPNOTSUPP) + error = 0; - if (is_reiserfs_priv_object(inode)) - return 0; + sec->name = NULL; + sec->value = NULL; + sec->length = 0; + return error; + } - if (out) - memcpy(out, name, len); + if (sec->length) { + blocks = reiserfs_xattr_jcreate_nblocks(inode) + + reiserfs_xattr_nblocks(inode, sec->length); + /* We don't want to count the directories twice if we have + * a default ACL. */ + REISERFS_I(inode)->i_flags |= i_has_xattr_dir; + } + return blocks; +} - return len; +int reiserfs_security_write(struct reiserfs_transaction_handle *th, + struct inode *inode, + struct reiserfs_security_handle *sec) +{ + int error; + if (strlen(sec->name) < sizeof(XATTR_SECURITY_PREFIX)) + return -EINVAL; + + error = reiserfs_xattr_set_handle(th, inode, sec->name, sec->value, + sec->length, XATTR_CREATE); + if (error == -ENODATA || error == -EOPNOTSUPP) + error = 0; + + return error; +} + +void reiserfs_security_free(struct reiserfs_security_handle *sec) +{ + kfree(sec->name); + kfree(sec->value); + sec->name = NULL; + sec->value = NULL; } -struct reiserfs_xattr_handler security_handler = { +struct xattr_handler reiserfs_xattr_security_handler = { .prefix = XATTR_SECURITY_PREFIX, .get = security_get, .set = security_set, - .del = security_del, .list = security_list, }; diff --git a/fs/reiserfs/xattr_trusted.c b/fs/reiserfs/xattr_trusted.c index 60abe2bb1f9..a865042f75e 100644 --- a/fs/reiserfs/xattr_trusted.c +++ b/fs/reiserfs/xattr_trusted.c @@ -13,10 +13,7 @@ trusted_get(struct inode *inode, const char *name, void *buffer, size_t size) if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX)) return -EINVAL; - if (!reiserfs_xattrs(inode->i_sb)) - return -EOPNOTSUPP; - - if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode))) + if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode)) return -EPERM; return reiserfs_xattr_get(inode, name, buffer, size); @@ -29,50 +26,30 @@ trusted_set(struct inode *inode, const char *name, const void *buffer, if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX)) return -EINVAL; - if (!reiserfs_xattrs(inode->i_sb)) - return -EOPNOTSUPP; - - if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode))) + if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode)) return -EPERM; return reiserfs_xattr_set(inode, name, buffer, size, flags); } -static int trusted_del(struct inode *inode, const char *name) +static size_t trusted_list(struct inode *inode, char *list, size_t list_size, + const char *name, size_t name_len) { - if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX)) - return -EINVAL; + const size_t len = name_len + 1; - if (!reiserfs_xattrs(inode->i_sb)) - return -EOPNOTSUPP; - - if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode))) - return -EPERM; - - return 0; -} - -static int -trusted_list(struct inode *inode, const char *name, int namelen, char *out) -{ - int len = namelen; - - if (!reiserfs_xattrs(inode->i_sb)) + if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode)) return 0; - if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode))) - return 0; - - if (out) - memcpy(out, name, len); - + if (list && len <= list_size) { + memcpy(list, name, name_len); + list[name_len] = '\0'; + } return len; } -struct reiserfs_xattr_handler trusted_handler = { +struct xattr_handler reiserfs_xattr_trusted_handler = { .prefix = XATTR_TRUSTED_PREFIX, .get = trusted_get, .set = trusted_set, - .del = trusted_del, .list = trusted_list, }; diff --git a/fs/reiserfs/xattr_user.c b/fs/reiserfs/xattr_user.c index 1384efcb938..e3238dc4f3d 100644 --- a/fs/reiserfs/xattr_user.c +++ b/fs/reiserfs/xattr_user.c @@ -6,10 +6,6 @@ #include <linux/reiserfs_xattr.h> #include <asm/uaccess.h> -#ifdef CONFIG_REISERFS_FS_POSIX_ACL -# include <linux/reiserfs_acl.h> -#endif - static int user_get(struct inode *inode, const char *name, void *buffer, size_t size) { @@ -25,7 +21,6 @@ static int user_set(struct inode *inode, const char *name, const void *buffer, size_t size, int flags) { - if (strlen(name) < sizeof(XATTR_USER_PREFIX)) return -EINVAL; @@ -34,33 +29,23 @@ user_set(struct inode *inode, const char *name, const void *buffer, return reiserfs_xattr_set(inode, name, buffer, size, flags); } -static int user_del(struct inode *inode, const char *name) +static size_t user_list(struct inode *inode, char *list, size_t list_size, + const char *name, size_t name_len) { - if (strlen(name) < sizeof(XATTR_USER_PREFIX)) - return -EINVAL; - - if (!reiserfs_xattrs_user(inode->i_sb)) - return -EOPNOTSUPP; - return 0; -} + const size_t len = name_len + 1; -static int -user_list(struct inode *inode, const char *name, int namelen, char *out) -{ - int len = namelen; if (!reiserfs_xattrs_user(inode->i_sb)) return 0; - - if (out) - memcpy(out, name, len); - + if (list && len <= list_size) { + memcpy(list, name, name_len); + list[name_len] = '\0'; + } return len; } -struct reiserfs_xattr_handler user_handler = { +struct xattr_handler reiserfs_xattr_user_handler = { .prefix = XATTR_USER_PREFIX, .get = user_get, .set = user_set, - .del = user_del, .list = user_list, }; diff --git a/fs/seq_file.c b/fs/seq_file.c index a1a4cfe1921..7f40f30c55c 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -513,7 +513,7 @@ int seq_bitmap(struct seq_file *m, const unsigned long *bits, } EXPORT_SYMBOL(seq_bitmap); -int seq_bitmap_list(struct seq_file *m, unsigned long *bits, +int seq_bitmap_list(struct seq_file *m, const unsigned long *bits, unsigned int nr_bits) { if (m->count < m->size) { diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index e7ddd0328dd..3e4803b4427 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -277,7 +277,7 @@ static int smb_hash_dentry(struct dentry *, struct qstr *); static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *); static int smb_delete_dentry(struct dentry *); -static struct dentry_operations smbfs_dentry_operations = +static const struct dentry_operations smbfs_dentry_operations = { .d_revalidate = smb_lookup_validate, .d_hash = smb_hash_dentry, @@ -285,7 +285,7 @@ static struct dentry_operations smbfs_dentry_operations = .d_delete = smb_delete_dentry, }; -static struct dentry_operations smbfs_dentry_operations_case = +static const struct dentry_operations smbfs_dentry_operations_case = { .d_revalidate = smb_lookup_validate, .d_delete = smb_delete_dentry, diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c index 321728f48f2..2a796031034 100644 --- a/fs/squashfs/block.c +++ b/fs/squashfs/block.c @@ -184,15 +184,7 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, offset = 0; } - if (msblk->stream.avail_out == 0) { - if (page == pages) { - ERROR("zlib_inflate tried to " - "decompress too much data, " - "expected %d bytes. Zlib " - "data probably corrupt\n", - srclength); - goto release_mutex; - } + if (msblk->stream.avail_out == 0 && page < pages) { msblk->stream.next_out = buffer[page++]; msblk->stream.avail_out = PAGE_CACHE_SIZE; } @@ -209,25 +201,20 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, zlib_init = 1; } - zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH); + zlib_err = zlib_inflate(&msblk->stream, Z_SYNC_FLUSH); if (msblk->stream.avail_in == 0 && k < b) put_bh(bh[k++]); } while (zlib_err == Z_OK); if (zlib_err != Z_STREAM_END) { - ERROR("zlib_inflate returned unexpected result" - " 0x%x, srclength %d, avail_in %d," - " avail_out %d\n", zlib_err, srclength, - msblk->stream.avail_in, - msblk->stream.avail_out); + ERROR("zlib_inflate error, data probably corrupt\n"); goto release_mutex; } zlib_err = zlib_inflateEnd(&msblk->stream); if (zlib_err != Z_OK) { - ERROR("zlib_inflateEnd returned unexpected result 0x%x," - " srclength %d\n", zlib_err, srclength); + ERROR("zlib_inflate error, data probably corrupt\n"); goto release_mutex; } length = msblk->stream.total_out; diff --git a/fs/super.c b/fs/super.c index 8349ed6b141..2ba481518ba 100644 --- a/fs/super.c +++ b/fs/super.c @@ -197,7 +197,7 @@ void deactivate_super(struct super_block *s) if (atomic_dec_and_lock(&s->s_active, &sb_lock)) { s->s_count -= S_BIAS-1; spin_unlock(&sb_lock); - DQUOT_OFF(s, 0); + vfs_dq_off(s, 0); down_write(&s->s_umount); fs->kill_sb(s); put_filesystem(fs); @@ -266,7 +266,7 @@ EXPORT_SYMBOL(unlock_super); void __fsync_super(struct super_block *sb) { sync_inodes_sb(sb, 0); - DQUOT_SYNC(sb); + vfs_dq_sync(sb); lock_super(sb); if (sb->s_dirt && sb->s_op->write_super) sb->s_op->write_super(sb); @@ -371,8 +371,10 @@ retry: continue; if (!grab_super(old)) goto retry; - if (s) + if (s) { + up_write(&s->s_umount); destroy_super(s); + } return old; } } @@ -387,6 +389,7 @@ retry: err = set(s, data); if (err) { spin_unlock(&sb_lock); + up_write(&s->s_umount); destroy_super(s); return ERR_PTR(err); } @@ -652,7 +655,7 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) mark_files_ro(sb); else if (!fs_may_remount_ro(sb)) return -EBUSY; - retval = DQUOT_OFF(sb, 1); + retval = vfs_dq_off(sb, 1); if (retval < 0 && retval != -ENOSYS) return -EBUSY; } @@ -667,11 +670,11 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) } sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); if (remount_rw) - DQUOT_ON_REMOUNT(sb); + vfs_dq_quota_on_remount(sb); return 0; } -static void do_emergency_remount(unsigned long foo) +static void do_emergency_remount(struct work_struct *work) { struct super_block *sb; @@ -694,12 +697,19 @@ static void do_emergency_remount(unsigned long foo) spin_lock(&sb_lock); } spin_unlock(&sb_lock); + kfree(work); printk("Emergency Remount complete\n"); } void emergency_remount(void) { - pdflush_operation(do_emergency_remount, 0); + struct work_struct *work; + + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (work) { + INIT_WORK(work, do_emergency_remount); + schedule_work(work); + } } /* @@ -828,7 +838,8 @@ int get_sb_bdev(struct file_system_type *fs_type, bdev->bd_super = s; } - return simple_set_mnt(mnt, s); + simple_set_mnt(mnt, s); + return 0; error_s: error = PTR_ERR(s); @@ -874,7 +885,8 @@ int get_sb_nodev(struct file_system_type *fs_type, return error; } s->s_flags |= MS_ACTIVE; - return simple_set_mnt(mnt, s); + simple_set_mnt(mnt, s); + return 0; } EXPORT_SYMBOL(get_sb_nodev); @@ -906,7 +918,8 @@ int get_sb_single(struct file_system_type *fs_type, s->s_flags |= MS_ACTIVE; } do_remount_sb(s, flags, data, 0); - return simple_set_mnt(mnt, s); + simple_set_mnt(mnt, s); + return 0; } EXPORT_SYMBOL(get_sb_single); diff --git a/fs/sync.c b/fs/sync.c index a16d53e5fe9..7abc65fbf21 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -25,7 +25,7 @@ static void do_sync(unsigned long wait) { wakeup_pdflush(0); sync_inodes(0); /* All mappings, inodes and their blockdevs */ - DQUOT_SYNC(NULL); + vfs_dq_sync(NULL); sync_supers(); /* Write the superblocks */ sync_filesystems(0); /* Start syncing the filesystems */ sync_filesystems(wait); /* Waitingly sync the filesystems */ @@ -42,9 +42,21 @@ SYSCALL_DEFINE0(sync) return 0; } +static void do_sync_work(struct work_struct *work) +{ + do_sync(0); + kfree(work); +} + void emergency_sync(void) { - pdflush_operation(do_sync, 0); + struct work_struct *work; + + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (work) { + INIT_WORK(work, do_sync_work); + schedule_work(work); + } } /* diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index f2c478c3424..93e0c0281d4 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -21,15 +21,28 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/mutex.h> +#include <linux/mm.h> #include <asm/uaccess.h> #include "sysfs.h" +/* + * There's one bin_buffer for each open file. + * + * filp->private_data points to bin_buffer and + * sysfs_dirent->s_bin_attr.buffers points to a the bin_buffer s + * sysfs_dirent->s_bin_attr.buffers is protected by sysfs_bin_lock + */ +static DEFINE_MUTEX(sysfs_bin_lock); + struct bin_buffer { - struct mutex mutex; - void *buffer; - int mmapped; + struct mutex mutex; + void *buffer; + int mmapped; + struct vm_operations_struct *vm_ops; + struct file *file; + struct hlist_node list; }; static int @@ -168,6 +181,175 @@ out_free: return count; } +static void bin_vma_open(struct vm_area_struct *vma) +{ + struct file *file = vma->vm_file; + struct bin_buffer *bb = file->private_data; + struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; + + if (!bb->vm_ops || !bb->vm_ops->open) + return; + + if (!sysfs_get_active_two(attr_sd)) + return; + + bb->vm_ops->open(vma); + + sysfs_put_active_two(attr_sd); +} + +static void bin_vma_close(struct vm_area_struct *vma) +{ + struct file *file = vma->vm_file; + struct bin_buffer *bb = file->private_data; + struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; + + if (!bb->vm_ops || !bb->vm_ops->close) + return; + + if (!sysfs_get_active_two(attr_sd)) + return; + + bb->vm_ops->close(vma); + + sysfs_put_active_two(attr_sd); +} + +static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct file *file = vma->vm_file; + struct bin_buffer *bb = file->private_data; + struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; + int ret; + + if (!bb->vm_ops || !bb->vm_ops->fault) + return VM_FAULT_SIGBUS; + + if (!sysfs_get_active_two(attr_sd)) + return VM_FAULT_SIGBUS; + + ret = bb->vm_ops->fault(vma, vmf); + + sysfs_put_active_two(attr_sd); + return ret; +} + +static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct file *file = vma->vm_file; + struct bin_buffer *bb = file->private_data; + struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; + int ret; + + if (!bb->vm_ops) + return VM_FAULT_SIGBUS; + + if (!bb->vm_ops->page_mkwrite) + return 0; + + if (!sysfs_get_active_two(attr_sd)) + return VM_FAULT_SIGBUS; + + ret = bb->vm_ops->page_mkwrite(vma, vmf); + + sysfs_put_active_two(attr_sd); + return ret; +} + +static int bin_access(struct vm_area_struct *vma, unsigned long addr, + void *buf, int len, int write) +{ + struct file *file = vma->vm_file; + struct bin_buffer *bb = file->private_data; + struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; + int ret; + + if (!bb->vm_ops || !bb->vm_ops->access) + return -EINVAL; + + if (!sysfs_get_active_two(attr_sd)) + return -EINVAL; + + ret = bb->vm_ops->access(vma, addr, buf, len, write); + + sysfs_put_active_two(attr_sd); + return ret; +} + +#ifdef CONFIG_NUMA +static int bin_set_policy(struct vm_area_struct *vma, struct mempolicy *new) +{ + struct file *file = vma->vm_file; + struct bin_buffer *bb = file->private_data; + struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; + int ret; + + if (!bb->vm_ops || !bb->vm_ops->set_policy) + return 0; + + if (!sysfs_get_active_two(attr_sd)) + return -EINVAL; + + ret = bb->vm_ops->set_policy(vma, new); + + sysfs_put_active_two(attr_sd); + return ret; +} + +static struct mempolicy *bin_get_policy(struct vm_area_struct *vma, + unsigned long addr) +{ + struct file *file = vma->vm_file; + struct bin_buffer *bb = file->private_data; + struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; + struct mempolicy *pol; + + if (!bb->vm_ops || !bb->vm_ops->get_policy) + return vma->vm_policy; + + if (!sysfs_get_active_two(attr_sd)) + return vma->vm_policy; + + pol = bb->vm_ops->get_policy(vma, addr); + + sysfs_put_active_two(attr_sd); + return pol; +} + +static int bin_migrate(struct vm_area_struct *vma, const nodemask_t *from, + const nodemask_t *to, unsigned long flags) +{ + struct file *file = vma->vm_file; + struct bin_buffer *bb = file->private_data; + struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; + int ret; + + if (!bb->vm_ops || !bb->vm_ops->migrate) + return 0; + + if (!sysfs_get_active_two(attr_sd)) + return 0; + + ret = bb->vm_ops->migrate(vma, from, to, flags); + + sysfs_put_active_two(attr_sd); + return ret; +} +#endif + +static struct vm_operations_struct bin_vm_ops = { + .open = bin_vma_open, + .close = bin_vma_close, + .fault = bin_fault, + .page_mkwrite = bin_page_mkwrite, + .access = bin_access, +#ifdef CONFIG_NUMA + .set_policy = bin_set_policy, + .get_policy = bin_get_policy, + .migrate = bin_migrate, +#endif +}; + static int mmap(struct file *file, struct vm_area_struct *vma) { struct bin_buffer *bb = file->private_data; @@ -179,18 +361,37 @@ static int mmap(struct file *file, struct vm_area_struct *vma) mutex_lock(&bb->mutex); /* need attr_sd for attr, its parent for kobj */ + rc = -ENODEV; if (!sysfs_get_active_two(attr_sd)) - return -ENODEV; + goto out_unlock; rc = -EINVAL; - if (attr->mmap) - rc = attr->mmap(kobj, attr, vma); + if (!attr->mmap) + goto out_put; + + rc = attr->mmap(kobj, attr, vma); + if (rc) + goto out_put; - if (rc == 0 && !bb->mmapped) - bb->mmapped = 1; - else - sysfs_put_active_two(attr_sd); + /* + * PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup() + * to satisfy versions of X which crash if the mmap fails: that + * substitutes a new vm_file, and we don't then want bin_vm_ops. + */ + if (vma->vm_file != file) + goto out_put; + rc = -EINVAL; + if (bb->mmapped && bb->vm_ops != vma->vm_ops) + goto out_put; + + rc = 0; + bb->mmapped = 1; + bb->vm_ops = vma->vm_ops; + vma->vm_ops = &bin_vm_ops; +out_put: + sysfs_put_active_two(attr_sd); +out_unlock: mutex_unlock(&bb->mutex); return rc; @@ -223,8 +424,13 @@ static int open(struct inode * inode, struct file * file) goto err_out; mutex_init(&bb->mutex); + bb->file = file; file->private_data = bb; + mutex_lock(&sysfs_bin_lock); + hlist_add_head(&bb->list, &attr_sd->s_bin_attr.buffers); + mutex_unlock(&sysfs_bin_lock); + /* open succeeded, put active references */ sysfs_put_active_two(attr_sd); return 0; @@ -237,11 +443,12 @@ static int open(struct inode * inode, struct file * file) static int release(struct inode * inode, struct file * file) { - struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; struct bin_buffer *bb = file->private_data; - if (bb->mmapped) - sysfs_put_active_two(attr_sd); + mutex_lock(&sysfs_bin_lock); + hlist_del(&bb->list); + mutex_unlock(&sysfs_bin_lock); + kfree(bb->buffer); kfree(bb); return 0; @@ -256,6 +463,26 @@ const struct file_operations bin_fops = { .release = release, }; + +void unmap_bin_file(struct sysfs_dirent *attr_sd) +{ + struct bin_buffer *bb; + struct hlist_node *tmp; + + if (sysfs_type(attr_sd) != SYSFS_KOBJ_BIN_ATTR) + return; + + mutex_lock(&sysfs_bin_lock); + + hlist_for_each_entry(bb, tmp, &attr_sd->s_bin_attr.buffers, list) { + struct inode *inode = bb->file->f_path.dentry->d_inode; + + unmap_mapping_range(inode->i_mapping, 0, 0, 1); + } + + mutex_unlock(&sysfs_bin_lock); +} + /** * sysfs_create_bin_file - create binary file for object. * @kobj: object. diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 82d3b79d0e0..d88d0fac9fa 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -302,7 +302,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) iput(inode); } -static struct dentry_operations sysfs_dentry_ops = { +static const struct dentry_operations sysfs_dentry_ops = { .d_iput = sysfs_d_iput, }; @@ -434,6 +434,26 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) } /** + * sysfs_pathname - return full path to sysfs dirent + * @sd: sysfs_dirent whose path we want + * @path: caller allocated buffer + * + * Gives the name "/" to the sysfs_root entry; any path returned + * is relative to wherever sysfs is mounted. + * + * XXX: does no error checking on @path size + */ +static char *sysfs_pathname(struct sysfs_dirent *sd, char *path) +{ + if (sd->s_parent) { + sysfs_pathname(sd->s_parent, path); + strcat(path, "/"); + } + strcat(path, sd->s_name); + return path; +} + +/** * sysfs_add_one - add sysfs_dirent to parent * @acxt: addrm context to use * @sd: sysfs_dirent to be added @@ -458,8 +478,16 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) int ret; ret = __sysfs_add_one(acxt, sd); - WARN(ret == -EEXIST, KERN_WARNING "sysfs: duplicate filename '%s' " - "can not be created\n", sd->s_name); + if (ret == -EEXIST) { + char *path = kzalloc(PATH_MAX, GFP_KERNEL); + WARN(1, KERN_WARNING + "sysfs: cannot create duplicate filename '%s'\n", + (path == NULL) ? sd->s_name : + strcat(strcat(sysfs_pathname(acxt->parent_sd, path), "/"), + sd->s_name)); + kfree(path); + } + return ret; } @@ -581,6 +609,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) sysfs_drop_dentry(sd); sysfs_deactivate(sd); + unmap_bin_file(sd); sysfs_put(sd); } } diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 1f4a3f87726..289c43a4726 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -659,13 +659,16 @@ void sysfs_remove_file_from_group(struct kobject *kobj, EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); struct sysfs_schedule_callback_struct { - struct kobject *kobj; + struct list_head workq_list; + struct kobject *kobj; void (*func)(void *); void *data; struct module *owner; struct work_struct work; }; +static DEFINE_MUTEX(sysfs_workq_mutex); +static LIST_HEAD(sysfs_workq); static void sysfs_schedule_callback_work(struct work_struct *work) { struct sysfs_schedule_callback_struct *ss = container_of(work, @@ -674,6 +677,9 @@ static void sysfs_schedule_callback_work(struct work_struct *work) (ss->func)(ss->data); kobject_put(ss->kobj); module_put(ss->owner); + mutex_lock(&sysfs_workq_mutex); + list_del(&ss->workq_list); + mutex_unlock(&sysfs_workq_mutex); kfree(ss); } @@ -695,15 +701,25 @@ static void sysfs_schedule_callback_work(struct work_struct *work) * until @func returns. * * Returns 0 if the request was submitted, -ENOMEM if storage could not - * be allocated, -ENODEV if a reference to @owner isn't available. + * be allocated, -ENODEV if a reference to @owner isn't available, + * -EAGAIN if a callback has already been scheduled for @kobj. */ int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), void *data, struct module *owner) { - struct sysfs_schedule_callback_struct *ss; + struct sysfs_schedule_callback_struct *ss, *tmp; if (!try_module_get(owner)) return -ENODEV; + + mutex_lock(&sysfs_workq_mutex); + list_for_each_entry_safe(ss, tmp, &sysfs_workq, workq_list) + if (ss->kobj == kobj) { + mutex_unlock(&sysfs_workq_mutex); + return -EAGAIN; + } + mutex_unlock(&sysfs_workq_mutex); + ss = kmalloc(sizeof(*ss), GFP_KERNEL); if (!ss) { module_put(owner); @@ -715,6 +731,10 @@ int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), ss->data = data; ss->owner = owner; INIT_WORK(&ss->work, sysfs_schedule_callback_work); + INIT_LIST_HEAD(&ss->workq_list); + mutex_lock(&sysfs_workq_mutex); + list_add_tail(&ss->workq_list, &sysfs_workq); + mutex_unlock(&sysfs_workq_mutex); schedule_work(&ss->work); return 0; } diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index dfa3d94cfc7..555f0ff988d 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -147,6 +147,7 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) { struct bin_attribute *bin_attr; + inode->i_private = sysfs_get(sd); inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; inode->i_op = &sysfs_inode_operations; @@ -214,6 +215,22 @@ struct inode * sysfs_get_inode(struct sysfs_dirent *sd) return inode; } +/* + * The sysfs_dirent serves as both an inode and a directory entry for sysfs. + * To prevent the sysfs inode numbers from being freed prematurely we take a + * reference to sysfs_dirent from the sysfs inode. A + * super_operations.delete_inode() implementation is needed to drop that + * reference upon inode destruction. + */ +void sysfs_delete_inode(struct inode *inode) +{ + struct sysfs_dirent *sd = inode->i_private; + + truncate_inode_pages(&inode->i_data, 0); + clear_inode(inode); + sysfs_put(sd); +} + int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) { struct sysfs_addrm_cxt acxt; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index ab343e371d6..49749955cca 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -17,11 +17,10 @@ #include <linux/pagemap.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/magic.h> #include "sysfs.h" -/* Random magic number */ -#define SYSFS_MAGIC 0x62656572 static struct vfsmount *sysfs_mount; struct super_block * sysfs_sb = NULL; @@ -30,6 +29,7 @@ struct kmem_cache *sysfs_dir_cachep; static const struct super_operations sysfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, + .delete_inode = sysfs_delete_inode, }; struct sysfs_dirent sysfs_root = { @@ -53,7 +53,9 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) sysfs_sb = sb; /* get root inode, initialize and unlock it */ + mutex_lock(&sysfs_mutex); inode = sysfs_get_inode(&sysfs_root); + mutex_unlock(&sysfs_mutex); if (!inode) { pr_debug("sysfs: could not get root inode\n"); return -ENOMEM; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 93c6d6b27c4..3fa0d98481e 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -28,6 +28,7 @@ struct sysfs_elem_attr { struct sysfs_elem_bin_attr { struct bin_attribute *bin_attr; + struct hlist_head buffers; }; /* @@ -145,6 +146,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) * inode.c */ struct inode *sysfs_get_inode(struct sysfs_dirent *sd); +void sysfs_delete_inode(struct inode *inode); int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); int sysfs_inode_init(void); @@ -163,6 +165,7 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, * bin.c */ extern const struct file_operations bin_fops; +void unmap_bin_file(struct sysfs_dirent *attr_sd); /* * symlink.c diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index a1f1ef33e81..33e047b59b8 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -38,7 +38,7 @@ static int sysv_hash(struct dentry *dentry, struct qstr *qstr) return 0; } -struct dentry_operations sysv_dentry_operations = { +const struct dentry_operations sysv_dentry_operations = { .d_hash = sysv_hash, }; diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h index 38ebe3f85b3..5784a318c88 100644 --- a/fs/sysv/sysv.h +++ b/fs/sysv/sysv.h @@ -170,7 +170,7 @@ extern const struct file_operations sysv_file_operations; extern const struct file_operations sysv_dir_operations; extern const struct address_space_operations sysv_aops; extern const struct super_operations sysv_sops; -extern struct dentry_operations sysv_dentry_operations; +extern const struct dentry_operations sysv_dentry_operations; enum { diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 93b6de51f26..0ff89fe71e5 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1434,8 +1434,9 @@ static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags) * mmap()d file has taken write protection fault and is being made * writable. UBIFS must ensure page is budgeted for. */ -static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page) +static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { + struct page *page = vmf->page; struct inode *inode = vma->vm_file->f_path.dentry->d_inode; struct ubifs_info *c = inode->i_sb->s_fs_info; struct timespec now = ubifs_current_time(inode); @@ -1447,7 +1448,7 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page) ubifs_assert(!(inode->i_sb->s_flags & MS_RDONLY)); if (unlikely(c->ro_media)) - return -EROFS; + return VM_FAULT_SIGBUS; /* -EROFS */ /* * We have not locked @page so far so we may budget for changing the @@ -1480,7 +1481,7 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page) if (err == -ENOSPC) ubifs_warn("out of space for mmapped file " "(inode number %lu)", inode->i_ino); - return err; + return VM_FAULT_SIGBUS; } lock_page(page); @@ -1520,6 +1521,8 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page) out_unlock: unlock_page(page); ubifs_release_budget(c, &req); + if (err) + err = VM_FAULT_SIGBUS; return err; } diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 1182b66a549..c5c98355459 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -2034,7 +2034,8 @@ static int ubifs_get_sb(struct file_system_type *fs_type, int flags, /* 'fill_super()' opens ubi again so we must close it here */ ubi_close_volume(ubi); - return simple_set_mnt(mnt, sb); + simple_set_mnt(mnt, sb); + return 0; out_deact: up_write(&sb->s_umount); diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index 1b809bd494b..2bb788a2acb 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -206,7 +206,7 @@ static void udf_bitmap_free_blocks(struct super_block *sb, ((char *)bh->b_data)[(bit + i) >> 3]); } else { if (inode) - DQUOT_FREE_BLOCK(inode, 1); + vfs_dq_free_block(inode, 1); udf_add_free_space(sbi, sbi->s_partition, 1); } } @@ -261,11 +261,11 @@ static int udf_bitmap_prealloc_blocks(struct super_block *sb, while (bit < (sb->s_blocksize << 3) && block_count > 0) { if (!udf_test_bit(bit, bh->b_data)) goto out; - else if (DQUOT_PREALLOC_BLOCK(inode, 1)) + else if (vfs_dq_prealloc_block(inode, 1)) goto out; else if (!udf_clear_bit(bit, bh->b_data)) { udf_debug("bit already cleared for block %d\n", bit); - DQUOT_FREE_BLOCK(inode, 1); + vfs_dq_free_block(inode, 1); goto out; } block_count--; @@ -393,7 +393,7 @@ got_block: /* * Check quota for allocation of this block. */ - if (inode && DQUOT_ALLOC_BLOCK(inode, 1)) { + if (inode && vfs_dq_alloc_block(inode, 1)) { mutex_unlock(&sbi->s_alloc_mutex); *err = -EDQUOT; return 0; @@ -452,7 +452,7 @@ static void udf_table_free_blocks(struct super_block *sb, /* We do this up front - There are some error conditions that could occure, but.. oh well */ if (inode) - DQUOT_FREE_BLOCK(inode, count); + vfs_dq_free_block(inode, count); if (udf_add_free_space(sbi, sbi->s_partition, count)) mark_buffer_dirty(sbi->s_lvid_bh); @@ -700,7 +700,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb, epos.offset -= adsize; alloc_count = (elen >> sb->s_blocksize_bits); - if (inode && DQUOT_PREALLOC_BLOCK(inode, + if (inode && vfs_dq_prealloc_block(inode, alloc_count > block_count ? block_count : alloc_count)) alloc_count = 0; else if (alloc_count > block_count) { @@ -806,7 +806,7 @@ static int udf_table_new_block(struct super_block *sb, goal_eloc.logicalBlockNum++; goal_elen -= sb->s_blocksize; - if (inode && DQUOT_ALLOC_BLOCK(inode, 1)) { + if (inode && vfs_dq_alloc_block(inode, 1)) { brelse(goal_epos.bh); mutex_unlock(&sbi->s_alloc_mutex); *err = -EDQUOT; diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index 31fc84297dd..47dbe5613f9 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c @@ -36,8 +36,8 @@ void udf_free_inode(struct inode *inode) * Note: we must free any quota before locking the superblock, * as writing the quota to disk may need the lock as well. */ - DQUOT_FREE_INODE(inode); - DQUOT_DROP(inode); + vfs_dq_free_inode(inode); + vfs_dq_drop(inode); clear_inode(inode); @@ -154,8 +154,8 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err) insert_inode_hash(inode); mark_inode_dirty(inode); - if (DQUOT_ALLOC_INODE(inode)) { - DQUOT_DROP(inode); + if (vfs_dq_alloc_inode(inode)) { + vfs_dq_drop(inode); inode->i_flags |= S_NOQUOTA; inode->i_nlink = 0; iput(inode); diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 0d9ada17373..54c16ec95df 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -85,7 +85,7 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count) "bit already cleared for fragment %u", i); } - DQUOT_FREE_BLOCK (inode, count); + vfs_dq_free_block(inode, count); fs32_add(sb, &ucg->cg_cs.cs_nffree, count); @@ -195,7 +195,7 @@ do_more: ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno); if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, 1); - DQUOT_FREE_BLOCK(inode, uspi->s_fpb); + vfs_dq_free_block(inode, uspi->s_fpb); fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1); uspi->cs_total.cs_nbfree++; @@ -556,7 +556,7 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment, fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1); for (i = oldcount; i < newcount; i++) ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i); - if(DQUOT_ALLOC_BLOCK(inode, count)) { + if (vfs_dq_alloc_block(inode, count)) { *err = -EDQUOT; return 0; } @@ -664,7 +664,7 @@ cg_found: for (i = count; i < uspi->s_fpb; i++) ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i); i = uspi->s_fpb - count; - DQUOT_FREE_BLOCK(inode, i); + vfs_dq_free_block(inode, i); fs32_add(sb, &ucg->cg_cs.cs_nffree, i); uspi->cs_total.cs_nffree += i; @@ -676,7 +676,7 @@ cg_found: result = ufs_bitmap_search (sb, ucpi, goal, allocsize); if (result == INVBLOCK) return 0; - if(DQUOT_ALLOC_BLOCK(inode, count)) { + if (vfs_dq_alloc_block(inode, count)) { *err = -EDQUOT; return 0; } @@ -747,7 +747,7 @@ gotit: ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno); if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, -1); - if(DQUOT_ALLOC_BLOCK(inode, uspi->s_fpb)) { + if (vfs_dq_alloc_block(inode, uspi->s_fpb)) { *err = -EDQUOT; return INVBLOCK; } diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index 6f5dcf00609..3527c00fef0 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -95,8 +95,8 @@ void ufs_free_inode (struct inode * inode) is_directory = S_ISDIR(inode->i_mode); - DQUOT_FREE_INODE(inode); - DQUOT_DROP(inode); + vfs_dq_free_inode(inode); + vfs_dq_drop(inode); clear_inode (inode); @@ -355,8 +355,8 @@ cg_found: unlock_super (sb); - if (DQUOT_ALLOC_INODE(inode)) { - DQUOT_DROP(inode); + if (vfs_dq_alloc_inode(inode)) { + vfs_dq_drop(inode); err = -EDQUOT; goto fail_without_unlock; } diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 39f87789856..3d2512c21f0 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -622,7 +622,6 @@ static int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode) struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; mode_t mode; - unsigned i; /* * Copy data to the in-core inode. @@ -655,11 +654,12 @@ static int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode) if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { - for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) - ufsi->i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i]; + memcpy(ufsi->i_u1.i_data, &ufs_inode->ui_u2.ui_addr, + sizeof(ufs_inode->ui_u2.ui_addr)); } else { - for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) - ufsi->i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i]; + memcpy(ufsi->i_u1.i_symlink, ufs_inode->ui_u2.ui_symlink, + sizeof(ufs_inode->ui_u2.ui_symlink) - 1); + ufsi->i_u1.i_symlink[sizeof(ufs_inode->ui_u2.ui_symlink) - 1] = 0; } return 0; } @@ -669,7 +669,6 @@ static int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode) struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; mode_t mode; - unsigned i; UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino); /* @@ -704,12 +703,12 @@ static int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode) */ if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { - for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) - ufsi->i_u1.u2_i_data[i] = - ufs2_inode->ui_u2.ui_addr.ui_db[i]; + memcpy(ufsi->i_u1.u2_i_data, &ufs2_inode->ui_u2.ui_addr, + sizeof(ufs2_inode->ui_u2.ui_addr)); } else { - for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) - ufsi->i_u1.i_symlink[i] = ufs2_inode->ui_u2.ui_symlink[i]; + memcpy(ufsi->i_u1.i_symlink, ufs2_inode->ui_u2.ui_symlink, + sizeof(ufs2_inode->ui_u2.ui_symlink) - 1); + ufsi->i_u1.i_symlink[sizeof(ufs2_inode->ui_u2.ui_symlink) - 1] = 0; } return 0; } @@ -781,7 +780,6 @@ static void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode) { struct super_block *sb = inode->i_sb; struct ufs_inode_info *ufsi = UFS_I(inode); - unsigned i; ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode); ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink); @@ -809,12 +807,12 @@ static void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode) /* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */ ufs_inode->ui_u2.ui_addr.ui_db[0] = ufsi->i_u1.i_data[0]; } else if (inode->i_blocks) { - for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) - ufs_inode->ui_u2.ui_addr.ui_db[i] = ufsi->i_u1.i_data[i]; + memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.i_data, + sizeof(ufs_inode->ui_u2.ui_addr)); } else { - for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) - ufs_inode->ui_u2.ui_symlink[i] = ufsi->i_u1.i_symlink[i]; + memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink, + sizeof(ufs_inode->ui_u2.ui_symlink)); } if (!inode->i_nlink) @@ -825,7 +823,6 @@ static void ufs2_update_inode(struct inode *inode, struct ufs2_inode *ufs_inode) { struct super_block *sb = inode->i_sb; struct ufs_inode_info *ufsi = UFS_I(inode); - unsigned i; UFSD("ENTER\n"); ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode); @@ -850,11 +847,11 @@ static void ufs2_update_inode(struct inode *inode, struct ufs2_inode *ufs_inode) /* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */ ufs_inode->ui_u2.ui_addr.ui_db[0] = ufsi->i_u1.u2_i_data[0]; } else if (inode->i_blocks) { - for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) - ufs_inode->ui_u2.ui_addr.ui_db[i] = ufsi->i_u1.u2_i_data[i]; + memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.u2_i_data, + sizeof(ufs_inode->ui_u2.ui_addr)); } else { - for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) - ufs_inode->ui_u2.ui_symlink[i] = ufsi->i_u1.i_symlink[i]; + memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink, + sizeof(ufs_inode->ui_u2.ui_symlink)); } if (!inode->i_nlink) diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index e3a9b1fac75..23119fe7ad6 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -147,7 +147,7 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry, } else { /* fast symlink */ inode->i_op = &ufs_fast_symlink_inode_operations; - memcpy((char*)&UFS_I(inode)->i_u1.i_data,symname,l); + memcpy(UFS_I(inode)->i_u1.i_symlink, symname, l); inode->i_size = l-1; } mark_inode_dirty(inode); diff --git a/fs/ufs/super.c b/fs/ufs/super.c index e65212dfb60..e1c1fc5ee23 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -41,7 +41,7 @@ * Stefan Reinauer <stepan@home.culture.mipt.ru> * * Module usage counts added on 96/04/29 by - * Gertjan van Wingerde <gertjan@cs.vu.nl> + * Gertjan van Wingerde <gwingerde@gmail.com> * * Clean swab support on 19970406 by * Francois-Rene Rideau <fare@tunes.org> @@ -636,6 +636,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) unsigned block_size, super_block_size; unsigned flags; unsigned super_block_offset; + unsigned maxsymlen; int ret = -EINVAL; uspi = NULL; @@ -1069,6 +1070,16 @@ magic_found: uspi->s_maxsymlinklen = fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen); + if (uspi->fs_magic == UFS2_MAGIC) + maxsymlen = 2 * 4 * (UFS_NDADDR + UFS_NINDIR); + else + maxsymlen = 4 * (UFS_NDADDR + UFS_NINDIR); + if (uspi->s_maxsymlinklen > maxsymlen) { + ufs_warning(sb, __func__, "ufs_read_super: excessive maximum " + "fast symlink size (%u)\n", uspi->s_maxsymlinklen); + uspi->s_maxsymlinklen = maxsymlen; + } + inode = ufs_iget(sb, UFS_ROOTINO); if (IS_ERR(inode)) { ret = PTR_ERR(inode); diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index 11c035168ea..69b3427d788 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h @@ -23,7 +23,7 @@ struct ufs_sb_info { struct ufs_inode_info { union { __fs32 i_data[15]; - __u8 i_symlink[4*15]; + __u8 i_symlink[2 * 4 * 15]; __fs64 u2_i_data[15]; } i_u1; __u32 i_flags; diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index cb329edc925..aa1016bb913 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -34,6 +34,12 @@ #include <linux/backing-dev.h> #include <linux/freezer.h> +#include "xfs_sb.h" +#include "xfs_inum.h" +#include "xfs_ag.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" + static kmem_zone_t *xfs_buf_zone; STATIC int xfsbufd(void *); STATIC int xfsbufd_wakeup(int, gfp_t); @@ -1435,10 +1441,12 @@ xfs_unregister_buftarg( void xfs_free_buftarg( - xfs_buftarg_t *btp) + struct xfs_mount *mp, + struct xfs_buftarg *btp) { xfs_flush_buftarg(btp, 1); - xfs_blkdev_issue_flush(btp); + if (mp->m_flags & XFS_MOUNT_BARRIER) + xfs_blkdev_issue_flush(btp); xfs_free_bufhash(btp); iput(btp->bt_mapping->host); diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index 288ae7c4c80..9b4d666ad31 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -413,7 +413,7 @@ static inline int XFS_bwrite(xfs_buf_t *bp) * Handling of buftargs. */ extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *, int); -extern void xfs_free_buftarg(xfs_buftarg_t *); +extern void xfs_free_buftarg(struct xfs_mount *, struct xfs_buftarg *); extern void xfs_wait_buftarg(xfs_buftarg_t *); extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); extern int xfs_flush_buftarg(xfs_buftarg_t *, int); diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index e14c4e3aea0..f4e25544157 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -234,9 +234,9 @@ xfs_file_mmap( STATIC int xfs_vm_page_mkwrite( struct vm_area_struct *vma, - struct page *page) + struct vm_fault *vmf) { - return block_page_mkwrite(vma, page, xfs_get_blocks); + return block_page_mkwrite(vma, vmf, xfs_get_blocks); } const struct file_operations xfs_file_operations = { diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index c71e226da7f..32ae5028e96 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -734,15 +734,15 @@ xfs_close_devices( { if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) { struct block_device *logdev = mp->m_logdev_targp->bt_bdev; - xfs_free_buftarg(mp->m_logdev_targp); + xfs_free_buftarg(mp, mp->m_logdev_targp); xfs_blkdev_put(logdev); } if (mp->m_rtdev_targp) { struct block_device *rtdev = mp->m_rtdev_targp->bt_bdev; - xfs_free_buftarg(mp->m_rtdev_targp); + xfs_free_buftarg(mp, mp->m_rtdev_targp); xfs_blkdev_put(rtdev); } - xfs_free_buftarg(mp->m_ddev_targp); + xfs_free_buftarg(mp, mp->m_ddev_targp); } /* @@ -811,9 +811,9 @@ xfs_open_devices( out_free_rtdev_targ: if (mp->m_rtdev_targp) - xfs_free_buftarg(mp->m_rtdev_targp); + xfs_free_buftarg(mp, mp->m_rtdev_targp); out_free_ddev_targ: - xfs_free_buftarg(mp->m_ddev_targp); + xfs_free_buftarg(mp, mp->m_ddev_targp); out_close_rtdev: if (rtdev) xfs_blkdev_put(rtdev); diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index e2fb6210d4c..478e587087f 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -246,9 +246,6 @@ xfs_iget_cache_miss( goto out_destroy; } - if (lock_flags) - xfs_ilock(ip, lock_flags); - /* * Preload the radix tree so we can insert safely under the * write spinlock. Note that we cannot sleep inside the preload @@ -256,7 +253,16 @@ xfs_iget_cache_miss( */ if (radix_tree_preload(GFP_KERNEL)) { error = EAGAIN; - goto out_unlock; + goto out_destroy; + } + + /* + * Because the inode hasn't been added to the radix-tree yet it can't + * be found by another thread, so we can do the non-sleeping lock here. + */ + if (lock_flags) { + if (!xfs_ilock_nowait(ip, lock_flags)) + BUG(); } mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1); @@ -284,7 +290,6 @@ xfs_iget_cache_miss( out_preload_end: write_unlock(&pag->pag_ici_lock); radix_tree_preload_end(); -out_unlock: if (lock_flags) xfs_iunlock(ip, lock_flags); out_destroy: diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index b1047de2fff..61af610d79b 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -1455,10 +1455,19 @@ xlog_recover_add_to_trans( item = item->ri_prev; if (item->ri_total == 0) { /* first region to be added */ - item->ri_total = in_f->ilf_size; - ASSERT(item->ri_total <= XLOG_MAX_REGIONS_IN_ITEM); - item->ri_buf = kmem_zalloc((item->ri_total * - sizeof(xfs_log_iovec_t)), KM_SLEEP); + if (in_f->ilf_size == 0 || + in_f->ilf_size > XLOG_MAX_REGIONS_IN_ITEM) { + xlog_warn( + "XFS: bad number of regions (%d) in inode log format", + in_f->ilf_size); + ASSERT(0); + return XFS_ERROR(EIO); + } + + item->ri_total = in_f->ilf_size; + item->ri_buf = + kmem_zalloc(item->ri_total * sizeof(xfs_log_iovec_t), + KM_SLEEP); } ASSERT(item->ri_total > item->ri_cnt); /* Description region is ri_buf[0] */ |