Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs

* 'for-linus' of git://oss.sgi.com/xfs/xfs:
  xfs: fix attr2 vs large data fork assert
  xfs: force buffer writeback before blocking on the ilock in inode reclaim
  xfs: validate acl count
This commit is contained in:
Linus Torvalds 2011-12-02 10:38:20 -08:00
commit ffb8fb5469
5 changed files with 74 additions and 25 deletions

View File

@ -42,6 +42,8 @@ xfs_acl_from_disk(struct xfs_acl *aclp)
int count, i; int count, i;
count = be32_to_cpu(aclp->acl_cnt); count = be32_to_cpu(aclp->acl_cnt);
if (count > XFS_ACL_MAX_ENTRIES)
return ERR_PTR(-EFSCORRUPTED);
acl = posix_acl_alloc(count, GFP_KERNEL); acl = posix_acl_alloc(count, GFP_KERNEL);
if (!acl) if (!acl)

View File

@ -110,6 +110,7 @@ xfs_attr_namesp_match(int arg_flags, int ondisk_flags)
/* /*
* Query whether the requested number of additional bytes of extended * Query whether the requested number of additional bytes of extended
* attribute space will be able to fit inline. * attribute space will be able to fit inline.
*
* Returns zero if not, else the di_forkoff fork offset to be used in the * Returns zero if not, else the di_forkoff fork offset to be used in the
* literal area for attribute data once the new bytes have been added. * literal area for attribute data once the new bytes have been added.
* *
@ -122,7 +123,7 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes)
int offset; int offset;
int minforkoff; /* lower limit on valid forkoff locations */ int minforkoff; /* lower limit on valid forkoff locations */
int maxforkoff; /* upper limit on valid forkoff locations */ int maxforkoff; /* upper limit on valid forkoff locations */
int dsize; int dsize;
xfs_mount_t *mp = dp->i_mount; xfs_mount_t *mp = dp->i_mount;
offset = (XFS_LITINO(mp) - bytes) >> 3; /* rounded down */ offset = (XFS_LITINO(mp) - bytes) >> 3; /* rounded down */
@ -136,47 +137,60 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes)
return (offset >= minforkoff) ? minforkoff : 0; return (offset >= minforkoff) ? minforkoff : 0;
} }
if (!(mp->m_flags & XFS_MOUNT_ATTR2)) { /*
if (bytes <= XFS_IFORK_ASIZE(dp)) * If the requested numbers of bytes is smaller or equal to the
return dp->i_d.di_forkoff; * current attribute fork size we can always proceed.
*
* Note that if_bytes in the data fork might actually be larger than
* the current data fork size is due to delalloc extents. In that
* case either the extent count will go down when they are converted
* to real extents, or the delalloc conversion will take care of the
* literal area rebalancing.
*/
if (bytes <= XFS_IFORK_ASIZE(dp))
return dp->i_d.di_forkoff;
/*
* For attr2 we can try to move the forkoff if there is space in the
* literal area, but for the old format we are done if there is no
* space in the fixed attribute fork.
*/
if (!(mp->m_flags & XFS_MOUNT_ATTR2))
return 0; return 0;
}
dsize = dp->i_df.if_bytes; dsize = dp->i_df.if_bytes;
switch (dp->i_d.di_format) { switch (dp->i_d.di_format) {
case XFS_DINODE_FMT_EXTENTS: case XFS_DINODE_FMT_EXTENTS:
/* /*
* If there is no attr fork and the data fork is extents, * If there is no attr fork and the data fork is extents,
* determine if creating the default attr fork will result * determine if creating the default attr fork will result
* in the extents form migrating to btree. If so, the * in the extents form migrating to btree. If so, the
* minimum offset only needs to be the space required for * minimum offset only needs to be the space required for
* the btree root. * the btree root.
*/ */
if (!dp->i_d.di_forkoff && dp->i_df.if_bytes > if (!dp->i_d.di_forkoff && dp->i_df.if_bytes >
xfs_default_attroffset(dp)) xfs_default_attroffset(dp))
dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS); dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS);
break; break;
case XFS_DINODE_FMT_BTREE: case XFS_DINODE_FMT_BTREE:
/* /*
* If have data btree then keep forkoff if we have one, * If we have a data btree then keep forkoff if we have one,
* otherwise we are adding a new attr, so then we set * otherwise we are adding a new attr, so then we set
* minforkoff to where the btree root can finish so we have * minforkoff to where the btree root can finish so we have
* plenty of room for attrs * plenty of room for attrs
*/ */
if (dp->i_d.di_forkoff) { if (dp->i_d.di_forkoff) {
if (offset < dp->i_d.di_forkoff) if (offset < dp->i_d.di_forkoff)
return 0; return 0;
else return dp->i_d.di_forkoff;
return dp->i_d.di_forkoff; }
} else dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot);
dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot);
break; break;
} }
/* /*
* A data fork btree root must have space for at least * A data fork btree root must have space for at least
* MINDBTPTRS key/ptr pairs if the data fork is small or empty. * MINDBTPTRS key/ptr pairs if the data fork is small or empty.
*/ */
minforkoff = MAX(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS)); minforkoff = MAX(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS));
@ -186,10 +200,10 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes)
maxforkoff = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS); maxforkoff = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS);
maxforkoff = maxforkoff >> 3; /* rounded down */ maxforkoff = maxforkoff >> 3; /* rounded down */
if (offset >= minforkoff && offset < maxforkoff)
return offset;
if (offset >= maxforkoff) if (offset >= maxforkoff)
return maxforkoff; return maxforkoff;
if (offset >= minforkoff)
return offset;
return 0; return 0;
} }

