Skip to content

Commit e0ea404

Browse files
committed
Merge tag 'xfs-for-linus-v3.12-rc1-2' of git://oss.sgi.com/xfs/xfs
Pull xfs update Digilent#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()
2 parents 48efe45 + 08474ed commit e0ea404

25 files changed

+461
-166
lines changed

fs/xfs/kmem.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,14 @@
2727

2828
/*
2929
* Greedy allocation. May fail and may return vmalloced memory.
30-
*
31-
* Must be freed using kmem_free_large.
3230
*/
3331
void *
3432
kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize)
3533
{
3634
void *ptr;
3735
size_t kmsize = maxsize;
3836

39-
while (!(ptr = kmem_zalloc_large(kmsize))) {
37+
while (!(ptr = vzalloc(kmsize))) {
4038
if ((kmsize >>= 1) <= minsize)
4139
kmsize = minsize;
4240
}
@@ -75,6 +73,17 @@ kmem_zalloc(size_t size, xfs_km_flags_t flags)
7573
return ptr;
7674
}
7775

76+
void *
77+
kmem_zalloc_large(size_t size, xfs_km_flags_t flags)
78+
{
79+
void *ptr;
80+
81+
ptr = kmem_zalloc(size, flags | KM_MAYFAIL);
82+
if (ptr)
83+
return ptr;
84+
return vzalloc(size);
85+
}
86+
7887
void
7988
kmem_free(const void *ptr)
8089
{

fs/xfs/kmem.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,10 @@ kmem_flags_convert(xfs_km_flags_t flags)
5757

5858
extern void *kmem_alloc(size_t, xfs_km_flags_t);
5959
extern void *kmem_zalloc(size_t, xfs_km_flags_t);
60+
extern void *kmem_zalloc_large(size_t size, xfs_km_flags_t);
6061
extern void *kmem_realloc(const void *, size_t, size_t, xfs_km_flags_t);
6162
extern void kmem_free(const void *);
6263

63-
static inline void *kmem_zalloc_large(size_t size)
64-
{
65-
return vzalloc(size);
66-
}
67-
static inline void kmem_free_large(void *ptr)
68-
{
69-
vfree(ptr);
70-
}
7164

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

fs/xfs/xfs_acl.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ xfs_get_acl(struct inode *inode, int type)
152152
* go out to the disk.
153153
*/
154154
len = XFS_ACL_MAX_SIZE(ip->i_mount);
155-
xfs_acl = kzalloc(len, GFP_KERNEL);
155+
xfs_acl = kmem_zalloc_large(len, KM_SLEEP);
156156
if (!xfs_acl)
157157
return ERR_PTR(-ENOMEM);
158158

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

178-
out_update_cache:
178+
out_update_cache:
179179
set_cached_acl(inode, type, acl);
180-
out:
181-
kfree(xfs_acl);
180+
out:
181+
kmem_free(xfs_acl);
182182
return acl;
183183
}
184184

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

212-
xfs_acl = kzalloc(len, GFP_KERNEL);
212+
xfs_acl = kmem_zalloc_large(len, KM_SLEEP);
213213
if (!xfs_acl)
214214
return -ENOMEM;
215215

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

225-
kfree(xfs_acl);
225+
kmem_free(xfs_acl);
226226
} else {
227227
/*
228228
* A NULL ACL argument means we want to remove the ACL.

fs/xfs/xfs_bmap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4450,7 +4450,7 @@ xfs_bmapi_write(
44504450
{
44514451
struct xfs_mount *mp = ip->i_mount;
44524452
struct xfs_ifork *ifp;
4453-
struct xfs_bmalloca bma = { 0 }; /* args for xfs_bmap_alloc */
4453+
struct xfs_bmalloca bma = { NULL }; /* args for xfs_bmap_alloc */
44544454
xfs_fileoff_t end; /* end of mapped file region */
44554455
int eof; /* after the end of extents */
44564456
int error; /* error return */

fs/xfs/xfs_bmap_btree.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,3 +925,47 @@ xfs_bmdr_maxrecs(
925925
return blocklen / sizeof(xfs_bmdr_rec_t);
926926
return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t));
927927
}
928+
929+
/*
930+
* Change the owner of a btree format fork fo the inode passed in. Change it to
931+
* the owner of that is passed in so that we can change owners before or after
932+
* we switch forks between inodes. The operation that the caller is doing will
933+
* determine whether is needs to change owner before or after the switch.
934+
*
935+
* For demand paged transactional modification, the fork switch should be done
936+
* after reading in all the blocks, modifying them and pinning them in the
937+
* transaction. For modification when the buffers are already pinned in memory,
938+
* the fork switch can be done before changing the owner as we won't need to
939+
* validate the owner until the btree buffers are unpinned and writes can occur
940+
* again.
941+
*
942+
* For recovery based ownership change, there is no transactional context and
943+
* so a buffer list must be supplied so that we can record the buffers that we
944+
* modified for the caller to issue IO on.
945+
*/
946+
int
947+
xfs_bmbt_change_owner(
948+
struct xfs_trans *tp,
949+
struct xfs_inode *ip,
950+
int whichfork,
951+
xfs_ino_t new_owner,
952+
struct list_head *buffer_list)
953+
{
954+
struct xfs_btree_cur *cur;
955+
int error;
956+
957+
ASSERT(tp || buffer_list);
958+
ASSERT(!(tp && buffer_list));
959+
if (whichfork == XFS_DATA_FORK)
960+
ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_BTREE);
961+
else
962+
ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_BTREE);
963+
964+
cur = xfs_bmbt_init_cursor(ip->i_mount, tp, ip, whichfork);
965+
if (!cur)
966+
return ENOMEM;
967+
968+
error = xfs_btree_change_owner(cur, new_owner, buffer_list);
969+
xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
970+
return error;
971+
}

