Commit af60eee1 authored by Nathan Scott's avatar Nathan Scott Committed by Stephen Lord

[XFS] Fix up the default ACL inherit case, in the presence of failure during...

[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
parent 3284f263
...@@ -109,14 +109,20 @@ linvfs_mknod( ...@@ -109,14 +109,20 @@ linvfs_mknod(
struct inode *ip; struct inode *ip;
vattr_t va; vattr_t va;
vnode_t *vp = NULL, *dvp = LINVFS_GET_VP(dir); vnode_t *vp = NULL, *dvp = LINVFS_GET_VP(dir);
xfs_acl_t *default_acl = NULL;
xattr_exists_t test_default_acl = _ACL_DEFAULT_EXISTS; xattr_exists_t test_default_acl = _ACL_DEFAULT_EXISTS;
int have_default_acl = 0; int error;
int error = EINVAL;
if (test_default_acl) if (test_default_acl && test_default_acl(dvp)) {
have_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; mode &= ~current->fs->umask;
memset(&va, 0, sizeof(va)); memset(&va, 0, sizeof(va));
...@@ -140,13 +146,36 @@ linvfs_mknod( ...@@ -140,13 +146,36 @@ linvfs_mknod(
break; break;
} }
if (default_acl) {
if (!error) { if (!error) {
ASSERT(vp); error = _ACL_INHERIT(vp, &va, default_acl);
ip = LINVFS_GET_IP(vp); if (!error) {
if (!ip) { 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); VN_RELE(vp);
return -ENOMEM;
} }
}
_ACL_FREE(default_acl);
}
if (!error) {
ASSERT(vp);
ip = LINVFS_GET_IP(vp);
if (S_ISCHR(mode) || S_ISBLK(mode)) if (S_ISCHR(mode) || S_ISBLK(mode))
ip->i_rdev = to_kdev_t(rdev); ip->i_rdev = to_kdev_t(rdev);
...@@ -155,19 +184,6 @@ linvfs_mknod( ...@@ -155,19 +184,6 @@ linvfs_mknod(
d_instantiate(dentry, ip); d_instantiate(dentry, ip);
validate_fields(dir); 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; return -error;
} }
......
...@@ -1718,6 +1718,7 @@ xfs_attr_node_get(xfs_da_args_t *args) ...@@ -1718,6 +1718,7 @@ xfs_attr_node_get(xfs_da_args_t *args)
int i; int i;
state = xfs_da_state_alloc(); state = xfs_da_state_alloc();
state->holeok = 1;
state->args = args; state->args = args;
state->mp = args->dp->i_mount; state->mp = args->dp->i_mount;
state->blocksize = state->mp->m_sb.sb_blocksize; state->blocksize = state->mp->m_sb.sb_blocksize;
......
/* /*
* 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 * 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 * 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) ...@@ -1141,10 +1141,13 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
xfs_da_node_entry_t *btree; xfs_da_node_entry_t *btree;
xfs_dablk_t blkno; xfs_dablk_t blkno;
int probe, span, max, error, retval; int probe, span, max, error, retval;
xfs_daddr_t mappedbno;
xfs_dahash_t hashval; xfs_dahash_t hashval;
xfs_da_args_t *args; xfs_da_args_t *args;
args = state->args; args = state->args;
mappedbno = state->holeok ? -2 : -1;
/* /*
* Descend thru the B-tree searching each level for the right * Descend thru the B-tree searching each level for the right
* node to use, until the right hashval is found. * 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) ...@@ -1160,15 +1163,15 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
* Read the next node down in the tree. * Read the next node down in the tree.
*/ */
blk->blkno = blkno; blk->blkno = blkno;
error = xfs_da_read_buf(state->args->trans, state->args->dp, error = xfs_da_read_buf(args->trans, args->dp, blkno,
blkno, -1, &blk->bp, mappedbno, &blk->bp, args->whichfork);
state->args->whichfork); if (!error && unlikely(state->holeok && !blk->bp))
error = XFS_ERROR(ENOATTR); /* always attr here */
if (error) { if (error) {
blk->blkno = 0; blk->blkno = 0;
state->path.active--; state->path.active--;
return(error); return(error);
} }
ASSERT(blk->bp != NULL);
curr = blk->bp->data; curr = blk->bp->data;
ASSERT(INT_GET(curr->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC || ASSERT(INT_GET(curr->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC ||
INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) || 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) ...@@ -1187,7 +1190,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
*/ */
max = INT_GET(node->hdr.count, ARCH_CONVERT); max = INT_GET(node->hdr.count, ARCH_CONVERT);
probe = span = max / 2; probe = span = max / 2;
hashval = state->args->hashval; hashval = args->hashval;
for (btree = &node->btree[probe]; span > 4; for (btree = &node->btree[probe]; span > 4;
btree = &node->btree[probe]) { btree = &node->btree[probe]) {
span /= 2; span /= 2;
...@@ -1250,22 +1253,22 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) ...@@ -1250,22 +1253,22 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
for (;;) { for (;;) {
if (blk->magic == XFS_DIR_LEAF_MAGIC) { if (blk->magic == XFS_DIR_LEAF_MAGIC) {
ASSERT(XFS_DIR_IS_V1(state->mp)); 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); &blk->index);
} else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) { } else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {
ASSERT(XFS_DIR_IS_V2(state->mp)); 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); &blk->index, state);
} }
#ifdef __KERNEL__ #ifdef __KERNEL__
else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
retval = xfs_attr_leaf_lookup_int(blk->bp, state->args); retval = xfs_attr_leaf_lookup_int(blk->bp, args);
blk->index = state->args->index; blk->index = args->index;
state->args->blkno = blk->blkno; args->blkno = blk->blkno;
} }
#endif #endif
if (((retval == ENOENT) || (retval == ENOATTR)) && if (((retval == ENOENT) || (retval == ENOATTR)) &&
(blk->hashval == state->args->hashval)) { (blk->hashval == args->hashval)) {
error = xfs_da_path_shift(state, &state->path, 1, 1, error = xfs_da_path_shift(state, &state->path, 1, 1,
&retval); &retval);
if (error) if (error)
......
...@@ -185,14 +185,14 @@ typedef struct xfs_da_args { ...@@ -185,14 +185,14 @@ typedef struct xfs_da_args {
int index; /* index of attr of interest in blk */ int index; /* index of attr of interest in blk */
xfs_dablk_t rmtblkno; /* remote attr value starting blkno */ xfs_dablk_t rmtblkno; /* remote attr value starting blkno */
int rmtblkcnt; /* remote attr value block count */ 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 */ xfs_dablk_t blkno2; /* blkno of 2nd attr leaf of interest */
int index2; /* index of 2nd attr in blk */ int index2; /* index of 2nd attr in blk */
xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */ xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */
int rmtblkcnt2; /* remote attr value block count */ int rmtblkcnt2; /* remote attr value block count */
int justcheck; /* check for ok with no space */ int justcheck : 1; /* T/F: check for ok with no space */
int addname; /* T/F: this is an add operation */ int rename : 1; /* T/F: this is an atomic rename op */
int oknoent; /* T/F: ok to return ENOENT, else die */ 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; } xfs_da_args_t;
/* /*
...@@ -253,6 +253,7 @@ typedef struct xfs_da_state { ...@@ -253,6 +253,7 @@ typedef struct xfs_da_state {
xfs_da_state_path_t path; /* search/split paths */ xfs_da_state_path_t path; /* search/split paths */
xfs_da_state_path_t altpath; /* alternate path for join */ xfs_da_state_path_t altpath; /* alternate path for join */
unsigned int inleaf : 1; /* insert into 1->lf, 0->splf */ 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 extravalid : 1; /* T/F: extrablk is in use */
unsigned int extraafter : 1; /* T/F: extrablk is after new */ unsigned int extraafter : 1; /* T/F: extrablk is after new */
xfs_da_state_blk_t extrablk; /* for double-splits on leafs */ xfs_da_state_blk_t extrablk; /* for double-splits on leafs */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment