mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
NFS client bugfix for Linux 6.17
Stable fixes: - NFS: Fix a data corrupting race when updating an existing write -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEESQctxSBg8JpV8KqEZwvnipYKAPIFAminvwMACgkQZwvnipYK APIFkxAAmmlm+6rVRmkb5W37hgcsntWS90CjIw6axH7WlFToypiDam83pCIYzAMc wzO5e03ZnKwp49zabTYSqoLD30/irZ3QwR6H1XIe6NToomYr43CZPjqctZLhVaeq HpLfBiJdxI2jJQMpHubQk66MyBhk0tXln+Pzzi59ZESOevbGWcT8bz6v849nIh0F emngSbMEKMXLrY+r/NsX31wF3Te4WYNyV/tumck3hOEZNouCKD/a2JKGEXdkWKw6 1IFiTxo4IT8vsVrUTKsG3QUtkv/v8iZ0FSl1f9FD1C6eubX5Jo4JcEQmDc6NoJTF 4viy0c19+8TUs//Kax4VlBE6opeb9jXba4iN0FOXeYsbqVXyv8fEuinLu174I+s4 bQNpScZ8/o/dMio/Qa6RgTvxIvk9kICJEmfF1IKeIb7Kn+nczpsD8CqwT/EKiCV2 ZotYZP5BP2BKYrtV5eUhWcl9mKpagz8ivHCevKvaG4JX+M2/XVNNspgkdr8hwu3j SX5lwOdLP//gHqt3x8PUCrD2G9Pn81qkshR5mfJAyWhPodwrP6vsDSvAnB93zeZB LVln0c1BHmvPpjAEnIzCh3mZXdzMHSVHxKldktYDfhfh/8tFJAkS7o3bXpgZ8dMF eHsYZHBJnByZBfi61B3RkWB9QU8KWi+winDQJpoU+MbZGxRdFmA= =Yh2D -----END PGP SIGNATURE----- Merge tag 'nfs-for-6.17-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client fix from Trond Myklebust: - NFS: Fix a data corrupting race when updating an existing write * tag 'nfs-for-6.17-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFS: Fix a race when updating an existing write
This commit is contained in:
commit
e86ba12cf8
@ -253,13 +253,14 @@ nfs_page_group_unlock(struct nfs_page *req)
|
|||||||
nfs_page_clear_headlock(req);
|
nfs_page_clear_headlock(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* nfs_page_group_sync_on_bit_locked
|
* nfs_page_group_sync_on_bit_locked - Test if all requests have @bit set
|
||||||
|
* @req: request in page group
|
||||||
|
* @bit: PG_* bit that is used to sync page group
|
||||||
*
|
*
|
||||||
* must be called with page group lock held
|
* must be called with page group lock held
|
||||||
*/
|
*/
|
||||||
static bool
|
bool nfs_page_group_sync_on_bit_locked(struct nfs_page *req, unsigned int bit)
|
||||||
nfs_page_group_sync_on_bit_locked(struct nfs_page *req, unsigned int bit)
|
|
||||||
{
|
{
|
||||||
struct nfs_page *head = req->wb_head;
|
struct nfs_page *head = req->wb_head;
|
||||||
struct nfs_page *tmp;
|
struct nfs_page *tmp;
|
||||||
|
@ -153,20 +153,10 @@ nfs_page_set_inode_ref(struct nfs_page *req, struct inode *inode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void nfs_cancel_remove_inode(struct nfs_page *req, struct inode *inode)
|
||||||
nfs_cancel_remove_inode(struct nfs_page *req, struct inode *inode)
|
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!test_bit(PG_REMOVE, &req->wb_flags))
|
|
||||||
return 0;
|
|
||||||
ret = nfs_page_group_lock(req);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
if (test_and_clear_bit(PG_REMOVE, &req->wb_flags))
|
if (test_and_clear_bit(PG_REMOVE, &req->wb_flags))
|
||||||
nfs_page_set_inode_ref(req, inode);
|
nfs_page_set_inode_ref(req, inode);
|
||||||
nfs_page_group_unlock(req);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -585,19 +575,18 @@ retry:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = nfs_page_group_lock(head);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
/* Ensure that nobody removed the request before we locked it */
|
/* Ensure that nobody removed the request before we locked it */
|
||||||
if (head != folio->private) {
|
if (head != folio->private) {
|
||||||
|
nfs_page_group_unlock(head);
|
||||||
nfs_unlock_and_release_request(head);
|
nfs_unlock_and_release_request(head);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = nfs_cancel_remove_inode(head, inode);
|
nfs_cancel_remove_inode(head, inode);
|
||||||
if (ret < 0)
|
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
ret = nfs_page_group_lock(head);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
/* lock each request in the page group */
|
/* lock each request in the page group */
|
||||||
for (subreq = head->wb_this_page;
|
for (subreq = head->wb_this_page;
|
||||||
@ -786,7 +775,8 @@ static void nfs_inode_remove_request(struct nfs_page *req)
|
|||||||
{
|
{
|
||||||
struct nfs_inode *nfsi = NFS_I(nfs_page_to_inode(req));
|
struct nfs_inode *nfsi = NFS_I(nfs_page_to_inode(req));
|
||||||
|
|
||||||
if (nfs_page_group_sync_on_bit(req, PG_REMOVE)) {
|
nfs_page_group_lock(req);
|
||||||
|
if (nfs_page_group_sync_on_bit_locked(req, PG_REMOVE)) {
|
||||||
struct folio *folio = nfs_page_to_folio(req->wb_head);
|
struct folio *folio = nfs_page_to_folio(req->wb_head);
|
||||||
struct address_space *mapping = folio->mapping;
|
struct address_space *mapping = folio->mapping;
|
||||||
|
|
||||||
@ -798,6 +788,7 @@ static void nfs_inode_remove_request(struct nfs_page *req)
|
|||||||
}
|
}
|
||||||
spin_unlock(&mapping->i_private_lock);
|
spin_unlock(&mapping->i_private_lock);
|
||||||
}
|
}
|
||||||
|
nfs_page_group_unlock(req);
|
||||||
|
|
||||||
if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) {
|
if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) {
|
||||||
atomic_long_dec(&nfsi->nrequests);
|
atomic_long_dec(&nfsi->nrequests);
|
||||||
|
@ -160,6 +160,7 @@ extern void nfs_join_page_group(struct nfs_page *head,
|
|||||||
extern int nfs_page_group_lock(struct nfs_page *);
|
extern int nfs_page_group_lock(struct nfs_page *);
|
||||||
extern void nfs_page_group_unlock(struct nfs_page *);
|
extern void nfs_page_group_unlock(struct nfs_page *);
|
||||||
extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int);
|
extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int);
|
||||||
|
extern bool nfs_page_group_sync_on_bit_locked(struct nfs_page *, unsigned int);
|
||||||
extern int nfs_page_set_headlock(struct nfs_page *req);
|
extern int nfs_page_set_headlock(struct nfs_page *req);
|
||||||
extern void nfs_page_clear_headlock(struct nfs_page *req);
|
extern void nfs_page_clear_headlock(struct nfs_page *req);
|
||||||
extern bool nfs_async_iocounter_wait(struct rpc_task *, struct nfs_lock_context *);
|
extern bool nfs_async_iocounter_wait(struct rpc_task *, struct nfs_lock_context *);
|
||||||
|
Loading…
Reference in New Issue
Block a user