fs/xfs/xfs_bmap_btree.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level);
236236
extern int xfs_bmdr_maxrecs(struct xfs_mount *, int blocklen, int leaf);
237237
extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf);
238238

239+
extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip,
240+
int whichfork, xfs_ino_t new_owner,
241+
struct list_head *buffer_list);
242+
239243
extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *,
240244
struct xfs_trans *, struct xfs_inode *, int);
241245

fs/xfs/xfs_bmap_util.c

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -612,13 +612,9 @@ xfs_getbmap(
612612

613613
if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx))
614614
return XFS_ERROR(ENOMEM);
615-
out = kmem_zalloc(bmv->bmv_count * sizeof(struct getbmapx), KM_MAYFAIL);
616-
if (!out) {
617-
out = kmem_zalloc_large(bmv->bmv_count *
618-
sizeof(struct getbmapx));
619-
if (!out)
620-
return XFS_ERROR(ENOMEM);
621-
}
615+
out = kmem_zalloc_large(bmv->bmv_count * sizeof(struct getbmapx), 0);
616+
if (!out)
617+
return XFS_ERROR(ENOMEM);
622618

623619
xfs_ilock(ip, XFS_IOLOCK_SHARED);
624620
if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) {
@@ -754,10 +750,7 @@ xfs_getbmap(
754750
break;
755751
}
756752

757-
if (is_vmalloc_addr(out))
758-
kmem_free_large(out);
759-
else
760-
kmem_free(out);
753+
kmem_free(out);
761754
return error;
762755
}
763756

