From 220b5284139be6ecbc39b353fd76f0923eccc3d6 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Tue, 14 Mar 2006 13:33:36 +1100 Subject: [PATCH] [XFS] Dynamically allocate vattr in places it makes sense to do so, to reduce stack use. Also re-use vattr in some places so that multiple copies are not held on-stack. SGI-PV: 947312 SGI-Modid: xfs-linux-melb:xfs-kern:25369a Signed-off-by: Nathan Scott --- fs/xfs/linux-2.6/xfs_file.c | 13 ++- fs/xfs/linux-2.6/xfs_ioctl.c | 128 +++++++++++++++---------- fs/xfs/linux-2.6/xfs_iops.c | 180 ++++++++++++++++++++--------------- fs/xfs/linux-2.6/xfs_vnode.c | 29 +++--- fs/xfs/linux-2.6/xfs_vnode.h | 1 + 5 files changed, 209 insertions(+), 142 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 269995ddfb..ce8fe40e16 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -420,7 +420,7 @@ linvfs_file_mmap( { struct inode *ip = filp->f_dentry->d_inode; vnode_t *vp = LINVFS_GET_VP(ip); - vattr_t va = { .va_mask = XFS_AT_UPDATIME }; + vattr_t *vattr; int error; vma->vm_ops = &linvfs_file_vm_ops; @@ -431,9 +431,14 @@ linvfs_file_mmap( } #endif /* CONFIG_XFS_DMAPI */ - VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error); - if (!error) - vn_revalidate(vp); /* update Linux inode flags */ + vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); + if (unlikely(!vattr)) + return -ENOMEM; + vattr->va_mask = XFS_AT_UPDATIME; + VOP_SETATTR(vp, vattr, XFS_AT_UPDATIME, NULL, error); + if (likely(!error)) + __vn_revalidate(vp, vattr); /* update flags */ + kfree(vattr); return 0; } diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 4db4779041..f182721ec9 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -1160,105 +1160,129 @@ xfs_ioc_xattr( void __user *arg) { struct fsxattr fa; - vattr_t va; - int error; + struct vattr *vattr; + int error = 0; int attr_flags; unsigned int flags; + vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); + if (unlikely(!vattr)) + return -ENOMEM; + switch (cmd) { case XFS_IOC_FSGETXATTR: { - va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ - XFS_AT_NEXTENTS | XFS_AT_PROJID; - VOP_GETATTR(vp, &va, 0, NULL, error); - if (error) - return -error; + vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ + XFS_AT_NEXTENTS | XFS_AT_PROJID; + VOP_GETATTR(vp, vattr, 0, NULL, error); + if (unlikely(error)) { + error = -error; + break; + } - fa.fsx_xflags = va.va_xflags; - fa.fsx_extsize = va.va_extsize; - fa.fsx_nextents = va.va_nextents; - fa.fsx_projid = va.va_projid; + fa.fsx_xflags = vattr->va_xflags; + fa.fsx_extsize = vattr->va_extsize; + fa.fsx_nextents = vattr->va_nextents; + fa.fsx_projid = vattr->va_projid; - if (copy_to_user(arg, &fa, sizeof(fa))) - return -XFS_ERROR(EFAULT); - return 0; + if (copy_to_user(arg, &fa, sizeof(fa))) { + error = -EFAULT; + break; + } + break; } case XFS_IOC_FSSETXATTR: { - if (copy_from_user(&fa, arg, sizeof(fa))) - return -XFS_ERROR(EFAULT); + if (copy_from_user(&fa, arg, sizeof(fa))) { + error = -EFAULT; + break; + } attr_flags = 0; if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) attr_flags |= ATTR_NONBLOCK; - va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID; - va.va_xflags = fa.fsx_xflags; - va.va_extsize = fa.fsx_extsize; - va.va_projid = fa.fsx_projid; + vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID; + vattr->va_xflags = fa.fsx_xflags; + vattr->va_extsize = fa.fsx_extsize; + vattr->va_projid = fa.fsx_projid; - VOP_SETATTR(vp, &va, attr_flags, NULL, error); - if (!error) - vn_revalidate(vp); /* update Linux inode flags */ - return -error; + VOP_SETATTR(vp, vattr, attr_flags, NULL, error); + if (likely(!error)) + __vn_revalidate(vp, vattr); /* update flags */ + error = -error; + break; } case XFS_IOC_FSGETXATTRA: { - va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ - XFS_AT_ANEXTENTS | XFS_AT_PROJID; - VOP_GETATTR(vp, &va, 0, NULL, error); - if (error) - return -error; + vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ + XFS_AT_ANEXTENTS | XFS_AT_PROJID; + VOP_GETATTR(vp, vattr, 0, NULL, error); + if (unlikely(error)) { + error = -error; + break; + } - fa.fsx_xflags = va.va_xflags; - fa.fsx_extsize = va.va_extsize; - fa.fsx_nextents = va.va_anextents; - fa.fsx_projid = va.va_projid; + fa.fsx_xflags = vattr->va_xflags; + fa.fsx_extsize = vattr->va_extsize; + fa.fsx_nextents = vattr->va_anextents; + fa.fsx_projid = vattr->va_projid; - if (copy_to_user(arg, &fa, sizeof(fa))) - return -XFS_ERROR(EFAULT); - return 0; + if (copy_to_user(arg, &fa, sizeof(fa))) { + error = -EFAULT; + break; + } + break; } case XFS_IOC_GETXFLAGS: { flags = xfs_di2lxflags(ip->i_d.di_flags); if (copy_to_user(arg, &flags, sizeof(flags))) - return -XFS_ERROR(EFAULT); - return 0; + error = -EFAULT; + break; } case XFS_IOC_SETXFLAGS: { - if (copy_from_user(&flags, arg, sizeof(flags))) - return -XFS_ERROR(EFAULT); + if (copy_from_user(&flags, arg, sizeof(flags))) { + error = -EFAULT; + break; + } if (flags & ~(LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \ LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \ - LINUX_XFLAG_SYNC)) - return -XFS_ERROR(EOPNOTSUPP); + LINUX_XFLAG_SYNC)) { + error = -EOPNOTSUPP; + break; + } attr_flags = 0; if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) attr_flags |= ATTR_NONBLOCK; - va.va_mask = XFS_AT_XFLAGS; - va.va_xflags = xfs_merge_ioc_xflags(flags, - xfs_ip2xflags(ip)); + vattr->va_mask = XFS_AT_XFLAGS; + vattr->va_xflags = xfs_merge_ioc_xflags(flags, + xfs_ip2xflags(ip)); - VOP_SETATTR(vp, &va, attr_flags, NULL, error); - if (!error) - vn_revalidate(vp); /* update Linux inode flags */ - return -error; + VOP_SETATTR(vp, vattr, attr_flags, NULL, error); + if (likely(!error)) + __vn_revalidate(vp, vattr); /* update flags */ + error = -error; + break; } case XFS_IOC_GETVERSION: { flags = LINVFS_GET_IP(vp)->i_generation; if (copy_to_user(arg, &flags, sizeof(flags))) - return -XFS_ERROR(EFAULT); - return 0; + error = -EFAULT; + break; } default: - return -ENOTTY; + error = -ENOTTY; + break; } + + kfree(vattr); + return error; } STATIC int diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index d7f6f2d8ac..b1219195c6 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -198,22 +198,22 @@ xfs_ichgtime_fast( * Pull the link count and size up from the xfs inode to the linux inode */ STATIC void -validate_fields( - struct inode *ip) +__linvfs_validate_fields( + struct inode *ip, + struct vattr *vattr) { vnode_t *vp = LINVFS_GET_VP(ip); - vattr_t va; int error; - va.va_mask = XFS_AT_NLINK|XFS_AT_SIZE|XFS_AT_NBLOCKS; - VOP_GETATTR(vp, &va, ATTR_LAZY, NULL, error); - if (likely(!error)) { - ip->i_nlink = va.va_nlink; - ip->i_blocks = va.va_nblocks; + vattr->va_mask = XFS_AT_NLINK|XFS_AT_SIZE|XFS_AT_NBLOCKS; + VOP_GETATTR(vp, vattr, ATTR_LAZY, NULL, error); + if (likely(!error)) { + ip->i_nlink = vattr->va_nlink; + ip->i_blocks = vattr->va_nblocks; - /* we're under i_mutex so i_size can't change under us */ - if (i_size_read(ip) != va.va_size) - i_size_write(ip, va.va_size); + /* we're under i_sem so i_size can't change under us */ + if (i_size_read(ip) != vattr->va_size) + i_size_write(ip, vattr->va_size); } } @@ -224,7 +224,7 @@ validate_fields( * inode, of course, such that log replay can't cause these to be lost). */ STATIC int -linvfs_init_security( +__linvfs_init_security( struct vnode *vp, struct inode *dir) { @@ -257,23 +257,23 @@ linvfs_init_security( * XXX(hch): nfsd is broken, better fix it instead. */ STATIC inline int -has_fs_struct(struct task_struct *task) +__linvfs_has_fs_struct(struct task_struct *task) { return (task->fs != init_task.fs); } STATIC inline void -cleanup_inode( +__linvfs_cleanup_inode( vnode_t *dvp, vnode_t *vp, - struct dentry *dentry, + struct dentry *dentry, int mode) { struct dentry teardown = {}; - int err2; + int error; /* Oh, the horror. - * If we can't add the ACL or we fail in + * If we can't add the ACL or we fail in * linvfs_init_security we must back out. * ENOSPC can hit here, among other things. */ @@ -281,9 +281,9 @@ cleanup_inode( teardown.d_name = dentry->d_name; if (S_ISDIR(mode)) - VOP_RMDIR(dvp, &teardown, NULL, err2); + VOP_RMDIR(dvp, &teardown, NULL, error); else - VOP_REMOVE(dvp, &teardown, NULL, err2); + VOP_REMOVE(dvp, &teardown, NULL, error); VN_RELE(vp); } @@ -295,7 +295,7 @@ linvfs_mknod( dev_t rdev) { struct inode *ip; - vattr_t va; + vattr_t *vattr; vnode_t *vp = NULL, *dvp = LINVFS_GET_VP(dir); xfs_acl_t *default_acl = NULL; attrexists_t test_default_acl = _ACL_DEFAULT_EXISTS; @@ -305,70 +305,76 @@ linvfs_mknod( * Irix uses Missed'em'V split, but doesn't want to see * the upper 5 bits of (14bit) major. */ - if (!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff) + if (unlikely(!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff)) return -EINVAL; - if (test_default_acl && test_default_acl(dvp)) { - if (!_ACL_ALLOC(default_acl)) + vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); + if (unlikely(!vattr)) + return -ENOMEM; + + if (unlikely(test_default_acl && test_default_acl(dvp))) { + if (!_ACL_ALLOC(default_acl)) { + kfree(vattr); return -ENOMEM; + } if (!_ACL_GET_DEFAULT(dvp, default_acl)) { _ACL_FREE(default_acl); default_acl = NULL; } } - if (IS_POSIXACL(dir) && !default_acl && has_fs_struct(current)) + if (IS_POSIXACL(dir) && !default_acl && __linvfs_has_fs_struct(current)) mode &= ~current->fs->umask; - memset(&va, 0, sizeof(va)); - va.va_mask = XFS_AT_TYPE|XFS_AT_MODE; - va.va_mode = mode; + memset(vattr, 0, sizeof(*vattr)); + vattr->va_mask = XFS_AT_TYPE|XFS_AT_MODE; + vattr->va_mode = mode; switch (mode & S_IFMT) { case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: - va.va_rdev = sysv_encode_dev(rdev); - va.va_mask |= XFS_AT_RDEV; + vattr->va_rdev = sysv_encode_dev(rdev); + vattr->va_mask |= XFS_AT_RDEV; /*FALLTHROUGH*/ case S_IFREG: - VOP_CREATE(dvp, dentry, &va, &vp, NULL, error); + VOP_CREATE(dvp, dentry, vattr, &vp, NULL, error); break; case S_IFDIR: - VOP_MKDIR(dvp, dentry, &va, &vp, NULL, error); + VOP_MKDIR(dvp, dentry, vattr, &vp, NULL, error); break; default: error = EINVAL; break; } - if (!error) - { - error = linvfs_init_security(vp, dir); + if (unlikely(!error)) { + error = __linvfs_init_security(vp, dir); if (error) - cleanup_inode(dvp, vp, dentry, mode); + __linvfs_cleanup_inode(dvp, vp, dentry, mode); } - if (default_acl) { + if (unlikely(default_acl)) { if (!error) { - error = _ACL_INHERIT(vp, &va, default_acl); - if (!error) + error = _ACL_INHERIT(vp, vattr, default_acl); + if (!error) VMODIFY(vp); else - cleanup_inode(dvp, vp, dentry, mode); + __linvfs_cleanup_inode(dvp, vp, dentry, mode); } _ACL_FREE(default_acl); } - if (!error) { + if (likely(!error)) { ASSERT(vp); ip = LINVFS_GET_IP(vp); if (S_ISCHR(mode) || S_ISBLK(mode)) ip->i_rdev = rdev; else if (S_ISDIR(mode)) - validate_fields(ip); + __linvfs_validate_fields(ip, vattr); d_instantiate(dentry, ip); - validate_fields(dir); + __linvfs_validate_fields(dir, vattr); } + kfree(vattr); return -error; } @@ -423,22 +429,28 @@ linvfs_link( struct inode *ip; /* inode of guy being linked to */ vnode_t *tdvp; /* target directory for new name/link */ vnode_t *vp; /* vp of name being linked */ + vattr_t *vattr; int error; ip = old_dentry->d_inode; /* inode being linked to */ if (S_ISDIR(ip->i_mode)) return -EPERM; + vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); + if (unlikely(!vattr)) + return -ENOMEM; + tdvp = LINVFS_GET_VP(dir); vp = LINVFS_GET_VP(ip); VOP_LINK(tdvp, vp, dentry, NULL, error); - if (!error) { + if (likely(!error)) { VMODIFY(tdvp); VN_HOLD(vp); - validate_fields(ip); + __linvfs_validate_fields(ip, vattr); d_instantiate(dentry, ip); } + kfree(vattr); return -error; } @@ -449,17 +461,22 @@ linvfs_unlink( { struct inode *inode; vnode_t *dvp; /* directory containing name to remove */ + vattr_t *vattr; int error; + vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); + if (unlikely(!vattr)) + return -ENOMEM; + inode = dentry->d_inode; dvp = LINVFS_GET_VP(dir); VOP_REMOVE(dvp, dentry, NULL, error); - if (!error) { - validate_fields(dir); /* For size only */ - validate_fields(inode); + if (likely(!error)) { + __linvfs_validate_fields(dir, vattr); /* size needs update */ + __linvfs_validate_fields(inode, vattr); } - + kfree(vattr); return -error; } @@ -470,7 +487,7 @@ linvfs_symlink( const char *symname) { struct inode *ip; - vattr_t va; + vattr_t *vattr; vnode_t *dvp; /* directory containing name of symlink */ vnode_t *cvp; /* used to lookup symlink to put in dentry */ int error; @@ -478,22 +495,27 @@ linvfs_symlink( dvp = LINVFS_GET_VP(dir); cvp = NULL; - memset(&va, 0, sizeof(va)); - va.va_mode = S_IFLNK | + vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); + if (unlikely(!vattr)) + return -ENOMEM; + + memset(vattr, 0, sizeof(*vattr)); + vattr->va_mode = S_IFLNK | (irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO); - va.va_mask = XFS_AT_TYPE|XFS_AT_MODE; + vattr->va_mask = XFS_AT_TYPE|XFS_AT_MODE; error = 0; - VOP_SYMLINK(dvp, dentry, &va, (char *)symname, &cvp, NULL, error); + VOP_SYMLINK(dvp, dentry, vattr, (char *)symname, &cvp, NULL, error); if (likely(!error && cvp)) { - error = linvfs_init_security(cvp, dir); + error = __linvfs_init_security(cvp, dir); if (likely(!error)) { ip = LINVFS_GET_IP(cvp); d_instantiate(dentry, ip); - validate_fields(dir); - validate_fields(ip); + __linvfs_validate_fields(dir, vattr); + __linvfs_validate_fields(ip, vattr); } } + kfree(vattr); return -error; } @@ -504,13 +526,19 @@ linvfs_rmdir( { struct inode *inode = dentry->d_inode; vnode_t *dvp = LINVFS_GET_VP(dir); + vattr_t *vattr; int error; + vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); + if (unlikely(!vattr)) + return -ENOMEM; + VOP_RMDIR(dvp, dentry, NULL, error); - if (!error) { - validate_fields(inode); - validate_fields(dir); + if (likely(!error)) { + __linvfs_validate_fields(inode, vattr); + __linvfs_validate_fields(dir, vattr); } + kfree(vattr); return -error; } @@ -524,22 +552,26 @@ linvfs_rename( struct inode *new_inode = ndentry->d_inode; vnode_t *fvp; /* from directory */ vnode_t *tvp; /* target directory */ + vattr_t *vattr; int error; + vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); + if (unlikely(!vattr)) + return -ENOMEM; + fvp = LINVFS_GET_VP(odir); tvp = LINVFS_GET_VP(ndir); VOP_RENAME(fvp, odentry, tvp, ndentry, NULL, error); - if (error) - return -error; - - if (new_inode) - validate_fields(new_inode); - - validate_fields(odir); - if (ndir != odir) - validate_fields(ndir); - return 0; + if (likely(!error)) { + if (new_inode) + __linvfs_validate_fields(new_inode, vattr); + __linvfs_validate_fields(odir, vattr); + if (ndir != odir) + __linvfs_validate_fields(ndir, vattr); + } + kfree(vattr); + return -error; } /* @@ -653,11 +685,10 @@ linvfs_setattr( struct inode *inode = dentry->d_inode; unsigned int ia_valid = attr->ia_valid; vnode_t *vp = LINVFS_GET_VP(inode); - vattr_t vattr; + vattr_t vattr = { 0 }; int flags = 0; int error; - memset(&vattr, 0, sizeof(vattr_t)); if (ia_valid & ATTR_UID) { vattr.va_mask |= XFS_AT_UID; vattr.va_uid = attr->ia_uid; @@ -699,10 +730,9 @@ linvfs_setattr( #endif VOP_SETATTR(vp, &vattr, flags, NULL, error); - if (error) - return -error; - vn_revalidate(vp); - return error; + if (likely(!error)) + __vn_revalidate(vp, &vattr); + return -error; } STATIC void diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c index 260dd8415d..225e7dd8b2 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.c +++ b/fs/xfs/linux-2.6/xfs_vnode.c @@ -83,7 +83,7 @@ vn_initialize( vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP); #endif /* XFS_VNODE_TRACE */ - vn_trace_exit(vp, "vn_initialize", (inst_t *)__return_address); + vn_trace_exit(vp, __FUNCTION__, (inst_t *)__return_address); return vp; } @@ -129,24 +129,31 @@ vn_revalidate_core( * Revalidate the Linux inode from the vnode. */ int -vn_revalidate( - struct vnode *vp) +__vn_revalidate( + struct vnode *vp, + struct vattr *vattr) { - vattr_t va; int error; - vn_trace_entry(vp, "vn_revalidate", (inst_t *)__return_address); - ASSERT(vp->v_fbhv != NULL); - - va.va_mask = XFS_AT_STAT|XFS_AT_XFLAGS; - VOP_GETATTR(vp, &va, 0, NULL, error); - if (!error) { - vn_revalidate_core(vp, &va); + vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); + vattr->va_mask = XFS_AT_STAT | XFS_AT_XFLAGS; + VOP_GETATTR(vp, vattr, 0, NULL, error); + if (likely(!error)) { + vn_revalidate_core(vp, vattr); VUNMODIFY(vp); } return -error; } +int +vn_revalidate( + struct vnode *vp) +{ + vattr_t vattr; + + return __vn_revalidate(vp, &vattr); +} + /* * Add a reference to a referenced vnode. */ diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 0fe2419461..0cf92ca80c 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h @@ -490,6 +490,7 @@ typedef struct vnode_map { (vmap).v_ino = (vp)->v_inode.i_ino; } extern int vn_revalidate(struct vnode *); +extern int __vn_revalidate(struct vnode *, vattr_t *); extern void vn_revalidate_core(struct vnode *, vattr_t *); extern void vn_iowait(struct vnode *vp); -- 2.20.1