Merge tag 'nfs-for-3.6-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust: "Features include: - More preparatory patches for modularising NFSv2/v3/v4. Split out the various NFSv2/v3/v4-specific code into separate files - More preparation for the NFSv4 migration code - Ensure that OPEN(O_CREATE) observes the pNFS mds threshold parameters - pNFS fast failover when the data servers are down - Various cleanups and debugging patches" * tag 'nfs-for-3.6-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (67 commits) nfs: fix fl_type tests in NFSv4 code NFS: fix pnfs regression with directio writes NFS: fix pnfs regression with directio reads sunrpc: clnt: Add missing braces nfs: fix stub return type warnings NFS: exit_nfs_v4() shouldn't be an __exit function SUNRPC: Add a missing spin_unlock to gss_mech_list_pseudoflavors NFS: Split out NFS v4 client functions NFS: Split out the NFS v4 filesystem types NFS: Create a single nfs_clone_super() function NFS: Split out NFS v4 server creating code NFS: Initialize the NFS v4 client from init_nfs_v4() NFS: Move the v4 getroot code to nfs4getroot.c NFS: Split out NFS v4 file operations NFS: Initialize v4 sysctls from nfs_init_v4() NFS: Create an init_nfs_v4() function NFS: Split out NFS v4 inode operations NFS: Split out NFS v3 inode operations NFS: Split out NFS v2 inode operations NFS: Clean up nfs4_proc_setclientid() and friends ...
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/hash.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/gss_api.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
@@ -122,6 +123,59 @@ rpcauth_unregister(const struct rpc_authops *ops)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpcauth_unregister);
|
||||
|
||||
/**
|
||||
* rpcauth_list_flavors - discover registered flavors and pseudoflavors
|
||||
* @array: array to fill in
|
||||
* @size: size of "array"
|
||||
*
|
||||
* Returns the number of array items filled in, or a negative errno.
|
||||
*
|
||||
* The returned array is not sorted by any policy. Callers should not
|
||||
* rely on the order of the items in the returned array.
|
||||
*/
|
||||
int
|
||||
rpcauth_list_flavors(rpc_authflavor_t *array, int size)
|
||||
{
|
||||
rpc_authflavor_t flavor;
|
||||
int result = 0;
|
||||
|
||||
spin_lock(&rpc_authflavor_lock);
|
||||
for (flavor = 0; flavor < RPC_AUTH_MAXFLAVOR; flavor++) {
|
||||
const struct rpc_authops *ops = auth_flavors[flavor];
|
||||
rpc_authflavor_t pseudos[4];
|
||||
int i, len;
|
||||
|
||||
if (result >= size) {
|
||||
result = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ops == NULL)
|
||||
continue;
|
||||
if (ops->list_pseudoflavors == NULL) {
|
||||
array[result++] = ops->au_flavor;
|
||||
continue;
|
||||
}
|
||||
len = ops->list_pseudoflavors(pseudos, ARRAY_SIZE(pseudos));
|
||||
if (len < 0) {
|
||||
result = len;
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
if (result >= size) {
|
||||
result = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
array[result++] = pseudos[i];
|
||||
}
|
||||
}
|
||||
spin_unlock(&rpc_authflavor_lock);
|
||||
|
||||
dprintk("RPC: %s returns %d\n", __func__, result);
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpcauth_list_flavors);
|
||||
|
||||
struct rpc_auth *
|
||||
rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
|
||||
{
|
||||
|
@@ -1619,6 +1619,7 @@ static const struct rpc_authops authgss_ops = {
|
||||
.crcreate = gss_create_cred,
|
||||
.pipes_create = gss_pipes_dentries_create,
|
||||
.pipes_destroy = gss_pipes_dentries_destroy,
|
||||
.list_pseudoflavors = gss_mech_list_pseudoflavors,
|
||||
};
|
||||
|
||||
static const struct rpc_credops gss_credops = {
|
||||
|
@@ -239,14 +239,28 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
|
||||
|
||||
EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor);
|
||||
|
||||
int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr)
|
||||
/**
|
||||
* gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors
|
||||
* @array: array to fill in
|
||||
* @size: size of "array"
|
||||
*
|
||||
* Returns the number of array items filled in, or a negative errno.
|
||||
*
|
||||
* The returned array is not sorted by any policy. Callers should not
|
||||
* rely on the order of the items in the returned array.
|
||||
*/
|
||||
int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size)
|
||||
{
|
||||
struct gss_api_mech *pos = NULL;
|
||||
int j, i = 0;
|
||||
|
||||
spin_lock(®istered_mechs_lock);
|
||||
list_for_each_entry(pos, ®istered_mechs, gm_list) {
|
||||
for (j=0; j < pos->gm_pf_num; j++) {
|
||||
for (j = 0; j < pos->gm_pf_num; j++) {
|
||||
if (i >= size) {
|
||||
spin_unlock(®istered_mechs_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
array_ptr[i++] = pos->gm_pfs[j].pseudoflavor;
|
||||
}
|
||||
}
|
||||
@@ -254,8 +268,6 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr)
|
||||
return i;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(gss_mech_list_pseudoflavors);
|
||||
|
||||
u32
|
||||
gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)
|
||||
{
|
||||
|
@@ -1844,12 +1844,13 @@ call_timeout(struct rpc_task *task)
|
||||
return;
|
||||
}
|
||||
if (RPC_IS_SOFT(task)) {
|
||||
if (clnt->cl_chatty)
|
||||
if (clnt->cl_chatty) {
|
||||
rcu_read_lock();
|
||||
printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
|
||||
clnt->cl_protname,
|
||||
rcu_dereference(clnt->cl_xprt)->servername);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
if (task->tk_flags & RPC_TASK_TIMEOUT)
|
||||
rpc_exit(task, -ETIMEDOUT);
|
||||
else
|
||||
|
127
net/sunrpc/xdr.c
127
net/sunrpc/xdr.c
@@ -128,34 +128,6 @@ xdr_terminate_string(struct xdr_buf *buf, const u32 len)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_terminate_string);
|
||||
|
||||
void
|
||||
xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
|
||||
unsigned int len)
|
||||
{
|
||||
struct kvec *tail = xdr->tail;
|
||||
u32 *p;
|
||||
|
||||
xdr->pages = pages;
|
||||
xdr->page_base = base;
|
||||
xdr->page_len = len;
|
||||
|
||||
p = (u32 *)xdr->head[0].iov_base + XDR_QUADLEN(xdr->head[0].iov_len);
|
||||
tail->iov_base = p;
|
||||
tail->iov_len = 0;
|
||||
|
||||
if (len & 3) {
|
||||
unsigned int pad = 4 - (len & 3);
|
||||
|
||||
*p = 0;
|
||||
tail->iov_base = (char *)p + (len & 3);
|
||||
tail->iov_len = pad;
|
||||
len += pad;
|
||||
}
|
||||
xdr->buflen += len;
|
||||
xdr->len += len;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_encode_pages);
|
||||
|
||||
void
|
||||
xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
|
||||
struct page **pages, unsigned int base, unsigned int len)
|
||||
@@ -456,6 +428,16 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_shift_buf);
|
||||
|
||||
/**
|
||||
* xdr_stream_pos - Return the current offset from the start of the xdr_stream
|
||||
* @xdr: pointer to struct xdr_stream
|
||||
*/
|
||||
unsigned int xdr_stream_pos(const struct xdr_stream *xdr)
|
||||
{
|
||||
return (unsigned int)(XDR_QUADLEN(xdr->buf->len) - xdr->nwords) << 2;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_stream_pos);
|
||||
|
||||
/**
|
||||
* xdr_init_encode - Initialize a struct xdr_stream for sending data.
|
||||
* @xdr: pointer to xdr_stream struct
|
||||
@@ -556,13 +538,11 @@ void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int b
|
||||
EXPORT_SYMBOL_GPL(xdr_write_pages);
|
||||
|
||||
static void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov,
|
||||
__be32 *p, unsigned int len)
|
||||
unsigned int len)
|
||||
{
|
||||
if (len > iov->iov_len)
|
||||
len = iov->iov_len;
|
||||
if (p == NULL)
|
||||
p = (__be32*)iov->iov_base;
|
||||
xdr->p = p;
|
||||
xdr->p = (__be32*)iov->iov_base;
|
||||
xdr->end = (__be32*)(iov->iov_base + len);
|
||||
xdr->iov = iov;
|
||||
xdr->page_ptr = NULL;
|
||||
@@ -609,7 +589,7 @@ static void xdr_set_next_page(struct xdr_stream *xdr)
|
||||
newbase -= xdr->buf->page_base;
|
||||
|
||||
if (xdr_set_page_base(xdr, newbase, PAGE_SIZE) < 0)
|
||||
xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len);
|
||||
xdr_set_iov(xdr, xdr->buf->tail, xdr->buf->len);
|
||||
}
|
||||
|
||||
static bool xdr_set_next_buffer(struct xdr_stream *xdr)
|
||||
@@ -618,7 +598,7 @@ static bool xdr_set_next_buffer(struct xdr_stream *xdr)
|
||||
xdr_set_next_page(xdr);
|
||||
else if (xdr->iov == xdr->buf->head) {
|
||||
if (xdr_set_page_base(xdr, 0, PAGE_SIZE) < 0)
|
||||
xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len);
|
||||
xdr_set_iov(xdr, xdr->buf->tail, xdr->buf->len);
|
||||
}
|
||||
return xdr->p != xdr->end;
|
||||
}
|
||||
@@ -634,10 +614,15 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
|
||||
xdr->buf = buf;
|
||||
xdr->scratch.iov_base = NULL;
|
||||
xdr->scratch.iov_len = 0;
|
||||
xdr->nwords = XDR_QUADLEN(buf->len);
|
||||
if (buf->head[0].iov_len != 0)
|
||||
xdr_set_iov(xdr, buf->head, p, buf->len);
|
||||
xdr_set_iov(xdr, buf->head, buf->len);
|
||||
else if (buf->page_len != 0)
|
||||
xdr_set_page_base(xdr, 0, buf->len);
|
||||
if (p != NULL && p > xdr->p && xdr->end >= p) {
|
||||
xdr->nwords -= p - xdr->p;
|
||||
xdr->p = p;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_init_decode);
|
||||
|
||||
@@ -662,12 +647,14 @@ EXPORT_SYMBOL_GPL(xdr_init_decode_pages);
|
||||
|
||||
static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
|
||||
{
|
||||
unsigned int nwords = XDR_QUADLEN(nbytes);
|
||||
__be32 *p = xdr->p;
|
||||
__be32 *q = p + XDR_QUADLEN(nbytes);
|
||||
__be32 *q = p + nwords;
|
||||
|
||||
if (unlikely(q > xdr->end || q < p))
|
||||
if (unlikely(nwords > xdr->nwords || q > xdr->end || q < p))
|
||||
return NULL;
|
||||
xdr->p = q;
|
||||
xdr->nwords -= nwords;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -734,6 +721,31 @@ __be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_inline_decode);
|
||||
|
||||
static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len)
|
||||
{
|
||||
struct xdr_buf *buf = xdr->buf;
|
||||
struct kvec *iov;
|
||||
unsigned int nwords = XDR_QUADLEN(len);
|
||||
unsigned int cur = xdr_stream_pos(xdr);
|
||||
|
||||
if (xdr->nwords == 0)
|
||||
return 0;
|
||||
if (nwords > xdr->nwords) {
|
||||
nwords = xdr->nwords;
|
||||
len = nwords << 2;
|
||||
}
|
||||
/* Realign pages to current pointer position */
|
||||
iov = buf->head;
|
||||
if (iov->iov_len > cur)
|
||||
xdr_shrink_bufhead(buf, iov->iov_len - cur);
|
||||
|
||||
/* Truncate page data and move it into the tail */
|
||||
if (buf->page_len > len)
|
||||
xdr_shrink_pagelen(buf, buf->page_len - len);
|
||||
xdr->nwords = XDR_QUADLEN(buf->len - cur);
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position
|
||||
* @xdr: pointer to xdr_stream struct
|
||||
@@ -742,39 +754,37 @@ EXPORT_SYMBOL_GPL(xdr_inline_decode);
|
||||
* Moves data beyond the current pointer position from the XDR head[] buffer
|
||||
* into the page list. Any data that lies beyond current position + "len"
|
||||
* bytes is moved into the XDR tail[].
|
||||
*
|
||||
* Returns the number of XDR encoded bytes now contained in the pages
|
||||
*/
|
||||
void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
|
||||
unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
|
||||
{
|
||||
struct xdr_buf *buf = xdr->buf;
|
||||
struct kvec *iov;
|
||||
ssize_t shift;
|
||||
unsigned int nwords;
|
||||
unsigned int end;
|
||||
int padding;
|
||||
unsigned int padding;
|
||||
|
||||
/* Realign pages to current pointer position */
|
||||
iov = buf->head;
|
||||
shift = iov->iov_len + (char *)iov->iov_base - (char *)xdr->p;
|
||||
if (shift > 0)
|
||||
xdr_shrink_bufhead(buf, shift);
|
||||
|
||||
/* Truncate page data and move it into the tail */
|
||||
if (buf->page_len > len)
|
||||
xdr_shrink_pagelen(buf, buf->page_len - len);
|
||||
padding = (XDR_QUADLEN(len) << 2) - len;
|
||||
len = xdr_align_pages(xdr, len);
|
||||
if (len == 0)
|
||||
return 0;
|
||||
nwords = XDR_QUADLEN(len);
|
||||
padding = (nwords << 2) - len;
|
||||
xdr->iov = iov = buf->tail;
|
||||
/* Compute remaining message length. */
|
||||
end = iov->iov_len;
|
||||
shift = buf->buflen - buf->len;
|
||||
if (shift < end)
|
||||
end -= shift;
|
||||
else if (shift > 0)
|
||||
end = 0;
|
||||
end = ((xdr->nwords - nwords) << 2) + padding;
|
||||
if (end > iov->iov_len)
|
||||
end = iov->iov_len;
|
||||
|
||||
/*
|
||||
* Position current pointer at beginning of tail, and
|
||||
* set remaining message length.
|
||||
*/
|
||||
xdr->p = (__be32 *)((char *)iov->iov_base + padding);
|
||||
xdr->end = (__be32 *)((char *)iov->iov_base + end);
|
||||
xdr->page_ptr = NULL;
|
||||
xdr->nwords = XDR_QUADLEN(end - padding);
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_read_pages);
|
||||
|
||||
@@ -790,12 +800,13 @@ EXPORT_SYMBOL_GPL(xdr_read_pages);
|
||||
*/
|
||||
void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
|
||||
{
|
||||
xdr_read_pages(xdr, len);
|
||||
len = xdr_align_pages(xdr, len);
|
||||
/*
|
||||
* Position current pointer at beginning of tail, and
|
||||
* set remaining message length.
|
||||
*/
|
||||
xdr_set_page_base(xdr, 0, len);
|
||||
if (len != 0)
|
||||
xdr_set_page_base(xdr, 0, len);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_enter_page);
|
||||
|
||||
|
Reference in New Issue
Block a user