@@ -1789,14 +1782,6 @@ xfs_swap_extents(
17891782
int taforkblks = 0;
17901783
__uint64_t tmp;
17911784

1792-
/*
1793-
* We have no way of updating owner information in the BMBT blocks for
1794-
* each inode on CRC enabled filesystems, so to avoid corrupting the
1795-
* this metadata we simply don't allow extent swaps to occur.
1796-
*/
1797-
if (xfs_sb_version_hascrc(&mp->m_sb))
1798-
return XFS_ERROR(EINVAL);
1799-
18001785
tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
18011786
if (!tempifp) {
18021787
error = XFS_ERROR(ENOMEM);
@@ -1920,6 +1905,42 @@ xfs_swap_extents(
19201905
goto out_trans_cancel;
19211906
}
19221907

1908+
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
1909+
xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
1910+
1911+
/*
1912+
* Before we've swapped the forks, lets set the owners of the forks
1913+
* appropriately. We have to do this as we are demand paging the btree
1914+
* buffers, and so the validation done on read will expect the owner
1915+
* field to be correctly set. Once we change the owners, we can swap the
1916+
* inode forks.
1917+
*
1918+
* Note the trickiness in setting the log flags - we set the owner log
1919+
* flag on the opposite inode (i.e. the inode we are setting the new
1920+
* owner to be) because once we swap the forks and log that, log
1921+
* recovery is going to see the fork as owned by the swapped inode,
1922+
* not the pre-swapped inodes.
1923+
*/
1924+
src_log_flags = XFS_ILOG_CORE;
1925+
target_log_flags = XFS_ILOG_CORE;
1926+
if (ip->i_d.di_version == 3 &&
1927+
ip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
1928+
target_log_flags |= XFS_ILOG_DOWNER;
1929+
error = xfs_bmbt_change_owner(tp, ip, XFS_DATA_FORK,
1930+
tip->i_ino, NULL);
1931+
if (error)
1932+
goto out_trans_cancel;
1933+
}
1934+
1935+
if (tip->i_d.di_version == 3 &&
1936+
tip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
1937+
src_log_flags |= XFS_ILOG_DOWNER;
1938+
error = xfs_bmbt_change_owner(tp, tip, XFS_DATA_FORK,
1939+
ip->i_ino, NULL);
1940+
if (error)
1941+
goto out_trans_cancel;
1942+
}
1943+
19231944
/*
19241945
* Swap the data forks of the inodes
19251946
*/
@@ -1957,7 +1978,6 @@ xfs_swap_extents(
19571978
tip->i_delayed_blks = ip->i_delayed_blks;
19581979
ip->i_delayed_blks = 0;
19591980

1960-
src_log_flags = XFS_ILOG_CORE;
19611981
switch (ip->i_d.di_format) {
19621982
case XFS_DINODE_FMT_EXTENTS:
19631983
/* If the extents fit in the inode, fix the
@@ -1971,11 +1991,12 @@ xfs_swap_extents(
19711991
src_log_flags |= XFS_ILOG_DEXT;
19721992
break;
19731993
case XFS_DINODE_FMT_BTREE:
1994+
ASSERT(ip->i_d.di_version < 3 ||
1995+
(src_log_flags & XFS_ILOG_DOWNER));
19741996
src_log_flags |= XFS_ILOG_DBROOT;
19751997
break;
19761998
}
19771999

1978-
target_log_flags = XFS_ILOG_CORE;
19792000
switch (tip->i_d.di_format) {
19802001
case XFS_DINODE_FMT_EXTENTS:
19812002
/* If the extents fit in the inode, fix the
@@ -1990,13 +2011,11 @@ xfs_swap_extents(
19902011
break;
19912012
case XFS_DINODE_FMT_BTREE:
19922013
target_log_flags |= XFS_ILOG_DBROOT;
2014+
ASSERT(tip->i_d.di_version < 3 ||
2015+
(target_log_flags & XFS_ILOG_DOWNER));
19932016
break;
19942017
}
19952018

1996-
1997-
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
1998-
xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
1999-
20002019
xfs_trans_log_inode(tp, ip, src_log_flags);
20012020
xfs_trans_log_inode(tp, tip, target_log_flags);
20022021

0 commit comments

Comments
 (0)