From e6305c43eda10ebfd2ad9e35d6e172ccc7bb3695 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 15 Jul 2008 21:03:57 -0400 Subject: [PATCH] sanitize ->permission() prototype * kill nameidata * argument; map the 3 bits in ->flags anybody cares about to new MAY_... ones and pass with the mask. * kill redundant gfs2_iop_permission() * sanitize ecryptfs_permission() * fix remaining places where ->permission() instances might barf on new MAY_... found in mask. The obvious next target in that direction is permission(9) folded fix for nfs_permission() breakage from Miklos Szeredi Signed-off-by: Al Viro --- fs/xfs/linux-2.6/xfs_iops.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'fs/xfs/linux-2.6/xfs_iops.c') diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 2bf287ef548..5fc61c824bb 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -589,8 +589,7 @@ xfs_check_acl( STATIC int xfs_vn_permission( struct inode *inode, - int mask, - struct nameidata *nd) + int mask) { return generic_permission(inode, mask, xfs_check_acl); } -- cgit v1.2.3-70-g09d2 From 911ee3de3d1cb6620e2ac4e0678ff434867e2644 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 19 May 2008 16:34:34 +1000 Subject: [XFS] Kill attr_capable checks as already done in xattr_permission. No need for addition permission checks in the xattr handler, fs/xattr.c:xattr_permission() already does them, and in fact slightly more strict then what was in the attr_capable handlers. SGI-PV: 981809 SGI-Modid: xfs-linux-melb:xfs-kern:31164a Signed-off-by: Christoph Hellwig Signed-off-by: Tim Shimmin Signed-off-by: Lachlan McIlroy --- fs/xfs/linux-2.6/xfs_iops.c | 13 +------------ fs/xfs/xfs_attr.c | 41 ----------------------------------------- fs/xfs/xfs_attr.h | 2 -- 3 files changed, 1 insertion(+), 55 deletions(-) (limited to 'fs/xfs/linux-2.6/xfs_iops.c') diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 5fc61c824bb..13b6cfd366c 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -739,15 +739,11 @@ xfs_vn_setxattr( char *attr = (char *)name; attrnames_t *namesp; int xflags = 0; - int error; namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); if (!namesp) return -EOPNOTSUPP; attr += namesp->attr_namelen; - error = namesp->attr_capable(vp, NULL); - if (error) - return error; /* Convert Linux syscall to XFS internal ATTR flags */ if (flags & XATTR_CREATE) @@ -769,15 +765,11 @@ xfs_vn_getxattr( char *attr = (char *)name; attrnames_t *namesp; int xflags = 0; - ssize_t error; namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); if (!namesp) return -EOPNOTSUPP; attr += namesp->attr_namelen; - error = namesp->attr_capable(vp, NULL); - if (error) - return error; /* Convert Linux syscall to XFS internal ATTR flags */ if (!size) { @@ -817,15 +809,12 @@ xfs_vn_removexattr( char *attr = (char *)name; attrnames_t *namesp; int xflags = 0; - int error; namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); if (!namesp) return -EOPNOTSUPP; attr += namesp->attr_namelen; - error = namesp->attr_capable(vp, NULL); - if (error) - return error; + xflags |= namesp->attr_flag; return namesp->attr_remove(vp, attr, xflags); } diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index df151a85918..86d8619f279 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -2622,43 +2622,6 @@ attr_lookup_namespace( return NULL; } -/* - * Some checks to prevent people abusing EAs to get over quota: - * - Don't allow modifying user EAs on devices/symlinks; - * - Don't allow modifying user EAs if sticky bit set; - */ -STATIC int -attr_user_capable( - bhv_vnode_t *vp, - cred_t *cred) -{ - struct inode *inode = vn_to_inode(vp); - - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; - if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) && - !capable(CAP_SYS_ADMIN)) - return -EPERM; - if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && - (current_fsuid(cred) != inode->i_uid) && !capable(CAP_FOWNER)) - return -EPERM; - return 0; -} - -STATIC int -attr_trusted_capable( - bhv_vnode_t *vp, - cred_t *cred) -{ - struct inode *inode = vn_to_inode(vp); - - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - return 0; -} - STATIC int attr_system_set( bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) @@ -2709,7 +2672,6 @@ struct attrnames attr_system = { .attr_get = attr_system_get, .attr_set = attr_system_set, .attr_remove = attr_system_remove, - .attr_capable = (attrcapable_t)fs_noerr, }; struct attrnames attr_trusted = { @@ -2719,7 +2681,6 @@ struct attrnames attr_trusted = { .attr_get = attr_generic_get, .attr_set = attr_generic_set, .attr_remove = attr_generic_remove, - .attr_capable = attr_trusted_capable, }; struct attrnames attr_secure = { @@ -2729,7 +2690,6 @@ struct attrnames attr_secure = { .attr_get = attr_generic_get, .attr_set = attr_generic_set, .attr_remove = attr_generic_remove, - .attr_capable = (attrcapable_t)fs_noerr, }; struct attrnames attr_user = { @@ -2738,7 +2698,6 @@ struct attrnames attr_user = { .attr_get = attr_generic_get, .attr_set = attr_generic_set, .attr_remove = attr_generic_remove, - .attr_capable = attr_user_capable, }; struct attrnames *attr_namespaces[] = diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h index 6cfc9384fe3..9b96d171b75 100644 --- a/fs/xfs/xfs_attr.h +++ b/fs/xfs/xfs_attr.h @@ -42,7 +42,6 @@ typedef int (*attrset_t)(bhv_vnode_t *, char *, void *, size_t, int); typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int); typedef int (*attrremove_t)(bhv_vnode_t *, char *, int); typedef int (*attrexists_t)(bhv_vnode_t *); -typedef int (*attrcapable_t)(bhv_vnode_t *, struct cred *); typedef struct attrnames { char * attr_name; @@ -52,7 +51,6 @@ typedef struct attrnames { attrset_t attr_set; attrremove_t attr_remove; attrexists_t attr_exists; - attrcapable_t attr_capable; } attrnames_t; #define ATTR_NAMECOUNT 4 -- cgit v1.2.3-70-g09d2 From 384f3ced07efdddf6838f6527366089d37843c94 Mon Sep 17 00:00:00 2001 From: Barry Naujok Date: Wed, 21 May 2008 16:58:22 +1000 Subject: [XFS] Return case-insensitive match for dentry cache This implements the code to store the actual filename found during a lookup in the dentry cache and to avoid multiple entries in the dcache pointing to the same inode. To avoid polluting the dcache, we implement a new directory inode operations for lookup. xfs_vn_ci_lookup() stores the correct case name in the dcache. The "actual name" is only allocated and returned for a case- insensitive match and not an actual match. Another unusual interaction with the dcache is not storing negative dentries like other filesystems doing a d_add(dentry, NULL) when an ENOENT is returned. During the VFS lookup, if a dentry returned has no inode, dput is called and ENOENT is returned. By not doing a d_add, this actually removes it completely from the dcache to be reused. create/rename have to be modified to support unhashed dentries being passed in. SGI-PV: 981521 SGI-Modid: xfs-linux-melb:xfs-kern:31208a Signed-off-by: Barry Naujok Signed-off-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_export.c | 2 +- fs/xfs/linux-2.6/xfs_iops.c | 57 ++++++++++++++++++++++++++++++++++++++++++- fs/xfs/linux-2.6/xfs_iops.h | 1 + fs/xfs/xfs_da_btree.h | 1 + fs/xfs/xfs_dir2.c | 40 ++++++++++++++++++++++++++++-- fs/xfs/xfs_dir2.h | 6 ++++- fs/xfs/xfs_dir2_block.c | 9 ++++--- fs/xfs/xfs_dir2_leaf.c | 5 ++-- fs/xfs/xfs_dir2_node.c | 16 ++++++++---- fs/xfs/xfs_dir2_sf.c | 17 +++++++------ fs/xfs/xfs_vnodeops.c | 19 +++++++++++---- fs/xfs/xfs_vnodeops.h | 2 +- 12 files changed, 146 insertions(+), 29 deletions(-) (limited to 'fs/xfs/linux-2.6/xfs_iops.c') diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c index c672b3238b1..987fe84f7b1 100644 --- a/fs/xfs/linux-2.6/xfs_export.c +++ b/fs/xfs/linux-2.6/xfs_export.c @@ -215,7 +215,7 @@ xfs_fs_get_parent( struct xfs_inode *cip; struct dentry *parent; - error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip); + error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip, NULL); if (unlikely(error)) return ERR_PTR(-error); diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 13b6cfd366c..9f0f8ee8d44 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -382,7 +382,7 @@ xfs_vn_lookup( return ERR_PTR(-ENAMETOOLONG); xfs_dentry_to_name(&name, dentry); - error = xfs_lookup(XFS_I(dir), &name, &cip); + error = xfs_lookup(XFS_I(dir), &name, &cip, NULL); if (unlikely(error)) { if (unlikely(error != ENOENT)) return ERR_PTR(-error); @@ -393,6 +393,42 @@ xfs_vn_lookup( return d_splice_alias(cip->i_vnode, dentry); } +STATIC struct dentry * +xfs_vn_ci_lookup( + struct inode *dir, + struct dentry *dentry, + struct nameidata *nd) +{ + struct xfs_inode *ip; + struct xfs_name xname; + struct xfs_name ci_name; + struct qstr dname; + int error; + + if (dentry->d_name.len >= MAXNAMELEN) + return ERR_PTR(-ENAMETOOLONG); + + xfs_dentry_to_name(&xname, dentry); + error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name); + if (unlikely(error)) { + if (unlikely(error != ENOENT)) + return ERR_PTR(-error); + d_add(dentry, NULL); + return NULL; + } + + /* if exact match, just splice and exit */ + if (!ci_name.name) + return d_splice_alias(ip->i_vnode, dentry); + + /* else case-insensitive match... */ + dname.name = ci_name.name; + dname.len = ci_name.len; + dentry = d_add_ci(ip->i_vnode, dentry, &dname); + kmem_free(ci_name.name); + return dentry; +} + STATIC int xfs_vn_link( struct dentry *old_dentry, @@ -892,6 +928,25 @@ const struct inode_operations xfs_dir_inode_operations = { .removexattr = xfs_vn_removexattr, }; +const struct inode_operations xfs_dir_ci_inode_operations = { + .create = xfs_vn_create, + .lookup = xfs_vn_ci_lookup, + .link = xfs_vn_link, + .unlink = xfs_vn_unlink, + .symlink = xfs_vn_symlink, + .mkdir = xfs_vn_mkdir, + .rmdir = xfs_vn_rmdir, + .mknod = xfs_vn_mknod, + .rename = xfs_vn_rename, + .permission = xfs_vn_permission, + .getattr = xfs_vn_getattr, + .setattr = xfs_vn_setattr, + .setxattr = xfs_vn_setxattr, + .getxattr = xfs_vn_getxattr, + .listxattr = xfs_vn_listxattr, + .removexattr = xfs_vn_removexattr, +}; + const struct inode_operations xfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = xfs_vn_follow_link, diff --git a/fs/xfs/linux-2.6/xfs_iops.h b/fs/xfs/linux-2.6/xfs_iops.h index 14d0deb7aff..3b4df5863e4 100644 --- a/fs/xfs/linux-2.6/xfs_iops.h +++ b/fs/xfs/linux-2.6/xfs_iops.h @@ -20,6 +20,7 @@ extern const struct inode_operations xfs_inode_operations; extern const struct inode_operations xfs_dir_inode_operations; +extern const struct inode_operations xfs_dir_ci_inode_operations; extern const struct inode_operations xfs_symlink_inode_operations; extern const struct file_operations xfs_file_operations; diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h index 8face64c11f..8be0b00ede9 100644 --- a/fs/xfs/xfs_da_btree.h +++ b/fs/xfs/xfs_da_btree.h @@ -143,6 +143,7 @@ typedef struct xfs_da_args { #define XFS_DA_OP_RENAME 0x0002 /* this is an atomic rename op */ #define XFS_DA_OP_ADDNAME 0x0004 /* this is an add operation */ #define XFS_DA_OP_OKNOENT 0x0008 /* lookup/add op, ENOENT ok, else die */ +#define XFS_DA_OP_CILOOKUP 0x0010 /* lookup to return CI name if found */ /* * Structure to describe buffer(s) for a block. diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index 3387acd3e47..882609c699c 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c @@ -192,15 +192,44 @@ xfs_dir_createname( return rval; } +/* + * If doing a CI lookup and case-insensitive match, dup actual name into + * args.value. Return EEXIST for success (ie. name found) or an error. + */ +int +xfs_dir_cilookup_result( + struct xfs_da_args *args, + const char *name, + int len) +{ + if (args->cmpresult == XFS_CMP_DIFFERENT) + return ENOENT; + if (args->cmpresult != XFS_CMP_CASE || + !(args->op_flags & XFS_DA_OP_CILOOKUP)) + return EEXIST; + + args->value = kmem_alloc(len, KM_MAYFAIL); + if (!args->value) + return ENOMEM; + + memcpy(args->value, name, len); + args->valuelen = len; + return EEXIST; +} + /* * Lookup a name in a directory, give back the inode number. + * If ci_name is not NULL, returns the actual name in ci_name if it differs + * to name, or ci_name->name is set to NULL for an exact match. */ + int xfs_dir_lookup( xfs_trans_t *tp, xfs_inode_t *dp, struct xfs_name *name, - xfs_ino_t *inum) /* out: inode number */ + xfs_ino_t *inum, /* out: inode number */ + struct xfs_name *ci_name) /* out: actual name if CI match */ { xfs_da_args_t args; int rval; @@ -217,6 +246,8 @@ xfs_dir_lookup( args.whichfork = XFS_DATA_FORK; args.trans = tp; args.op_flags = XFS_DA_OP_OKNOENT; + if (ci_name) + args.op_flags |= XFS_DA_OP_CILOOKUP; args.cmpresult = XFS_CMP_DIFFERENT; if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) @@ -233,8 +264,13 @@ xfs_dir_lookup( rval = xfs_dir2_node_lookup(&args); if (rval == EEXIST) rval = 0; - if (rval == 0) + if (!rval) { *inum = args.inumber; + if (ci_name) { + ci_name->name = args.value; + ci_name->len = args.valuelen; + } + } return rval; } diff --git a/fs/xfs/xfs_dir2.h b/fs/xfs/xfs_dir2.h index 6392f939029..1d9ef96f33a 100644 --- a/fs/xfs/xfs_dir2.h +++ b/fs/xfs/xfs_dir2.h @@ -74,7 +74,8 @@ extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp, xfs_fsblock_t *first, struct xfs_bmap_free *flist, xfs_extlen_t tot); extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp, - struct xfs_name *name, xfs_ino_t *inum); + struct xfs_name *name, xfs_ino_t *inum, + struct xfs_name *ci_name); extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name, xfs_ino_t ino, xfs_fsblock_t *first, @@ -99,4 +100,7 @@ extern int xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp, extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, struct xfs_dabuf *bp); +extern int xfs_dir_cilookup_result(struct xfs_da_args *args, const char *name, + int len); + #endif /* __XFS_DIR2_H__ */ diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c index dee225918db..e2fa0a1d8e9 100644 --- a/fs/xfs/xfs_dir2_block.c +++ b/fs/xfs/xfs_dir2_block.c @@ -610,14 +610,15 @@ xfs_dir2_block_lookup( /* * Get the offset from the leaf entry, to point to the data. */ - dep = (xfs_dir2_data_entry_t *) - ((char *)block + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address))); + dep = (xfs_dir2_data_entry_t *)((char *)block + + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address))); /* - * Fill in inode number, release the block. + * Fill in inode number, CI name if appropriate, release the block. */ args->inumber = be64_to_cpu(dep->inumber); + error = xfs_dir_cilookup_result(args, dep->name, dep->namelen); xfs_da_brelse(args->trans, bp); - return XFS_ERROR(EEXIST); + return XFS_ERROR(error); } /* diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index 2ebbed4f1b0..f110242d6df 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c @@ -1299,12 +1299,13 @@ xfs_dir2_leaf_lookup( ((char *)dbp->data + xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address))); /* - * Return the found inode number. + * Return the found inode number & CI name if appropriate */ args->inumber = be64_to_cpu(dep->inumber); + error = xfs_dir_cilookup_result(args, dep->name, dep->namelen); xfs_da_brelse(tp, dbp); xfs_da_brelse(tp, lbp); - return XFS_ERROR(EEXIST); + return XFS_ERROR(error); } /* diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c index c71cff85950..1b543022346 100644 --- a/fs/xfs/xfs_dir2_node.c +++ b/fs/xfs/xfs_dir2_node.c @@ -549,7 +549,7 @@ xfs_dir2_leafn_lookup_for_entry( xfs_dir2_data_entry_t *dep; /* data block entry */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ - int di; /* data entry index */ + int di = -1; /* data entry index */ int index; /* leaf entry index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ @@ -577,6 +577,7 @@ xfs_dir2_leafn_lookup_for_entry( if (state->extravalid) { curbp = state->extrablk.bp; curdb = state->extrablk.blkno; + di = state->extrablk.index; } /* * Loop over leaf entries with the right hash value. @@ -637,7 +638,6 @@ xfs_dir2_leafn_lookup_for_entry( } /* Didn't find an exact match. */ error = ENOENT; - di = -1; ASSERT(index == be16_to_cpu(leaf->hdr.count) || (args->op_flags & XFS_DA_OP_OKNOENT)); out: @@ -652,7 +652,7 @@ out: state->extravalid = 0; } /* - * Return the index, that will be the insertion point. + * Return the index, that will be the deletion point for remove/replace. */ *indexp = index; return XFS_ERROR(error); @@ -1820,8 +1820,14 @@ xfs_dir2_node_lookup( error = xfs_da_node_lookup_int(state, &rval); if (error) rval = error; - else if (rval == ENOENT && args->cmpresult == XFS_CMP_CASE) - rval = EEXIST; /* a case-insensitive match was found */ + else if (rval == ENOENT && args->cmpresult == XFS_CMP_CASE) { + /* If a CI match, dup the actual name and return EEXIST */ + xfs_dir2_data_entry_t *dep; + + dep = (xfs_dir2_data_entry_t *)((char *)state->extrablk.bp-> + data + state->extrablk.index); + rval = xfs_dir_cilookup_result(args, dep->name, dep->namelen); + } /* * Release the btree blocks and leaf block. */ diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c index 9409fd3e565..b46af0013ec 100644 --- a/fs/xfs/xfs_dir2_sf.c +++ b/fs/xfs/xfs_dir2_sf.c @@ -812,9 +812,11 @@ xfs_dir2_sf_lookup( { xfs_inode_t *dp; /* incore directory inode */ int i; /* entry index */ + int error; xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ xfs_dir2_sf_t *sfp; /* shortform structure */ enum xfs_dacmp cmp; /* comparison result */ + xfs_dir2_sf_entry_t *ci_sfep; /* case-insens. entry */ xfs_dir2_trace_args("sf_lookup", args); xfs_dir2_sf_check(args); @@ -852,6 +854,7 @@ xfs_dir2_sf_lookup( /* * Loop over all the entries trying to match ours. */ + ci_sfep = NULL; for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count; i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { /* @@ -867,19 +870,19 @@ xfs_dir2_sf_lookup( xfs_dir2_sf_inumberp(sfep)); if (cmp == XFS_CMP_EXACT) return XFS_ERROR(EEXIST); + ci_sfep = sfep; } } ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); /* * Here, we can only be doing a lookup (not a rename or replace). - * If a case-insensitive match was found earlier, return "found". + * If a case-insensitive match was not found, return ENOENT. */ - if (args->cmpresult == XFS_CMP_CASE) - return XFS_ERROR(EEXIST); - /* - * Didn't find it. - */ - return XFS_ERROR(ENOENT); + if (!ci_sfep) + return XFS_ERROR(ENOENT); + /* otherwise process the CI match as required by the caller */ + error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen); + return XFS_ERROR(error); } /* diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 9b8b87fcd4e..b6a065eb25a 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -1610,12 +1610,18 @@ xfs_inactive( return VN_INACTIVE_CACHE; } - +/* + * Lookups up an inode from "name". If ci_name is not NULL, then a CI match + * is allowed, otherwise it has to be an exact match. If a CI match is found, + * ci_name->name will point to a the actual name (caller must free) or + * will be set to NULL if an exact match is found. + */ int xfs_lookup( xfs_inode_t *dp, struct xfs_name *name, - xfs_inode_t **ipp) + xfs_inode_t **ipp, + struct xfs_name *ci_name) { xfs_ino_t inum; int error; @@ -1627,7 +1633,7 @@ xfs_lookup( return XFS_ERROR(EIO); lock_mode = xfs_ilock_map_shared(dp); - error = xfs_dir_lookup(NULL, dp, name, &inum); + error = xfs_dir_lookup(NULL, dp, name, &inum, ci_name); xfs_iunlock_map_shared(dp, lock_mode); if (error) @@ -1635,12 +1641,15 @@ xfs_lookup( error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp, 0); if (error) - goto out; + goto out_free_name; xfs_itrace_ref(*ipp); return 0; - out: +out_free_name: + if (ci_name) + kmem_free(ci_name->name); +out: *ipp = NULL; return error; } diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index 57335ba4ce5..7e9a8b241f2 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h @@ -22,7 +22,7 @@ int xfs_fsync(struct xfs_inode *ip); int xfs_release(struct xfs_inode *ip); int xfs_inactive(struct xfs_inode *ip); int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, - struct xfs_inode **ipp); + struct xfs_inode **ipp, struct xfs_name *ci_name); int xfs_create(struct xfs_inode *dp, struct xfs_name *name, mode_t mode, xfs_dev_t rdev, struct xfs_inode **ipp, struct cred *credp); int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, -- cgit v1.2.3-70-g09d2 From 866d5dc974682c6247d5fde94dbc6545f864e7d7 Mon Sep 17 00:00:00 2001 From: Barry Naujok Date: Thu, 22 May 2008 17:21:40 +1000 Subject: [XFS] Remove d_add call for an ENOENT lookup return code SGI-PV: 981521 SGI-Modid: xfs-linux-melb:xfs-kern:31214a Signed-off-by: Barry Naujok Signed-off-by: David Chinner --- fs/xfs/linux-2.6/xfs_iops.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'fs/xfs/linux-2.6/xfs_iops.c') diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 9f0f8ee8d44..62330f28395 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -413,7 +413,11 @@ xfs_vn_ci_lookup( if (unlikely(error)) { if (unlikely(error != ENOENT)) return ERR_PTR(-error); - d_add(dentry, NULL); + /* + * call d_add(dentry, NULL) here when d_drop_negative_children + * is called in xfs_vn_mknod (ie. allow negative dentries + * with CI filesystems). + */ return NULL; } -- cgit v1.2.3-70-g09d2 From d532506cd8b59543b376e155508f88a03a81dad1 Mon Sep 17 00:00:00 2001 From: Barry Naujok Date: Mon, 16 Jun 2008 12:07:41 +1000 Subject: [XFS] Invalidate dentry in unlink/rmdir if in case-insensitive mode The vfs_unlink/d_delete functionality in the Linux VFS make the dentry negative if it is the only inode being referenced. Case-insensitive mode doesn't work with negative dentries, so if using CI-mode, invalidate the dentry on unlink/rmdir. SGI-PV: 983102 SGI-Modid: xfs-linux-melb:xfs-kern:31308a Signed-off-by: Barry Naujok Signed-off-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_iops.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'fs/xfs/linux-2.6/xfs_iops.c') diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 62330f28395..190ed61bcd4 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -475,6 +475,13 @@ xfs_vn_unlink( if (likely(!error)) { xfs_validate_fields(dir); /* size needs update */ xfs_validate_fields(inode); + /* + * With unlink, the VFS makes the dentry "negative": no inode, + * but still hashed. This is incompatible with case-insensitive + * mode, so invalidate (unhash) the dentry in CI-mode. + */ + if (xfs_sb_version_hasasciici(&XFS_M(dir->i_sb)->m_sb)) + d_invalidate(dentry); } return -error; } @@ -531,6 +538,13 @@ xfs_vn_rmdir( if (likely(!error)) { xfs_validate_fields(inode); xfs_validate_fields(dir); + /* + * With rmdir, the VFS makes the dentry "negative": no inode, + * but still hashed. This is incompatible with case-insensitive + * mode, so invalidate (unhash) the dentry in CI-mode. + */ + if (xfs_sb_version_hasasciici(&XFS_M(dir->i_sb)->m_sb)) + d_invalidate(dentry); } return -error; } -- cgit v1.2.3-70-g09d2 From 0ec585163ac81e329bde25fb6311a043a1c63952 Mon Sep 17 00:00:00 2001 From: Lachlan McIlroy Date: Mon, 23 Jun 2008 13:23:01 +1000 Subject: [XFS] Use the generic xattr methods. Use the generic set, get and removexattr methods and supply the s_xattr array with fine-grained handlers. All XFS/Linux highlevel attr handling is rewritten from scratch and placed into fs/xfs/linux-2.6/xfs_xattr.c so that it's separated from the generic low-level code. SGI-PV: 982343 SGI-Modid: xfs-linux-melb:xfs-kern:31234a Signed-off-by: Christoph Hellwig Signed-off-by: Tim Shimmin Signed-off-by: Lachlan McIlroy --- fs/xfs/Makefile | 3 +- fs/xfs/linux-2.6/xfs_iops.c | 118 +++---------------- fs/xfs/linux-2.6/xfs_iops.h | 1 + fs/xfs/linux-2.6/xfs_super.c | 1 + fs/xfs/linux-2.6/xfs_super.h | 1 + fs/xfs/xfs_attr.c | 272 ------------------------------------------- fs/xfs/xfs_attr.h | 17 --- 7 files changed, 18 insertions(+), 395 deletions(-) (limited to 'fs/xfs/linux-2.6/xfs_iops.c') diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 36ec614e699..737c9a42536 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -106,7 +106,8 @@ xfs-y += $(addprefix $(XFS_LINUX)/, \ xfs_iops.o \ xfs_lrw.o \ xfs_super.o \ - xfs_vnode.o) + xfs_vnode.o \ + xfs_xattr.o) # Objects in support/ xfs-y += $(addprefix support/, \ diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 190ed61bcd4..3ae80155de3 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -275,7 +275,7 @@ xfs_vn_mknod( struct xfs_inode *ip = NULL; xfs_acl_t *default_acl = NULL; struct xfs_name name; - attrexists_t test_default_acl = _ACL_DEFAULT_EXISTS; + int (*test_default_acl)(struct inode *) = _ACL_DEFAULT_EXISTS; int error; /* @@ -781,98 +781,6 @@ xfs_vn_truncate( WARN_ON(error); } -STATIC int -xfs_vn_setxattr( - struct dentry *dentry, - const char *name, - const void *data, - size_t size, - int flags) -{ - bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); - char *attr = (char *)name; - attrnames_t *namesp; - int xflags = 0; - - namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); - if (!namesp) - return -EOPNOTSUPP; - attr += namesp->attr_namelen; - - /* Convert Linux syscall to XFS internal ATTR flags */ - if (flags & XATTR_CREATE) - xflags |= ATTR_CREATE; - if (flags & XATTR_REPLACE) - xflags |= ATTR_REPLACE; - xflags |= namesp->attr_flag; - return namesp->attr_set(vp, attr, (void *)data, size, xflags); -} - -STATIC ssize_t -xfs_vn_getxattr( - struct dentry *dentry, - const char *name, - void *data, - size_t size) -{ - bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); - char *attr = (char *)name; - attrnames_t *namesp; - int xflags = 0; - - namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); - if (!namesp) - return -EOPNOTSUPP; - attr += namesp->attr_namelen; - - /* Convert Linux syscall to XFS internal ATTR flags */ - if (!size) { - xflags |= ATTR_KERNOVAL; - data = NULL; - } - xflags |= namesp->attr_flag; - return namesp->attr_get(vp, attr, (void *)data, size, xflags); -} - -STATIC ssize_t -xfs_vn_listxattr( - struct dentry *dentry, - char *data, - size_t size) -{ - bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); - int error, xflags = ATTR_KERNAMELS; - ssize_t result; - - if (!size) - xflags |= ATTR_KERNOVAL; - xflags |= capable(CAP_SYS_ADMIN) ? ATTR_KERNFULLS : ATTR_KERNORMALS; - - error = attr_generic_list(vp, data, size, xflags, &result); - if (error < 0) - return error; - return result; -} - -STATIC int -xfs_vn_removexattr( - struct dentry *dentry, - const char *name) -{ - bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); - char *attr = (char *)name; - attrnames_t *namesp; - int xflags = 0; - - namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); - if (!namesp) - return -EOPNOTSUPP; - attr += namesp->attr_namelen; - - xflags |= namesp->attr_flag; - return namesp->attr_remove(vp, attr, xflags); -} - STATIC long xfs_vn_fallocate( struct inode *inode, @@ -920,10 +828,10 @@ const struct inode_operations xfs_inode_operations = { .truncate = xfs_vn_truncate, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, - .setxattr = xfs_vn_setxattr, - .getxattr = xfs_vn_getxattr, + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .removexattr = generic_removexattr, .listxattr = xfs_vn_listxattr, - .removexattr = xfs_vn_removexattr, .fallocate = xfs_vn_fallocate, }; @@ -940,10 +848,10 @@ const struct inode_operations xfs_dir_inode_operations = { .permission = xfs_vn_permission, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, - .setxattr = xfs_vn_setxattr, - .getxattr = xfs_vn_getxattr, + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .removexattr = generic_removexattr, .listxattr = xfs_vn_listxattr, - .removexattr = xfs_vn_removexattr, }; const struct inode_operations xfs_dir_ci_inode_operations = { @@ -959,10 +867,10 @@ const struct inode_operations xfs_dir_ci_inode_operations = { .permission = xfs_vn_permission, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, - .setxattr = xfs_vn_setxattr, - .getxattr = xfs_vn_getxattr, + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .removexattr = generic_removexattr, .listxattr = xfs_vn_listxattr, - .removexattr = xfs_vn_removexattr, }; const struct inode_operations xfs_symlink_inode_operations = { @@ -972,8 +880,8 @@ const struct inode_operations xfs_symlink_inode_operations = { .permission = xfs_vn_permission, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, - .setxattr = xfs_vn_setxattr, - .getxattr = xfs_vn_getxattr, + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .removexattr = generic_removexattr, .listxattr = xfs_vn_listxattr, - .removexattr = xfs_vn_removexattr, }; diff --git a/fs/xfs/linux-2.6/xfs_iops.h b/fs/xfs/linux-2.6/xfs_iops.h index 3b4df5863e4..d97ba934a2a 100644 --- a/fs/xfs/linux-2.6/xfs_iops.h +++ b/fs/xfs/linux-2.6/xfs_iops.h @@ -27,6 +27,7 @@ extern const struct file_operations xfs_file_operations; extern const struct file_operations xfs_dir_file_operations; extern const struct file_operations xfs_invis_file_operations; +extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size); struct xfs_inode; extern void xfs_ichgtime(struct xfs_inode *, int); diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index cce59cc6e74..967603c4699 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -1766,6 +1766,7 @@ xfs_fs_fill_super( goto out_free_mp; sb_min_blocksize(sb, BBSIZE); + sb->s_xattr = xfs_xattr_handlers; sb->s_export_op = &xfs_export_operations; sb->s_qcop = &xfs_quotactl_operations; sb->s_op = &xfs_super_operations; diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/linux-2.6/xfs_super.h index 212bdc7a789..b7d13da01bd 100644 --- a/fs/xfs/linux-2.6/xfs_super.h +++ b/fs/xfs/linux-2.6/xfs_super.h @@ -110,6 +110,7 @@ extern void xfs_flush_device(struct xfs_inode *); extern void xfs_blkdev_issue_flush(struct xfs_buftarg *); extern const struct export_operations xfs_export_operations; +extern struct xattr_handler *xfs_xattr_handlers[]; #define XFS_M(sb) ((struct xfs_mount *)((sb)->s_fs_info)) diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 557dad611de..9d91af4929b 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -57,11 +57,6 @@ * Provide the external interfaces to manage attribute lists. */ -#define ATTR_SYSCOUNT 2 -static struct attrnames posix_acl_access; -static struct attrnames posix_acl_default; -static struct attrnames *attr_system_names[ATTR_SYSCOUNT]; - /*======================================================================== * Function prototypes for the kernel. *========================================================================*/ @@ -2378,270 +2373,3 @@ xfs_attr_trace_enter(int type, char *where, (void *)a13, (void *)a14, (void *)a15); } #endif /* XFS_ATTR_TRACE */ - - -/*======================================================================== - * System (pseudo) namespace attribute interface routines. - *========================================================================*/ - -STATIC int -posix_acl_access_set( - bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) -{ - return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS); -} - -STATIC int -posix_acl_access_remove( - bhv_vnode_t *vp, char *name, int xflags) -{ - return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); -} - -STATIC int -posix_acl_access_get( - bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) -{ - return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS); -} - -STATIC int -posix_acl_access_exists( - bhv_vnode_t *vp) -{ - return xfs_acl_vhasacl_access(vp); -} - -STATIC int -posix_acl_default_set( - bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) -{ - return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT); -} - -STATIC int -posix_acl_default_get( - bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) -{ - return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT); -} - -STATIC int -posix_acl_default_remove( - bhv_vnode_t *vp, char *name, int xflags) -{ - return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT); -} - -STATIC int -posix_acl_default_exists( - bhv_vnode_t *vp) -{ - return xfs_acl_vhasacl_default(vp); -} - -static struct attrnames posix_acl_access = { - .attr_name = "posix_acl_access", - .attr_namelen = sizeof("posix_acl_access") - 1, - .attr_get = posix_acl_access_get, - .attr_set = posix_acl_access_set, - .attr_remove = posix_acl_access_remove, - .attr_exists = posix_acl_access_exists, -}; - -static struct attrnames posix_acl_default = { - .attr_name = "posix_acl_default", - .attr_namelen = sizeof("posix_acl_default") - 1, - .attr_get = posix_acl_default_get, - .attr_set = posix_acl_default_set, - .attr_remove = posix_acl_default_remove, - .attr_exists = posix_acl_default_exists, -}; - -static struct attrnames *attr_system_names[] = - { &posix_acl_access, &posix_acl_default }; - - -/*======================================================================== - * Namespace-prefix-style attribute name interface routines. - *========================================================================*/ - -STATIC int -attr_generic_set( - bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) -{ - return -xfs_attr_set(xfs_vtoi(vp), name, data, size, xflags); -} - -STATIC int -attr_generic_get( - bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) -{ - int error, asize = size; - - error = xfs_attr_get(xfs_vtoi(vp), name, data, &asize, xflags); - if (!error) - return asize; - return -error; -} - -STATIC int -attr_generic_remove( - bhv_vnode_t *vp, char *name, int xflags) -{ - return -xfs_attr_remove(xfs_vtoi(vp), name, xflags); -} - -STATIC int -attr_generic_listadd( - attrnames_t *prefix, - attrnames_t *namesp, - void *data, - size_t size, - ssize_t *result) -{ - char *p = data + *result; - - *result += prefix->attr_namelen; - *result += namesp->attr_namelen + 1; - if (!size) - return 0; - if (*result > size) - return -ERANGE; - strcpy(p, prefix->attr_name); - p += prefix->attr_namelen; - strcpy(p, namesp->attr_name); - p += namesp->attr_namelen + 1; - return 0; -} - -STATIC int -attr_system_list( - bhv_vnode_t *vp, - void *data, - size_t size, - ssize_t *result) -{ - attrnames_t *namesp; - int i, error = 0; - - for (i = 0; i < ATTR_SYSCOUNT; i++) { - namesp = attr_system_names[i]; - if (!namesp->attr_exists || !namesp->attr_exists(vp)) - continue; - error = attr_generic_listadd(&attr_system, namesp, - data, size, result); - if (error) - break; - } - return error; -} - -int -attr_generic_list( - bhv_vnode_t *vp, void *data, size_t size, int xflags, ssize_t *result) -{ - attrlist_cursor_kern_t cursor = { 0 }; - int error; - - error = xfs_attr_list(xfs_vtoi(vp), data, size, xflags, &cursor); - if (error > 0) - return -error; - *result = -error; - return attr_system_list(vp, data, size, result); -} - -attrnames_t * -attr_lookup_namespace( - char *name, - struct attrnames **names, - int nnames) -{ - int i; - - for (i = 0; i < nnames; i++) - if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen)) - return names[i]; - return NULL; -} - -STATIC int -attr_system_set( - bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) -{ - attrnames_t *namesp; - int error; - - if (xflags & ATTR_CREATE) - return -EINVAL; - - namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); - if (!namesp) - return -EOPNOTSUPP; - error = namesp->attr_set(vp, name, data, size, xflags); - if (!error) - error = vn_revalidate(vp); - return error; -} - -STATIC int -attr_system_get( - bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) -{ - attrnames_t *namesp; - - namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); - if (!namesp) - return -EOPNOTSUPP; - return namesp->attr_get(vp, name, data, size, xflags); -} - -STATIC int -attr_system_remove( - bhv_vnode_t *vp, char *name, int xflags) -{ - attrnames_t *namesp; - - namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); - if (!namesp) - return -EOPNOTSUPP; - return namesp->attr_remove(vp, name, xflags); -} - -struct attrnames attr_system = { - .attr_name = "system.", - .attr_namelen = sizeof("system.") - 1, - .attr_flag = ATTR_SYSTEM, - .attr_get = attr_system_get, - .attr_set = attr_system_set, - .attr_remove = attr_system_remove, -}; - -struct attrnames attr_trusted = { - .attr_name = "trusted.", - .attr_namelen = sizeof("trusted.") - 1, - .attr_flag = ATTR_ROOT, - .attr_get = attr_generic_get, - .attr_set = attr_generic_set, - .attr_remove = attr_generic_remove, -}; - -struct attrnames attr_secure = { - .attr_name = "security.", - .attr_namelen = sizeof("security.") - 1, - .attr_flag = ATTR_SECURE, - .attr_get = attr_generic_get, - .attr_set = attr_generic_set, - .attr_remove = attr_generic_remove, -}; - -struct attrnames attr_user = { - .attr_name = "user.", - .attr_namelen = sizeof("user.") - 1, - .attr_get = attr_generic_get, - .attr_set = attr_generic_set, - .attr_remove = attr_generic_remove, -}; - -struct attrnames *attr_namespaces[] = - { &attr_system, &attr_trusted, &attr_secure, &attr_user }; diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h index 9b96d171b75..c1f7d43e5ec 100644 --- a/fs/xfs/xfs_attr.h +++ b/fs/xfs/xfs_attr.h @@ -38,30 +38,14 @@ struct cred; struct xfs_attr_list_context; -typedef int (*attrset_t)(bhv_vnode_t *, char *, void *, size_t, int); -typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int); -typedef int (*attrremove_t)(bhv_vnode_t *, char *, int); -typedef int (*attrexists_t)(bhv_vnode_t *); - typedef struct attrnames { char * attr_name; unsigned int attr_namelen; - unsigned int attr_flag; - attrget_t attr_get; - attrset_t attr_set; - attrremove_t attr_remove; - attrexists_t attr_exists; } attrnames_t; -#define ATTR_NAMECOUNT 4 extern struct attrnames attr_user; extern struct attrnames attr_secure; -extern struct attrnames attr_system; extern struct attrnames attr_trusted; -extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT]; - -extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int); -extern int attr_generic_list(bhv_vnode_t *, void *, size_t, int, ssize_t *); #define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */ #define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */ @@ -69,7 +53,6 @@ extern int attr_generic_list(bhv_vnode_t *, void *, size_t, int, ssize_t *); #define ATTR_SECURE 0x0008 /* use attrs in security namespace */ #define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */ #define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */ -#define ATTR_SYSTEM 0x0100 /* use attrs in system (pseudo) namespace */ #define ATTR_KERNACCESS 0x0400 /* [kernel] iaccess, inode held io-locked */ #define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */ -- cgit v1.2.3-70-g09d2 From 8f112e3bc3508afc8d1612868d178359446c08fd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 23 Jun 2008 13:25:17 +1000 Subject: [XFS] Merge xfs_rmdir into xfs_remove xfs_remove and xfs_rmdir are almost the same with a little more work performed in xfs_rmdir due to the . and .. entries. This patch merges xfs_rmdir into xfs_remove and performs these actions conditionally. Also clean up the error handling which was a nightmare in both versions before. SGI-PV: 981498 SGI-Modid: xfs-linux-melb:xfs-kern:31335a Signed-off-by: Christoph Hellwig Signed-off-by: Barry Naujok Signed-off-by: Lachlan McIlroy --- fs/xfs/linux-2.6/xfs_iops.c | 54 +++----- fs/xfs/xfs_vnodeops.c | 324 ++++++++++++-------------------------------- fs/xfs/xfs_vnodeops.h | 2 - 3 files changed, 102 insertions(+), 278 deletions(-) (limited to 'fs/xfs/linux-2.6/xfs_iops.c') diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 3ae80155de3..1f89c19cd4c 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -245,8 +245,7 @@ STATIC void xfs_cleanup_inode( struct inode *dir, struct inode *inode, - struct dentry *dentry, - int mode) + struct dentry *dentry) { struct xfs_name teardown; @@ -257,10 +256,7 @@ xfs_cleanup_inode( */ xfs_dentry_to_name(&teardown, dentry); - if (S_ISDIR(mode)) - xfs_rmdir(XFS_I(dir), &teardown, XFS_I(inode)); - else - xfs_remove(XFS_I(dir), &teardown, XFS_I(inode)); + xfs_remove(XFS_I(dir), &teardown, XFS_I(inode)); iput(inode); } @@ -342,7 +338,7 @@ xfs_vn_mknod( return -error; out_cleanup_inode: - xfs_cleanup_inode(dir, inode, dentry, mode); + xfs_cleanup_inode(dir, inode, dentry); out_free_acl: if (default_acl) _ACL_FREE(default_acl); @@ -518,37 +514,11 @@ xfs_vn_symlink( return 0; out_cleanup_inode: - xfs_cleanup_inode(dir, inode, dentry, 0); + xfs_cleanup_inode(dir, inode, dentry); out: return -error; } -STATIC int -xfs_vn_rmdir( - struct inode *dir, - struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - struct xfs_name name; - int error; - - xfs_dentry_to_name(&name, dentry); - - error = xfs_rmdir(XFS_I(dir), &name, XFS_I(inode)); - if (likely(!error)) { - xfs_validate_fields(inode); - xfs_validate_fields(dir); - /* - * With rmdir, the VFS makes the dentry "negative": no inode, - * but still hashed. This is incompatible with case-insensitive - * mode, so invalidate (unhash) the dentry in CI-mode. - */ - if (xfs_sb_version_hasasciici(&XFS_M(dir->i_sb)->m_sb)) - d_invalidate(dentry); - } - return -error; -} - STATIC int xfs_vn_rename( struct inode *odir, @@ -842,7 +812,13 @@ const struct inode_operations xfs_dir_inode_operations = { .unlink = xfs_vn_unlink, .symlink = xfs_vn_symlink, .mkdir = xfs_vn_mkdir, - .rmdir = xfs_vn_rmdir, + /* + * Yes, XFS uses the same method for rmdir and unlink. + * + * There are some subtile differences deeper in the code, + * but we use S_ISDIR to check for those. + */ + .rmdir = xfs_vn_unlink, .mknod = xfs_vn_mknod, .rename = xfs_vn_rename, .permission = xfs_vn_permission, @@ -861,7 +837,13 @@ const struct inode_operations xfs_dir_ci_inode_operations = { .unlink = xfs_vn_unlink, .symlink = xfs_vn_symlink, .mkdir = xfs_vn_mkdir, - .rmdir = xfs_vn_rmdir, + /* + * Yes, XFS uses the same method for rmdir and unlink. + * + * There are some subtile differences deeper in the code, + * but we use S_ISDIR to check for those. + */ + .rmdir = xfs_vn_unlink, .mknod = xfs_vn_mknod, .rename = xfs_vn_rename, .permission = xfs_vn_permission, diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index d76565bfcb7..8297a8c5af9 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -2116,13 +2116,6 @@ again: #endif } -#ifdef DEBUG -#define REMOVE_DEBUG_TRACE(x) {remove_which_error_return = (x);} -int remove_which_error_return = 0; -#else /* ! DEBUG */ -#define REMOVE_DEBUG_TRACE(x) -#endif /* ! DEBUG */ - int xfs_remove( xfs_inode_t *dp, @@ -2131,6 +2124,7 @@ xfs_remove( { xfs_mount_t *mp = dp->i_mount; xfs_trans_t *tp = NULL; + int is_dir = S_ISDIR(ip->i_d.di_mode); int error = 0; xfs_bmap_free_t free_list; xfs_fsblock_t first_block; @@ -2138,8 +2132,10 @@ xfs_remove( int committed; int link_zero; uint resblks; + uint log_count; xfs_itrace_entry(dp); + xfs_itrace_entry(ip); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -2152,19 +2148,23 @@ xfs_remove( return error; } - xfs_itrace_entry(ip); - xfs_itrace_ref(ip); - error = XFS_QM_DQATTACH(mp, dp, 0); - if (!error) - error = XFS_QM_DQATTACH(mp, ip, 0); - if (error) { - REMOVE_DEBUG_TRACE(__LINE__); + if (error) + goto std_return; + + error = XFS_QM_DQATTACH(mp, ip, 0); + if (error) goto std_return; - } - tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE); + if (is_dir) { + tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR); + log_count = XFS_DEFAULT_LOG_COUNT; + } else { + tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE); + log_count = XFS_REMOVE_LOG_COUNT; + } cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + /* * We try to get the real space reservation first, * allowing for directory btree deletion(s) implying @@ -2176,25 +2176,21 @@ xfs_remove( */ resblks = XFS_REMOVE_SPACE_RES(mp); error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, - XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); + XFS_TRANS_PERM_LOG_RES, log_count); if (error == ENOSPC) { resblks = 0; error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, - XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); + XFS_TRANS_PERM_LOG_RES, log_count); } if (error) { ASSERT(error != ENOSPC); - REMOVE_DEBUG_TRACE(__LINE__); - xfs_trans_cancel(tp, 0); - return error; + cancel_flags = 0; + goto out_trans_cancel; } error = xfs_lock_dir_and_entry(dp, ip); - if (error) { - REMOVE_DEBUG_TRACE(__LINE__); - xfs_trans_cancel(tp, cancel_flags); - goto std_return; - } + if (error) + goto out_trans_cancel; /* * At this point, we've gotten both the directory and the entry @@ -2206,6 +2202,21 @@ xfs_remove( IHOLD(dp); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + /* + * If we're removing a directory perform some additional validation. + */ + if (is_dir) { + ASSERT(ip->i_d.di_nlink >= 2); + if (ip->i_d.di_nlink != 2) { + error = XFS_ERROR(ENOTEMPTY); + goto out_trans_cancel; + } + if (!xfs_dir_isempty(ip)) { + error = XFS_ERROR(ENOTEMPTY); + goto out_trans_cancel; + } + } + /* * Entry must exist since we did a lookup in xfs_lock_dir_and_entry. */ @@ -2214,39 +2225,64 @@ xfs_remove( &first_block, &free_list, resblks); if (error) { ASSERT(error != ENOENT); - REMOVE_DEBUG_TRACE(__LINE__); - goto error1; + goto out_bmap_cancel; } xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + /* + * Bump the in memory generation count on the parent + * directory so that other can know that it has changed. + */ dp->i_gen++; xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); - error = xfs_droplink(tp, ip); - if (error) { - REMOVE_DEBUG_TRACE(__LINE__); - goto error1; + if (is_dir) { + /* + * Drop the link from ip's "..". + */ + error = xfs_droplink(tp, dp); + if (error) + goto out_bmap_cancel; + + /* + * Drop the link from dp to ip. + */ + error = xfs_droplink(tp, ip); + if (error) + goto out_bmap_cancel; + } else { + /* + * When removing a non-directory we need to log the parent + * inode here for the i_gen update. For a directory this is + * done implicitly by the xfs_droplink call for the ".." entry. + */ + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); } - /* Determine if this is the last link while + /* + * Drop the "." link from ip to self. + */ + error = xfs_droplink(tp, ip); + if (error) + goto out_bmap_cancel; + + /* + * Determine if this is the last link while * we are in the transaction. */ - link_zero = (ip)->i_d.di_nlink==0; + link_zero = (ip->i_d.di_nlink == 0); /* * If this is a synchronous mount, make sure that the * remove transaction goes to disk before returning to * the user. */ - if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { + if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) xfs_trans_set_sync(tp); - } error = xfs_bmap_finish(&tp, &free_list, &committed); - if (error) { - REMOVE_DEBUG_TRACE(__LINE__); - goto error_rele; - } + if (error) + goto out_bmap_cancel; error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); if (error) @@ -2258,38 +2294,26 @@ xfs_remove( * will get killed on last close in xfs_close() so we don't * have to worry about that. */ - if (link_zero && xfs_inode_is_filestream(ip)) + if (!is_dir && link_zero && xfs_inode_is_filestream(ip)) xfs_filestream_deassociate(ip); xfs_itrace_exit(ip); + xfs_itrace_exit(dp); -/* Fall through to std_return with error = 0 */ std_return: if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) { - (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, - dp, DM_RIGHT_NULL, - NULL, DM_RIGHT_NULL, - name->name, NULL, ip->i_d.di_mode, error, 0); + XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, dp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, name->name, NULL, + ip->i_d.di_mode, error, 0); } - return error; - error1: - xfs_bmap_cancel(&free_list); - cancel_flags |= XFS_TRANS_ABORT; - xfs_trans_cancel(tp, cancel_flags); - goto std_return; + return error; - error_rele: - /* - * In this case make sure to not release the inode until after - * the current transaction is aborted. Releasing it beforehand - * can cause us to go to xfs_inactive and start a recursive - * transaction which can easily deadlock with the current one. - */ + out_bmap_cancel: xfs_bmap_cancel(&free_list); cancel_flags |= XFS_TRANS_ABORT; + out_trans_cancel: xfs_trans_cancel(tp, cancel_flags); - goto std_return; } @@ -2655,186 +2679,6 @@ std_return: goto std_return; } -int -xfs_rmdir( - xfs_inode_t *dp, - struct xfs_name *name, - xfs_inode_t *cdp) -{ - xfs_mount_t *mp = dp->i_mount; - xfs_trans_t *tp; - int error; - xfs_bmap_free_t free_list; - xfs_fsblock_t first_block; - int cancel_flags; - int committed; - int last_cdp_link; - uint resblks; - - xfs_itrace_entry(dp); - - if (XFS_FORCED_SHUTDOWN(mp)) - return XFS_ERROR(EIO); - - if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) { - error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, - dp, DM_RIGHT_NULL, - NULL, DM_RIGHT_NULL, name->name, - NULL, cdp->i_d.di_mode, 0, 0); - if (error) - return XFS_ERROR(error); - } - - /* - * Get the dquots for the inodes. - */ - error = XFS_QM_DQATTACH(mp, dp, 0); - if (!error) - error = XFS_QM_DQATTACH(mp, cdp, 0); - if (error) { - REMOVE_DEBUG_TRACE(__LINE__); - goto std_return; - } - - tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR); - cancel_flags = XFS_TRANS_RELEASE_LOG_RES; - /* - * We try to get the real space reservation first, - * allowing for directory btree deletion(s) implying - * possible bmap insert(s). If we can't get the space - * reservation then we use 0 instead, and avoid the bmap - * btree insert(s) in the directory code by, if the bmap - * insert tries to happen, instead trimming the LAST - * block from the directory. - */ - resblks = XFS_REMOVE_SPACE_RES(mp); - error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, - XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT); - if (error == ENOSPC) { - resblks = 0; - error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, - XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT); - } - if (error) { - ASSERT(error != ENOSPC); - cancel_flags = 0; - goto error_return; - } - XFS_BMAP_INIT(&free_list, &first_block); - - /* - * Now lock the child directory inode and the parent directory - * inode in the proper order. This will take care of validating - * that the directory entry for the child directory inode has - * not changed while we were obtaining a log reservation. - */ - error = xfs_lock_dir_and_entry(dp, cdp); - if (error) { - xfs_trans_cancel(tp, cancel_flags); - goto std_return; - } - - IHOLD(dp); - xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); - - IHOLD(cdp); - xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL); - - ASSERT(cdp->i_d.di_nlink >= 2); - if (cdp->i_d.di_nlink != 2) { - error = XFS_ERROR(ENOTEMPTY); - goto error_return; - } - if (!xfs_dir_isempty(cdp)) { - error = XFS_ERROR(ENOTEMPTY); - goto error_return; - } - - error = xfs_dir_removename(tp, dp, name, cdp->i_ino, - &first_block, &free_list, resblks); - if (error) - goto error1; - - xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); - - /* - * Bump the in memory generation count on the parent - * directory so that other can know that it has changed. - */ - dp->i_gen++; - - /* - * Drop the link from cdp's "..". - */ - error = xfs_droplink(tp, dp); - if (error) { - goto error1; - } - - /* - * Drop the link from dp to cdp. - */ - error = xfs_droplink(tp, cdp); - if (error) { - goto error1; - } - - /* - * Drop the "." link from cdp to self. - */ - error = xfs_droplink(tp, cdp); - if (error) { - goto error1; - } - - /* Determine these before committing transaction */ - last_cdp_link = (cdp)->i_d.di_nlink==0; - - /* - * If this is a synchronous mount, make sure that the - * rmdir transaction goes to disk before returning to - * the user. - */ - if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { - xfs_trans_set_sync(tp); - } - - error = xfs_bmap_finish (&tp, &free_list, &committed); - if (error) { - xfs_bmap_cancel(&free_list); - xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | - XFS_TRANS_ABORT)); - goto std_return; - } - - error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); - if (error) { - goto std_return; - } - - - /* Fall through to std_return with error = 0 or the errno - * from xfs_trans_commit. */ - std_return: - if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) { - (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, - dp, DM_RIGHT_NULL, - NULL, DM_RIGHT_NULL, - name->name, NULL, cdp->i_d.di_mode, - error, 0); - } - return error; - - error1: - xfs_bmap_cancel(&free_list); - cancel_flags |= XFS_TRANS_ABORT; - /* FALLTHROUGH */ - - error_return: - xfs_trans_cancel(tp, cancel_flags); - goto std_return; -} - int xfs_symlink( xfs_inode_t *dp, diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index 7e9a8b241f2..454fa9a3e52 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h @@ -31,8 +31,6 @@ int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip, struct xfs_name *target_name); int xfs_mkdir(struct xfs_inode *dp, struct xfs_name *dir_name, mode_t mode, struct xfs_inode **ipp, struct cred *credp); -int xfs_rmdir(struct xfs_inode *dp, struct xfs_name *name, - struct xfs_inode *cdp); int xfs_readdir(struct xfs_inode *dp, void *dirent, size_t bufsize, xfs_off_t *offset, filldir_t filldir); int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name, -- cgit v1.2.3-70-g09d2 From e5700704b2b0853c059e424284cceeff3032ea28 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 23 Jun 2008 13:25:25 +1000 Subject: [XFS] Don't update i_size for directories and special files The core kernel uses vfs_getattr to look at the inode size and similar attributes, so there is no need to keep i_size uptodate for directories or special files. This means we can remove xfs_validate_fields because the I/O path already keeps i_size uptodate for regular files. SGI-PV: 981498 SGI-Modid: xfs-linux-melb:xfs-kern:31336a Signed-off-by: Christoph Hellwig Signed-off-by: Barry Naujok Signed-off-by: Lachlan McIlroy --- fs/xfs/linux-2.6/xfs_iops.c | 61 ++++++++++----------------------------------- 1 file changed, 13 insertions(+), 48 deletions(-) (limited to 'fs/xfs/linux-2.6/xfs_iops.c') diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 1f89c19cd4c..7b42569968f 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -181,23 +181,6 @@ xfs_ichgtime_fast( mark_inode_dirty_sync(inode); } - -/* - * Pull the link count and size up from the xfs inode to the linux inode - */ -STATIC void -xfs_validate_fields( - struct inode *inode) -{ - struct xfs_inode *ip = XFS_I(inode); - loff_t size; - - /* we're under i_sem so i_size can't change under us */ - size = XFS_ISIZE(ip); - if (i_size_read(inode) != size) - i_size_write(inode, size); -} - /* * Hook in SELinux. This is not quite correct yet, what we really need * here (as we do for default ACLs) is a mechanism by which creation of @@ -331,10 +314,7 @@ xfs_vn_mknod( } - if (S_ISDIR(mode)) - xfs_validate_fields(inode); d_instantiate(dentry, inode); - xfs_validate_fields(dir); return -error; out_cleanup_inode: @@ -450,7 +430,6 @@ xfs_vn_link( } xfs_iflags_set(XFS_I(dir), XFS_IMODIFIED); - xfs_validate_fields(inode); d_instantiate(dentry, inode); return 0; } @@ -460,26 +439,23 @@ xfs_vn_unlink( struct inode *dir, struct dentry *dentry) { - struct inode *inode; struct xfs_name name; int error; - inode = dentry->d_inode; xfs_dentry_to_name(&name, dentry); - error = xfs_remove(XFS_I(dir), &name, XFS_I(inode)); - if (likely(!error)) { - xfs_validate_fields(dir); /* size needs update */ - xfs_validate_fields(inode); - /* - * With unlink, the VFS makes the dentry "negative": no inode, - * but still hashed. This is incompatible with case-insensitive - * mode, so invalidate (unhash) the dentry in CI-mode. - */ - if (xfs_sb_version_hasasciici(&XFS_M(dir->i_sb)->m_sb)) - d_invalidate(dentry); - } - return -error; + error = -xfs_remove(XFS_I(dir), &name, XFS_I(dentry->d_inode)); + if (error) + return error; + + /* + * With unlink, the VFS makes the dentry "negative": no inode, + * but still hashed. This is incompatible with case-insensitive + * mode, so invalidate (unhash) the dentry in CI-mode. + */ + if (xfs_sb_version_hasasciici(&XFS_M(dir->i_sb)->m_sb)) + d_invalidate(dentry); + return 0; } STATIC int @@ -509,8 +485,6 @@ xfs_vn_symlink( goto out_cleanup_inode; d_instantiate(dentry, inode); - xfs_validate_fields(dir); - xfs_validate_fields(inode); return 0; out_cleanup_inode: @@ -529,22 +503,13 @@ xfs_vn_rename( struct inode *new_inode = ndentry->d_inode; struct xfs_name oname; struct xfs_name nname; - int error; xfs_dentry_to_name(&oname, odentry); xfs_dentry_to_name(&nname, ndentry); - error = xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode), + return -xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode), XFS_I(ndir), &nname, new_inode ? XFS_I(new_inode) : NULL); - if (likely(!error)) { - if (new_inode) - xfs_validate_fields(new_inode); - xfs_validate_fields(odir); - if (ndir != odir) - xfs_validate_fields(ndir); - } - return -error; } /* -- cgit v1.2.3-70-g09d2 From 0f285c8a1c4cacfd9f2aec077b06e2b537ee57ab Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 18 Jul 2008 17:13:28 +1000 Subject: [XFS] Now that xfs_setattr is only used for attributes set from ->setattr it can be switched to take struct iattr directly and thus simplify the implementation greatly. Also rename the ATTR_ flags to XFS_ATTR_ to not conflict with the ATTR_ flags used by the VFS. SGI-PV: 984565 SGI-Modid: xfs-linux-melb:xfs-kern:31678a Signed-off-by: Christoph Hellwig Signed-off-by: Tim Shimmin Signed-off-by: Lachlan McIlroy --- fs/xfs/linux-2.6/xfs_ioctl.c | 4 +- fs/xfs/linux-2.6/xfs_iops.c | 56 +++----------- fs/xfs/linux-2.6/xfs_vnode.h | 73 ------------------ fs/xfs/xfs_acl.c | 18 ++--- fs/xfs/xfs_dmapi.h | 2 +- fs/xfs/xfs_vnodeops.c | 172 ++++++++++++++++++------------------------- fs/xfs/xfs_vnodeops.h | 8 +- 7 files changed, 102 insertions(+), 231 deletions(-) (limited to 'fs/xfs/linux-2.6/xfs_iops.c') diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index d2bbb0532ef..d1b0da6bcdc 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -688,9 +688,9 @@ xfs_ioc_space( return -XFS_ERROR(EFAULT); if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) - attr_flags |= ATTR_NONBLOCK; + attr_flags |= XFS_ATTR_NONBLOCK; if (ioflags & IO_INVIS) - attr_flags |= ATTR_DMI; + attr_flags |= XFS_ATTR_DMI; error = xfs_change_file_space(ip, cmd, &bf, filp->f_pos, NULL, attr_flags); diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 7b42569968f..669bbdc2085 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -648,54 +648,20 @@ xfs_vn_getattr( STATIC int xfs_vn_setattr( struct dentry *dentry, - struct iattr *attr) + struct iattr *iattr) { struct inode *inode = dentry->d_inode; - unsigned int ia_valid = attr->ia_valid; - bhv_vattr_t vattr = { 0 }; - int flags = 0; int error; - if (ia_valid & ATTR_UID) { - vattr.va_mask |= XFS_AT_UID; - vattr.va_uid = attr->ia_uid; - } - if (ia_valid & ATTR_GID) { - vattr.va_mask |= XFS_AT_GID; - vattr.va_gid = attr->ia_gid; - } - if (ia_valid & ATTR_SIZE) { - vattr.va_mask |= XFS_AT_SIZE; - vattr.va_size = attr->ia_size; - } - if (ia_valid & ATTR_ATIME) { - vattr.va_mask |= XFS_AT_ATIME; - vattr.va_atime = attr->ia_atime; - inode->i_atime = attr->ia_atime; - } - if (ia_valid & ATTR_MTIME) { - vattr.va_mask |= XFS_AT_MTIME; - vattr.va_mtime = attr->ia_mtime; - } - if (ia_valid & ATTR_CTIME) { - vattr.va_mask |= XFS_AT_CTIME; - vattr.va_ctime = attr->ia_ctime; - } - if (ia_valid & ATTR_MODE) { - vattr.va_mask |= XFS_AT_MODE; - vattr.va_mode = attr->ia_mode; + if (iattr->ia_valid & ATTR_ATIME) + inode->i_atime = iattr->ia_atime; + + if (iattr->ia_valid & ATTR_MODE) { if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) inode->i_mode &= ~S_ISGID; } - if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) - flags |= ATTR_UTIME; -#ifdef ATTR_NO_BLOCK - if ((ia_valid & ATTR_NO_BLOCK)) - flags |= ATTR_NONBLOCK; -#endif - - error = xfs_setattr(XFS_I(inode), &vattr, flags, NULL); + error = xfs_setattr(XFS_I(inode), iattr, 0, NULL); if (likely(!error)) vn_revalidate(vn_from_inode(inode)); return -error; @@ -739,18 +705,18 @@ xfs_vn_fallocate( xfs_ilock(ip, XFS_IOLOCK_EXCL); error = xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf, - 0, NULL, ATTR_NOLOCK); + 0, NULL, XFS_ATTR_NOLOCK); if (!error && !(mode & FALLOC_FL_KEEP_SIZE) && offset + len > i_size_read(inode)) new_size = offset + len; /* Change file size if needed */ if (new_size) { - bhv_vattr_t va; + struct iattr iattr; - va.va_mask = XFS_AT_SIZE; - va.va_size = new_size; - error = xfs_setattr(ip, &va, ATTR_NOLOCK, NULL); + iattr.ia_valid = ATTR_SIZE; + iattr.ia_size = new_size; + error = xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK, NULL); } xfs_iunlock(ip, XFS_IOLOCK_EXCL); diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 7797c9cdb59..96e4a7b5391 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h @@ -19,7 +19,6 @@ #define __XFS_VNODE_H__ struct file; -struct bhv_vattr; struct xfs_iomap; struct attrlist_cursor_kern; @@ -66,69 +65,6 @@ static inline struct inode *vn_to_inode(bhv_vnode_t *vnode) Prevent VM access to the pages until the operation completes. */ -/* - * Vnode attributes. va_mask indicates those attributes the caller - * wants to set or extract. - */ -typedef struct bhv_vattr { - int va_mask; /* bit-mask of attributes present */ - mode_t va_mode; /* file access mode and type */ - xfs_nlink_t va_nlink; /* number of references to file */ - uid_t va_uid; /* owner user id */ - gid_t va_gid; /* owner group id */ - xfs_ino_t va_nodeid; /* file id */ - xfs_off_t va_size; /* file size in bytes */ - u_long va_blocksize; /* blocksize preferred for i/o */ - struct timespec va_atime; /* time of last access */ - struct timespec va_mtime; /* time of last modification */ - struct timespec va_ctime; /* time file changed */ - u_int va_gen; /* generation number of file */ - xfs_dev_t va_rdev; /* device the special file represents */ - __int64_t va_nblocks; /* number of blocks allocated */ - u_long va_xflags; /* random extended file flags */ - u_long va_extsize; /* file extent size */ - u_long va_nextents; /* number of extents in file */ - u_long va_anextents; /* number of attr extents in file */ - prid_t va_projid; /* project id */ -} bhv_vattr_t; - -/* - * setattr or getattr attributes - */ -#define XFS_AT_TYPE 0x00000001 -#define XFS_AT_MODE 0x00000002 -#define XFS_AT_UID 0x00000004 -#define XFS_AT_GID 0x00000008 -#define XFS_AT_FSID 0x00000010 -#define XFS_AT_NODEID 0x00000020 -#define XFS_AT_NLINK 0x00000040 -#define XFS_AT_SIZE 0x00000080 -#define XFS_AT_ATIME 0x00000100 -#define XFS_AT_MTIME 0x00000200 -#define XFS_AT_CTIME 0x00000400 -#define XFS_AT_RDEV 0x00000800 -#define XFS_AT_BLKSIZE 0x00001000 -#define XFS_AT_NBLOCKS 0x00002000 -#define XFS_AT_VCODE 0x00004000 -#define XFS_AT_MAC 0x00008000 -#define XFS_AT_UPDATIME 0x00010000 -#define XFS_AT_UPDMTIME 0x00020000 -#define XFS_AT_UPDCTIME 0x00040000 -#define XFS_AT_ACL 0x00080000 -#define XFS_AT_CAP 0x00100000 -#define XFS_AT_INF 0x00200000 -#define XFS_AT_NEXTENTS 0x01000000 -#define XFS_AT_ANEXTENTS 0x02000000 -#define XFS_AT_SIZE_NOPERM 0x08000000 -#define XFS_AT_GENCOUNT 0x10000000 - -#define XFS_AT_TIMES (XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME) - -#define XFS_AT_UPDTIMES (XFS_AT_UPDATIME|XFS_AT_UPDMTIME|XFS_AT_UPDCTIME) - -#define XFS_AT_NOSET (XFS_AT_NLINK|XFS_AT_RDEV|XFS_AT_FSID|XFS_AT_NODEID|\ - XFS_AT_TYPE|XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|\ - XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_GENCOUNT) extern void vn_init(void); extern int vn_revalidate(bhv_vnode_t *); @@ -204,15 +140,6 @@ static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt) #define VN_DIRTY(vp) mapping_tagged(vn_to_inode(vp)->i_mapping, \ PAGECACHE_TAG_DIRTY) -/* - * Flags to vop_setattr/getattr. - */ -#define ATTR_UTIME 0x01 /* non-default utime(2) request */ -#define ATTR_DMI 0x08 /* invocation from a DMI function */ -#define ATTR_LAZY 0x80 /* set/get attributes lazily */ -#define ATTR_NONBLOCK 0x100 /* return EAGAIN if operation would block */ -#define ATTR_NOLOCK 0x200 /* Don't grab any conflicting locks */ -#define ATTR_NOSIZETOK 0x400 /* Don't get the SIZE token */ /* * Tracking vnode activity. diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 93057af2fe3..3e4648ad9cf 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -719,7 +719,7 @@ xfs_acl_setmode( xfs_acl_t *acl, int *basicperms) { - bhv_vattr_t va; + struct iattr iattr; xfs_acl_entry_t *ap; xfs_acl_entry_t *gap = NULL; int i, nomask = 1; @@ -733,25 +733,25 @@ xfs_acl_setmode( * Copy the u::, g::, o::, and m:: bits from the ACL into the * mode. The m:: bits take precedence over the g:: bits. */ - va.va_mask = XFS_AT_MODE; - va.va_mode = xfs_vtoi(vp)->i_d.di_mode; - va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); + iattr.ia_valid = ATTR_MODE; + iattr.ia_mode = xfs_vtoi(vp)->i_d.di_mode; + iattr.ia_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); ap = acl->acl_entry; for (i = 0; i < acl->acl_cnt; ++i) { switch (ap->ae_tag) { case ACL_USER_OBJ: - va.va_mode |= ap->ae_perm << 6; + iattr.ia_mode |= ap->ae_perm << 6; break; case ACL_GROUP_OBJ: gap = ap; break; case ACL_MASK: /* more than just standard modes */ nomask = 0; - va.va_mode |= ap->ae_perm << 3; + iattr.ia_mode |= ap->ae_perm << 3; *basicperms = 0; break; case ACL_OTHER: - va.va_mode |= ap->ae_perm; + iattr.ia_mode |= ap->ae_perm; break; default: /* more than just standard modes */ *basicperms = 0; @@ -762,9 +762,9 @@ xfs_acl_setmode( /* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */ if (gap && nomask) - va.va_mode |= gap->ae_perm << 3; + iattr.ia_mode |= gap->ae_perm << 3; - return xfs_setattr(xfs_vtoi(vp), &va, 0, sys_cred); + return xfs_setattr(xfs_vtoi(vp), &iattr, 0, sys_cred); } /* diff --git a/fs/xfs/xfs_dmapi.h b/fs/xfs/xfs_dmapi.h index f71784ab6a6..cdc2d3464a1 100644 --- a/fs/xfs/xfs_dmapi.h +++ b/fs/xfs/xfs_dmapi.h @@ -166,6 +166,6 @@ typedef enum { #define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \ DM_FLAGS_NDELAY : 0) -#define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0) +#define AT_DELAY_FLAG(f) ((f & XFS_ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0) #endif /* __XFS_DMAPI_H__ */ diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index ed399523b78..b792a121b1a 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -75,19 +75,16 @@ xfs_open( return 0; } -/* - * xfs_setattr - */ int xfs_setattr( - xfs_inode_t *ip, - bhv_vattr_t *vap, + struct xfs_inode *ip, + struct iattr *iattr, int flags, cred_t *credp) { xfs_mount_t *mp = ip->i_mount; + int mask = iattr->ia_valid; xfs_trans_t *tp; - int mask; int code; uint lock_flags; uint commit_flags=0; @@ -103,30 +100,9 @@ xfs_setattr( if (mp->m_flags & XFS_MOUNT_RDONLY) return XFS_ERROR(EROFS); - /* - * Cannot set certain attributes. - */ - mask = vap->va_mask; - if (mask & XFS_AT_NOSET) { - return XFS_ERROR(EINVAL); - } - if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); - /* - * Timestamps do not need to be logged and hence do not - * need to be done within a transaction. - */ - if (mask & XFS_AT_UPDTIMES) { - ASSERT((mask & ~XFS_AT_UPDTIMES) == 0); - timeflags = ((mask & XFS_AT_UPDATIME) ? XFS_ICHGTIME_ACC : 0) | - ((mask & XFS_AT_UPDCTIME) ? XFS_ICHGTIME_CHG : 0) | - ((mask & XFS_AT_UPDMTIME) ? XFS_ICHGTIME_MOD : 0); - xfs_ichgtime(ip, timeflags); - return 0; - } - olddquot1 = olddquot2 = NULL; udqp = gdqp = NULL; @@ -138,17 +114,17 @@ xfs_setattr( * If the IDs do change before we take the ilock, we're covered * because the i_*dquot fields will get updated anyway. */ - if (XFS_IS_QUOTA_ON(mp) && (mask & (XFS_AT_UID|XFS_AT_GID))) { + if (XFS_IS_QUOTA_ON(mp) && (mask & (ATTR_UID|ATTR_GID))) { uint qflags = 0; - if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) { - uid = vap->va_uid; + if ((mask & ATTR_UID) && XFS_IS_UQUOTA_ON(mp)) { + uid = iattr->ia_uid; qflags |= XFS_QMOPT_UQUOTA; } else { uid = ip->i_d.di_uid; } - if ((mask & XFS_AT_GID) && XFS_IS_GQUOTA_ON(mp)) { - gid = vap->va_gid; + if ((mask & ATTR_GID) && XFS_IS_GQUOTA_ON(mp)) { + gid = iattr->ia_gid; qflags |= XFS_QMOPT_GQUOTA; } else { gid = ip->i_d.di_gid; @@ -173,10 +149,10 @@ xfs_setattr( */ tp = NULL; lock_flags = XFS_ILOCK_EXCL; - if (flags & ATTR_NOLOCK) + if (flags & XFS_ATTR_NOLOCK) need_iolock = 0; - if (!(mask & XFS_AT_SIZE)) { - if ((mask != (XFS_AT_CTIME|XFS_AT_ATIME|XFS_AT_MTIME)) || + if (!(mask & ATTR_SIZE)) { + if ((mask != (ATTR_CTIME|ATTR_ATIME|ATTR_MTIME)) || (mp->m_flags & XFS_MOUNT_WSYNC)) { tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); commit_flags = 0; @@ -189,10 +165,10 @@ xfs_setattr( } } else { if (DM_EVENT_ENABLED(ip, DM_EVENT_TRUNCATE) && - !(flags & ATTR_DMI)) { + !(flags & XFS_ATTR_DMI)) { int dmflags = AT_DELAY_FLAG(flags) | DM_SEM_FLAG_WR; code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, ip, - vap->va_size, 0, dmflags, NULL); + iattr->ia_size, 0, dmflags, NULL); if (code) { lock_flags = 0; goto error_return; @@ -212,7 +188,7 @@ xfs_setattr( * Only the owner or users with CAP_FOWNER * capability may do these things. */ - if (mask & (XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID)) { + if (mask & (ATTR_MODE|ATTR_UID|ATTR_GID)) { /* * CAP_FOWNER overrides the following restrictions: * @@ -236,21 +212,21 @@ xfs_setattr( * IDs of the calling process shall match the group owner of * the file when setting the set-group-ID bit on that file */ - if (mask & XFS_AT_MODE) { + if (mask & ATTR_MODE) { mode_t m = 0; - if ((vap->va_mode & S_ISUID) && !file_owner) + if ((iattr->ia_mode & S_ISUID) && !file_owner) m |= S_ISUID; - if ((vap->va_mode & S_ISGID) && + if ((iattr->ia_mode & S_ISGID) && !in_group_p((gid_t)ip->i_d.di_gid)) m |= S_ISGID; #if 0 /* Linux allows this, Irix doesn't. */ - if ((vap->va_mode & S_ISVTX) && !S_ISDIR(ip->i_d.di_mode)) + if ((iattr->ia_mode & S_ISVTX) && !S_ISDIR(ip->i_d.di_mode)) m |= S_ISVTX; #endif if (m && !capable(CAP_FSETID)) - vap->va_mode &= ~m; + iattr->ia_mode &= ~m; } } @@ -261,7 +237,7 @@ xfs_setattr( * and can change the group id only to a group of which he * or she is a member. */ - if (mask & (XFS_AT_UID|XFS_AT_GID)) { + if (mask & (ATTR_UID|ATTR_GID)) { /* * These IDs could have changed since we last looked at them. * But, we're assured that if the ownership did change @@ -270,8 +246,8 @@ xfs_setattr( */ iuid = ip->i_d.di_uid; igid = ip->i_d.di_gid; - gid = (mask & XFS_AT_GID) ? vap->va_gid : igid; - uid = (mask & XFS_AT_UID) ? vap->va_uid : iuid; + gid = (mask & ATTR_GID) ? iattr->ia_gid : igid; + uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid; /* * CAP_CHOWN overrides the following restrictions: @@ -308,13 +284,13 @@ xfs_setattr( /* * Truncate file. Must have write permission and not be a directory. */ - if (mask & XFS_AT_SIZE) { + if (mask & ATTR_SIZE) { /* Short circuit the truncate case for zero length files */ - if ((vap->va_size == 0) && - (ip->i_size == 0) && (ip->i_d.di_nextents == 0)) { + if (iattr->ia_size == 0 && + ip->i_size == 0 && ip->i_d.di_nextents == 0) { xfs_iunlock(ip, XFS_ILOCK_EXCL); lock_flags &= ~XFS_ILOCK_EXCL; - if (mask & XFS_AT_CTIME) + if (mask & ATTR_CTIME) xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); code = 0; goto error_return; @@ -337,9 +313,9 @@ xfs_setattr( /* * Change file access or modified times. */ - if (mask & (XFS_AT_ATIME|XFS_AT_MTIME)) { + if (mask & (ATTR_ATIME|ATTR_MTIME)) { if (!file_owner) { - if ((flags & ATTR_UTIME) && + if ((mask & (ATTR_MTIME_SET|ATTR_ATIME_SET)) && !capable(CAP_FOWNER)) { code = XFS_ERROR(EPERM); goto error_return; @@ -349,23 +325,22 @@ xfs_setattr( /* * Now we can make the changes. Before we join the inode - * to the transaction, if XFS_AT_SIZE is set then take care of + * to the transaction, if ATTR_SIZE is set then take care of * the part of the truncation that must be done without the * inode lock. This needs to be done before joining the inode * to the transaction, because the inode cannot be unlocked * once it is a part of the transaction. */ - if (mask & XFS_AT_SIZE) { + if (mask & ATTR_SIZE) { code = 0; - if ((vap->va_size > ip->i_size) && - (flags & ATTR_NOSIZETOK) == 0) { + if (iattr->ia_size > ip->i_size) { /* * Do the first part of growing a file: zero any data * in the last block that is beyond the old EOF. We * need to do this before the inode is joined to the * transaction to modify the i_size. */ - code = xfs_zero_eof(ip, vap->va_size, ip->i_size); + code = xfs_zero_eof(ip, iattr->ia_size, ip->i_size); } xfs_iunlock(ip, XFS_ILOCK_EXCL); @@ -382,10 +357,10 @@ xfs_setattr( * not within the range we care about here. */ if (!code && - (ip->i_size != ip->i_d.di_size) && - (vap->va_size > ip->i_d.di_size)) { + ip->i_size != ip->i_d.di_size && + iattr->ia_size > ip->i_d.di_size) { code = xfs_flush_pages(ip, - ip->i_d.di_size, vap->va_size, + ip->i_d.di_size, iattr->ia_size, XFS_B_ASYNC, FI_NONE); } @@ -393,7 +368,7 @@ xfs_setattr( vn_iowait(ip); if (!code) - code = xfs_itruncate_data(ip, vap->va_size); + code = xfs_itruncate_data(ip, iattr->ia_size); if (code) { ASSERT(tp == NULL); lock_flags &= ~XFS_ILOCK_EXCL; @@ -422,31 +397,30 @@ xfs_setattr( /* * Truncate file. Must have write permission and not be a directory. */ - if (mask & XFS_AT_SIZE) { + if (mask & ATTR_SIZE) { /* * Only change the c/mtime if we are changing the size * or we are explicitly asked to change it. This handles * the semantic difference between truncate() and ftruncate() * as implemented in the VFS. */ - if (vap->va_size != ip->i_size || (mask & XFS_AT_CTIME)) + if (iattr->ia_size != ip->i_size || (mask & ATTR_CTIME)) timeflags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; - if (vap->va_size > ip->i_size) { - ip->i_d.di_size = vap->va_size; - ip->i_size = vap->va_size; - if (!(flags & ATTR_DMI)) + if (iattr->ia_size > ip->i_size) { + ip->i_d.di_size = iattr->ia_size; + ip->i_size = iattr->ia_size; + if (!(flags & XFS_ATTR_DMI)) xfs_ichgtime(ip, XFS_ICHGTIME_CHG); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - } else if ((vap->va_size <= ip->i_size) || - ((vap->va_size == 0) && ip->i_d.di_nextents)) { + } else if (iattr->ia_size <= ip->i_size || + (iattr->ia_size == 0 && ip->i_d.di_nextents)) { /* * signal a sync transaction unless * we're truncating an already unlinked * file on a wsync filesystem */ - code = xfs_itruncate_finish(&tp, ip, - (xfs_fsize_t)vap->va_size, + code = xfs_itruncate_finish(&tp, ip, iattr->ia_size, XFS_DATA_FORK, ((ip->i_d.di_nlink != 0 || !(mp->m_flags & XFS_MOUNT_WSYNC)) @@ -468,9 +442,9 @@ xfs_setattr( /* * Change file access modes. */ - if (mask & XFS_AT_MODE) { + if (mask & ATTR_MODE) { ip->i_d.di_mode &= S_IFMT; - ip->i_d.di_mode |= vap->va_mode & ~S_IFMT; + ip->i_d.di_mode |= iattr->ia_mode & ~S_IFMT; xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); timeflags |= XFS_ICHGTIME_CHG; @@ -483,7 +457,7 @@ xfs_setattr( * and can change the group id only to a group of which he * or she is a member. */ - if (mask & (XFS_AT_UID|XFS_AT_GID)) { + if (mask & (ATTR_UID|ATTR_GID)) { /* * CAP_FSETID overrides the following restrictions: * @@ -501,7 +475,7 @@ xfs_setattr( */ if (iuid != uid) { if (XFS_IS_UQUOTA_ON(mp)) { - ASSERT(mask & XFS_AT_UID); + ASSERT(mask & ATTR_UID); ASSERT(udqp); olddquot1 = XFS_QM_DQVOPCHOWN(mp, tp, ip, &ip->i_udquot, udqp); @@ -511,7 +485,7 @@ xfs_setattr( if (igid != gid) { if (XFS_IS_GQUOTA_ON(mp)) { ASSERT(!XFS_IS_PQUOTA_ON(mp)); - ASSERT(mask & XFS_AT_GID); + ASSERT(mask & ATTR_GID); ASSERT(gdqp); olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, &ip->i_gdquot, gdqp); @@ -527,31 +501,31 @@ xfs_setattr( /* * Change file access or modified times. */ - if (mask & (XFS_AT_ATIME|XFS_AT_MTIME)) { - if (mask & XFS_AT_ATIME) { - ip->i_d.di_atime.t_sec = vap->va_atime.tv_sec; - ip->i_d.di_atime.t_nsec = vap->va_atime.tv_nsec; + if (mask & (ATTR_ATIME|ATTR_MTIME)) { + if (mask & ATTR_ATIME) { + ip->i_d.di_atime.t_sec = iattr->ia_atime.tv_sec; + ip->i_d.di_atime.t_nsec = iattr->ia_atime.tv_nsec; ip->i_update_core = 1; timeflags &= ~XFS_ICHGTIME_ACC; } - if (mask & XFS_AT_MTIME) { - ip->i_d.di_mtime.t_sec = vap->va_mtime.tv_sec; - ip->i_d.di_mtime.t_nsec = vap->va_mtime.tv_nsec; + if (mask & ATTR_MTIME) { + ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec; + ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec; timeflags &= ~XFS_ICHGTIME_MOD; timeflags |= XFS_ICHGTIME_CHG; } - if (tp && (flags & ATTR_UTIME)) + if (tp && (mask & (ATTR_MTIME_SET|ATTR_ATIME_SET))) xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); } /* - * Change file inode change time only if XFS_AT_CTIME set + * Change file inode change time only if ATTR_CTIME set * AND we have been called by a DMI function. */ - if ( (flags & ATTR_DMI) && (mask & XFS_AT_CTIME) ) { - ip->i_d.di_ctime.t_sec = vap->va_ctime.tv_sec; - ip->i_d.di_ctime.t_nsec = vap->va_ctime.tv_nsec; + if ((flags & XFS_ATTR_DMI) && (mask & ATTR_CTIME)) { + ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec; + ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec; ip->i_update_core = 1; timeflags &= ~XFS_ICHGTIME_CHG; } @@ -560,7 +534,7 @@ xfs_setattr( * Send out timestamp changes that need to be set to the * current time. Not done when called by a DMI function. */ - if (timeflags && !(flags & ATTR_DMI)) + if (timeflags && !(flags & XFS_ATTR_DMI)) xfs_ichgtime(ip, timeflags); XFS_STATS_INC(xs_ig_attrchg); @@ -598,7 +572,7 @@ xfs_setattr( } if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE) && - !(flags & ATTR_DMI)) { + !(flags & XFS_ATTR_DMI)) { (void) XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, NULL, NULL, 0, 0, AT_DELAY_FLAG(flags)); @@ -3113,7 +3087,7 @@ xfs_alloc_file_space( /* Generate a DMAPI event if needed. */ if (alloc_type != 0 && offset < ip->i_size && - (attr_flags&ATTR_DMI) == 0 && + (attr_flags & XFS_ATTR_DMI) == 0 && DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) { xfs_off_t end_dmi_offset; @@ -3227,7 +3201,7 @@ retry: allocatesize_fsb -= allocated_fsb; } dmapi_enospc_check: - if (error == ENOSPC && (attr_flags & ATTR_DMI) == 0 && + if (error == ENOSPC && (attr_flags & XFS_ATTR_DMI) == 0 && DM_EVENT_ENABLED(ip, DM_EVENT_NOSPACE)) { error = XFS_SEND_NAMESP(mp, DM_EVENT_NOSPACE, ip, DM_RIGHT_NULL, @@ -3374,7 +3348,7 @@ xfs_free_file_space( end_dmi_offset = offset + len; endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset); - if (offset < ip->i_size && (attr_flags & ATTR_DMI) == 0 && + if (offset < ip->i_size && (attr_flags & XFS_ATTR_DMI) == 0 && DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) { if (end_dmi_offset > ip->i_size) end_dmi_offset = ip->i_size; @@ -3385,7 +3359,7 @@ xfs_free_file_space( return error; } - if (attr_flags & ATTR_NOLOCK) + if (attr_flags & XFS_ATTR_NOLOCK) need_iolock = 0; if (need_iolock) { xfs_ilock(ip, XFS_IOLOCK_EXCL); @@ -3562,7 +3536,7 @@ xfs_change_file_space( xfs_off_t startoffset; xfs_off_t llen; xfs_trans_t *tp; - bhv_vattr_t va; + struct iattr iattr; xfs_itrace_entry(ip); @@ -3636,10 +3610,10 @@ xfs_change_file_space( break; } - va.va_mask = XFS_AT_SIZE; - va.va_size = startoffset; + iattr.ia_valid = ATTR_SIZE; + iattr.ia_size = startoffset; - error = xfs_setattr(ip, &va, attr_flags, credp); + error = xfs_setattr(ip, &iattr, attr_flags, credp); if (error) return error; @@ -3669,7 +3643,7 @@ xfs_change_file_space( xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ihold(tp, ip); - if ((attr_flags & ATTR_DMI) == 0) { + if ((attr_flags & XFS_ATTR_DMI) == 0) { ip->i_d.di_mode &= ~S_ISUID; /* diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index 454fa9a3e52..e932a96bec5 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h @@ -2,9 +2,9 @@ #define _XFS_VNODEOPS_H 1 struct attrlist_cursor_kern; -struct bhv_vattr; struct cred; struct file; +struct iattr; struct inode; struct iovec; struct kiocb; @@ -15,8 +15,12 @@ struct xfs_iomap; int xfs_open(struct xfs_inode *ip); -int xfs_setattr(struct xfs_inode *ip, struct bhv_vattr *vap, int flags, +int xfs_setattr(struct xfs_inode *ip, struct iattr *vap, int flags, struct cred *credp); +#define XFS_ATTR_DMI 0x01 /* invocation from a DMI function */ +#define XFS_ATTR_NONBLOCK 0x02 /* return EAGAIN if operation would block */ +#define XFS_ATTR_NOLOCK 0x04 /* Don't grab any conflicting locks */ + int xfs_readlink(struct xfs_inode *ip, char *link); int xfs_fsync(struct xfs_inode *ip); int xfs_release(struct xfs_inode *ip); -- cgit v1.2.3-70-g09d2 From f13fae2d2a9372a5155d20bc9da4c14f02193277 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 21 Jul 2008 16:16:15 +1000 Subject: [XFS] Remove vn_revalidate calls in xfs. These days most of the attributes in struct inode are properly kept in sync by XFS. This patch removes the need for vn_revalidate completely by: - keeping inode.i_flags uptodate after any flags are updated in xfs_ioctl_setattr - keeping i_mode, i_uid and i_gid uptodate in xfs_setattr SGI-PV: 984566 SGI-Modid: xfs-linux-melb:xfs-kern:31679a Signed-off-by: Christoph Hellwig Signed-off-by: Tim Shimmin Signed-off-by: Lachlan McIlroy --- fs/xfs/linux-2.6/xfs_ioctl.c | 29 +++++++++++++++++++++++-- fs/xfs/linux-2.6/xfs_iops.c | 16 +------------- fs/xfs/linux-2.6/xfs_vnode.c | 50 -------------------------------------------- fs/xfs/linux-2.6/xfs_vnode.h | 1 - fs/xfs/linux-2.6/xfs_xattr.c | 7 ++----- fs/xfs/xfs_vnodeops.c | 9 ++++++++ 6 files changed, 39 insertions(+), 73 deletions(-) (limited to 'fs/xfs/linux-2.6/xfs_iops.c') diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index d1b0da6bcdc..acb978d9d08 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -923,6 +923,30 @@ xfs_set_diflags( ip->i_d.di_flags = di_flags; } +STATIC void +xfs_diflags_to_linux( + struct xfs_inode *ip) +{ + struct inode *inode = XFS_ITOV(ip); + unsigned int xflags = xfs_ip2xflags(ip); + + if (xflags & XFS_XFLAG_IMMUTABLE) + inode->i_flags |= S_IMMUTABLE; + else + inode->i_flags &= ~S_IMMUTABLE; + if (xflags & XFS_XFLAG_APPEND) + inode->i_flags |= S_APPEND; + else + inode->i_flags &= ~S_APPEND; + if (xflags & XFS_XFLAG_SYNC) + inode->i_flags |= S_SYNC; + else + inode->i_flags &= ~S_SYNC; + if (xflags & XFS_XFLAG_NOATIME) + inode->i_flags |= S_NOATIME; + else + inode->i_flags &= ~S_NOATIME; +} #define FSX_PROJID 1 #define FSX_EXTSIZE 2 @@ -1121,8 +1145,10 @@ xfs_ioctl_setattr( if (mask & FSX_EXTSIZE) ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog; - if (mask & FSX_XFLAGS) + if (mask & FSX_XFLAGS) { xfs_set_diflags(ip, fa->fsx_xflags); + xfs_diflags_to_linux(ip); + } xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_ichgtime(ip, XFS_ICHGTIME_CHG); @@ -1160,7 +1186,6 @@ xfs_ioctl_setattr( (mask & FSX_NONBLOCK) ? DM_FLAGS_NDELAY : 0); } - vn_revalidate(XFS_ITOV(ip)); /* update flags */ return 0; error_return: diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 669bbdc2085..e88f5102808 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -650,21 +650,7 @@ xfs_vn_setattr( struct dentry *dentry, struct iattr *iattr) { - struct inode *inode = dentry->d_inode; - int error; - - if (iattr->ia_valid & ATTR_ATIME) - inode->i_atime = iattr->ia_atime; - - if (iattr->ia_valid & ATTR_MODE) { - if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) - inode->i_mode &= ~S_ISGID; - } - - error = xfs_setattr(XFS_I(inode), iattr, 0, NULL); - if (likely(!error)) - vn_revalidate(vn_from_inode(inode)); - return -error; + return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0, NULL); } /* diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c index bc7afe00733..25488b6d988 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.c +++ b/fs/xfs/linux-2.6/xfs_vnode.c @@ -82,56 +82,6 @@ vn_ioerror( xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ, f, l); } -/* - * Revalidate the Linux inode from the XFS inode. - * Note: i_size _not_ updated; we must hold the inode - * semaphore when doing that - callers responsibility. - */ -int -vn_revalidate( - bhv_vnode_t *vp) -{ - struct inode *inode = vn_to_inode(vp); - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - unsigned long xflags; - - xfs_itrace_entry(ip); - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - xfs_ilock(ip, XFS_ILOCK_SHARED); - inode->i_mode = ip->i_d.di_mode; - inode->i_uid = ip->i_d.di_uid; - inode->i_gid = ip->i_d.di_gid; - inode->i_mtime.tv_sec = ip->i_d.di_mtime.t_sec; - inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; - inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; - inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; - - xflags = xfs_ip2xflags(ip); - if (xflags & XFS_XFLAG_IMMUTABLE) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; - if (xflags & XFS_XFLAG_APPEND) - inode->i_flags |= S_APPEND; - else - inode->i_flags &= ~S_APPEND; - if (xflags & XFS_XFLAG_SYNC) - inode->i_flags |= S_SYNC; - else - inode->i_flags &= ~S_SYNC; - if (xflags & XFS_XFLAG_NOATIME) - inode->i_flags |= S_NOATIME; - else - inode->i_flags &= ~S_NOATIME; - xfs_iunlock(ip, XFS_ILOCK_SHARED); - - xfs_iflags_clear(ip, XFS_IMODIFIED); - return 0; -} /* * 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 96e4a7b5391..41ca2cec5d3 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h @@ -67,7 +67,6 @@ static inline struct inode *vn_to_inode(bhv_vnode_t *vnode) extern void vn_init(void); -extern int vn_revalidate(bhv_vnode_t *); /* * Yeah, these don't take vnode anymore at all, all this should be diff --git a/fs/xfs/linux-2.6/xfs_xattr.c b/fs/xfs/linux-2.6/xfs_xattr.c index b4acb68fc9f..964621fde6e 100644 --- a/fs/xfs/linux-2.6/xfs_xattr.c +++ b/fs/xfs/linux-2.6/xfs_xattr.c @@ -64,7 +64,7 @@ static int xfs_xattr_system_set(struct inode *inode, const char *name, const void *value, size_t size, int flags) { - int error, acl; + int acl; acl = xfs_decode_acl(name); if (acl < 0) @@ -75,10 +75,7 @@ xfs_xattr_system_set(struct inode *inode, const char *name, if (!value) return xfs_acl_vremove(inode, acl); - error = xfs_acl_vset(inode, (void *)value, size, acl); - if (!error) - vn_revalidate(inode); - return error; + return xfs_acl_vset(inode, (void *)value, size, acl); } static struct xattr_handler xfs_xattr_system_handler = { diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index b792a121b1a..76a1166af82 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -83,6 +83,7 @@ xfs_setattr( cred_t *credp) { xfs_mount_t *mp = ip->i_mount; + struct inode *inode = XFS_ITOV(ip); int mask = iattr->ia_valid; xfs_trans_t *tp; int code; @@ -446,6 +447,9 @@ xfs_setattr( ip->i_d.di_mode &= S_IFMT; ip->i_d.di_mode |= iattr->ia_mode & ~S_IFMT; + inode->i_mode &= S_IFMT; + inode->i_mode |= iattr->ia_mode & ~S_IFMT; + xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); timeflags |= XFS_ICHGTIME_CHG; } @@ -481,6 +485,7 @@ xfs_setattr( &ip->i_udquot, udqp); } ip->i_d.di_uid = uid; + inode->i_uid = uid; } if (igid != gid) { if (XFS_IS_GQUOTA_ON(mp)) { @@ -491,6 +496,7 @@ xfs_setattr( &ip->i_gdquot, gdqp); } ip->i_d.di_gid = gid; + inode->i_gid = gid; } xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); @@ -503,12 +509,14 @@ xfs_setattr( */ if (mask & (ATTR_ATIME|ATTR_MTIME)) { if (mask & ATTR_ATIME) { + inode->i_atime = iattr->ia_atime; ip->i_d.di_atime.t_sec = iattr->ia_atime.tv_sec; ip->i_d.di_atime.t_nsec = iattr->ia_atime.tv_nsec; ip->i_update_core = 1; timeflags &= ~XFS_ICHGTIME_ACC; } if (mask & ATTR_MTIME) { + inode->i_mtime = iattr->ia_mtime; ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec; ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec; timeflags &= ~XFS_ICHGTIME_MOD; @@ -524,6 +532,7 @@ xfs_setattr( */ if ((flags & XFS_ATTR_DMI) && (mask & ATTR_CTIME)) { + inode->i_ctime = iattr->ia_ctime; ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec; ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec; ip->i_update_core = 1; -- cgit v1.2.3-70-g09d2