Skip to content

Commit

Permalink
Merge tag 'for-linus-v3.10-rc5' of git://oss.sgi.com/xfs/xfs
Browse files Browse the repository at this point in the history
Pull more xfs updates from Ben Myers:
 "Here are several fixes for filesystems with CRC support turned on:
  fixes for quota, remote attributes, and recovery.  There is also some
  feature work related to CRCs: the implementation of CRCs for the inode
  unlinked lists, disabling noattr2/attr2 options when appropriate, and
  bumping the maximum number of ACLs.

  I would have preferred to defer this last category of items to 3.11.
  This would require setting a feature bit for the on-disk changes, so
  there is some pressure to get these in 3.10.  I believe this
  represents the end of the CRC related queue.

   - Rework of dquot CRCs
   - Fix for remote attribute invalidation of a leaf
   - Fix ordering of transaction replay in recovery
   - Implement CRCs for inode unlinked list
   - Disable noattr2/attr2 mount options when CRCs are enabled
   - Bump the limitation of ACL entries for v5 superblocks"

* tag 'for-linus-v3.10-rc5' of git://oss.sgi.com/xfs/xfs:
  xfs: increase number of ACL entries for V5 superblocks
  xfs: disable noattr2/attr2 mount options for CRC enabled filesystems
  xfs: inode unlinked list needs to recalculate the inode CRC
  xfs: fix log recovery transaction item reordering
  xfs: fix remote attribute invalidation for a leaf
  xfs: rework dquot CRCs
  • Loading branch information
Linus Torvalds committed Jun 6, 2013
2 parents 29eb778 + 0a8aa19 commit e6395b6
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 59 deletions.
3 changes: 3 additions & 0 deletions Documentation/filesystems/xfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ When mounting an XFS filesystem, the following options are accepted.
removing extended attributes) the on-disk superblock feature
bit field will be updated to reflect this format being in use.

CRC enabled filesystems always use the attr2 format, and so
will reject the noattr2 mount option if it is set.

barrier
Enables the use of block layer write barriers for writes into
the journal and unwritten extent conversion. This allows for
Expand Down
31 changes: 18 additions & 13 deletions fs/xfs/xfs_acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "xfs_bmap_btree.h"
#include "xfs_inode.h"
#include "xfs_vnodeops.h"
#include "xfs_sb.h"
#include "xfs_mount.h"
#include "xfs_trace.h"
#include <linux/slab.h>
#include <linux/xattr.h>
Expand All @@ -34,15 +36,17 @@
*/

STATIC struct posix_acl *
xfs_acl_from_disk(struct xfs_acl *aclp)
xfs_acl_from_disk(
struct xfs_acl *aclp,
int max_entries)
{
struct posix_acl_entry *acl_e;
struct posix_acl *acl;
struct xfs_acl_entry *ace;
unsigned int count, i;

count = be32_to_cpu(aclp->acl_cnt);
if (count > XFS_ACL_MAX_ENTRIES)
if (count > max_entries)
return ERR_PTR(-EFSCORRUPTED);

acl = posix_acl_alloc(count, GFP_KERNEL);
Expand Down Expand Up @@ -108,9 +112,9 @@ xfs_get_acl(struct inode *inode, int type)
struct xfs_inode *ip = XFS_I(inode);
struct posix_acl *acl;
struct xfs_acl *xfs_acl;
int len = sizeof(struct xfs_acl);
unsigned char *ea_name;
int error;
int len;

acl = get_cached_acl(inode, type);
if (acl != ACL_NOT_CACHED)
Expand All @@ -133,8 +137,8 @@ xfs_get_acl(struct inode *inode, int type)
* If we have a cached ACLs value just return it, not need to
* go out to the disk.
*/

xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
len = XFS_ACL_MAX_SIZE(ip->i_mount);
xfs_acl = kzalloc(len, GFP_KERNEL);
if (!xfs_acl)
return ERR_PTR(-ENOMEM);

Expand All @@ -153,7 +157,7 @@ xfs_get_acl(struct inode *inode, int type)
goto out;
}

acl = xfs_acl_from_disk(xfs_acl);
acl = xfs_acl_from_disk(xfs_acl, XFS_ACL_MAX_ENTRIES(ip->i_mount));
if (IS_ERR(acl))
goto out;

Expand Down Expand Up @@ -189,16 +193,17 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)

