6dfe5a049f
xfs_attr_inactive() is supposed to clean up the attribute fork when the inode is being freed. While it removes attribute fork extents, it completely ignores attributes in local format, which means that there can still be active attributes on the inode after xfs_attr_inactive() has run. This leads to problems with concurrent inode writeback - the in-core inode attribute fork is removed without locking on the assumption that nothing will be attempting to access the attribute fork after a call to xfs_attr_inactive() because it isn't supposed to exist on disk any more. To fix this, make xfs_attr_inactive() completely remove all traces of the attribute fork from the inode, regardless of it's state. Further, also remove the in-core attribute fork structure safely so that there is nothing further that needs to be done by callers to clean up the attribute fork. This means we can remove the in-core and on-disk attribute forks atomically. Also, on error simply remove the in-memory attribute fork. There's nothing that can be done with it once we have failed to remove the on-disk attribute fork, so we may as well just blow it away here anyway. cc: <stable@vger.kernel.org> # 3.12 to 4.0 Reported-by: Waiman Long <waiman.long@hp.com> Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
111 lines
4.1 KiB
C
111 lines
4.1 KiB
C
/*
|
|
* Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc.
|
|
* Copyright (c) 2013 Red Hat, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it would be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
#ifndef __XFS_ATTR_LEAF_H__
|
|
#define __XFS_ATTR_LEAF_H__
|
|
|
|
struct attrlist;
|
|
struct attrlist_cursor_kern;
|
|
struct xfs_attr_list_context;
|
|
struct xfs_da_args;
|
|
struct xfs_da_state;
|
|
struct xfs_da_state_blk;
|
|
struct xfs_inode;
|
|
struct xfs_trans;
|
|
|
|
/*
|
|
* Used to keep a list of "remote value" extents when unlinking an inode.
|
|
*/
|
|
typedef struct xfs_attr_inactive_list {
|
|
xfs_dablk_t valueblk; /* block number of value bytes */
|
|
int valuelen; /* number of bytes in value */
|
|
} xfs_attr_inactive_list_t;
|
|
|
|
|
|
/*========================================================================
|
|
* Function prototypes for the kernel.
|
|
*========================================================================*/
|
|
|
|
/*
|
|
* Internal routines when attribute fork size < XFS_LITINO(mp).
|
|
*/
|
|
void xfs_attr_shortform_create(struct xfs_da_args *args);
|
|
void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff);
|
|
int xfs_attr_shortform_lookup(struct xfs_da_args *args);
|
|
int xfs_attr_shortform_getvalue(struct xfs_da_args *args);
|
|
int xfs_attr_shortform_to_leaf(struct xfs_da_args *args);
|
|
int xfs_attr_shortform_remove(struct xfs_da_args *args);
|
|
int xfs_attr_shortform_list(struct xfs_attr_list_context *context);
|
|
int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
|
|
int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes);
|
|
void xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp);
|
|
|
|
/*
|
|
* Internal routines when attribute fork size == XFS_LBSIZE(mp).
|
|
*/
|
|
int xfs_attr3_leaf_to_node(struct xfs_da_args *args);
|
|
int xfs_attr3_leaf_to_shortform(struct xfs_buf *bp,
|
|
struct xfs_da_args *args, int forkoff);
|
|
int xfs_attr3_leaf_clearflag(struct xfs_da_args *args);
|
|
int xfs_attr3_leaf_setflag(struct xfs_da_args *args);
|
|
int xfs_attr3_leaf_flipflags(struct xfs_da_args *args);
|
|
|
|
/*
|
|
* Routines used for growing the Btree.
|
|
*/
|
|
int xfs_attr3_leaf_split(struct xfs_da_state *state,
|
|
struct xfs_da_state_blk *oldblk,
|
|
struct xfs_da_state_blk *newblk);
|
|
int xfs_attr3_leaf_lookup_int(struct xfs_buf *leaf,
|
|
struct xfs_da_args *args);
|
|
int xfs_attr3_leaf_getvalue(struct xfs_buf *bp, struct xfs_da_args *args);
|
|
int xfs_attr3_leaf_add(struct xfs_buf *leaf_buffer,
|
|
struct xfs_da_args *args);
|
|
int xfs_attr3_leaf_remove(struct xfs_buf *leaf_buffer,
|
|
struct xfs_da_args *args);
|
|
int xfs_attr3_leaf_list_int(struct xfs_buf *bp,
|
|
struct xfs_attr_list_context *context);
|
|
|
|
/*
|
|
* Routines used for shrinking the Btree.
|
|
*/
|
|
int xfs_attr3_leaf_toosmall(struct xfs_da_state *state, int *retval);
|
|
void xfs_attr3_leaf_unbalance(struct xfs_da_state *state,
|
|
struct xfs_da_state_blk *drop_blk,
|
|
struct xfs_da_state_blk *save_blk);
|
|
int xfs_attr3_root_inactive(struct xfs_trans **trans, struct xfs_inode *dp);
|
|
|
|
/*
|
|
* Utility routines.
|
|
*/
|
|
xfs_dahash_t xfs_attr_leaf_lasthash(struct xfs_buf *bp, int *count);
|
|
int xfs_attr_leaf_order(struct xfs_buf *leaf1_bp,
|
|
struct xfs_buf *leaf2_bp);
|
|
int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int *local);
|
|
int xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
|
|
xfs_dablk_t bno, xfs_daddr_t mappedbno,
|
|
struct xfs_buf **bpp);
|
|
void xfs_attr3_leaf_hdr_from_disk(struct xfs_da_geometry *geo,
|
|
struct xfs_attr3_icleaf_hdr *to,
|
|
struct xfs_attr_leafblock *from);
|
|
void xfs_attr3_leaf_hdr_to_disk(struct xfs_da_geometry *geo,
|
|
struct xfs_attr_leafblock *to,
|
|
struct xfs_attr3_icleaf_hdr *from);
|
|
|
|
#endif /* __XFS_ATTR_LEAF_H__ */
|