Skip to content

Commit

Permalink
Merge tag 'xfs-for-linus-v3.12-rc1-2' of git://oss.sgi.com/xfs/xfs
Browse files Browse the repository at this point in the history
Pull xfs update #2 from Ben Myers:
 "Here we have defrag support for v5 superblock, a number of bugfixes
  and a cleanup or two.

   - defrag support for CRC filesystems
   - fix endian worning in xlog_recover_get_buf_lsn
   - fixes for sparse warnings
   - fix for assert in xfs_dir3_leaf_hdr_from_disk
   - fix for log recovery of remote symlinks
   - fix for log recovery of btree root splits
   - fixes formemory allocation failures with ACLs
   - fix for assert in xfs_buf_item_relse
   - fix for assert in xfs_inode_buf_verify
   - fix an assignment in an assert that should be a test in
     xfs_bmbt_change_owner
   - remove dead code in xlog_recover_inode_pass2"

* tag 'xfs-for-linus-v3.12-rc1-2' of git://oss.sgi.com/xfs/xfs:
  xfs: remove dead code from xlog_recover_inode_pass2
  xfs: = vs == typo in ASSERT()
  xfs: don't assert fail on bad inode numbers
  xfs: aborted buf items can be in the AIL.
  xfs: factor all the kmalloc-or-vmalloc fallback allocations
  xfs: fix memory allocation failures with ACLs
  xfs: ensure we copy buffer type in da btree root splits
  xfs: set remote symlink buffer type for recovery
  xfs: recovery of swap extents operations for CRC filesystems
  xfs: swap extents operations for CRC filesystems
  xfs: check magic numbers in dir3 leaf verifier first
  xfs: fix some minor sparse warnings
  xfs: fix endian warning in xlog_recover_get_buf_lsn()
  • Loading branch information
torvalds committed Sep 12, 2013
2 parents 48efe45 + 08474ed commit e0ea404
Show file tree
Hide file tree
Showing 25 changed files with 461 additions and 166 deletions.
15 changes: 12 additions & 3 deletions fs/xfs/kmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,14 @@

/*
* Greedy allocation. May fail and may return vmalloced memory.
*
* Must be freed using kmem_free_large.
*/
void *
kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize)
{
void *ptr;
size_t kmsize = maxsize;

while (!(ptr = kmem_zalloc_large(kmsize))) {
while (!(ptr = vzalloc(kmsize))) {
if ((kmsize >>= 1) <= minsize)
kmsize = minsize;
}
Expand Down Expand Up @@ -75,6 +73,17 @@ kmem_zalloc(size_t size, xfs_km_flags_t flags)
return ptr;
}

void *
kmem_zalloc_large(size_t size, xfs_km_flags_t flags)
{
void *ptr;

ptr = kmem_zalloc(size, flags | KM_MAYFAIL);
if (ptr)
return ptr;
return vzalloc(size);
}

void
kmem_free(const void *ptr)
{
Expand Down
9 changes: 1 addition & 8 deletions fs/xfs/kmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,10 @@ kmem_flags_convert(xfs_km_flags_t flags)

extern void *kmem_alloc(size_t, xfs_km_flags_t);
extern void *kmem_zalloc(size_t, xfs_km_flags_t);
extern void *kmem_zalloc_large(size_t size, xfs_km_flags_t);
extern void *kmem_realloc(const void *, size_t, size_t, xfs_km_flags_t);
extern void kmem_free(const void *);

static inline void *kmem_zalloc_large(size_t size)
{
return vzalloc(size);
}
static inline void kmem_free_large(void *ptr)
{
vfree(ptr);
}

extern void *kmem_zalloc_greedy(size_t *, size_t, size_t);

Expand Down
12 changes: 6 additions & 6 deletions fs/xfs/xfs_acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ xfs_get_acl(struct inode *inode, int type)
* go out to the disk.
*/
len = XFS_ACL_MAX_SIZE(ip->i_mount);
xfs_acl = kzalloc(len, GFP_KERNEL);
xfs_acl = kmem_zalloc_large(len, KM_SLEEP);
if (!xfs_acl)
return ERR_PTR(-ENOMEM);

Expand All @@ -175,10 +175,10 @@ xfs_get_acl(struct inode *inode, int type)
if (IS_ERR(acl))
goto out;

out_update_cache:
out_update_cache:
set_cached_acl(inode, type, acl);
out:
kfree(xfs_acl);
out:
kmem_free(xfs_acl);
return acl;
}

Expand Down Expand Up @@ -209,7 +209,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
struct xfs_acl *xfs_acl;
int len = XFS_ACL_MAX_SIZE(ip->i_mount);

xfs_acl = kzalloc(len, GFP_KERNEL);
xfs_acl = kmem_zalloc_large(len, KM_SLEEP);
if (!xfs_acl)
return -ENOMEM;

Expand All @@ -222,7 +222,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
len, ATTR_ROOT);

