Fix miscellaneous nfsd bugs, in NFSv4.1 callbacks, NFSv4.1
lock-notification callbacks, NFSv3 readdir encoding, and the cache/upcall code. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJcv3EfAAoJECebzXlCjuG+j8IQAIMJFCpMTSu3lw0X9BjJFwe/ TELdvH4eXm+xtnz0Rbp4RTmlNgt/ox1ySp+sPQqcDutJcU6ImtJS1JY5BmoSU80p 2ZTRzVOusSS1dP6EDwnYQlR3rI3ObCdDYtkjfboqDd4UJM0hvuCrdQols3DRZF1/ gBMUDNk8Sch64JMs8EcpItmNWgZ1QDmL6vbKsYDB8HWfBcFkNOs/Q1OecSD7F9Dh k+GojPb4pXRCgN8heeFr2H2mXxJSDOPyyybBSQOtbv58rT7IXTpVvAt+WHpjy917 ljOSD/EuCY+IvX6oY8xPrly9a3t4Mh4eQQFj1EZGSlNucqDgsi1B421QcxGZSkF4 WZkTRC5BppairSx4dnW96Nx0BbCysj2dvZ0MOnUa59YRwRbyrnHKCv221SzFBidI 0slxNBYW7Rw2ViFJ6fBPjsjH0XWM9Hq4wC84kj8XXNeDDh2KzXPtUtUzp3iDpKQg jP0UiEYnt6OXWvHOH0hfh52Mds48iIUSRmKL4huDT8Ijnt9KBZxnTunClJt6g1SH MsIttRsZ2fLo/M5SlWzvQ7XNoKNn/s49Z3SZjqYEKqL9aMwuMoMcIgolqlh5oFPu j3cqprDNXuij+2pl35IuQRbk57G2DZ1maShJ5n8I7l0uBe6DMX7T+4d4rHy75Tu9 otqz4WYU2Yjnnmv5Kp/H =9hKY -----END PGP SIGNATURE----- Merge tag 'nfsd-5.1-1' of git://linux-nfs.org/~bfields/linux Pull nfsd bugfixes from Bruce Fields: "Fix miscellaneous nfsd bugs, in NFSv4.1 callbacks, NFSv4.1 lock-notification callbacks, NFSv3 readdir encoding, and the cache/upcall code" * tag 'nfsd-5.1-1' of git://linux-nfs.org/~bfields/linux: nfsd: wake blocked file lock waiters before sending callback nfsd: wake waiters blocked on file_lock before deleting it nfsd: Don't release the callback slot unless it was actually held nfsd/nfsd3_proc_readdir: fix buffer count and page pointers sunrpc: don't mark uninitialised items as VALID.
This commit is contained in:
Коммит
12a54b150f
|
@ -442,7 +442,9 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
|
|||
struct nfsd3_readdirargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_readdirres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
int count;
|
||||
int count = 0;
|
||||
struct page **p;
|
||||
caddr_t page_addr = NULL;
|
||||
|
||||
dprintk("nfsd: READDIR(3) %s %d bytes at %d\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
|
@ -462,7 +464,18 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
|
|||
nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie,
|
||||
&resp->common, nfs3svc_encode_entry);
|
||||
memcpy(resp->verf, argp->verf, 8);
|
||||
resp->count = resp->buffer - argp->buffer;
|
||||
count = 0;
|
||||
for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
|
||||
page_addr = page_address(*p);
|
||||
|
||||
if (((caddr_t)resp->buffer >= page_addr) &&
|
||||
((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
|
||||
count += (caddr_t)resp->buffer - page_addr;
|
||||
break;
|
||||
}
|
||||
count += PAGE_SIZE;
|
||||
}
|
||||
resp->count = count >> 2;
|
||||
if (resp->offset) {
|
||||
loff_t offset = argp->cookie;
|
||||
|
||||
|
|
|
@ -573,6 +573,7 @@ int
|
|||
nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_readdirargs *args = rqstp->rq_argp;
|
||||
int len;
|
||||
u32 max_blocksize = svc_max_payload(rqstp);
|
||||
|
||||
p = decode_fh(p, &args->fh);
|
||||
|
@ -582,8 +583,14 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p)
|
|||
args->verf = p; p += 2;
|
||||
args->dircount = ~0;
|
||||
args->count = ntohl(*p++);
|
||||
args->count = min_t(u32, args->count, max_blocksize);
|
||||
args->buffer = page_address(*(rqstp->rq_next_page++));
|
||||
len = args->count = min_t(u32, args->count, max_blocksize);
|
||||
|
||||
while (len > 0) {
|
||||
struct page *p = *(rqstp->rq_next_page++);
|
||||
if (!args->buffer)
|
||||
args->buffer = page_address(p);
|
||||
len -= PAGE_SIZE;
|
||||
}
|
||||
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
|
|
@ -1010,8 +1010,9 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
|
|||
cb->cb_seq_status = 1;
|
||||
cb->cb_status = 0;
|
||||
if (minorversion) {
|
||||
if (!nfsd41_cb_get_slot(clp, task))
|
||||
if (!cb->cb_holds_slot && !nfsd41_cb_get_slot(clp, task))
|
||||
return;
|
||||
cb->cb_holds_slot = true;
|
||||
}
|
||||
rpc_call_start(task);
|
||||
}
|
||||
|
@ -1038,6 +1039,9 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!cb->cb_holds_slot)
|
||||
goto need_restart;
|
||||
|
||||
switch (cb->cb_seq_status) {
|
||||
case 0:
|
||||
/*
|
||||
|
@ -1076,6 +1080,7 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
|
|||
cb->cb_seq_status);
|
||||
}
|
||||
|
||||
cb->cb_holds_slot = false;
|
||||
clear_bit(0, &clp->cl_cb_slot_busy);
|
||||
rpc_wake_up_next(&clp->cl_cb_waitq);
|
||||
dprintk("%s: freed slot, new seqid=%d\n", __func__,
|
||||
|
@ -1283,6 +1288,7 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
|
|||
cb->cb_seq_status = 1;
|
||||
cb->cb_status = 0;
|
||||
cb->cb_need_restart = false;
|
||||
cb->cb_holds_slot = false;
|
||||
}
|
||||
|
||||
void nfsd4_run_cb(struct nfsd4_callback *cb)
|
||||
|
|
|
@ -265,6 +265,7 @@ find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh,
|
|||
static void
|
||||
free_blocked_lock(struct nfsd4_blocked_lock *nbl)
|
||||
{
|
||||
locks_delete_block(&nbl->nbl_lock);
|
||||
locks_release_private(&nbl->nbl_lock);
|
||||
kfree(nbl);
|
||||
}
|
||||
|
@ -293,11 +294,18 @@ remove_blocked_locks(struct nfs4_lockowner *lo)
|
|||
nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock,
|
||||
nbl_lru);
|
||||
list_del_init(&nbl->nbl_lru);
|
||||
locks_delete_block(&nbl->nbl_lock);
|
||||
free_blocked_lock(nbl);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd4_cb_notify_lock_prepare(struct nfsd4_callback *cb)
|
||||
{
|
||||
struct nfsd4_blocked_lock *nbl = container_of(cb,
|
||||
struct nfsd4_blocked_lock, nbl_cb);
|
||||
locks_delete_block(&nbl->nbl_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task)
|
||||
{
|
||||
|
@ -325,6 +333,7 @@ nfsd4_cb_notify_lock_release(struct nfsd4_callback *cb)
|
|||
}
|
||||
|
||||
static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = {
|
||||
.prepare = nfsd4_cb_notify_lock_prepare,
|
||||
.done = nfsd4_cb_notify_lock_done,
|
||||
.release = nfsd4_cb_notify_lock_release,
|
||||
};
|
||||
|
@ -4863,7 +4872,6 @@ nfs4_laundromat(struct nfsd_net *nn)
|
|||
nbl = list_first_entry(&reaplist,
|
||||
struct nfsd4_blocked_lock, nbl_lru);
|
||||
list_del_init(&nbl->nbl_lru);
|
||||
locks_delete_block(&nbl->nbl_lock);
|
||||
free_blocked_lock(nbl);
|
||||
}
|
||||
out:
|
||||
|
|
|
@ -70,6 +70,7 @@ struct nfsd4_callback {
|
|||
int cb_seq_status;
|
||||
int cb_status;
|
||||
bool cb_need_restart;
|
||||
bool cb_holds_slot;
|
||||
};
|
||||
|
||||
struct nfsd4_callback_ops {
|
||||
|
|
|
@ -54,6 +54,7 @@ static void cache_init(struct cache_head *h, struct cache_detail *detail)
|
|||
h->last_refresh = now;
|
||||
}
|
||||
|
||||
static inline int cache_is_valid(struct cache_head *h);
|
||||
static void cache_fresh_locked(struct cache_head *head, time_t expiry,
|
||||
struct cache_detail *detail);
|
||||
static void cache_fresh_unlocked(struct cache_head *head,
|
||||
|
@ -105,6 +106,8 @@ static struct cache_head *sunrpc_cache_add_entry(struct cache_detail *detail,
|
|||
if (cache_is_expired(detail, tmp)) {
|
||||
hlist_del_init_rcu(&tmp->cache_list);
|
||||
detail->entries --;
|
||||
if (cache_is_valid(tmp) == -EAGAIN)
|
||||
set_bit(CACHE_NEGATIVE, &tmp->flags);
|
||||
cache_fresh_locked(tmp, 0, detail);
|
||||
freeme = tmp;
|
||||
break;
|
||||
|
|
Загрузка…
Ссылка в новой задаче