View File

@ -2835,6 +2835,27 @@ corrupt_out:
return XFS_ERROR(EFSCORRUPTED); return XFS_ERROR(EFSCORRUPTED);
} }
void
xfs_promote_inode(
struct xfs_inode *ip)
{
struct xfs_buf *bp;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
bp = xfs_incore(ip->i_mount->m_ddev_targp, ip->i_imap.im_blkno,
ip->i_imap.im_len, XBF_TRYLOCK);
if (!bp)
return;
if (XFS_BUF_ISDELAYWRITE(bp)) {
xfs_buf_delwri_promote(bp);
wake_up_process(ip->i_mount->m_ddev_targp->bt_task);
}
xfs_buf_relse(bp);
}
/* /*
* Return a pointer to the extent record at file index idx. * Return a pointer to the extent record at file index idx.
*/ */

View File

@ -498,6 +498,7 @@ int xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
void xfs_iext_realloc(xfs_inode_t *, int, int); void xfs_iext_realloc(xfs_inode_t *, int, int);
void xfs_iunpin_wait(xfs_inode_t *); void xfs_iunpin_wait(xfs_inode_t *);
int xfs_iflush(xfs_inode_t *, uint); int xfs_iflush(xfs_inode_t *, uint);
void xfs_promote_inode(struct xfs_inode *);
void xfs_lock_inodes(xfs_inode_t **, int, uint); void xfs_lock_inodes(xfs_inode_t **, int, uint);
void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint); void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);

View File

@ -770,6 +770,17 @@ restart:
if (!xfs_iflock_nowait(ip)) { if (!xfs_iflock_nowait(ip)) {
if (!(sync_mode & SYNC_WAIT)) if (!(sync_mode & SYNC_WAIT))
goto out; goto out;
/*
* If we only have a single dirty inode in a cluster there is
* a fair chance that the AIL push may have pushed it into
* the buffer, but xfsbufd won't touch it until 30 seconds
* from now, and thus we will lock up here.
*
* Promote the inode buffer to the front of the delwri list
* and wake up xfsbufd now.
*/
xfs_promote_inode(ip);
xfs_iflock(ip); xfs_iflock(ip);
} }