From af60eee1af46701881c2c8c4240a35b1a05ee8f8 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Mon, 11 Aug 2003 20:49:01 -0500 Subject: [PATCH] [XFS] Fix up the default ACL inherit case, in the presence of failure during applying the default ACL (eg. from ENOSPC). SGI Modid: 2.5.x-xfs:slinx:155553a --- fs/xfs/linux/xfs_iops.c | 60 ++++++++++++++++++++++++++--------------- fs/xfs/xfs_attr.c | 1 + fs/xfs/xfs_da_btree.c | 27 ++++++++++--------- fs/xfs/xfs_da_btree.h | 9 ++++--- 4 files changed, 59 insertions(+), 38 deletions(-) diff --git a/fs/xfs/linux/xfs_iops.c b/fs/xfs/linux/xfs_iops.c index c66aff5b1609a..11eac5784afa6 100644 --- a/fs/xfs/linux/xfs_iops.c +++ b/fs/xfs/linux/xfs_iops.c @@ -109,14 +109,20 @@ linvfs_mknod( struct inode *ip; vattr_t va; vnode_t *vp = NULL, *dvp = LINVFS_GET_VP(dir); + xfs_acl_t *default_acl = NULL; xattr_exists_t test_default_acl = _ACL_DEFAULT_EXISTS; - int have_default_acl = 0; - int error = EINVAL; + int error; - if (test_default_acl) - have_default_acl = test_default_acl(dvp); + if (test_default_acl && test_default_acl(dvp)) { + if (!_ACL_ALLOC(default_acl)) + return -ENOMEM; + if (!_ACL_GET_DEFAULT(dvp, default_acl)) { + _ACL_FREE(default_acl); + default_acl = NULL; + } + } - if (IS_POSIXACL(dir) && !have_default_acl && has_fs_struct(current)) + if (IS_POSIXACL(dir) && !default_acl && has_fs_struct(current)) mode &= ~current->fs->umask; memset(&va, 0, sizeof(va)); @@ -140,13 +146,36 @@ linvfs_mknod( break; } + if (default_acl) { + if (!error) { + error = _ACL_INHERIT(vp, &va, default_acl); + if (!error) { + VMODIFY(vp); + } else { + struct dentry teardown = {}; + int err2; + + /* Oh, the horror. + * If we can't add the ACL we must back out. + * ENOSPC can hit here, among other things. + */ + teardown.d_inode = ip = LINVFS_GET_IP(vp); + teardown.d_name = dentry->d_name; + remove_inode_hash(ip); + make_bad_inode(ip); + if (S_ISDIR(mode)) + VOP_RMDIR(dvp, &teardown, NULL, err2); + else + VOP_REMOVE(dvp, &teardown, NULL, err2); + VN_RELE(vp); + } + } + _ACL_FREE(default_acl); + } + if (!error) { ASSERT(vp); ip = LINVFS_GET_IP(vp); - if (!ip) { - VN_RELE(vp); - return -ENOMEM; - } if (S_ISCHR(mode) || S_ISBLK(mode)) ip->i_rdev = to_kdev_t(rdev); @@ -155,19 +184,6 @@ linvfs_mknod( d_instantiate(dentry, ip); validate_fields(dir); } - - if (!error && have_default_acl) { - _ACL_DECL (pdacl); - - if (!_ACL_ALLOC(pdacl)) { - error = -ENOMEM; - } else { - if (_ACL_GET_DEFAULT(dvp, pdacl)) - error = _ACL_INHERIT(vp, &va, pdacl); - VMODIFY(vp); - _ACL_FREE(pdacl); - } - } return -error; } diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 3514de27c85c3..90048386b3ab6 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -1718,6 +1718,7 @@ xfs_attr_node_get(xfs_da_args_t *args) int i; state = xfs_da_state_alloc(); + state->holeok = 1; state->args = args; state->mp = args->dp->i_mount; state->blocksize = state->mp->m_sb.sb_blocksize; diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index bd112587e784b..76aadaa992e56 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -1141,10 +1141,13 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) xfs_da_node_entry_t *btree; xfs_dablk_t blkno; int probe, span, max, error, retval; + xfs_daddr_t mappedbno; xfs_dahash_t hashval; xfs_da_args_t *args; args = state->args; + mappedbno = state->holeok ? -2 : -1; + /* * Descend thru the B-tree searching each level for the right * node to use, until the right hashval is found. @@ -1160,15 +1163,15 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) * Read the next node down in the tree. */ blk->blkno = blkno; - error = xfs_da_read_buf(state->args->trans, state->args->dp, - blkno, -1, &blk->bp, - state->args->whichfork); + error = xfs_da_read_buf(args->trans, args->dp, blkno, + mappedbno, &blk->bp, args->whichfork); + if (!error && unlikely(state->holeok && !blk->bp)) + error = XFS_ERROR(ENOATTR); /* always attr here */ if (error) { blk->blkno = 0; state->path.active--; return(error); } - ASSERT(blk->bp != NULL); curr = blk->bp->data; ASSERT(INT_GET(curr->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC || INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) || @@ -1187,7 +1190,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) */ max = INT_GET(node->hdr.count, ARCH_CONVERT); probe = span = max / 2; - hashval = state->args->hashval; + hashval = args->hashval; for (btree = &node->btree[probe]; span > 4; btree = &node->btree[probe]) { span /= 2; @@ -1250,22 +1253,22 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) for (;;) { if (blk->magic == XFS_DIR_LEAF_MAGIC) { ASSERT(XFS_DIR_IS_V1(state->mp)); - retval = xfs_dir_leaf_lookup_int(blk->bp, state->args, + retval = xfs_dir_leaf_lookup_int(blk->bp, args, &blk->index); } else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) { ASSERT(XFS_DIR_IS_V2(state->mp)); - retval = xfs_dir2_leafn_lookup_int(blk->bp, state->args, + retval = xfs_dir2_leafn_lookup_int(blk->bp, args, &blk->index, state); } #ifdef __KERNEL__ else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { - retval = xfs_attr_leaf_lookup_int(blk->bp, state->args); - blk->index = state->args->index; - state->args->blkno = blk->blkno; + retval = xfs_attr_leaf_lookup_int(blk->bp, args); + blk->index = args->index; + args->blkno = blk->blkno; } #endif if (((retval == ENOENT) || (retval == ENOATTR)) && - (blk->hashval == state->args->hashval)) { + (blk->hashval == args->hashval)) { error = xfs_da_path_shift(state, &state->path, 1, 1, &retval); if (error) diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h index e575998a58ad2..86f286bdab633 100644 --- a/fs/xfs/xfs_da_btree.h +++ b/fs/xfs/xfs_da_btree.h @@ -185,14 +185,14 @@ typedef struct xfs_da_args { int index; /* index of attr of interest in blk */ xfs_dablk_t rmtblkno; /* remote attr value starting blkno */ int rmtblkcnt; /* remote attr value block count */ - int rename; /* T/F: this is an atomic rename op */ xfs_dablk_t blkno2; /* blkno of 2nd attr leaf of interest */ int index2; /* index of 2nd attr in blk */ xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */ int rmtblkcnt2; /* remote attr value block count */ - int justcheck; /* check for ok with no space */ - int addname; /* T/F: this is an add operation */ - int oknoent; /* T/F: ok to return ENOENT, else die */ + int justcheck : 1; /* T/F: check for ok with no space */ + int rename : 1; /* T/F: this is an atomic rename op */ + int addname : 1; /* T/F: this is an add operation */ + int oknoent : 1; /* T/F: ok to return ENOENT, else die */ } xfs_da_args_t; /* @@ -253,6 +253,7 @@ typedef struct xfs_da_state { xfs_da_state_path_t path; /* search/split paths */ xfs_da_state_path_t altpath; /* alternate path for join */ unsigned int inleaf : 1; /* insert into 1->lf, 0->splf */ + unsigned int holeok : 1; /* T/F: can deal with a hole */ unsigned int extravalid : 1; /* T/F: extrablk is in use */ unsigned int extraafter : 1; /* T/F: extrablk is after new */ xfs_da_state_blk_t extrablk; /* for double-splits on leafs */ -- 2.53.0