kfree(xfs_acl);
kmem_free(xfs_acl);
} else {
/*
* A NULL ACL argument means we want to remove the ACL.
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -4450,7 +4450,7 @@ xfs_bmapi_write(
{
struct xfs_mount *mp = ip->i_mount;
struct xfs_ifork *ifp;
struct xfs_bmalloca bma = { 0 }; /* args for xfs_bmap_alloc */
struct xfs_bmalloca bma = { NULL }; /* args for xfs_bmap_alloc */
xfs_fileoff_t end; /* end of mapped file region */
int eof; /* after the end of extents */
int error; /* error return */
Expand Down
44 changes: 44 additions & 0 deletions fs/xfs/xfs_bmap_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -925,3 +925,47 @@ xfs_bmdr_maxrecs(
return blocklen / sizeof(xfs_bmdr_rec_t);
return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t));
}

/*
* Change the owner of a btree format fork fo the inode passed in. Change it to
* the owner of that is passed in so that we can change owners before or after
* we switch forks between inodes. The operation that the caller is doing will
* determine whether is needs to change owner before or after the switch.
*
* For demand paged transactional modification, the fork switch should be done
* after reading in all the blocks, modifying them and pinning them in the
* transaction. For modification when the buffers are already pinned in memory,
* the fork switch can be done before changing the owner as we won't need to
* validate the owner until the btree buffers are unpinned and writes can occur
* again.
*
* For recovery based ownership change, there is no transactional context and
* so a buffer list must be supplied so that we can record the buffers that we
* modified for the caller to issue IO on.
*/
int
xfs_bmbt_change_owner(
struct xfs_trans *tp,
struct xfs_inode *ip,
int whichfork,
xfs_ino_t new_owner,
struct list_head *buffer_list)
{
struct xfs_btree_cur *cur;
int error;

ASSERT(tp || buffer_list);
ASSERT(!(tp && buffer_list));
if (whichfork == XFS_DATA_FORK)
ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_BTREE);
else
ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_BTREE);

cur = xfs_bmbt_init_cursor(ip->i_mount, tp, ip, whichfork);
if (!cur)
return ENOMEM;

error = xfs_btree_change_owner(cur, new_owner, buffer_list);
xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
return error;
}
4 changes: 4 additions & 0 deletions fs/xfs/xfs_bmap_btree.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level);
extern int xfs_bmdr_maxrecs(struct xfs_mount *, int blocklen, int leaf);
extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf);

extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip,
int whichfork, xfs_ino_t new_owner,
struct list_head *buffer_list);

extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *,
struct xfs_trans *, struct xfs_inode *, int);

Expand Down
69 changes: 44 additions & 25 deletions fs/xfs/xfs_bmap_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,13 +612,9 @@ xfs_getbmap(

if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx))
return XFS_ERROR(ENOMEM);
out = kmem_zalloc(bmv->bmv_count * sizeof(struct getbmapx), KM_MAYFAIL);
if (!out) {
out = kmem_zalloc_large(bmv->bmv_count *
sizeof(struct getbmapx));
if (!out)
return XFS_ERROR(ENOMEM);
}
out = kmem_zalloc_large(bmv->bmv_count * sizeof(struct getbmapx), 0);
if (!out)
return XFS_ERROR(ENOMEM);

