mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'nfsd-5.4' of git://linux-nfs.org/~bfields/linux
Pull nfsd updates from Bruce Fields:
"Highlights:
- Add a new knfsd file cache, so that we don't have to open and close
on each (NFSv2/v3) READ or WRITE. This can speed up read and write
in some cases. It also replaces our readahead cache.
- Prevent silent data loss on write errors, by treating write errors
like server reboots for the purposes of write caching, thus forcing
clients to resend their writes.
- Tweak the code that allocates sessions to be more forgiving, so
that NFSv4.1 mounts are less likely to hang when a server already
has a lot of clients.
- Eliminate an arbitrary limit on NFSv4 ACL sizes; they should now be
limited only by the backend filesystem and the maximum RPC size.
- Allow the server to enforce use of the correct kerberos credentials
when a client reclaims state after a reboot.
And some miscellaneous smaller bugfixes and cleanup"
* tag 'nfsd-5.4' of git://linux-nfs.org/~bfields/linux: (34 commits)
sunrpc: clean up indentation issue
nfsd: fix nfs read eof detection
nfsd: Make nfsd_reset_boot_verifier_locked static
nfsd: degraded slot-count more gracefully as allocation nears exhaustion.
nfsd: handle drc over-allocation gracefully.
nfsd: add support for upcall version 2
nfsd: add a "GetVersion" upcall for nfsdcld
nfsd: Reset the boot verifier on all write I/O errors
nfsd: Don't garbage collect files that might contain write errors
nfsd: Support the server resetting the boot verifier
nfsd: nfsd_file cache entries should be per net namespace
nfsd: eliminate an unnecessary acl size limit
Deprecate nfsd fault injection
nfsd: remove duplicated include from filecache.c
nfsd: Fix the documentation for svcxdr_tmpalloc()
nfsd: Fix up some unused variable warnings
nfsd: close cached files prior to a REMOVE or RENAME that would replace target
nfsd: rip out the raparms cache
nfsd: have nfsd_test_lock use the nfsd_file cache
nfsd: hook up nfs4_preprocess_stateid_op to the nfsd_file cache
...
This commit is contained in:
@@ -327,6 +327,7 @@ void flush_delayed_fput(void)
|
||||
{
|
||||
delayed_fput(NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(flush_delayed_fput);
|
||||
|
||||
static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput);
|
||||
|
||||
|
||||
62
fs/locks.c
62
fs/locks.c
@@ -212,6 +212,7 @@ struct file_lock_list_struct {
|
||||
static DEFINE_PER_CPU(struct file_lock_list_struct, file_lock_list);
|
||||
DEFINE_STATIC_PERCPU_RWSEM(file_rwsem);
|
||||
|
||||
|
||||
/*
|
||||
* The blocked_hash is used to find POSIX lock loops for deadlock detection.
|
||||
* It is protected by blocked_lock_lock.
|
||||
@@ -1991,6 +1992,64 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp,
|
||||
}
|
||||
EXPORT_SYMBOL(generic_setlease);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SRCU)
|
||||
/*
|
||||
* Kernel subsystems can register to be notified on any attempt to set
|
||||
* a new lease with the lease_notifier_chain. This is used by (e.g.) nfsd
|
||||
* to close files that it may have cached when there is an attempt to set a
|
||||
* conflicting lease.
|
||||
*/
|
||||
static struct srcu_notifier_head lease_notifier_chain;
|
||||
|
||||
static inline void
|
||||
lease_notifier_chain_init(void)
|
||||
{
|
||||
srcu_init_notifier_head(&lease_notifier_chain);
|
||||
}
|
||||
|
||||
static inline void
|
||||
setlease_notifier(long arg, struct file_lock *lease)
|
||||
{
|
||||
if (arg != F_UNLCK)
|
||||
srcu_notifier_call_chain(&lease_notifier_chain, arg, lease);
|
||||
}
|
||||
|
||||
int lease_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return srcu_notifier_chain_register(&lease_notifier_chain, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lease_register_notifier);
|
||||
|
||||
void lease_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
srcu_notifier_chain_unregister(&lease_notifier_chain, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lease_unregister_notifier);
|
||||
|
||||
#else /* !IS_ENABLED(CONFIG_SRCU) */
|
||||
static inline void
|
||||
lease_notifier_chain_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
setlease_notifier(long arg, struct file_lock *lease)
|
||||
{
|
||||
}
|
||||
|
||||
int lease_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lease_register_notifier);
|
||||
|
||||
void lease_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lease_unregister_notifier);
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_SRCU) */
|
||||
|
||||
/**
|
||||
* vfs_setlease - sets a lease on an open file
|
||||
* @filp: file pointer
|
||||
@@ -2011,6 +2070,8 @@ EXPORT_SYMBOL(generic_setlease);
|
||||
int
|
||||
vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv)
|
||||
{
|
||||
if (lease)
|
||||
setlease_notifier(arg, *lease);
|
||||
if (filp->f_op->setlease)
|
||||
return filp->f_op->setlease(filp, arg, lease, priv);
|
||||
else
|
||||
@@ -2924,6 +2985,7 @@ static int __init filelock_init(void)
|
||||
INIT_HLIST_HEAD(&fll->hlist);
|
||||
}
|
||||
|
||||
lease_notifier_chain_init();
|
||||
return 0;
|
||||
}
|
||||
core_initcall(filelock_init);
|
||||
|
||||
@@ -3,6 +3,7 @@ config NFSD
|
||||
tristate "NFS server support"
|
||||
depends on INET
|
||||
depends on FILE_LOCKING
|
||||
depends on FSNOTIFY
|
||||
select LOCKD
|
||||
select SUNRPC
|
||||
select EXPORTFS
|
||||
@@ -147,7 +148,7 @@ config NFSD_V4_SECURITY_LABEL
|
||||
|
||||
config NFSD_FAULT_INJECTION
|
||||
bool "NFS server manual fault injection"
|
||||
depends on NFSD_V4 && DEBUG_KERNEL && DEBUG_FS
|
||||
depends on NFSD_V4 && DEBUG_KERNEL && DEBUG_FS && BROKEN
|
||||
help
|
||||
This option enables support for manually injecting faults
|
||||
into the NFS server. This is intended to be used for
|
||||
|
||||
@@ -11,7 +11,8 @@ obj-$(CONFIG_NFSD) += nfsd.o
|
||||
nfsd-y += trace.o
|
||||
|
||||
nfsd-y += nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
|
||||
export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o
|
||||
export.o auth.o lockd.o nfscache.o nfsxdr.o \
|
||||
stats.o filecache.o
|
||||
nfsd-$(CONFIG_NFSD_FAULT_INJECTION) += fault_inject.o
|
||||
nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
|
||||
nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
|
||||
|
||||
@@ -39,14 +39,6 @@ struct nfs4_acl;
|
||||
struct svc_fh;
|
||||
struct svc_rqst;
|
||||
|
||||
/*
|
||||
* Maximum ACL we'll accept from a client; chosen (somewhat
|
||||
* arbitrarily) so that kmalloc'ing the ACL shouldn't require a
|
||||
* high-order allocation. This allows 204 ACEs on x86_64:
|
||||
*/
|
||||
#define NFS4_ACL_MAX ((PAGE_SIZE - sizeof(struct nfs4_acl)) \
|
||||
/ sizeof(struct nfs4_ace))
|
||||
|
||||
int nfs4_acl_bytes(int entries);
|
||||
int nfs4_acl_get_whotype(char *, u32);
|
||||
__be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "blocklayoutxdr.h"
|
||||
#include "pnfs.h"
|
||||
#include "filecache.h"
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PNFS
|
||||
|
||||
@@ -404,7 +405,7 @@ static void
|
||||
nfsd4_scsi_fence_client(struct nfs4_layout_stateid *ls)
|
||||
{
|
||||
struct nfs4_client *clp = ls->ls_stid.sc_client;
|
||||
struct block_device *bdev = ls->ls_file->f_path.mnt->mnt_sb->s_bdev;
|
||||
struct block_device *bdev = ls->ls_file->nf_file->f_path.mnt->mnt_sb->s_bdev;
|
||||
|
||||
bdev->bd_disk->fops->pr_ops->pr_preempt(bdev, NFSD_MDS_PR_KEY,
|
||||
nfsd4_scsi_pr_key(clp), 0, true);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "nfsfh.h"
|
||||
#include "netns.h"
|
||||
#include "pnfs.h"
|
||||
#include "filecache.h"
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_EXPORT
|
||||
|
||||
@@ -232,6 +233,17 @@ static struct cache_head *expkey_alloc(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void expkey_flush(void)
|
||||
{
|
||||
/*
|
||||
* Take the nfsd_mutex here to ensure that the file cache is not
|
||||
* destroyed while we're in the middle of flushing.
|
||||
*/
|
||||
mutex_lock(&nfsd_mutex);
|
||||
nfsd_file_cache_purge(current->nsproxy->net_ns);
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
}
|
||||
|
||||
static const struct cache_detail svc_expkey_cache_template = {
|
||||
.owner = THIS_MODULE,
|
||||
.hash_size = EXPKEY_HASHMAX,
|
||||
@@ -244,6 +256,7 @@ static const struct cache_detail svc_expkey_cache_template = {
|
||||
.init = expkey_init,
|
||||
.update = expkey_update,
|
||||
.alloc = expkey_alloc,
|
||||
.flush = expkey_flush,
|
||||
};
|
||||
|
||||
static int
|
||||
|
||||
934
fs/nfsd/filecache.c
Normal file
934
fs/nfsd/filecache.c
Normal file
File diff suppressed because it is too large
Load Diff
61
fs/nfsd/filecache.h
Normal file
61
fs/nfsd/filecache.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef _FS_NFSD_FILECACHE_H
|
||||
#define _FS_NFSD_FILECACHE_H
|
||||
|
||||
#include <linux/fsnotify_backend.h>
|
||||
|
||||
/*
|
||||
* This is the fsnotify_mark container that nfsd attaches to the files that it
|
||||
* is holding open. Note that we have a separate refcount here aside from the
|
||||
* one in the fsnotify_mark. We only want a single fsnotify_mark attached to
|
||||
* the inode, and for each nfsd_file to hold a reference to it.
|
||||
*
|
||||
* The fsnotify_mark is itself refcounted, but that's not sufficient to tell us
|
||||
* how to put that reference. If there are still outstanding nfsd_files that
|
||||
* reference the mark, then we would want to call fsnotify_put_mark on it.
|
||||
* If there were not, then we'd need to call fsnotify_destroy_mark. Since we
|
||||
* can't really tell the difference, we use the nfm_mark to keep track of how
|
||||
* many nfsd_files hold references to the mark. When that counter goes to zero
|
||||
* then we know to call fsnotify_destroy_mark on it.
|
||||
*/
|
||||
struct nfsd_file_mark {
|
||||
struct fsnotify_mark nfm_mark;
|
||||
atomic_t nfm_ref;
|
||||
};
|
||||
|
||||
/*
|
||||
* A representation of a file that has been opened by knfsd. These are hashed
|
||||
* in the hashtable by inode pointer value. Note that this object doesn't
|
||||
* hold a reference to the inode by itself, so the nf_inode pointer should
|
||||
* never be dereferenced, only used for comparison.
|
||||
*/
|
||||
struct nfsd_file {
|
||||
struct hlist_node nf_node;
|
||||
struct list_head nf_lru;
|
||||
struct rcu_head nf_rcu;
|
||||
struct file *nf_file;
|
||||
const struct cred *nf_cred;
|
||||
struct net *nf_net;
|
||||
#define NFSD_FILE_HASHED (0)
|
||||
#define NFSD_FILE_PENDING (1)
|
||||
#define NFSD_FILE_BREAK_READ (2)
|
||||
#define NFSD_FILE_BREAK_WRITE (3)
|
||||
#define NFSD_FILE_REFERENCED (4)
|
||||
unsigned long nf_flags;
|
||||
struct inode *nf_inode;
|
||||
unsigned int nf_hashval;
|
||||
atomic_t nf_ref;
|
||||
unsigned char nf_may;
|
||||
struct nfsd_file_mark *nf_mark;
|
||||
};
|
||||
|
||||
int nfsd_file_cache_init(void);
|
||||
void nfsd_file_cache_purge(struct net *);
|
||||
void nfsd_file_cache_shutdown(void);
|
||||
void nfsd_file_put(struct nfsd_file *nf);
|
||||
struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
|
||||
void nfsd_file_close_inode_sync(struct inode *inode);
|
||||
bool nfsd_file_is_cached(struct inode *inode);
|
||||
__be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
unsigned int may_flags, struct nfsd_file **nfp);
|
||||
int nfsd_file_cache_stats_open(struct inode *, struct file *);
|
||||
#endif /* _FS_NFSD_FILECACHE_H */
|
||||
@@ -104,6 +104,7 @@ struct nfsd_net {
|
||||
|
||||
/* Time of server startup */
|
||||
struct timespec64 nfssvc_boot;
|
||||
seqlock_t boot_lock;
|
||||
|
||||
/*
|
||||
* Max number of connections this nfsd container will allow. Defaults
|
||||
@@ -179,4 +180,7 @@ struct nfsd_net {
|
||||
extern void nfsd_netns_free_versions(struct nfsd_net *nn);
|
||||
|
||||
extern unsigned int nfsd_net_id;
|
||||
|
||||
void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn);
|
||||
void nfsd_reset_boot_verifier(struct nfsd_net *nn);
|
||||
#endif /* __NFSD_NETNS_H__ */
|
||||
|
||||
@@ -172,13 +172,8 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
|
||||
nfserr = nfsd_read(rqstp, &resp->fh,
|
||||
argp->offset,
|
||||
rqstp->rq_vec, argp->vlen,
|
||||
&resp->count);
|
||||
if (nfserr == 0) {
|
||||
struct inode *inode = d_inode(resp->fh.fh_dentry);
|
||||
resp->eof = nfsd_eof_on_read(cnt, resp->count, argp->offset,
|
||||
inode->i_size);
|
||||
}
|
||||
|
||||
&resp->count,
|
||||
&resp->eof);
|
||||
RETURN_STATUS(nfserr);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ static u32 nfs3_ftypes[] = {
|
||||
NF3SOCK, NF3BAD, NF3LNK, NF3BAD,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* XDR functions for basic NFS types
|
||||
*/
|
||||
@@ -751,14 +752,16 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_writeres *resp = rqstp->rq_resp;
|
||||
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
||||
__be32 verf[2];
|
||||
|
||||
p = encode_wcc_data(rqstp, p, &resp->fh);
|
||||
if (resp->status == 0) {
|
||||
*p++ = htonl(resp->count);
|
||||
*p++ = htonl(resp->committed);
|
||||
/* unique identifier, y2038 overflow can be ignored */
|
||||
*p++ = htonl((u32)nn->nfssvc_boot.tv_sec);
|
||||
*p++ = htonl(nn->nfssvc_boot.tv_nsec);
|
||||
nfsd_copy_boot_verifier(verf, nn);
|
||||
*p++ = verf[0];
|
||||
*p++ = verf[1];
|
||||
}
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
@@ -1125,13 +1128,15 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_commitres *resp = rqstp->rq_resp;
|
||||
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
||||
__be32 verf[2];
|
||||
|
||||
p = encode_wcc_data(rqstp, p, &resp->fh);
|
||||
/* Write verifier */
|
||||
if (resp->status == 0) {
|
||||
/* unique identifier, y2038 overflow can be ignored */
|
||||
*p++ = htonl((u32)nn->nfssvc_boot.tv_sec);
|
||||
*p++ = htonl(nn->nfssvc_boot.tv_nsec);
|
||||
nfsd_copy_boot_verifier(verf, nn);
|
||||
*p++ = verf[0];
|
||||
*p++ = verf[1];
|
||||
}
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
@@ -512,11 +512,9 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp,
|
||||
if (unlikely(status))
|
||||
return status;
|
||||
|
||||
if (cb != NULL) {
|
||||
status = decode_cb_sequence4res(xdr, cb);
|
||||
if (unlikely(status || cb->cb_seq_status))
|
||||
return status;
|
||||
}
|
||||
status = decode_cb_sequence4res(xdr, cb);
|
||||
if (unlikely(status || cb->cb_seq_status))
|
||||
return status;
|
||||
|
||||
return decode_cb_op_status(xdr, OP_CB_RECALL, &cb->cb_status);
|
||||
}
|
||||
@@ -604,11 +602,10 @@ static int nfs4_xdr_dec_cb_layout(struct rpc_rqst *rqstp,
|
||||
if (unlikely(status))
|
||||
return status;
|
||||
|
||||
if (cb) {
|
||||
status = decode_cb_sequence4res(xdr, cb);
|
||||
if (unlikely(status || cb->cb_seq_status))
|
||||
return status;
|
||||
}
|
||||
status = decode_cb_sequence4res(xdr, cb);
|
||||
if (unlikely(status || cb->cb_seq_status))
|
||||
return status;
|
||||
|
||||
return decode_cb_op_status(xdr, OP_CB_LAYOUTRECALL, &cb->cb_status);
|
||||
}
|
||||
#endif /* CONFIG_NFSD_PNFS */
|
||||
@@ -663,11 +660,10 @@ static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp,
|
||||
if (unlikely(status))
|
||||
return status;
|
||||
|
||||
if (cb) {
|
||||
status = decode_cb_sequence4res(xdr, cb);
|
||||
if (unlikely(status || cb->cb_seq_status))
|
||||
return status;
|
||||
}
|
||||
status = decode_cb_sequence4res(xdr, cb);
|
||||
if (unlikely(status || cb->cb_seq_status))
|
||||
return status;
|
||||
|
||||
return decode_cb_op_status(xdr, OP_CB_NOTIFY_LOCK, &cb->cb_status);
|
||||
}
|
||||
|
||||
@@ -759,11 +755,10 @@ static int nfs4_xdr_dec_cb_offload(struct rpc_rqst *rqstp,
|
||||
if (unlikely(status))
|
||||
return status;
|
||||
|
||||
if (cb) {
|
||||
status = decode_cb_sequence4res(xdr, cb);
|
||||
if (unlikely(status || cb->cb_seq_status))
|
||||
return status;
|
||||
}
|
||||
status = decode_cb_sequence4res(xdr, cb);
|
||||
if (unlikely(status || cb->cb_seq_status))
|
||||
return status;
|
||||
|
||||
return decode_cb_op_status(xdr, OP_CB_OFFLOAD, &cb->cb_status);
|
||||
}
|
||||
/*
|
||||
|
||||
@@ -169,8 +169,8 @@ nfsd4_free_layout_stateid(struct nfs4_stid *stid)
|
||||
spin_unlock(&fp->fi_lock);
|
||||
|
||||
if (!nfsd4_layout_ops[ls->ls_layout_type]->disable_recalls)
|
||||
vfs_setlease(ls->ls_file, F_UNLCK, NULL, (void **)&ls);
|
||||
fput(ls->ls_file);
|
||||
vfs_setlease(ls->ls_file->nf_file, F_UNLCK, NULL, (void **)&ls);
|
||||
nfsd_file_put(ls->ls_file);
|
||||
|
||||
if (ls->ls_recalled)
|
||||
atomic_dec(&ls->ls_stid.sc_file->fi_lo_recalls);
|
||||
@@ -197,7 +197,7 @@ nfsd4_layout_setlease(struct nfs4_layout_stateid *ls)
|
||||
fl->fl_end = OFFSET_MAX;
|
||||
fl->fl_owner = ls;
|
||||
fl->fl_pid = current->tgid;
|
||||
fl->fl_file = ls->ls_file;
|
||||
fl->fl_file = ls->ls_file->nf_file;
|
||||
|
||||
status = vfs_setlease(fl->fl_file, fl->fl_type, &fl, NULL);
|
||||
if (status) {
|
||||
@@ -236,13 +236,13 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
|
||||
NFSPROC4_CLNT_CB_LAYOUT);
|
||||
|
||||
if (parent->sc_type == NFS4_DELEG_STID)
|
||||
ls->ls_file = get_file(fp->fi_deleg_file);
|
||||
ls->ls_file = nfsd_file_get(fp->fi_deleg_file);
|
||||
else
|
||||
ls->ls_file = find_any_file(fp);
|
||||
BUG_ON(!ls->ls_file);
|
||||
|
||||
if (nfsd4_layout_setlease(ls)) {
|
||||
fput(ls->ls_file);
|
||||
nfsd_file_put(ls->ls_file);
|
||||
put_nfs4_file(fp);
|
||||
kmem_cache_free(nfs4_layout_stateid_cache, ls);
|
||||
return NULL;
|
||||
@@ -626,7 +626,7 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls)
|
||||
|
||||
argv[0] = (char *)nfsd_recall_failed;
|
||||
argv[1] = addr_str;
|
||||
argv[2] = ls->ls_file->f_path.mnt->mnt_sb->s_id;
|
||||
argv[2] = ls->ls_file->nf_file->f_path.mnt->mnt_sb->s_id;
|
||||
argv[3] = NULL;
|
||||
|
||||
error = call_usermodehelper(nfsd_recall_failed, argv, envp,
|
||||
|
||||
@@ -568,17 +568,11 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
|
||||
static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net)
|
||||
{
|
||||
__be32 verf[2];
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
__be32 *verf = (__be32 *)verifier->data;
|
||||
|
||||
/*
|
||||
* This is opaque to client, so no need to byte-swap. Use
|
||||
* __force to keep sparse happy. y2038 time_t overflow is
|
||||
* irrelevant in this usage.
|
||||
*/
|
||||
verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec;
|
||||
verf[1] = (__force __be32)nn->nfssvc_boot.tv_nsec;
|
||||
memcpy(verifier->data, verf, sizeof(verifier->data));
|
||||
BUILD_BUG_ON(2*sizeof(*verf) != sizeof(verifier->data));
|
||||
|
||||
nfsd_copy_boot_verifier(verf, net_generic(net, nfsd_net_id));
|
||||
}
|
||||
|
||||
static __be32
|
||||
@@ -761,7 +755,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_read *read = &u->read;
|
||||
__be32 status;
|
||||
|
||||
read->rd_filp = NULL;
|
||||
read->rd_nf = NULL;
|
||||
if (read->rd_offset >= OFFSET_MAX)
|
||||
return nfserr_inval;
|
||||
|
||||
@@ -782,7 +776,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
/* check stateid */
|
||||
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
||||
&read->rd_stateid, RD_STATE,
|
||||
&read->rd_filp, &read->rd_tmp_file);
|
||||
&read->rd_nf);
|
||||
if (status) {
|
||||
dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
|
||||
goto out;
|
||||
@@ -798,8 +792,8 @@ out:
|
||||
static void
|
||||
nfsd4_read_release(union nfsd4_op_u *u)
|
||||
{
|
||||
if (u->read.rd_filp)
|
||||
fput(u->read.rd_filp);
|
||||
if (u->read.rd_nf)
|
||||
nfsd_file_put(u->read.rd_nf);
|
||||
trace_nfsd_read_done(u->read.rd_rqstp, u->read.rd_fhp,
|
||||
u->read.rd_offset, u->read.rd_length);
|
||||
}
|
||||
@@ -954,7 +948,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
|
||||
status = nfs4_preprocess_stateid_op(rqstp, cstate,
|
||||
&cstate->current_fh, &setattr->sa_stateid,
|
||||
WR_STATE, NULL, NULL);
|
||||
WR_STATE, NULL);
|
||||
if (status) {
|
||||
dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
|
||||
return status;
|
||||
@@ -993,7 +987,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
{
|
||||
struct nfsd4_write *write = &u->write;
|
||||
stateid_t *stateid = &write->wr_stateid;
|
||||
struct file *filp = NULL;
|
||||
struct nfsd_file *nf = NULL;
|
||||
__be32 status = nfs_ok;
|
||||
unsigned long cnt;
|
||||
int nvecs;
|
||||
@@ -1005,7 +999,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
trace_nfsd_write_start(rqstp, &cstate->current_fh,
|
||||
write->wr_offset, cnt);
|
||||
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
||||
stateid, WR_STATE, &filp, NULL);
|
||||
stateid, WR_STATE, &nf);
|
||||
if (status) {
|
||||
dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
|
||||
return status;
|
||||
@@ -1018,10 +1012,10 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
&write->wr_head, write->wr_buflen);
|
||||
WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec));
|
||||
|
||||
status = nfsd_vfs_write(rqstp, &cstate->current_fh, filp,
|
||||
status = nfsd_vfs_write(rqstp, &cstate->current_fh, nf->nf_file,
|
||||
write->wr_offset, rqstp->rq_vec, nvecs, &cnt,
|
||||
write->wr_how_written);
|
||||
fput(filp);
|
||||
nfsd_file_put(nf);
|
||||
|
||||
write->wr_bytes_written = cnt;
|
||||
trace_nfsd_write_done(rqstp, &cstate->current_fh,
|
||||
@@ -1031,8 +1025,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
|
||||
static __be32
|
||||
nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
stateid_t *src_stateid, struct file **src,
|
||||
stateid_t *dst_stateid, struct file **dst)
|
||||
stateid_t *src_stateid, struct nfsd_file **src,
|
||||
stateid_t *dst_stateid, struct nfsd_file **dst)
|
||||
{
|
||||
__be32 status;
|
||||
|
||||
@@ -1040,22 +1034,22 @@ nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
return nfserr_nofilehandle;
|
||||
|
||||
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
|
||||
src_stateid, RD_STATE, src, NULL);
|
||||
src_stateid, RD_STATE, src);
|
||||
if (status) {
|
||||
dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
||||
dst_stateid, WR_STATE, dst, NULL);
|
||||
dst_stateid, WR_STATE, dst);
|
||||
if (status) {
|
||||
dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
|
||||
goto out_put_src;
|
||||
}
|
||||
|
||||
/* fix up for NFS-specific error code */
|
||||
if (!S_ISREG(file_inode(*src)->i_mode) ||
|
||||
!S_ISREG(file_inode(*dst)->i_mode)) {
|
||||
if (!S_ISREG(file_inode((*src)->nf_file)->i_mode) ||
|
||||
!S_ISREG(file_inode((*dst)->nf_file)->i_mode)) {
|
||||
status = nfserr_wrong_type;
|
||||
goto out_put_dst;
|
||||
}
|
||||
@@ -1063,9 +1057,9 @@ nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
out:
|
||||
return status;
|
||||
out_put_dst:
|
||||
fput(*dst);
|
||||
nfsd_file_put(*dst);
|
||||
out_put_src:
|
||||
fput(*src);
|
||||
nfsd_file_put(*src);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1074,7 +1068,7 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
union nfsd4_op_u *u)
|
||||
{
|
||||
struct nfsd4_clone *clone = &u->clone;
|
||||
struct file *src, *dst;
|
||||
struct nfsd_file *src, *dst;
|
||||
__be32 status;
|
||||
|
||||
status = nfsd4_verify_copy(rqstp, cstate, &clone->cl_src_stateid, &src,
|
||||
@@ -1082,11 +1076,11 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
status = nfsd4_clone_file_range(src, clone->cl_src_pos,
|
||||
dst, clone->cl_dst_pos, clone->cl_count);
|
||||
status = nfsd4_clone_file_range(src->nf_file, clone->cl_src_pos,
|
||||
dst->nf_file, clone->cl_dst_pos, clone->cl_count);
|
||||
|
||||
fput(dst);
|
||||
fput(src);
|
||||
nfsd_file_put(dst);
|
||||
nfsd_file_put(src);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
@@ -1176,8 +1170,9 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
|
||||
do {
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
bytes_copied = nfsd_copy_file_range(copy->file_src, src_pos,
|
||||
copy->file_dst, dst_pos, bytes_total);
|
||||
bytes_copied = nfsd_copy_file_range(copy->nf_src->nf_file,
|
||||
src_pos, copy->nf_dst->nf_file, dst_pos,
|
||||
bytes_total);
|
||||
if (bytes_copied <= 0)
|
||||
break;
|
||||
bytes_total -= bytes_copied;
|
||||
@@ -1204,8 +1199,8 @@ static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync)
|
||||
status = nfs_ok;
|
||||
}
|
||||
|
||||
fput(copy->file_src);
|
||||
fput(copy->file_dst);
|
||||
nfsd_file_put(copy->nf_src);
|
||||
nfsd_file_put(copy->nf_dst);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1218,16 +1213,16 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
|
||||
memcpy(&dst->cp_res, &src->cp_res, sizeof(src->cp_res));
|
||||
memcpy(&dst->fh, &src->fh, sizeof(src->fh));
|
||||
dst->cp_clp = src->cp_clp;
|
||||
dst->file_dst = get_file(src->file_dst);
|
||||
dst->file_src = get_file(src->file_src);
|
||||
dst->nf_dst = nfsd_file_get(src->nf_dst);
|
||||
dst->nf_src = nfsd_file_get(src->nf_src);
|
||||
memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid));
|
||||
}
|
||||
|
||||
static void cleanup_async_copy(struct nfsd4_copy *copy)
|
||||
{
|
||||
nfs4_free_cp_state(copy);
|
||||
fput(copy->file_dst);
|
||||
fput(copy->file_src);
|
||||
nfsd_file_put(copy->nf_dst);
|
||||
nfsd_file_put(copy->nf_src);
|
||||
spin_lock(©->cp_clp->async_lock);
|
||||
list_del(©->copies);
|
||||
spin_unlock(©->cp_clp->async_lock);
|
||||
@@ -1264,8 +1259,8 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_copy *async_copy = NULL;
|
||||
|
||||
status = nfsd4_verify_copy(rqstp, cstate, ©->cp_src_stateid,
|
||||
©->file_src, ©->cp_dst_stateid,
|
||||
©->file_dst);
|
||||
©->nf_src, ©->cp_dst_stateid,
|
||||
©->nf_dst);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
@@ -1347,21 +1342,21 @@ nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_fallocate *fallocate, int flags)
|
||||
{
|
||||
__be32 status;
|
||||
struct file *file;
|
||||
struct nfsd_file *nf;
|
||||
|
||||
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
||||
&fallocate->falloc_stateid,
|
||||
WR_STATE, &file, NULL);
|
||||
WR_STATE, &nf);
|
||||
if (status != nfs_ok) {
|
||||
dprintk("NFSD: nfsd4_fallocate: couldn't process stateid!\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = nfsd4_vfs_fallocate(rqstp, &cstate->current_fh, file,
|
||||
status = nfsd4_vfs_fallocate(rqstp, &cstate->current_fh, nf->nf_file,
|
||||
fallocate->falloc_offset,
|
||||
fallocate->falloc_length,
|
||||
flags);
|
||||
fput(file);
|
||||
nfsd_file_put(nf);
|
||||
return status;
|
||||
}
|
||||
static __be32
|
||||
@@ -1406,11 +1401,11 @@ nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_seek *seek = &u->seek;
|
||||
int whence;
|
||||
__be32 status;
|
||||
struct file *file;
|
||||
struct nfsd_file *nf;
|
||||
|
||||
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
||||
&seek->seek_stateid,
|
||||
RD_STATE, &file, NULL);
|
||||
RD_STATE, &nf);
|
||||
if (status) {
|
||||
dprintk("NFSD: nfsd4_seek: couldn't process stateid!\n");
|
||||
return status;
|
||||
@@ -1432,14 +1427,14 @@ nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
* Note: This call does change file->f_pos, but nothing in NFSD
|
||||
* should ever file->f_pos.
|
||||
*/
|
||||
seek->seek_pos = vfs_llseek(file, seek->seek_offset, whence);
|
||||
seek->seek_pos = vfs_llseek(nf->nf_file, seek->seek_offset, whence);
|
||||
if (seek->seek_pos < 0)
|
||||
status = nfserrno(seek->seek_pos);
|
||||
else if (seek->seek_pos >= i_size_read(file_inode(file)))
|
||||
else if (seek->seek_pos >= i_size_read(file_inode(nf->nf_file)))
|
||||
seek->seek_eof = true;
|
||||
|
||||
out:
|
||||
fput(file);
|
||||
nfsd_file_put(nf);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -49,6 +49,7 @@
|
||||
#include "cache.h"
|
||||
#include "netns.h"
|
||||
#include "pnfs.h"
|
||||
#include "filecache.h"
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
#include <linux/security.h>
|
||||
@@ -203,6 +204,13 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
|
||||
return p;
|
||||
}
|
||||
|
||||
static unsigned int compoundargs_bytes_left(struct nfsd4_compoundargs *argp)
|
||||
{
|
||||
unsigned int this = (char *)argp->end - (char *)argp->p;
|
||||
|
||||
return this + argp->pagelen;
|
||||
}
|
||||
|
||||
static int zero_clientid(clientid_t *clid)
|
||||
{
|
||||
return (clid->cl_boot == 0) && (clid->cl_id == 0);
|
||||
@@ -211,10 +219,10 @@ static int zero_clientid(clientid_t *clid)
|
||||
/**
|
||||
* svcxdr_tmpalloc - allocate memory to be freed after compound processing
|
||||
* @argp: NFSv4 compound argument structure
|
||||
* @p: pointer to be freed (with kfree())
|
||||
* @len: length of buffer to allocate
|
||||
*
|
||||
* Marks @p to be freed when processing the compound operation
|
||||
* described in @argp finishes.
|
||||
* Allocates a buffer of size @len to be freed when processing the compound
|
||||
* operation described in @argp finishes.
|
||||
*/
|
||||
static void *
|
||||
svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len)
|
||||
@@ -347,7 +355,12 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
|
||||
READ_BUF(4); len += 4;
|
||||
nace = be32_to_cpup(p++);
|
||||
|
||||
if (nace > NFS4_ACL_MAX)
|
||||
if (nace > compoundargs_bytes_left(argp)/20)
|
||||
/*
|
||||
* Even with 4-byte names there wouldn't be
|
||||
* space for that many aces; something fishy is
|
||||
* going on:
|
||||
*/
|
||||
return nfserr_fbig;
|
||||
|
||||
*acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace));
|
||||
@@ -1418,7 +1431,6 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
|
||||
struct nfsd4_create_session *sess)
|
||||
{
|
||||
DECODE_HEAD;
|
||||
u32 dummy;
|
||||
|
||||
READ_BUF(16);
|
||||
COPYMEM(&sess->clientid, 8);
|
||||
@@ -1427,7 +1439,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
|
||||
|
||||
/* Fore channel attrs */
|
||||
READ_BUF(28);
|
||||
dummy = be32_to_cpup(p++); /* headerpadsz is always 0 */
|
||||
p++; /* headerpadsz is always 0 */
|
||||
sess->fore_channel.maxreq_sz = be32_to_cpup(p++);
|
||||
sess->fore_channel.maxresp_sz = be32_to_cpup(p++);
|
||||
sess->fore_channel.maxresp_cached = be32_to_cpup(p++);
|
||||
@@ -1444,7 +1456,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
|
||||
|
||||
/* Back channel attrs */
|
||||
READ_BUF(28);
|
||||
dummy = be32_to_cpup(p++); /* headerpadsz is always 0 */
|
||||
p++; /* headerpadsz is always 0 */
|
||||
sess->back_channel.maxreq_sz = be32_to_cpup(p++);
|
||||
sess->back_channel.maxresp_sz = be32_to_cpup(p++);
|
||||
sess->back_channel.maxresp_cached = be32_to_cpup(p++);
|
||||
@@ -1736,7 +1748,6 @@ static __be32
|
||||
nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
|
||||
{
|
||||
DECODE_HEAD;
|
||||
unsigned int tmp;
|
||||
|
||||
status = nfsd4_decode_stateid(argp, ©->cp_src_stateid);
|
||||
if (status)
|
||||
@@ -1751,7 +1762,7 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
|
||||
p = xdr_decode_hyper(p, ©->cp_count);
|
||||
p++; /* ca_consecutive: we always do consecutive copies */
|
||||
copy->cp_synchronous = be32_to_cpup(p++);
|
||||
tmp = be32_to_cpup(p); /* Source server list not supported */
|
||||
/* tmp = be32_to_cpup(p); Source server list not supported */
|
||||
|
||||
DECODE_TAIL;
|
||||
}
|
||||
@@ -3217,9 +3228,8 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
|
||||
if (!p)
|
||||
return nfserr_resource;
|
||||
encode_cinfo(p, &create->cr_cinfo);
|
||||
nfserr = nfsd4_encode_bitmap(xdr, create->cr_bmval[0],
|
||||
return nfsd4_encode_bitmap(xdr, create->cr_bmval[0],
|
||||
create->cr_bmval[1], create->cr_bmval[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __be32
|
||||
@@ -3462,7 +3472,7 @@ static __be32 nfsd4_encode_splice_read(
|
||||
|
||||
len = maxcount;
|
||||
nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp,
|
||||
file, read->rd_offset, &maxcount);
|
||||
file, read->rd_offset, &maxcount, &eof);
|
||||
read->rd_length = maxcount;
|
||||
if (nfserr) {
|
||||
/*
|
||||
@@ -3474,9 +3484,6 @@ static __be32 nfsd4_encode_splice_read(
|
||||
return nfserr;
|
||||
}
|
||||
|
||||
eof = nfsd_eof_on_read(len, maxcount, read->rd_offset,
|
||||
d_inode(read->rd_fhp->fh_dentry)->i_size);
|
||||
|
||||
*(p++) = htonl(eof);
|
||||
*(p++) = htonl(maxcount);
|
||||
|
||||
@@ -3547,15 +3554,13 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
|
||||
|
||||
len = maxcount;
|
||||
nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
|
||||
resp->rqstp->rq_vec, read->rd_vlen, &maxcount);
|
||||
resp->rqstp->rq_vec, read->rd_vlen, &maxcount,
|
||||
&eof);
|
||||
read->rd_length = maxcount;
|
||||
if (nfserr)
|
||||
return nfserr;
|
||||
xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3));
|
||||
|
||||
eof = nfsd_eof_on_read(len, maxcount, read->rd_offset,
|
||||
d_inode(read->rd_fhp->fh_dentry)->i_size);
|
||||
|
||||
tmp = htonl(eof);
|
||||
write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4);
|
||||
tmp = htonl(maxcount);
|
||||
@@ -3574,11 +3579,14 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
{
|
||||
unsigned long maxcount;
|
||||
struct xdr_stream *xdr = &resp->xdr;
|
||||
struct file *file = read->rd_filp;
|
||||
struct file *file;
|
||||
int starting_len = xdr->buf->len;
|
||||
struct raparms *ra = NULL;
|
||||
__be32 *p;
|
||||
|
||||
if (nfserr)
|
||||
return nfserr;
|
||||
file = read->rd_nf->nf_file;
|
||||
|
||||
p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
|
||||
if (!p) {
|
||||
WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags));
|
||||
@@ -3596,18 +3604,12 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
(xdr->buf->buflen - xdr->buf->len));
|
||||
maxcount = min_t(unsigned long, maxcount, read->rd_length);
|
||||
|
||||
if (read->rd_tmp_file)
|
||||
ra = nfsd_init_raparms(file);
|
||||
|
||||
if (file->f_op->splice_read &&
|
||||
test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
|
||||
nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
|
||||
else
|
||||
nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
|
||||
|
||||
if (ra)
|
||||
nfsd_put_raparams(file, ra);
|
||||
|
||||
if (nfserr)
|
||||
xdr_truncate_encode(xdr, starting_len);
|
||||
|
||||
|
||||
@@ -1476,6 +1476,7 @@ static __net_init int nfsd_init_net(struct net *net)
|
||||
|
||||
atomic_set(&nn->ntf_refcnt, 0);
|
||||
init_waitqueue_head(&nn->ntf_wq);
|
||||
seqlock_init(&nn->boot_lock);
|
||||
|
||||
mnt = vfs_kern_mount(&nfsd_fs_type, SB_KERNMOUNT, "nfsd", NULL);
|
||||
if (IS_ERR(mnt)) {
|
||||
|
||||
@@ -172,6 +172,7 @@ nfsd_proc_read(struct svc_rqst *rqstp)
|
||||
struct nfsd_readargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_readres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
u32 eof;
|
||||
|
||||
dprintk("nfsd: READ %s %d bytes at %d\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@@ -195,7 +196,8 @@ nfsd_proc_read(struct svc_rqst *rqstp)
|
||||
nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
|
||||
argp->offset,
|
||||
rqstp->rq_vec, argp->vlen,
|
||||
&resp->count);
|
||||
&resp->count,
|
||||
&eof);
|
||||
|
||||
if (nfserr) return nfserr;
|
||||
return fh_getattr(&resp->fh, &resp->stat);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user