mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
NFS client bugfixes for Linux 5.11
Highlights include: Bugfixes: - SUNRPC: Handle 0 length opaque XDR object data properly - Fix a layout segment leak in pnfs_layout_process() - pNFS/NFSv4: Update the layout barrier when we schedule a layoutreturn - pNFS/NFSv4: Improve rejection of out-of-order layouts - pNFS/NFSv4: Try to return invalid layout in pnfs_layout_process() -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEESQctxSBg8JpV8KqEZwvnipYKAPIFAmAW4QgACgkQZwvnipYK APJNZw/6AnLawj0kjn7z0Wc2LA0QWxbAVGYGe28gQdy6qiBbuOiFDeH8itKk6m1c R6ZPpFHFKYk6+CsNcNws2sz9gBQj7wzDIy3sHenIaiNgY/fWNKDC8woKkJFSUSMl GSQ9rkCYwRJu1JxP7r/9gnw/86oUTy/PgMaGdz6CMZJlq9iNa8t2UqMOfmcN8EZ3 AIewe4fSV5ebfycVz6btdJy8OCwyUfQ1OMilfh+0+5HYlk/xUxr57+AHi9r8w6bq 3tzIq3imQRgZsPPo/DJo/D4hfeFYX849/Tp+I5ydREWIwREBz2PO8bHNFnDoeoLo AJ8mkawvpx+jsHFaAHql6STvY7uTY7qqBqsX2qSCqd6n2VEU0+cnDCY1IcgjcfBR ozaYHJQm9ZhHzska3r/aKBQmkth9LIPU6aIMcYtjzC3ywua2vfCBSPRYKES80kIV Pzgf5yRZFTEp7jGV9Uhf3Hucm3oIF9WVonDpSPbThdHUUXAYAVK1HZwgWx72HskL BEhdaD+zsacv58C1+BE3vlh6A/j/cZAQifTfflgkLE3JE1IiKJwFjH4q6jgLwccx kWLopK9Ds+ta+kLtlCuNTsPt7aGUoZZleH1Ghzdkw5Dfv2eEnR3YM6raa294avw4 DzKE/Rzgv5JuoSJhkWW/PiBZHcxMsv3SK7LTjO2oteFz88olsgo= =gLzv -----END PGP SIGNATURE----- Merge tag 'nfs-for-5.11-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client fixes from Trond Myklebust: - SUNRPC: Handle 0 length opaque XDR object data properly - Fix a layout segment leak in pnfs_layout_process() - pNFS/NFSv4: Update the layout barrier when we schedule a layoutreturn - pNFS/NFSv4: Improve rejection of out-of-order layouts - pNFS/NFSv4: Try to return invalid layout in pnfs_layout_process() * tag 'nfs-for-5.11-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: SUNRPC: Handle 0 length opaque XDR object data properly SUNRPC: Move simple_get_bytes and simple_get_netobj into private header pNFS/NFSv4: Improve rejection of out-of-order layouts pNFS/NFSv4: Update the layout barrier when we schedule a layoutreturn pNFS/NFSv4: Try to return invalid layout in pnfs_layout_process() pNFS/NFSv4: Fix a layout segment leak in pnfs_layout_process()
This commit is contained in:
commit
c178fae3a9
@ -324,6 +324,21 @@ pnfs_grab_inode_layout_hdr(struct pnfs_layout_hdr *lo)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare 2 layout stateid sequence ids, to see which is newer,
|
||||||
|
* taking into account wraparound issues.
|
||||||
|
*/
|
||||||
|
static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
|
||||||
|
{
|
||||||
|
return (s32)(s1 - s2) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pnfs_barrier_update(struct pnfs_layout_hdr *lo, u32 newseq)
|
||||||
|
{
|
||||||
|
if (pnfs_seqid_is_newer(newseq, lo->plh_barrier))
|
||||||
|
lo->plh_barrier = newseq;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pnfs_set_plh_return_info(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode,
|
pnfs_set_plh_return_info(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode,
|
||||||
u32 seq)
|
u32 seq)
|
||||||
@ -335,6 +350,7 @@ pnfs_set_plh_return_info(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode,
|
|||||||
if (seq != 0) {
|
if (seq != 0) {
|
||||||
WARN_ON_ONCE(lo->plh_return_seq != 0 && lo->plh_return_seq != seq);
|
WARN_ON_ONCE(lo->plh_return_seq != 0 && lo->plh_return_seq != seq);
|
||||||
lo->plh_return_seq = seq;
|
lo->plh_return_seq = seq;
|
||||||
|
pnfs_barrier_update(lo, seq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,15 +655,6 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Compare 2 layout stateid sequence ids, to see which is newer,
|
|
||||||
* taking into account wraparound issues.
|
|
||||||
*/
|
|
||||||
static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
|
|
||||||
{
|
|
||||||
return (s32)(s1 - s2) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
pnfs_should_free_range(const struct pnfs_layout_range *lseg_range,
|
pnfs_should_free_range(const struct pnfs_layout_range *lseg_range,
|
||||||
const struct pnfs_layout_range *recall_range)
|
const struct pnfs_layout_range *recall_range)
|
||||||
@ -984,8 +991,7 @@ pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new,
|
|||||||
new_barrier = be32_to_cpu(new->seqid);
|
new_barrier = be32_to_cpu(new->seqid);
|
||||||
else if (new_barrier == 0)
|
else if (new_barrier == 0)
|
||||||
return;
|
return;
|
||||||
if (pnfs_seqid_is_newer(new_barrier, lo->plh_barrier))
|
pnfs_barrier_update(lo, new_barrier);
|
||||||
lo->plh_barrier = new_barrier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -994,7 +1000,7 @@ pnfs_layout_stateid_blocked(const struct pnfs_layout_hdr *lo,
|
|||||||
{
|
{
|
||||||
u32 seqid = be32_to_cpu(stateid->seqid);
|
u32 seqid = be32_to_cpu(stateid->seqid);
|
||||||
|
|
||||||
return !pnfs_seqid_is_newer(seqid, lo->plh_barrier);
|
return !pnfs_seqid_is_newer(seqid, lo->plh_barrier) && lo->plh_barrier;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lget is set to 1 if called from inside send_layoutget call chain */
|
/* lget is set to 1 if called from inside send_layoutget call chain */
|
||||||
@ -1183,20 +1189,17 @@ pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo,
|
|||||||
return false;
|
return false;
|
||||||
set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags);
|
set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags);
|
||||||
pnfs_get_layout_hdr(lo);
|
pnfs_get_layout_hdr(lo);
|
||||||
|
nfs4_stateid_copy(stateid, &lo->plh_stateid);
|
||||||
|
*cred = get_cred(lo->plh_lc_cred);
|
||||||
if (test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags)) {
|
if (test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags)) {
|
||||||
nfs4_stateid_copy(stateid, &lo->plh_stateid);
|
|
||||||
*cred = get_cred(lo->plh_lc_cred);
|
|
||||||
if (lo->plh_return_seq != 0)
|
if (lo->plh_return_seq != 0)
|
||||||
stateid->seqid = cpu_to_be32(lo->plh_return_seq);
|
stateid->seqid = cpu_to_be32(lo->plh_return_seq);
|
||||||
if (iomode != NULL)
|
if (iomode != NULL)
|
||||||
*iomode = lo->plh_return_iomode;
|
*iomode = lo->plh_return_iomode;
|
||||||
pnfs_clear_layoutreturn_info(lo);
|
pnfs_clear_layoutreturn_info(lo);
|
||||||
return true;
|
} else if (iomode != NULL)
|
||||||
}
|
|
||||||
nfs4_stateid_copy(stateid, &lo->plh_stateid);
|
|
||||||
*cred = get_cred(lo->plh_lc_cred);
|
|
||||||
if (iomode != NULL)
|
|
||||||
*iomode = IOMODE_ANY;
|
*iomode = IOMODE_ANY;
|
||||||
|
pnfs_barrier_update(lo, be32_to_cpu(stateid->seqid));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1909,6 +1912,11 @@ static void nfs_layoutget_end(struct pnfs_layout_hdr *lo)
|
|||||||
wake_up_var(&lo->plh_outstanding);
|
wake_up_var(&lo->plh_outstanding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool pnfs_is_first_layoutget(struct pnfs_layout_hdr *lo)
|
||||||
|
{
|
||||||
|
return test_bit(NFS_LAYOUT_FIRST_LAYOUTGET, &lo->plh_flags);
|
||||||
|
}
|
||||||
|
|
||||||
static void pnfs_clear_first_layoutget(struct pnfs_layout_hdr *lo)
|
static void pnfs_clear_first_layoutget(struct pnfs_layout_hdr *lo)
|
||||||
{
|
{
|
||||||
unsigned long *bitlock = &lo->plh_flags;
|
unsigned long *bitlock = &lo->plh_flags;
|
||||||
@ -2383,23 +2391,34 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
|
|||||||
goto out_forget;
|
goto out_forget;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pnfs_layout_is_valid(lo)) {
|
if (nfs4_stateid_match_other(&lo->plh_stateid, &res->stateid)) {
|
||||||
/* We have a completely new layout */
|
|
||||||
pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, true);
|
|
||||||
} else if (nfs4_stateid_match_other(&lo->plh_stateid, &res->stateid)) {
|
|
||||||
/* existing state ID, make sure the sequence number matches. */
|
/* existing state ID, make sure the sequence number matches. */
|
||||||
if (pnfs_layout_stateid_blocked(lo, &res->stateid)) {
|
if (pnfs_layout_stateid_blocked(lo, &res->stateid)) {
|
||||||
|
if (!pnfs_layout_is_valid(lo) &&
|
||||||
|
pnfs_is_first_layoutget(lo))
|
||||||
|
lo->plh_barrier = 0;
|
||||||
dprintk("%s forget reply due to sequence\n", __func__);
|
dprintk("%s forget reply due to sequence\n", __func__);
|
||||||
goto out_forget;
|
goto out_forget;
|
||||||
}
|
}
|
||||||
pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, false);
|
pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, false);
|
||||||
} else {
|
} else if (pnfs_layout_is_valid(lo)) {
|
||||||
/*
|
/*
|
||||||
* We got an entirely new state ID. Mark all segments for the
|
* We got an entirely new state ID. Mark all segments for the
|
||||||
* inode invalid, and retry the layoutget
|
* inode invalid, and retry the layoutget
|
||||||
*/
|
*/
|
||||||
pnfs_mark_layout_stateid_invalid(lo, &free_me);
|
struct pnfs_layout_range range = {
|
||||||
|
.iomode = IOMODE_ANY,
|
||||||
|
.length = NFS4_MAX_UINT64,
|
||||||
|
};
|
||||||
|
pnfs_set_plh_return_info(lo, IOMODE_ANY, 0);
|
||||||
|
pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs,
|
||||||
|
&range, 0);
|
||||||
goto out_forget;
|
goto out_forget;
|
||||||
|
} else {
|
||||||
|
/* We have a completely new layout */
|
||||||
|
if (!pnfs_is_first_layoutget(lo))
|
||||||
|
goto out_forget;
|
||||||
|
pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pnfs_get_lseg(lseg);
|
pnfs_get_lseg(lseg);
|
||||||
|
@ -25,8 +25,7 @@ struct rpc_rqst;
|
|||||||
#define XDR_QUADLEN(l) (((l) + 3) >> 2)
|
#define XDR_QUADLEN(l) (((l) + 3) >> 2)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic opaque `network object.' At the kernel level, this type
|
* Generic opaque `network object.'
|
||||||
* is used only by lockd.
|
|
||||||
*/
|
*/
|
||||||
#define XDR_MAX_NETOBJ 1024
|
#define XDR_MAX_NETOBJ 1024
|
||||||
struct xdr_netobj {
|
struct xdr_netobj {
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/hashtable.h>
|
#include <linux/hashtable.h>
|
||||||
|
|
||||||
|
#include "auth_gss_internal.h"
|
||||||
#include "../netns.h"
|
#include "../netns.h"
|
||||||
|
|
||||||
#include <trace/events/rpcgss.h>
|
#include <trace/events/rpcgss.h>
|
||||||
@ -125,35 +126,6 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
|
|||||||
clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
|
clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const void *
|
|
||||||
simple_get_bytes(const void *p, const void *end, void *res, size_t len)
|
|
||||||
{
|
|
||||||
const void *q = (const void *)((const char *)p + len);
|
|
||||||
if (unlikely(q > end || q < p))
|
|
||||||
return ERR_PTR(-EFAULT);
|
|
||||||
memcpy(res, p, len);
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline const void *
|
|
||||||
simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest)
|
|
||||||
{
|
|
||||||
const void *q;
|
|
||||||
unsigned int len;
|
|
||||||
|
|
||||||
p = simple_get_bytes(p, end, &len, sizeof(len));
|
|
||||||
if (IS_ERR(p))
|
|
||||||
return p;
|
|
||||||
q = (const void *)((const char *)p + len);
|
|
||||||
if (unlikely(q > end || q < p))
|
|
||||||
return ERR_PTR(-EFAULT);
|
|
||||||
dest->data = kmemdup(p, len, GFP_NOFS);
|
|
||||||
if (unlikely(dest->data == NULL))
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
dest->len = len;
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct gss_cl_ctx *
|
static struct gss_cl_ctx *
|
||||||
gss_cred_get_ctx(struct rpc_cred *cred)
|
gss_cred_get_ctx(struct rpc_cred *cred)
|
||||||
{
|
{
|
||||||
|
45
net/sunrpc/auth_gss/auth_gss_internal.h
Normal file
45
net/sunrpc/auth_gss/auth_gss_internal.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
/*
|
||||||
|
* linux/net/sunrpc/auth_gss/auth_gss_internal.h
|
||||||
|
*
|
||||||
|
* Internal definitions for RPCSEC_GSS client authentication
|
||||||
|
*
|
||||||
|
* Copyright (c) 2000 The Regents of the University of Michigan.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/sunrpc/xdr.h>
|
||||||
|
|
||||||
|
static inline const void *
|
||||||
|
simple_get_bytes(const void *p, const void *end, void *res, size_t len)
|
||||||
|
{
|
||||||
|
const void *q = (const void *)((const char *)p + len);
|
||||||
|
if (unlikely(q > end || q < p))
|
||||||
|
return ERR_PTR(-EFAULT);
|
||||||
|
memcpy(res, p, len);
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const void *
|
||||||
|
simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest)
|
||||||
|
{
|
||||||
|
const void *q;
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
p = simple_get_bytes(p, end, &len, sizeof(len));
|
||||||
|
if (IS_ERR(p))
|
||||||
|
return p;
|
||||||
|
q = (const void *)((const char *)p + len);
|
||||||
|
if (unlikely(q > end || q < p))
|
||||||
|
return ERR_PTR(-EFAULT);
|
||||||
|
if (len) {
|
||||||
|
dest->data = kmemdup(p, len, GFP_NOFS);
|
||||||
|
if (unlikely(dest->data == NULL))
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
} else
|
||||||
|
dest->data = NULL;
|
||||||
|
dest->len = len;
|
||||||
|
return q;
|
||||||
|
}
|
@ -21,6 +21,8 @@
|
|||||||
#include <linux/sunrpc/xdr.h>
|
#include <linux/sunrpc/xdr.h>
|
||||||
#include <linux/sunrpc/gss_krb5_enctypes.h>
|
#include <linux/sunrpc/gss_krb5_enctypes.h>
|
||||||
|
|
||||||
|
#include "auth_gss_internal.h"
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||||
#endif
|
#endif
|
||||||
@ -143,35 +145,6 @@ get_gss_krb5_enctype(int etype)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const void *
|
|
||||||
simple_get_bytes(const void *p, const void *end, void *res, int len)
|
|
||||||
{
|
|
||||||
const void *q = (const void *)((const char *)p + len);
|
|
||||||
if (unlikely(q > end || q < p))
|
|
||||||
return ERR_PTR(-EFAULT);
|
|
||||||
memcpy(res, p, len);
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const void *
|
|
||||||
simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
|
|
||||||
{
|
|
||||||
const void *q;
|
|
||||||
unsigned int len;
|
|
||||||
|
|
||||||
p = simple_get_bytes(p, end, &len, sizeof(len));
|
|
||||||
if (IS_ERR(p))
|
|
||||||
return p;
|
|
||||||
q = (const void *)((const char *)p + len);
|
|
||||||
if (unlikely(q > end || q < p))
|
|
||||||
return ERR_PTR(-EFAULT);
|
|
||||||
res->data = kmemdup(p, len, GFP_NOFS);
|
|
||||||
if (unlikely(res->data == NULL))
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
res->len = len;
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline const void *
|
static inline const void *
|
||||||
get_key(const void *p, const void *end,
|
get_key(const void *p, const void *end,
|
||||||
struct krb5_ctx *ctx, struct crypto_sync_skcipher **res)
|
struct krb5_ctx *ctx, struct crypto_sync_skcipher **res)
|
||||||
|
Loading…
Reference in New Issue
Block a user