xfs_ilock(ip, XFS_IOLOCK_SHARED);
if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) {
Expand Down Expand Up @@ -754,10 +750,7 @@ xfs_getbmap(
break;
}

if (is_vmalloc_addr(out))
kmem_free_large(out);
else
kmem_free(out);
kmem_free(out);
return error;
}

Expand Down Expand Up @@ -1789,14 +1782,6 @@ xfs_swap_extents(
int taforkblks = 0;
__uint64_t tmp;

/*
* We have no way of updating owner information in the BMBT blocks for
* each inode on CRC enabled filesystems, so to avoid corrupting the
* this metadata we simply don't allow extent swaps to occur.
*/
if (xfs_sb_version_hascrc(&mp->m_sb))
return XFS_ERROR(EINVAL);

tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
if (!tempifp) {
error = XFS_ERROR(ENOMEM);
Expand Down Expand Up @@ -1920,6 +1905,42 @@ xfs_swap_extents(
goto out_trans_cancel;
}

xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);

/*
* Before we've swapped the forks, lets set the owners of the forks
* appropriately. We have to do this as we are demand paging the btree
* buffers, and so the validation done on read will expect the owner
* field to be correctly set. Once we change the owners, we can swap the
* inode forks.
*
* Note the trickiness in setting the log flags - we set the owner log
* flag on the opposite inode (i.e. the inode we are setting the new
* owner to be) because once we swap the forks and log that, log
* recovery is going to see the fork as owned by the swapped inode,
* not the pre-swapped inodes.
*/
src_log_flags = XFS_ILOG_CORE;
target_log_flags = XFS_ILOG_CORE;
if (ip->i_d.di_version == 3 &&
ip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
target_log_flags |= XFS_ILOG_DOWNER;
error = xfs_bmbt_change_owner(tp, ip, XFS_DATA_FORK,
tip->i_ino, NULL);
if (error)
goto out_trans_cancel;
}

if (tip->i_d.di_version == 3 &&
tip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
src_log_flags |= XFS_ILOG_DOWNER;
error = xfs_bmbt_change_owner(tp, tip, XFS_DATA_FORK,
ip->i_ino, NULL);
if (error)
goto out_trans_cancel;
}

/*
* Swap the data forks of the inodes
*/
Expand Down Expand Up @@ -1957,7 +1978,6 @@ xfs_swap_extents(
tip->i_delayed_blks = ip->i_delayed_blks;
ip->i_delayed_blks = 0;

src_log_flags = XFS_ILOG_CORE;
switch (ip->i_d.di_format) {
case XFS_DINODE_FMT_EXTENTS:
/* If the extents fit in the inode, fix the
Expand All @@ -1971,11 +1991,12 @@ xfs_swap_extents(
src_log_flags |= XFS_ILOG_DEXT;
break;
case XFS_DINODE_FMT_BTREE:
ASSERT(ip->i_d.di_version < 3 ||
(src_log_flags & XFS_ILOG_DOWNER));
src_log_flags |= XFS_ILOG_DBROOT;
break;
}

target_log_flags = XFS_ILOG_CORE;
switch (tip->i_d.di_format) {
case XFS_DINODE_FMT_EXTENTS:
/* If the extents fit in the inode, fix the
Expand All @@ -1990,13 +2011,11 @@ xfs_swap_extents(
break;
case XFS_DINODE_FMT_BTREE:
target_log_flags |= XFS_ILOG_DBROOT;
ASSERT(tip->i_d.di_version < 3 ||
(target_log_flags & XFS_ILOG_DOWNER));
break;
}


xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);

xfs_trans_log_inode(tp, ip, src_log_flags);
xfs_trans_log_inode(tp, tip, target_log_flags);

Expand Down
Loading

0 comments on commit e0ea404

Please sign in to comment.