if (acl) {
struct xfs_acl *xfs_acl;
int len;
int len = XFS_ACL_MAX_SIZE(ip->i_mount);

xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
xfs_acl = kzalloc(len, GFP_KERNEL);
if (!xfs_acl)
return -ENOMEM;

xfs_acl_to_disk(xfs_acl, acl);
len = sizeof(struct xfs_acl) -
(sizeof(struct xfs_acl_entry) *
(XFS_ACL_MAX_ENTRIES - acl->a_count));

/* subtract away the unused acl entries */
len -= sizeof(struct xfs_acl_entry) *
(XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);

error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
len, ATTR_ROOT);
Expand Down Expand Up @@ -243,7 +248,7 @@ xfs_set_mode(struct inode *inode, umode_t mode)
static int
xfs_acl_exists(struct inode *inode, unsigned char *name)
{
int len = sizeof(struct xfs_acl);
int len = XFS_ACL_MAX_SIZE(XFS_M(inode->i_sb));

return (xfs_attr_get(XFS_I(inode), name, NULL, &len,
ATTR_ROOT|ATTR_KERNOVAL) == 0);
Expand Down Expand Up @@ -379,7 +384,7 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name,
goto out_release;

error = -EINVAL;
if (acl->a_count > XFS_ACL_MAX_ENTRIES)
if (acl->a_count > XFS_ACL_MAX_ENTRIES(XFS_M(inode->i_sb)))
goto out_release;

if (type == ACL_TYPE_ACCESS) {
Expand Down
31 changes: 24 additions & 7 deletions fs/xfs/xfs_acl.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,36 @@ struct inode;
struct posix_acl;
struct xfs_inode;

#define XFS_ACL_MAX_ENTRIES 25
#define XFS_ACL_NOT_PRESENT (-1)

/* On-disk XFS access control list structure */
struct xfs_acl_entry {
__be32 ae_tag;
__be32 ae_id;
__be16 ae_perm;
__be16 ae_pad; /* fill the implicit hole in the structure */
};

struct xfs_acl {
__be32 acl_cnt;
struct xfs_acl_entry {
__be32 ae_tag;
__be32 ae_id;
__be16 ae_perm;
} acl_entry[XFS_ACL_MAX_ENTRIES];
__be32 acl_cnt;
struct xfs_acl_entry acl_entry[0];
};

/*
* The number of ACL entries allowed is defined by the on-disk format.
* For v4 superblocks, that is limited to 25 entries. For v5 superblocks, it is
* limited only by the maximum size of the xattr that stores the information.
*/
#define XFS_ACL_MAX_ENTRIES(mp) \
(xfs_sb_version_hascrc(&mp->m_sb) \
? (XATTR_SIZE_MAX - sizeof(struct xfs_acl)) / \
sizeof(struct xfs_acl_entry) \
: 25)

#define XFS_ACL_MAX_SIZE(mp) \
(sizeof(struct xfs_acl) + \
sizeof(struct xfs_acl_entry) * XFS_ACL_MAX_ENTRIES((mp)))

/* On-disk XFS extended attribute names */
#define SGI_ACL_FILE (unsigned char *)"SGI_ACL_FILE"
#define SGI_ACL_DEFAULT (unsigned char *)"SGI_ACL_DEFAULT"
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_attr_leaf.c
Original file line number Diff line number Diff line change
Expand Up @@ -3258,7 +3258,7 @@ xfs_attr3_leaf_inactive(
name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
if (name_rmt->valueblk) {
lp->valueblk = be32_to_cpu(name_rmt->valueblk);
lp->valuelen = XFS_B_TO_FSB(dp->i_mount,
lp->valuelen = xfs_attr3_rmt_blocks(dp->i_mount,
be32_to_cpu(name_rmt->valuelen));
lp++;
}
Expand Down
37 changes: 16 additions & 21 deletions fs/xfs/xfs_dquot.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,11 @@ xfs_qm_init_dquot_blk(
d->dd_diskdq.d_version = XFS_DQUOT_VERSION;
d->dd_diskdq.d_id = cpu_to_be32(curid);
d->dd_diskdq.d_flags = type;
if (xfs_sb_version_hascrc(&mp->m_sb))
if (xfs_sb_version_hascrc(&mp->m_sb)) {
uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid);
xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
XFS_DQUOT_CRC_OFF);
}
}

xfs_trans_dquot_buf(tp, bp,
Expand Down Expand Up @@ -286,23 +289,6 @@ xfs_dquot_set_prealloc_limits(struct xfs_dquot *dqp)
dqp->q_low_space[XFS_QLOWSP_5_PCNT] = space * 5;
}

STATIC void
xfs_dquot_buf_calc_crc(
struct xfs_mount *mp,
struct xfs_buf *bp)
{
struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr;
int i;

if (!xfs_sb_version_hascrc(&mp->m_sb))
return;

for (i = 0; i < mp->m_quotainfo->qi_dqperchunk; i++, d++) {
xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
offsetof(struct xfs_dqblk, dd_crc));
}
}

STATIC bool
xfs_dquot_buf_verify_crc(
struct xfs_mount *mp,
Expand All @@ -328,12 +314,11 @@ xfs_dquot_buf_verify_crc(

for (i = 0; i < ndquots; i++, d++) {
if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
offsetof(struct xfs_dqblk, dd_crc)))
XFS_DQUOT_CRC_OFF))
return false;
if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid))
return false;
}

