NFS client bugfixes for Linux 3.6
- NFSv3 mounts need to fail if the FSINFO rpc call fails - Ensure that the NFS commit cache gets torn down when we unload the NFS module. - Fix memory scribble issues when interrupting a LAYOUTGET rpc call - Fix NFSv4 legacy idmapper regressions - Fix issues with the NFSv4 getacl command - Fix a regression when using the legacy "mount -t nfs4" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJQNPyKAAoJEGcL54qWCgDyQlAP/AmnLaJmKMPj5P4GCiA/uxMV sr0XSSVAv+OgUtRxLNO5PDyunVIIEjwA5nGa2RZEG14+eYwNEeQehaGoaGqoKLhh ATOCMvHHEs5qSKLckWsZWflf6U/MLimYS3D/hHVUtP0QWbBMtol3ImABs2ht/VUc HW0wQoEG+5mhbhC87d4ku5E+OHQzYeNNmdX2VkKOmT0CwRd/bfsHxlGwMmcHldP2 TSge+MRhoKNycpy0j7nugHj2pZ12UiX+O8371OlAketnPk0OA+6RNGMyNo49IQAn VEN9MFWc4ypH1+hJ0OvhzmUA6Zn2/lyQXUtwM1DcXeBmLI4aClb3bT3G3xKNh09O yLEvkh2aUUlmoTSgP7vDK/Ui3QwVnsaJULvg+gywQJG6qTSFgUQfErNKgJmabHQb d0EuumlSGnJ7qdC5nmrUp+M/CpbfGh15ax/JnTRGVK7C3jeCm18vc2np+z4EUDp/ USzrvuBu1B8eI0nQNoht0BeNf7sEJGgFIn8BJzxDakP8buXPMqEvFwA8c1JmMeBX E6pbG2jHqPdrTJtxQTpMRqhA0MxbFlVNi5cCs6U7ifiBqbRWEXyNVgAHTwoIxIrn ASbL0s8gZH+EMEXNOmPmFiO2NUjBCeSzAjrsTmSpWa13YmGfiroZN8N/iPzLnFf+ FR3SFUnoJHq7x4uLZoAX =lqfh -----END PGP SIGNATURE----- Merge tag 'nfs-for-3.6-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client bugfixes from Trond Myklebust: - NFSv3 mounts need to fail if the FSINFO rpc call fails - Ensure that the NFS commit cache gets torn down when we unload the NFS module. - Fix memory scribble issues when interrupting a LAYOUTGET rpc call - Fix NFSv4 legacy idmapper regressions - Fix issues with the NFSv4 getacl command - Fix a regression when using the legacy "mount -t nfs4" * tag 'nfs-for-3.6-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFSv3: Ensure that do_proc_get_root() reports errors correctly NFSv4: Ensure that nfs4_alloc_client cleans up on error. NFS: return -ENOKEY when the upcall fails to map the name NFS: Clear key construction data if the idmap upcall fails NFSv4: Don't use private xdr_stream fields in decode_getacl NFSv4: Fix the acl cache size calculation NFSv4: Fix pointer arithmetic in decode_getacl NFS: Alias the nfs module to nfs4 NFS: Fix a regression when loading the NFS v4 module NFSv4.1: Remove a bogus BUG_ON() in nfs4_layoutreturn_done pnfs-obj: Better IO pattern in case of unaligned offset NFS41: add pg_layout_private to nfs_pageio_descriptor pnfs: nfs4_proc_layoutget returns void pnfs: defer release of pages in layoutget nfs: tear down caches in nfs_init_writepagecache when allocation fails
This commit is contained in:
commit
ad746be969
@ -12,19 +12,19 @@ nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
|
||||
nfs-$(CONFIG_SYSCTL) += sysctl.o
|
||||
nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
|
||||
|
||||
obj-$(CONFIG_NFS_V2) += nfs2.o
|
||||
nfs2-y := nfs2super.o proc.o nfs2xdr.o
|
||||
obj-$(CONFIG_NFS_V2) += nfsv2.o
|
||||
nfsv2-y := nfs2super.o proc.o nfs2xdr.o
|
||||
|
||||
obj-$(CONFIG_NFS_V3) += nfs3.o
|
||||
nfs3-y := nfs3super.o nfs3client.o nfs3proc.o nfs3xdr.o
|
||||
nfs3-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
|
||||
obj-$(CONFIG_NFS_V3) += nfsv3.o
|
||||
nfsv3-y := nfs3super.o nfs3client.o nfs3proc.o nfs3xdr.o
|
||||
nfsv3-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
|
||||
|
||||
obj-$(CONFIG_NFS_V4) += nfs4.o
|
||||
nfs4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \
|
||||
obj-$(CONFIG_NFS_V4) += nfsv4.o
|
||||
nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \
|
||||
delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \
|
||||
nfs4namespace.o nfs4getroot.o nfs4client.o
|
||||
nfs4-$(CONFIG_SYSCTL) += nfs4sysctl.o
|
||||
nfs4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o
|
||||
nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o
|
||||
nfsv4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o
|
||||
|
||||
obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
|
||||
nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
|
||||
|
@ -105,7 +105,7 @@ struct nfs_subversion *get_nfs_version(unsigned int version)
|
||||
|
||||
if (IS_ERR(nfs)) {
|
||||
mutex_lock(&nfs_version_mutex);
|
||||
request_module("nfs%d", version);
|
||||
request_module("nfsv%d", version);
|
||||
nfs = find_nfs_version(version);
|
||||
mutex_unlock(&nfs_version_mutex);
|
||||
}
|
||||
|
@ -61,6 +61,12 @@ struct idmap {
|
||||
struct mutex idmap_mutex;
|
||||
};
|
||||
|
||||
struct idmap_legacy_upcalldata {
|
||||
struct rpc_pipe_msg pipe_msg;
|
||||
struct idmap_msg idmap_msg;
|
||||
struct idmap *idmap;
|
||||
};
|
||||
|
||||
/**
|
||||
* nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
|
||||
* @fattr: fully initialised struct nfs_fattr
|
||||
@ -324,6 +330,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
|
||||
ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
|
||||
name, namelen, type, data,
|
||||
data_size, idmap);
|
||||
idmap->idmap_key_cons = NULL;
|
||||
mutex_unlock(&idmap->idmap_mutex);
|
||||
}
|
||||
return ret;
|
||||
@ -380,11 +387,13 @@ static const match_table_t nfs_idmap_tokens = {
|
||||
static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *);
|
||||
static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
|
||||
size_t);
|
||||
static void idmap_release_pipe(struct inode *);
|
||||
static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
|
||||
|
||||
static const struct rpc_pipe_ops idmap_upcall_ops = {
|
||||
.upcall = rpc_pipe_generic_upcall,
|
||||
.downcall = idmap_pipe_downcall,
|
||||
.release_pipe = idmap_release_pipe,
|
||||
.destroy_msg = idmap_pipe_destroy_msg,
|
||||
};
|
||||
|
||||
@ -616,7 +625,8 @@ void nfs_idmap_quit(void)
|
||||
nfs_idmap_quit_keyring();
|
||||
}
|
||||
|
||||
static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im,
|
||||
static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
|
||||
struct idmap_msg *im,
|
||||
struct rpc_pipe_msg *msg)
|
||||
{
|
||||
substring_t substr;
|
||||
@ -659,6 +669,7 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
|
||||
const char *op,
|
||||
void *aux)
|
||||
{
|
||||
struct idmap_legacy_upcalldata *data;
|
||||
struct rpc_pipe_msg *msg;
|
||||
struct idmap_msg *im;
|
||||
struct idmap *idmap = (struct idmap *)aux;
|
||||
@ -666,15 +677,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
|
||||
int ret = -ENOMEM;
|
||||
|
||||
/* msg and im are freed in idmap_pipe_destroy_msg */
|
||||
msg = kmalloc(sizeof(*msg), GFP_KERNEL);
|
||||
if (!msg)
|
||||
goto out0;
|
||||
|
||||
im = kmalloc(sizeof(*im), GFP_KERNEL);
|
||||
if (!im)
|
||||
data = kmalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
goto out1;
|
||||
|
||||
ret = nfs_idmap_prepare_message(key->description, im, msg);
|
||||
msg = &data->pipe_msg;
|
||||
im = &data->idmap_msg;
|
||||
data->idmap = idmap;
|
||||
|
||||
ret = nfs_idmap_prepare_message(key->description, idmap, im, msg);
|
||||
if (ret < 0)
|
||||
goto out2;
|
||||
|
||||
@ -683,15 +694,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
|
||||
|
||||
ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
|
||||
if (ret < 0)
|
||||
goto out2;
|
||||
goto out3;
|
||||
|
||||
return ret;
|
||||
|
||||
out3:
|
||||
idmap->idmap_key_cons = NULL;
|
||||
out2:
|
||||
kfree(im);
|
||||
kfree(data);
|
||||
out1:
|
||||
kfree(msg);
|
||||
out0:
|
||||
complete_request_key(cons, ret);
|
||||
return ret;
|
||||
}
|
||||
@ -749,9 +760,8 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
|
||||
}
|
||||
|
||||
if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
|
||||
ret = mlen;
|
||||
complete_request_key(cons, -ENOKEY);
|
||||
goto out_incomplete;
|
||||
ret = -ENOKEY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
|
||||
@ -768,16 +778,32 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
|
||||
|
||||
out:
|
||||
complete_request_key(cons, ret);
|
||||
out_incomplete:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
|
||||
{
|
||||
struct idmap_legacy_upcalldata *data = container_of(msg,
|
||||
struct idmap_legacy_upcalldata,
|
||||
pipe_msg);
|
||||
struct idmap *idmap = data->idmap;
|
||||
struct key_construction *cons;
|
||||
if (msg->errno) {
|
||||
cons = ACCESS_ONCE(idmap->idmap_key_cons);
|
||||
idmap->idmap_key_cons = NULL;
|
||||
complete_request_key(cons, msg->errno);
|
||||
}
|
||||
/* Free memory allocated in nfs_idmap_legacy_upcall() */
|
||||
kfree(msg->data);
|
||||
kfree(msg);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static void
|
||||
idmap_release_pipe(struct inode *inode)
|
||||
{
|
||||
struct rpc_inode *rpci = RPC_I(inode);
|
||||
struct idmap *idmap = (struct idmap *)rpci->private;
|
||||
idmap->idmap_key_cons = NULL;
|
||||
}
|
||||
|
||||
int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
|
||||
|
@ -69,7 +69,7 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle,
|
||||
nfs_fattr_init(info->fattr);
|
||||
status = rpc_call_sync(client, &msg, 0);
|
||||
dprintk("%s: reply fsinfo: %d\n", __func__, status);
|
||||
if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
|
||||
if (status == 0 && !(info->fattr->valid & NFS_ATTR_FATTR)) {
|
||||
msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
|
||||
msg.rpc_resp = info->fattr;
|
||||
status = rpc_call_sync(client, &msg, 0);
|
||||
|
@ -205,6 +205,9 @@ extern const struct dentry_operations nfs4_dentry_operations;
|
||||
int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
|
||||
unsigned, umode_t, int *);
|
||||
|
||||
/* super.c */
|
||||
extern struct file_system_type nfs4_fs_type;
|
||||
|
||||
/* nfs4namespace.c */
|
||||
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *);
|
||||
struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *);
|
||||
|
@ -74,7 +74,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
|
||||
return clp;
|
||||
|
||||
error:
|
||||
kfree(clp);
|
||||
nfs_free_client(clp);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
|
@ -3737,9 +3737,10 @@ out:
|
||||
static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len)
|
||||
{
|
||||
struct nfs4_cached_acl *acl;
|
||||
size_t buflen = sizeof(*acl) + acl_len;
|
||||
|
||||
if (pages && acl_len <= PAGE_SIZE) {
|
||||
acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL);
|
||||
if (pages && buflen <= PAGE_SIZE) {
|
||||
acl = kmalloc(buflen, GFP_KERNEL);
|
||||
if (acl == NULL)
|
||||
goto out;
|
||||
acl->cached = 1;
|
||||
@ -3819,7 +3820,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
acl_len = res.acl_len - res.acl_data_offset;
|
||||
acl_len = res.acl_len;
|
||||
if (acl_len > args.acl_len)
|
||||
nfs4_write_cached_acl(inode, NULL, 0, acl_len);
|
||||
else
|
||||
@ -6223,11 +6224,58 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
|
||||
dprintk("<-- %s\n", __func__);
|
||||
}
|
||||
|
||||
static size_t max_response_pages(struct nfs_server *server)
|
||||
{
|
||||
u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
|
||||
return nfs_page_array_len(0, max_resp_sz);
|
||||
}
|
||||
|
||||
static void nfs4_free_pages(struct page **pages, size_t size)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!pages)
|
||||
return;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (!pages[i])
|
||||
break;
|
||||
__free_page(pages[i]);
|
||||
}
|
||||
kfree(pages);
|
||||
}
|
||||
|
||||
static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags)
|
||||
{
|
||||
struct page **pages;
|
||||
int i;
|
||||
|
||||
pages = kcalloc(size, sizeof(struct page *), gfp_flags);
|
||||
if (!pages) {
|
||||
dprintk("%s: can't alloc array of %zu pages\n", __func__, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
pages[i] = alloc_page(gfp_flags);
|
||||
if (!pages[i]) {
|
||||
dprintk("%s: failed to allocate page\n", __func__);
|
||||
nfs4_free_pages(pages, size);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pages;
|
||||
}
|
||||
|
||||
static void nfs4_layoutget_release(void *calldata)
|
||||
{
|
||||
struct nfs4_layoutget *lgp = calldata;
|
||||
struct nfs_server *server = NFS_SERVER(lgp->args.inode);
|
||||
size_t max_pages = max_response_pages(server);
|
||||
|
||||
dprintk("--> %s\n", __func__);
|
||||
nfs4_free_pages(lgp->args.layout.pages, max_pages);
|
||||
put_nfs_open_context(lgp->args.ctx);
|
||||
kfree(calldata);
|
||||
dprintk("<-- %s\n", __func__);
|
||||
@ -6239,9 +6287,10 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {
|
||||
.rpc_release = nfs4_layoutget_release,
|
||||
};
|
||||
|
||||
int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
|
||||
void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(lgp->args.inode);
|
||||
size_t max_pages = max_response_pages(server);
|
||||
struct rpc_task *task;
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
|
||||
@ -6259,12 +6308,19 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
|
||||
|
||||
dprintk("--> %s\n", __func__);
|
||||
|
||||
lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags);
|
||||
if (!lgp->args.layout.pages) {
|
||||
nfs4_layoutget_release(lgp);
|
||||
return;
|
||||
}
|
||||
lgp->args.layout.pglen = max_pages * PAGE_SIZE;
|
||||
|
||||
lgp->res.layoutp = &lgp->args.layout;
|
||||
lgp->res.seq_res.sr_slot = NULL;
|
||||
nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
|
||||
task = rpc_run_task(&task_setup_data);
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
return;
|
||||
status = nfs4_wait_for_completion_rpc_task(task);
|
||||
if (status == 0)
|
||||
status = task->tk_status;
|
||||
@ -6272,7 +6328,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
|
||||
status = pnfs_layout_process(lgp);
|
||||
rpc_put_task(task);
|
||||
dprintk("<-- %s status=%d\n", __func__, status);
|
||||
return status;
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -6304,12 +6360,8 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
|
||||
return;
|
||||
}
|
||||
spin_lock(&lo->plh_inode->i_lock);
|
||||
if (task->tk_status == 0) {
|
||||
if (lrp->res.lrs_present) {
|
||||
if (task->tk_status == 0 && lrp->res.lrs_present)
|
||||
pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
|
||||
} else
|
||||
BUG_ON(!list_empty(&lo->plh_segs));
|
||||
}
|
||||
lo->plh_block_lgets--;
|
||||
spin_unlock(&lo->plh_inode->i_lock);
|
||||
dprintk("<-- %s\n", __func__);
|
||||
|
@ -23,14 +23,6 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
|
||||
static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data);
|
||||
|
||||
static struct file_system_type nfs4_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "nfs4",
|
||||
.mount = nfs_fs_mount,
|
||||
.kill_sb = nfs_kill_super,
|
||||
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
|
||||
};
|
||||
|
||||
static struct file_system_type nfs4_remote_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "nfs4",
|
||||
@ -344,14 +336,8 @@ static int __init init_nfs_v4(void)
|
||||
if (err)
|
||||
goto out1;
|
||||
|
||||
err = register_filesystem(&nfs4_fs_type);
|
||||
if (err < 0)
|
||||
goto out2;
|
||||
|
||||
register_nfs_version(&nfs_v4);
|
||||
return 0;
|
||||
out2:
|
||||
nfs4_unregister_sysctl();
|
||||
out1:
|
||||
nfs_idmap_quit();
|
||||
out:
|
||||
@ -361,7 +347,6 @@ out:
|
||||
static void __exit exit_nfs_v4(void)
|
||||
{
|
||||
unregister_nfs_version(&nfs_v4);
|
||||
unregister_filesystem(&nfs4_fs_type);
|
||||
nfs4_unregister_sysctl();
|
||||
nfs_idmap_quit();
|
||||
}
|
||||
|
@ -5045,22 +5045,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
|
||||
struct nfs_getaclres *res)
|
||||
{
|
||||
unsigned int savep;
|
||||
__be32 *bm_p;
|
||||
uint32_t attrlen,
|
||||
bitmap[3] = {0};
|
||||
int status;
|
||||
size_t page_len = xdr->buf->page_len;
|
||||
unsigned int pg_offset;
|
||||
|
||||
res->acl_len = 0;
|
||||
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
|
||||
goto out;
|
||||
|
||||
bm_p = xdr->p;
|
||||
res->acl_data_offset = be32_to_cpup(bm_p) + 2;
|
||||
res->acl_data_offset <<= 2;
|
||||
/* Check if the acl data starts beyond the allocated buffer */
|
||||
if (res->acl_data_offset > page_len)
|
||||
return -ERANGE;
|
||||
xdr_enter_page(xdr, xdr->buf->page_len);
|
||||
|
||||
/* Calculate the offset of the page data */
|
||||
pg_offset = xdr->buf->head[0].iov_len;
|
||||
|
||||
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
|
||||
goto out;
|
||||
@ -5074,23 +5071,20 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
|
||||
/* The bitmap (xdr len + bitmaps) and the attr xdr len words
|
||||
* are stored with the acl data to handle the problem of
|
||||
* variable length bitmaps.*/
|
||||
xdr->p = bm_p;
|
||||
res->acl_data_offset = xdr_stream_pos(xdr) - pg_offset;
|
||||
|
||||
/* We ignore &savep and don't do consistency checks on
|
||||
* the attr length. Let userspace figure it out.... */
|
||||
attrlen += res->acl_data_offset;
|
||||
if (attrlen > page_len) {
|
||||
res->acl_len = attrlen;
|
||||
if (attrlen > (xdr->nwords << 2)) {
|
||||
if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
|
||||
/* getxattr interface called with a NULL buf */
|
||||
res->acl_len = attrlen;
|
||||
goto out;
|
||||
}
|
||||
dprintk("NFS: acl reply: attrlen %u > page_len %zu\n",
|
||||
attrlen, page_len);
|
||||
dprintk("NFS: acl reply: attrlen %u > page_len %u\n",
|
||||
attrlen, xdr->nwords << 2);
|
||||
return -EINVAL;
|
||||
}
|
||||
xdr_read_pages(xdr, attrlen);
|
||||
res->acl_len = attrlen;
|
||||
} else
|
||||
status = -EOPNOTSUPP;
|
||||
|
||||
|
@ -570,17 +570,66 @@ static bool objio_pg_test(struct nfs_pageio_descriptor *pgio,
|
||||
return false;
|
||||
|
||||
return pgio->pg_count + req->wb_bytes <=
|
||||
(unsigned long)pgio->pg_layout_private;
|
||||
}
|
||||
|
||||
void objio_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
|
||||
{
|
||||
pnfs_generic_pg_init_read(pgio, req);
|
||||
if (unlikely(pgio->pg_lseg == NULL))
|
||||
return; /* Not pNFS */
|
||||
|
||||
pgio->pg_layout_private = (void *)
|
||||
OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length;
|
||||
}
|
||||
|
||||
static bool aligned_on_raid_stripe(u64 offset, struct ore_layout *layout,
|
||||
unsigned long *stripe_end)
|
||||
{
|
||||
u32 stripe_off;
|
||||
unsigned stripe_size;
|
||||
|
||||
if (layout->raid_algorithm == PNFS_OSD_RAID_0)
|
||||
return true;
|
||||
|
||||
stripe_size = layout->stripe_unit *
|
||||
(layout->group_width - layout->parity);
|
||||
|
||||
div_u64_rem(offset, stripe_size, &stripe_off);
|
||||
if (!stripe_off)
|
||||
return true;
|
||||
|
||||
*stripe_end = stripe_size - stripe_off;
|
||||
return false;
|
||||
}
|
||||
|
||||
void objio_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
|
||||
{
|
||||
unsigned long stripe_end = 0;
|
||||
|
||||
pnfs_generic_pg_init_write(pgio, req);
|
||||
if (unlikely(pgio->pg_lseg == NULL))
|
||||
return; /* Not pNFS */
|
||||
|
||||
if (req->wb_offset ||
|
||||
!aligned_on_raid_stripe(req->wb_index * PAGE_SIZE,
|
||||
&OBJIO_LSEG(pgio->pg_lseg)->layout,
|
||||
&stripe_end)) {
|
||||
pgio->pg_layout_private = (void *)stripe_end;
|
||||
} else {
|
||||
pgio->pg_layout_private = (void *)
|
||||
OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct nfs_pageio_ops objio_pg_read_ops = {
|
||||
.pg_init = pnfs_generic_pg_init_read,
|
||||
.pg_init = objio_init_read,
|
||||
.pg_test = objio_pg_test,
|
||||
.pg_doio = pnfs_generic_pg_readpages,
|
||||
};
|
||||
|
||||
static const struct nfs_pageio_ops objio_pg_write_ops = {
|
||||
.pg_init = pnfs_generic_pg_init_write,
|
||||
.pg_init = objio_init_write,
|
||||
.pg_test = objio_pg_test,
|
||||
.pg_doio = pnfs_generic_pg_writepages,
|
||||
};
|
||||
|
@ -49,6 +49,7 @@ void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
|
||||
hdr->io_start = req_offset(hdr->req);
|
||||
hdr->good_bytes = desc->pg_count;
|
||||
hdr->dreq = desc->pg_dreq;
|
||||
hdr->layout_private = desc->pg_layout_private;
|
||||
hdr->release = release;
|
||||
hdr->completion_ops = desc->pg_completion_ops;
|
||||
if (hdr->completion_ops->init_hdr)
|
||||
@ -268,6 +269,7 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
|
||||
desc->pg_error = 0;
|
||||
desc->pg_lseg = NULL;
|
||||
desc->pg_dreq = NULL;
|
||||
desc->pg_layout_private = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_pageio_init);
|
||||
|
||||
|
@ -583,9 +583,6 @@ send_layoutget(struct pnfs_layout_hdr *lo,
|
||||
struct nfs_server *server = NFS_SERVER(ino);
|
||||
struct nfs4_layoutget *lgp;
|
||||
struct pnfs_layout_segment *lseg = NULL;
|
||||
struct page **pages = NULL;
|
||||
int i;
|
||||
u32 max_resp_sz, max_pages;
|
||||
|
||||
dprintk("--> %s\n", __func__);
|
||||
|
||||
@ -594,20 +591,6 @@ send_layoutget(struct pnfs_layout_hdr *lo,
|
||||
if (lgp == NULL)
|
||||
return NULL;
|
||||
|
||||
/* allocate pages for xdr post processing */
|
||||
max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
|
||||
max_pages = nfs_page_array_len(0, max_resp_sz);
|
||||
|
||||
pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags);
|
||||
if (!pages)
|
||||
goto out_err_free;
|
||||
|
||||
for (i = 0; i < max_pages; i++) {
|
||||
pages[i] = alloc_page(gfp_flags);
|
||||
if (!pages[i])
|
||||
goto out_err_free;
|
||||
}
|
||||
|
||||
lgp->args.minlength = PAGE_CACHE_SIZE;
|
||||
if (lgp->args.minlength > range->length)
|
||||
lgp->args.minlength = range->length;
|
||||
@ -616,39 +599,19 @@ send_layoutget(struct pnfs_layout_hdr *lo,
|
||||
lgp->args.type = server->pnfs_curr_ld->id;
|
||||
lgp->args.inode = ino;
|
||||
lgp->args.ctx = get_nfs_open_context(ctx);
|
||||
lgp->args.layout.pages = pages;
|
||||
lgp->args.layout.pglen = max_pages * PAGE_SIZE;
|
||||
lgp->lsegpp = &lseg;
|
||||
lgp->gfp_flags = gfp_flags;
|
||||
|
||||
/* Synchronously retrieve layout information from server and
|
||||
* store in lseg.
|
||||
*/
|
||||
nfs4_proc_layoutget(lgp);
|
||||
nfs4_proc_layoutget(lgp, gfp_flags);
|
||||
if (!lseg) {
|
||||
/* remember that LAYOUTGET failed and suspend trying */
|
||||
set_bit(lo_fail_bit(range->iomode), &lo->plh_flags);
|
||||
}
|
||||
|
||||
/* free xdr pages */
|
||||
for (i = 0; i < max_pages; i++)
|
||||
__free_page(pages[i]);
|
||||
kfree(pages);
|
||||
|
||||
return lseg;
|
||||
|
||||
out_err_free:
|
||||
/* free any allocated xdr pages, lgp as it's not used */
|
||||
if (pages) {
|
||||
for (i = 0; i < max_pages; i++) {
|
||||
if (!pages[i])
|
||||
break;
|
||||
__free_page(pages[i]);
|
||||
}
|
||||
kfree(pages);
|
||||
}
|
||||
kfree(lgp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -172,7 +172,7 @@ extern int nfs4_proc_getdevicelist(struct nfs_server *server,
|
||||
struct pnfs_devicelist *devlist);
|
||||
extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
|
||||
struct pnfs_device *dev);
|
||||
extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
|
||||
extern void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags);
|
||||
extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp);
|
||||
|
||||
/* pnfs.c */
|
||||
|
@ -319,6 +319,34 @@ EXPORT_SYMBOL_GPL(nfs_sops);
|
||||
static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *);
|
||||
static int nfs4_validate_mount_data(void *options,
|
||||
struct nfs_parsed_mount_data *args, const char *dev_name);
|
||||
|
||||
struct file_system_type nfs4_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "nfs4",
|
||||
.mount = nfs_fs_mount,
|
||||
.kill_sb = nfs_kill_super,
|
||||
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(nfs4_fs_type);
|
||||
|
||||
static int __init register_nfs4_fs(void)
|
||||
{
|
||||
return register_filesystem(&nfs4_fs_type);
|
||||
}
|
||||
|
||||
static void unregister_nfs4_fs(void)
|
||||
{
|
||||
unregister_filesystem(&nfs4_fs_type);
|
||||
}
|
||||
#else
|
||||
static int __init register_nfs4_fs(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unregister_nfs4_fs(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct shrinker acl_shrinker = {
|
||||
@ -337,12 +365,18 @@ int __init register_nfs_fs(void)
|
||||
if (ret < 0)
|
||||
goto error_0;
|
||||
|
||||
ret = nfs_register_sysctl();
|
||||
ret = register_nfs4_fs();
|
||||
if (ret < 0)
|
||||
goto error_1;
|
||||
|
||||
ret = nfs_register_sysctl();
|
||||
if (ret < 0)
|
||||
goto error_2;
|
||||
register_shrinker(&acl_shrinker);
|
||||
return 0;
|
||||
|
||||
error_2:
|
||||
unregister_nfs4_fs();
|
||||
error_1:
|
||||
unregister_filesystem(&nfs_fs_type);
|
||||
error_0:
|
||||
@ -356,6 +390,7 @@ void __exit unregister_nfs_fs(void)
|
||||
{
|
||||
unregister_shrinker(&acl_shrinker);
|
||||
nfs_unregister_sysctl();
|
||||
unregister_nfs4_fs();
|
||||
unregister_filesystem(&nfs_fs_type);
|
||||
}
|
||||
|
||||
@ -2645,4 +2680,6 @@ MODULE_PARM_DESC(max_session_slots, "Maximum number of outstanding NFSv4.1 "
|
||||
module_param(send_implementation_id, ushort, 0644);
|
||||
MODULE_PARM_DESC(send_implementation_id,
|
||||
"Send implementation ID with NFSv4.1 exchange_id");
|
||||
MODULE_ALIAS("nfs4");
|
||||
|
||||
#endif /* CONFIG_NFS_V4 */
|
||||
|
@ -1814,19 +1814,19 @@ int __init nfs_init_writepagecache(void)
|
||||
nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE,
|
||||
nfs_wdata_cachep);
|
||||
if (nfs_wdata_mempool == NULL)
|
||||
return -ENOMEM;
|
||||
goto out_destroy_write_cache;
|
||||
|
||||
nfs_cdata_cachep = kmem_cache_create("nfs_commit_data",
|
||||
sizeof(struct nfs_commit_data),
|
||||
0, SLAB_HWCACHE_ALIGN,
|
||||
NULL);
|
||||
if (nfs_cdata_cachep == NULL)
|
||||
return -ENOMEM;
|
||||
goto out_destroy_write_mempool;
|
||||
|
||||
nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT,
|
||||
nfs_wdata_cachep);
|
||||
if (nfs_commit_mempool == NULL)
|
||||
return -ENOMEM;
|
||||
goto out_destroy_commit_cache;
|
||||
|
||||
/*
|
||||
* NFS congestion size, scale with available memory.
|
||||
@ -1849,11 +1849,20 @@ int __init nfs_init_writepagecache(void)
|
||||
nfs_congestion_kb = 256*1024;
|
||||
|
||||
return 0;
|
||||
|
||||
out_destroy_commit_cache:
|
||||
kmem_cache_destroy(nfs_cdata_cachep);
|
||||
out_destroy_write_mempool:
|
||||
mempool_destroy(nfs_wdata_mempool);
|
||||
out_destroy_write_cache:
|
||||
kmem_cache_destroy(nfs_wdata_cachep);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void nfs_destroy_writepagecache(void)
|
||||
{
|
||||
mempool_destroy(nfs_commit_mempool);
|
||||
kmem_cache_destroy(nfs_cdata_cachep);
|
||||
mempool_destroy(nfs_wdata_mempool);
|
||||
kmem_cache_destroy(nfs_wdata_cachep);
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ struct nfs_pageio_descriptor {
|
||||
const struct nfs_pgio_completion_ops *pg_completion_ops;
|
||||
struct pnfs_layout_segment *pg_lseg;
|
||||
struct nfs_direct_req *pg_dreq;
|
||||
void *pg_layout_private;
|
||||
};
|
||||
|
||||
#define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags))
|
||||
|
@ -1248,6 +1248,7 @@ struct nfs_pgio_header {
|
||||
void (*release) (struct nfs_pgio_header *hdr);
|
||||
const struct nfs_pgio_completion_ops *completion_ops;
|
||||
struct nfs_direct_req *dreq;
|
||||
void *layout_private;
|
||||
spinlock_t lock;
|
||||
/* fields protected by lock */
|
||||
int pnfs_error;
|
||||
|
Loading…
Reference in New Issue
Block a user