|
@@ -1030,7 +1030,7 @@ xfs_dir_ialloc(
|
|
tp->t_flags &= ~(XFS_TRANS_DQ_DIRTY);
|
|
tp->t_flags &= ~(XFS_TRANS_DQ_DIRTY);
|
|
}
|
|
}
|
|
|
|
|
|
- code = xfs_trans_roll(&tp, 0);
|
|
|
|
|
|
+ code = xfs_trans_roll(&tp, NULL);
|
|
if (committed != NULL)
|
|
if (committed != NULL)
|
|
*committed = 1;
|
|
*committed = 1;
|
|
|
|
|
|
@@ -1161,11 +1161,9 @@ xfs_create(
|
|
rdev = 0;
|
|
rdev = 0;
|
|
resblks = XFS_MKDIR_SPACE_RES(mp, name->len);
|
|
resblks = XFS_MKDIR_SPACE_RES(mp, name->len);
|
|
tres = &M_RES(mp)->tr_mkdir;
|
|
tres = &M_RES(mp)->tr_mkdir;
|
|
- tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
|
|
|
|
} else {
|
|
} else {
|
|
resblks = XFS_CREATE_SPACE_RES(mp, name->len);
|
|
resblks = XFS_CREATE_SPACE_RES(mp, name->len);
|
|
tres = &M_RES(mp)->tr_create;
|
|
tres = &M_RES(mp)->tr_create;
|
|
- tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1174,20 +1172,19 @@ xfs_create(
|
|
* the case we'll drop the one we have and get a more
|
|
* the case we'll drop the one we have and get a more
|
|
* appropriate transaction later.
|
|
* appropriate transaction later.
|
|
*/
|
|
*/
|
|
- error = xfs_trans_reserve(tp, tres, resblks, 0);
|
|
|
|
|
|
+ error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp);
|
|
if (error == -ENOSPC) {
|
|
if (error == -ENOSPC) {
|
|
/* flush outstanding delalloc blocks and retry */
|
|
/* flush outstanding delalloc blocks and retry */
|
|
xfs_flush_inodes(mp);
|
|
xfs_flush_inodes(mp);
|
|
- error = xfs_trans_reserve(tp, tres, resblks, 0);
|
|
|
|
|
|
+ error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp);
|
|
}
|
|
}
|
|
if (error == -ENOSPC) {
|
|
if (error == -ENOSPC) {
|
|
/* No space at all so try a "no-allocation" reservation */
|
|
/* No space at all so try a "no-allocation" reservation */
|
|
resblks = 0;
|
|
resblks = 0;
|
|
- error = xfs_trans_reserve(tp, tres, 0, 0);
|
|
|
|
|
|
+ error = xfs_trans_alloc(mp, tres, 0, 0, 0, &tp);
|
|
}
|
|
}
|
|
if (error)
|
|
if (error)
|
|
- goto out_trans_cancel;
|
|
|
|
-
|
|
|
|
|
|
+ goto out_release_inode;
|
|
|
|
|
|
xfs_ilock(dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL |
|
|
xfs_ilock(dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL |
|
|
XFS_IOLOCK_PARENT | XFS_ILOCK_PARENT);
|
|
XFS_IOLOCK_PARENT | XFS_ILOCK_PARENT);
|
|
@@ -1337,17 +1334,16 @@ xfs_create_tmpfile(
|
|
return error;
|
|
return error;
|
|
|
|
|
|
resblks = XFS_IALLOC_SPACE_RES(mp);
|
|
resblks = XFS_IALLOC_SPACE_RES(mp);
|
|
- tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE_TMPFILE);
|
|
|
|
-
|
|
|
|
tres = &M_RES(mp)->tr_create_tmpfile;
|
|
tres = &M_RES(mp)->tr_create_tmpfile;
|
|
- error = xfs_trans_reserve(tp, tres, resblks, 0);
|
|
|
|
|
|
+
|
|
|
|
+ error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp);
|
|
if (error == -ENOSPC) {
|
|
if (error == -ENOSPC) {
|
|
/* No space at all so try a "no-allocation" reservation */
|
|
/* No space at all so try a "no-allocation" reservation */
|
|
resblks = 0;
|
|
resblks = 0;
|
|
- error = xfs_trans_reserve(tp, tres, 0, 0);
|
|
|
|
|
|
+ error = xfs_trans_alloc(mp, tres, 0, 0, 0, &tp);
|
|
}
|
|
}
|
|
if (error)
|
|
if (error)
|
|
- goto out_trans_cancel;
|
|
|
|
|
|
+ goto out_release_inode;
|
|
|
|
|
|
error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
|
|
error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
|
|
pdqp, resblks, 1, 0);
|
|
pdqp, resblks, 1, 0);
|
|
@@ -1432,15 +1428,14 @@ xfs_link(
|
|
if (error)
|
|
if (error)
|
|
goto std_return;
|
|
goto std_return;
|
|
|
|
|
|
- tp = xfs_trans_alloc(mp, XFS_TRANS_LINK);
|
|
|
|
resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
|
|
resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
|
|
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_link, resblks, 0);
|
|
|
|
|
|
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, resblks, 0, 0, &tp);
|
|
if (error == -ENOSPC) {
|
|
if (error == -ENOSPC) {
|
|
resblks = 0;
|
|
resblks = 0;
|
|
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_link, 0, 0);
|
|
|
|
|
|
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, 0, 0, 0, &tp);
|
|
}
|
|
}
|
|
if (error)
|
|
if (error)
|
|
- goto error_return;
|
|
|
|
|
|
+ goto std_return;
|
|
|
|
|
|
xfs_ilock(tdp, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT);
|
|
xfs_ilock(tdp, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT);
|
|
xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);
|
|
xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);
|
|
@@ -1710,11 +1705,9 @@ xfs_inactive_truncate(
|
|
struct xfs_trans *tp;
|
|
struct xfs_trans *tp;
|
|
int error;
|
|
int error;
|
|
|
|
|
|
- tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
|
|
|
|
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
|
|
|
|
|
|
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
|
|
if (error) {
|
|
if (error) {
|
|
ASSERT(XFS_FORCED_SHUTDOWN(mp));
|
|
ASSERT(XFS_FORCED_SHUTDOWN(mp));
|
|
- xfs_trans_cancel(tp);
|
|
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1764,8 +1757,6 @@ xfs_inactive_ifree(
|
|
struct xfs_trans *tp;
|
|
struct xfs_trans *tp;
|
|
int error;
|
|
int error;
|
|
|
|
|
|
- tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* The ifree transaction might need to allocate blocks for record
|
|
* The ifree transaction might need to allocate blocks for record
|
|
* insertion to the finobt. We don't want to fail here at ENOSPC, so
|
|
* insertion to the finobt. We don't want to fail here at ENOSPC, so
|
|
@@ -1781,9 +1772,8 @@ xfs_inactive_ifree(
|
|
* now remains allocated and sits on the unlinked list until the fs is
|
|
* now remains allocated and sits on the unlinked list until the fs is
|
|
* repaired.
|
|
* repaired.
|
|
*/
|
|
*/
|
|
- tp->t_flags |= XFS_TRANS_RESERVE;
|
|
|
|
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree,
|
|
|
|
- XFS_IFREE_SPACE_RES(mp), 0);
|
|
|
|
|
|
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ifree,
|
|
|
|
+ XFS_IFREE_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp);
|
|
if (error) {
|
|
if (error) {
|
|
if (error == -ENOSPC) {
|
|
if (error == -ENOSPC) {
|
|
xfs_warn_ratelimited(mp,
|
|
xfs_warn_ratelimited(mp,
|
|
@@ -1792,7 +1782,6 @@ xfs_inactive_ifree(
|
|
} else {
|
|
} else {
|
|
ASSERT(XFS_FORCED_SHUTDOWN(mp));
|
|
ASSERT(XFS_FORCED_SHUTDOWN(mp));
|
|
}
|
|
}
|
|
- xfs_trans_cancel(tp);
|
|
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2525,11 +2514,6 @@ xfs_remove(
|
|
if (error)
|
|
if (error)
|
|
goto std_return;
|
|
goto std_return;
|
|
|
|
|
|
- if (is_dir)
|
|
|
|
- tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR);
|
|
|
|
- else
|
|
|
|
- tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE);
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* We try to get the real space reservation first,
|
|
* We try to get the real space reservation first,
|
|
* allowing for directory btree deletion(s) implying
|
|
* allowing for directory btree deletion(s) implying
|
|
@@ -2540,14 +2524,15 @@ xfs_remove(
|
|
* block from the directory.
|
|
* block from the directory.
|
|
*/
|
|
*/
|
|
resblks = XFS_REMOVE_SPACE_RES(mp);
|
|
resblks = XFS_REMOVE_SPACE_RES(mp);
|
|
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_remove, resblks, 0);
|
|
|
|
|
|
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_remove, resblks, 0, 0, &tp);
|
|
if (error == -ENOSPC) {
|
|
if (error == -ENOSPC) {
|
|
resblks = 0;
|
|
resblks = 0;
|
|
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_remove, 0, 0);
|
|
|
|
|
|
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_remove, 0, 0, 0,
|
|
|
|
+ &tp);
|
|
}
|
|
}
|
|
if (error) {
|
|
if (error) {
|
|
ASSERT(error != -ENOSPC);
|
|
ASSERT(error != -ENOSPC);
|
|
- goto out_trans_cancel;
|
|
|
|
|
|
+ goto std_return;
|
|
}
|
|
}
|
|
|
|
|
|
xfs_ilock(dp, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT);
|
|
xfs_ilock(dp, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT);
|
|
@@ -2855,6 +2840,7 @@ xfs_rename_alloc_whiteout(
|
|
* and flag it as linkable.
|
|
* and flag it as linkable.
|
|
*/
|
|
*/
|
|
drop_nlink(VFS_I(tmpfile));
|
|
drop_nlink(VFS_I(tmpfile));
|
|
|
|
+ xfs_setup_iops(tmpfile);
|
|
xfs_finish_inode_setup(tmpfile);
|
|
xfs_finish_inode_setup(tmpfile);
|
|
VFS_I(tmpfile)->i_state |= I_LINKABLE;
|
|
VFS_I(tmpfile)->i_state |= I_LINKABLE;
|
|
|
|
|
|
@@ -2910,15 +2896,15 @@ xfs_rename(
|
|
xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, wip,
|
|
xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, wip,
|
|
inodes, &num_inodes);
|
|
inodes, &num_inodes);
|
|
|
|
|
|
- tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME);
|
|
|
|
spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len);
|
|
spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len);
|
|
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_rename, spaceres, 0);
|
|
|
|
|
|
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_rename, spaceres, 0, 0, &tp);
|
|
if (error == -ENOSPC) {
|
|
if (error == -ENOSPC) {
|
|
spaceres = 0;
|
|
spaceres = 0;
|
|
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_rename, 0, 0);
|
|
|
|
|
|
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_rename, 0, 0, 0,
|
|
|
|
+ &tp);
|
|
}
|
|
}
|
|
if (error)
|
|
if (error)
|
|
- goto out_trans_cancel;
|
|
|
|
|
|
+ goto out_release_wip;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Attach the dquots to the inodes
|
|
* Attach the dquots to the inodes
|
|
@@ -3155,6 +3141,7 @@ out_bmap_cancel:
|
|
xfs_bmap_cancel(&free_list);
|
|
xfs_bmap_cancel(&free_list);
|
|
out_trans_cancel:
|
|
out_trans_cancel:
|
|
xfs_trans_cancel(tp);
|
|
xfs_trans_cancel(tp);
|
|
|
|
+out_release_wip:
|
|
if (wip)
|
|
if (wip)
|
|
IRELE(wip);
|
|
IRELE(wip);
|
|
return error;
|
|
return error;
|
|
@@ -3162,16 +3149,16 @@ out_trans_cancel:
|
|
|
|
|
|
STATIC int
|
|
STATIC int
|
|
xfs_iflush_cluster(
|
|
xfs_iflush_cluster(
|
|
- xfs_inode_t *ip,
|
|
|
|
- xfs_buf_t *bp)
|
|
|
|
|
|
+ struct xfs_inode *ip,
|
|
|
|
+ struct xfs_buf *bp)
|
|
{
|
|
{
|
|
- xfs_mount_t *mp = ip->i_mount;
|
|
|
|
|
|
+ struct xfs_mount *mp = ip->i_mount;
|
|
struct xfs_perag *pag;
|
|
struct xfs_perag *pag;
|
|
unsigned long first_index, mask;
|
|
unsigned long first_index, mask;
|
|
unsigned long inodes_per_cluster;
|
|
unsigned long inodes_per_cluster;
|
|
- int ilist_size;
|
|
|
|
- xfs_inode_t **ilist;
|
|
|
|
- xfs_inode_t *iq;
|
|
|
|
|
|
+ int cilist_size;
|
|
|
|
+ struct xfs_inode **cilist;
|
|
|
|
+ struct xfs_inode *cip;
|
|
int nr_found;
|
|
int nr_found;
|
|
int clcount = 0;
|
|
int clcount = 0;
|
|
int bufwasdelwri;
|
|
int bufwasdelwri;
|
|
@@ -3180,23 +3167,23 @@ xfs_iflush_cluster(
|
|
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
|
|
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
|
|
|
|
|
|
inodes_per_cluster = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog;
|
|
inodes_per_cluster = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog;
|
|
- ilist_size = inodes_per_cluster * sizeof(xfs_inode_t *);
|
|
|
|
- ilist = kmem_alloc(ilist_size, KM_MAYFAIL|KM_NOFS);
|
|
|
|
- if (!ilist)
|
|
|
|
|
|
+ cilist_size = inodes_per_cluster * sizeof(xfs_inode_t *);
|
|
|
|
+ cilist = kmem_alloc(cilist_size, KM_MAYFAIL|KM_NOFS);
|
|
|
|
+ if (!cilist)
|
|
goto out_put;
|
|
goto out_put;
|
|
|
|
|
|
mask = ~(((mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog)) - 1);
|
|
mask = ~(((mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog)) - 1);
|
|
first_index = XFS_INO_TO_AGINO(mp, ip->i_ino) & mask;
|
|
first_index = XFS_INO_TO_AGINO(mp, ip->i_ino) & mask;
|
|
rcu_read_lock();
|
|
rcu_read_lock();
|
|
/* really need a gang lookup range call here */
|
|
/* really need a gang lookup range call here */
|
|
- nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, (void**)ilist,
|
|
|
|
|
|
+ nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, (void**)cilist,
|
|
first_index, inodes_per_cluster);
|
|
first_index, inodes_per_cluster);
|
|
if (nr_found == 0)
|
|
if (nr_found == 0)
|
|
goto out_free;
|
|
goto out_free;
|
|
|
|
|
|
for (i = 0; i < nr_found; i++) {
|
|
for (i = 0; i < nr_found; i++) {
|
|
- iq = ilist[i];
|
|
|
|
- if (iq == ip)
|
|
|
|
|
|
+ cip = cilist[i];
|
|
|
|
+ if (cip == ip)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -3205,20 +3192,30 @@ xfs_iflush_cluster(
|
|
* We need to check under the i_flags_lock for a valid inode
|
|
* We need to check under the i_flags_lock for a valid inode
|
|
* here. Skip it if it is not valid or the wrong inode.
|
|
* here. Skip it if it is not valid or the wrong inode.
|
|
*/
|
|
*/
|
|
- spin_lock(&ip->i_flags_lock);
|
|
|
|
- if (!ip->i_ino ||
|
|
|
|
- (XFS_INO_TO_AGINO(mp, iq->i_ino) & mask) != first_index) {
|
|
|
|
- spin_unlock(&ip->i_flags_lock);
|
|
|
|
|
|
+ spin_lock(&cip->i_flags_lock);
|
|
|
|
+ if (!cip->i_ino ||
|
|
|
|
+ __xfs_iflags_test(cip, XFS_ISTALE)) {
|
|
|
|
+ spin_unlock(&cip->i_flags_lock);
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
- spin_unlock(&ip->i_flags_lock);
|
|
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Once we fall off the end of the cluster, no point checking
|
|
|
|
+ * any more inodes in the list because they will also all be
|
|
|
|
+ * outside the cluster.
|
|
|
|
+ */
|
|
|
|
+ if ((XFS_INO_TO_AGINO(mp, cip->i_ino) & mask) != first_index) {
|
|
|
|
+ spin_unlock(&cip->i_flags_lock);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ spin_unlock(&cip->i_flags_lock);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Do an un-protected check to see if the inode is dirty and
|
|
* Do an un-protected check to see if the inode is dirty and
|
|
* is a candidate for flushing. These checks will be repeated
|
|
* is a candidate for flushing. These checks will be repeated
|
|
* later after the appropriate locks are acquired.
|
|
* later after the appropriate locks are acquired.
|
|
*/
|
|
*/
|
|
- if (xfs_inode_clean(iq) && xfs_ipincount(iq) == 0)
|
|
|
|
|
|
+ if (xfs_inode_clean(cip) && xfs_ipincount(cip) == 0)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -3226,15 +3223,28 @@ xfs_iflush_cluster(
|
|
* then this inode cannot be flushed and is skipped.
|
|
* then this inode cannot be flushed and is skipped.
|
|
*/
|
|
*/
|
|
|
|
|
|
- if (!xfs_ilock_nowait(iq, XFS_ILOCK_SHARED))
|
|
|
|
|
|
+ if (!xfs_ilock_nowait(cip, XFS_ILOCK_SHARED))
|
|
|
|
+ continue;
|
|
|
|
+ if (!xfs_iflock_nowait(cip)) {
|
|
|
|
+ xfs_iunlock(cip, XFS_ILOCK_SHARED);
|
|
continue;
|
|
continue;
|
|
- if (!xfs_iflock_nowait(iq)) {
|
|
|
|
- xfs_iunlock(iq, XFS_ILOCK_SHARED);
|
|
|
|
|
|
+ }
|
|
|
|
+ if (xfs_ipincount(cip)) {
|
|
|
|
+ xfs_ifunlock(cip);
|
|
|
|
+ xfs_iunlock(cip, XFS_ILOCK_SHARED);
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
- if (xfs_ipincount(iq)) {
|
|
|
|
- xfs_ifunlock(iq);
|
|
|
|
- xfs_iunlock(iq, XFS_ILOCK_SHARED);
|
|
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Check the inode number again, just to be certain we are not
|
|
|
|
+ * racing with freeing in xfs_reclaim_inode(). See the comments
|
|
|
|
+ * in that function for more information as to why the initial
|
|
|
|
+ * check is not sufficient.
|
|
|
|
+ */
|
|
|
|
+ if (!cip->i_ino) {
|
|
|
|
+ xfs_ifunlock(cip);
|
|
|
|
+ xfs_iunlock(cip, XFS_ILOCK_SHARED);
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3242,18 +3252,18 @@ xfs_iflush_cluster(
|
|
* arriving here means that this inode can be flushed. First
|
|
* arriving here means that this inode can be flushed. First
|
|
* re-check that it's dirty before flushing.
|
|
* re-check that it's dirty before flushing.
|
|
*/
|
|
*/
|
|
- if (!xfs_inode_clean(iq)) {
|
|
|
|
|
|
+ if (!xfs_inode_clean(cip)) {
|
|
int error;
|
|
int error;
|
|
- error = xfs_iflush_int(iq, bp);
|
|
|
|
|
|
+ error = xfs_iflush_int(cip, bp);
|
|
if (error) {
|
|
if (error) {
|
|
- xfs_iunlock(iq, XFS_ILOCK_SHARED);
|
|
|
|
|
|
+ xfs_iunlock(cip, XFS_ILOCK_SHARED);
|
|
goto cluster_corrupt_out;
|
|
goto cluster_corrupt_out;
|
|
}
|
|
}
|
|
clcount++;
|
|
clcount++;
|
|
} else {
|
|
} else {
|
|
- xfs_ifunlock(iq);
|
|
|
|
|
|
+ xfs_ifunlock(cip);
|
|
}
|
|
}
|
|
- xfs_iunlock(iq, XFS_ILOCK_SHARED);
|
|
|
|
|
|
+ xfs_iunlock(cip, XFS_ILOCK_SHARED);
|
|
}
|
|
}
|
|
|
|
|
|
if (clcount) {
|
|
if (clcount) {
|
|
@@ -3263,7 +3273,7 @@ xfs_iflush_cluster(
|
|
|
|
|
|
out_free:
|
|
out_free:
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
- kmem_free(ilist);
|
|
|
|
|
|
+ kmem_free(cilist);
|
|
out_put:
|
|
out_put:
|
|
xfs_perag_put(pag);
|
|
xfs_perag_put(pag);
|
|
return 0;
|
|
return 0;
|
|
@@ -3306,8 +3316,8 @@ cluster_corrupt_out:
|
|
/*
|
|
/*
|
|
* Unlocks the flush lock
|
|
* Unlocks the flush lock
|
|
*/
|
|
*/
|
|
- xfs_iflush_abort(iq, false);
|
|
|
|
- kmem_free(ilist);
|
|
|
|
|
|
+ xfs_iflush_abort(cip, false);
|
|
|
|
+ kmem_free(cilist);
|
|
xfs_perag_put(pag);
|
|
xfs_perag_put(pag);
|
|
return -EFSCORRUPTED;
|
|
return -EFSCORRUPTED;
|
|
}
|
|
}
|
|
@@ -3327,7 +3337,7 @@ xfs_iflush(
|
|
struct xfs_buf **bpp)
|
|
struct xfs_buf **bpp)
|
|
{
|
|
{
|
|
struct xfs_mount *mp = ip->i_mount;
|
|
struct xfs_mount *mp = ip->i_mount;
|
|
- struct xfs_buf *bp;
|
|
|
|
|
|
+ struct xfs_buf *bp = NULL;
|
|
struct xfs_dinode *dip;
|
|
struct xfs_dinode *dip;
|
|
int error;
|
|
int error;
|
|
|
|
|
|
@@ -3369,14 +3379,22 @@ xfs_iflush(
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Get the buffer containing the on-disk inode.
|
|
|
|
|
|
+ * Get the buffer containing the on-disk inode. We are doing a try-lock
|
|
|
|
+ * operation here, so we may get an EAGAIN error. In that case, we
|
|
|
|
+ * simply want to return with the inode still dirty.
|
|
|
|
+ *
|
|
|
|
+ * If we get any other error, we effectively have a corruption situation
|
|
|
|
+ * and we cannot flush the inode, so we treat it the same as failing
|
|
|
|
+ * xfs_iflush_int().
|
|
*/
|
|
*/
|
|
error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, XBF_TRYLOCK,
|
|
error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, XBF_TRYLOCK,
|
|
0);
|
|
0);
|
|
- if (error || !bp) {
|
|
|
|
|
|
+ if (error == -EAGAIN) {
|
|
xfs_ifunlock(ip);
|
|
xfs_ifunlock(ip);
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
+ if (error)
|
|
|
|
+ goto corrupt_out;
|
|
|
|
|
|
/*
|
|
/*
|
|
* First flush out the inode that xfs_iflush was called with.
|
|
* First flush out the inode that xfs_iflush was called with.
|
|
@@ -3404,7 +3422,8 @@ xfs_iflush(
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
corrupt_out:
|
|
corrupt_out:
|
|
- xfs_buf_relse(bp);
|
|
|
|
|
|
+ if (bp)
|
|
|
|
+ xfs_buf_relse(bp);
|
|
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
|
|
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
|
|
cluster_corrupt_out:
|
|
cluster_corrupt_out:
|
|
error = -EFSCORRUPTED;
|
|
error = -EFSCORRUPTED;
|