return true;
}

Expand Down Expand Up @@ -393,6 +378,11 @@ xfs_dquot_buf_read_verify(
}
}

/*
* we don't calculate the CRC here as that is done when the dquot is flushed to
* the buffer after the update is done. This ensures that the dquot in the
* buffer always has an up-to-date CRC value.
*/
void
xfs_dquot_buf_write_verify(
struct xfs_buf *bp)
Expand All @@ -404,7 +394,6 @@ xfs_dquot_buf_write_verify(
xfs_buf_ioerror(bp, EFSCORRUPTED);
return;
}
xfs_dquot_buf_calc_crc(mp, bp);
}

const struct xfs_buf_ops xfs_dquot_buf_ops = {
Expand Down Expand Up @@ -1151,11 +1140,17 @@ xfs_qm_dqflush(
* copy the lsn into the on-disk dquot now while we have the in memory
* dquot here. This can't be done later in the write verifier as we
* can't get access to the log item at that point in time.
*
* We also calculate the CRC here so that the on-disk dquot in the
* buffer always has a valid CRC. This ensures there is no possibility
* of a dquot without an up-to-date CRC getting to disk.
*/
if (xfs_sb_version_hascrc(&mp->m_sb)) {
struct xfs_dqblk *dqb = (struct xfs_dqblk *)ddqp;

dqb->dd_lsn = cpu_to_be64(dqp->q_logitem.qli_item.li_lsn);
xfs_update_cksum((char *)dqb, sizeof(struct xfs_dqblk),
XFS_DQUOT_CRC_OFF);
}

/*
Expand Down
16 changes: 16 additions & 0 deletions fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1638,6 +1638,10 @@ xfs_iunlink(
dip->di_next_unlinked = agi->agi_unlinked[bucket_index];
offset = ip->i_imap.im_boffset +
offsetof(xfs_dinode_t, di_next_unlinked);

/* need to recalc the inode CRC if appropriate */
xfs_dinode_calc_crc(mp, dip);

xfs_trans_inode_buf(tp, ibp);
xfs_trans_log_buf(tp, ibp, offset,
(offset + sizeof(xfs_agino_t) - 1));
Expand Down Expand Up @@ -1723,6 +1727,10 @@ xfs_iunlink_remove(
dip->di_next_unlinked = cpu_to_be32(NULLAGINO);
offset = ip->i_imap.im_boffset +
offsetof(xfs_dinode_t, di_next_unlinked);

/* need to recalc the inode CRC if appropriate */
xfs_dinode_calc_crc(mp, dip);

xfs_trans_inode_buf(tp, ibp);
xfs_trans_log_buf(tp, ibp, offset,
(offset + sizeof(xfs_agino_t) - 1));
Expand Down Expand Up @@ -1796,6 +1804,10 @@ xfs_iunlink_remove(
dip->di_next_unlinked = cpu_to_be32(NULLAGINO);
offset = ip->i_imap.im_boffset +
offsetof(xfs_dinode_t, di_next_unlinked);

/* need to recalc the inode CRC if appropriate */
xfs_dinode_calc_crc(mp, dip);

xfs_trans_inode_buf(tp, ibp);
xfs_trans_log_buf(tp, ibp, offset,
(offset + sizeof(xfs_agino_t) - 1));
Expand All @@ -1809,6 +1821,10 @@ xfs_iunlink_remove(
last_dip->di_next_unlinked = cpu_to_be32(next_agino);
ASSERT(next_agino != 0);
offset = last_offset + offsetof(xfs_dinode_t, di_next_unlinked);

/* need to recalc the inode CRC if appropriate */
xfs_dinode_calc_crc(mp, last_dip);

xfs_trans_inode_buf(tp, last_ibp);
xfs_trans_log_buf(tp, last_ibp, offset,
(offset + sizeof(xfs_agino_t) - 1));
Expand Down
Loading

0 comments on commit e6395b6

Please sign in to comment.