Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6

* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
  nfs: don't lose MS_SYNCHRONOUS on remount of noac mount
  NFS: Return meaningful status from decode_secinfo()
  NFSv4: Ensure we request the ordinary fileid when doing readdirplus
  NFSv4: Ensure that clientid and session establishment can time out
  SUNRPC: Allow RPC calls to return ETIMEDOUT instead of EIO
  NFSv4.1: Don't loop forever in nfs4_proc_create_session
  NFSv4: Handle NFS4ERR_WRONGSEC outside of nfs4_handle_exception()
  NFSv4.1: Don't update sequence number if rpc_task is not sent
  NFSv4.1: Ensure state manager thread dies on last umount
  SUNRPC: Fix the SUNRPC Kerberos V RPCSEC_GSS module dependencies
  NFS: Use correct variable for page bounds checking
  NFS: don't negotiate when user specifies sec flavor
  NFS: Attempt mount with default sec flavor first
  NFS: flav_array honors NFS_MAX_SECFLAVORS
  NFS: Fix infinite loop in gss_create_upcall()
  Don't mark_inode_dirty_sync() while holding lock
  NFS: Get rid of pointless test in nfs_commit_done
  NFS: Remove unused argument from nfs_find_best_sec()
  NFS: Eliminate duplicate call to nfs_mark_request_dirty
  NFS: Remove dead code from nfs_fs_mount()
This commit is contained in:
Linus Torvalds 2011-04-28 13:13:07 -07:00
commit 9cab1ba421
15 changed files with 165 additions and 122 deletions

View File

@ -119,7 +119,7 @@ Elong:
} }
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors, struct inode *inode) static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
{ {
struct gss_api_mech *mech; struct gss_api_mech *mech;
struct xdr_netobj oid; struct xdr_netobj oid;
@ -166,7 +166,7 @@ static int nfs_negotiate_security(const struct dentry *parent,
} }
flavors = page_address(page); flavors = page_address(page);
ret = secinfo(parent->d_inode, &dentry->d_name, flavors); ret = secinfo(parent->d_inode, &dentry->d_name, flavors);
*flavor = nfs_find_best_sec(flavors, dentry->d_inode); *flavor = nfs_find_best_sec(flavors);
put_page(page); put_page(page);
} }

View File

@ -47,6 +47,7 @@ enum nfs4_client_state {
NFS4CLNT_LAYOUTRECALL, NFS4CLNT_LAYOUTRECALL,
NFS4CLNT_SESSION_RESET, NFS4CLNT_SESSION_RESET,
NFS4CLNT_RECALL_SLOT, NFS4CLNT_RECALL_SLOT,
NFS4CLNT_LEASE_CONFIRM,
}; };
enum nfs4_session_state { enum nfs4_session_state {

View File

@ -46,6 +46,7 @@
#include <linux/nfs4.h> #include <linux/nfs4.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_page.h> #include <linux/nfs_page.h>
#include <linux/nfs_mount.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/module.h> #include <linux/module.h>
@ -443,8 +444,8 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
if (res->sr_status == 1) if (res->sr_status == 1)
res->sr_status = NFS_OK; res->sr_status = NFS_OK;
/* -ERESTARTSYS can result in skipping nfs41_sequence_setup */ /* don't increment the sequence number if the task wasn't sent */
if (!res->sr_slot) if (!RPC_WAS_SENT(task))
goto out; goto out;
/* Check the SEQUENCE operation status */ /* Check the SEQUENCE operation status */
@ -2185,9 +2186,14 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs4_exception exception = { }; struct nfs4_exception exception = { };
int err; int err;
do { do {
err = nfs4_handle_exception(server, err = _nfs4_lookup_root(server, fhandle, info);
_nfs4_lookup_root(server, fhandle, info), switch (err) {
&exception); case 0:
case -NFS4ERR_WRONGSEC:
break;
default:
err = nfs4_handle_exception(server, err, &exception);
}
} while (exception.retry); } while (exception.retry);
return err; return err;
} }
@ -2208,25 +2214,47 @@ out:
return ret; return ret;
} }
static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info)
{
int i, len, status = 0;
rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS];
len = gss_mech_list_pseudoflavors(&flav_array[0]);
flav_array[len] = RPC_AUTH_NULL;
len += 1;
for (i = 0; i < len; i++) {
status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
continue;
break;
}
/*
* -EACCESS could mean that the user doesn't have correct permissions
* to access the mount. It could also mean that we tried to mount
* with a gss auth flavor, but rpc.gssd isn't running. Either way,
* existing mount programs don't handle -EACCES very well so it should
* be mapped to -EPERM instead.
*/
if (status == -EACCES)
status = -EPERM;
return status;
}
/* /*
* get the file handle for the "/" directory on the server * get the file handle for the "/" directory on the server
*/ */
static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info) struct nfs_fsinfo *info)
{ {
int i, len, status = 0; int status = nfs4_lookup_root(server, fhandle, info);
rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS + 2]; if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR))
/*
flav_array[0] = RPC_AUTH_UNIX; * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM
len = gss_mech_list_pseudoflavors(&flav_array[1]); * by nfs4_map_errors() as this function exits.
flav_array[1+len] = RPC_AUTH_NULL; */
len += 2; status = nfs4_find_root_sec(server, fhandle, info);
for (i = 0; i < len; i++) {
status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
if (status != -EPERM)
break;
}
if (status == 0) if (status == 0)
status = nfs4_server_capabilities(server, fhandle); status = nfs4_server_capabilities(server, fhandle);
if (status == 0) if (status == 0)
@ -3723,21 +3751,20 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
sizeof(setclientid.sc_uaddr), "%s.%u.%u", sizeof(setclientid.sc_uaddr), "%s.%u.%u",
clp->cl_ipaddr, port >> 8, port & 255); clp->cl_ipaddr, port >> 8, port & 255);
status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
if (status != -NFS4ERR_CLID_INUSE) if (status != -NFS4ERR_CLID_INUSE)
break; break;
if (signalled()) if (loop != 0) {
++clp->cl_id_uniquifier;
break; break;
if (loop++ & 1) }
ssleep(clp->cl_lease_time / HZ + 1); ++loop;
else ssleep(clp->cl_lease_time / HZ + 1);
if (++clp->cl_id_uniquifier == 0)
break;
} }
return status; return status;
} }
static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
struct nfs4_setclientid_res *arg, struct nfs4_setclientid_res *arg,
struct rpc_cred *cred) struct rpc_cred *cred)
{ {
@ -3752,7 +3779,7 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp,
int status; int status;
now = jiffies; now = jiffies;
status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
if (status == 0) { if (status == 0) {
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
clp->cl_lease_time = fsinfo.lease_time * HZ; clp->cl_lease_time = fsinfo.lease_time * HZ;
@ -3762,26 +3789,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp,
return status; return status;
} }
int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
struct nfs4_setclientid_res *arg,
struct rpc_cred *cred)
{
long timeout = 0;
int err;
do {
err = _nfs4_proc_setclientid_confirm(clp, arg, cred);
switch (err) {
case 0:
return err;
case -NFS4ERR_RESOURCE:
/* The IBM lawyers misread another document! */
case -NFS4ERR_DELAY:
err = nfs4_delay(clp->cl_rpcclient, &timeout);
}
} while (err == 0);
return err;
}
struct nfs4_delegreturndata { struct nfs4_delegreturndata {
struct nfs4_delegreturnargs args; struct nfs4_delegreturnargs args;
struct nfs4_delegreturnres res; struct nfs4_delegreturnres res;
@ -4786,7 +4793,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
init_utsname()->domainname, init_utsname()->domainname,
clp->cl_rpcclient->cl_auth->au_flavor); clp->cl_rpcclient->cl_auth->au_flavor);
status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
if (!status) if (!status)
status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
dprintk("<-- %s status= %d\n", __func__, status); dprintk("<-- %s status= %d\n", __func__, status);
@ -4869,7 +4876,8 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
.rpc_client = clp->cl_rpcclient, .rpc_client = clp->cl_rpcclient,
.rpc_message = &msg, .rpc_message = &msg,
.callback_ops = &nfs4_get_lease_time_ops, .callback_ops = &nfs4_get_lease_time_ops,
.callback_data = &data .callback_data = &data,
.flags = RPC_TASK_TIMEOUT,
}; };
int status; int status;
@ -5171,7 +5179,7 @@ static int _nfs4_proc_create_session(struct nfs_client *clp)
nfs4_init_channel_attrs(&args); nfs4_init_channel_attrs(&args);
args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN);
status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
if (!status) if (!status)
/* Verify the session's negotiated channel_attrs values */ /* Verify the session's negotiated channel_attrs values */
@ -5194,20 +5202,10 @@ int nfs4_proc_create_session(struct nfs_client *clp)
int status; int status;
unsigned *ptr; unsigned *ptr;
struct nfs4_session *session = clp->cl_session; struct nfs4_session *session = clp->cl_session;
long timeout = 0;
int err;
dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); dprintk("--> %s clp=%p session=%p\n", __func__, clp, session);
do { status = _nfs4_proc_create_session(clp);
status = _nfs4_proc_create_session(clp);
if (status == -NFS4ERR_DELAY) {
err = nfs4_delay(clp->cl_rpcclient, &timeout);
if (err)
status = err;
}
} while (status == -NFS4ERR_DELAY);
if (status) if (status)
goto out; goto out;
@ -5248,7 +5246,7 @@ int nfs4_proc_destroy_session(struct nfs4_session *session)
msg.rpc_argp = session; msg.rpc_argp = session;
msg.rpc_resp = NULL; msg.rpc_resp = NULL;
msg.rpc_cred = NULL; msg.rpc_cred = NULL;
status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
if (status) if (status)
printk(KERN_WARNING printk(KERN_WARNING

View File

@ -64,10 +64,15 @@ static LIST_HEAD(nfs4_clientid_list);
int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
{ {
struct nfs4_setclientid_res clid; struct nfs4_setclientid_res clid = {
.clientid = clp->cl_clientid,
.confirm = clp->cl_confirm,
};
unsigned short port; unsigned short port;
int status; int status;
if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
goto do_confirm;
port = nfs_callback_tcpport; port = nfs_callback_tcpport;
if (clp->cl_addr.ss_family == AF_INET6) if (clp->cl_addr.ss_family == AF_INET6)
port = nfs_callback_tcpport6; port = nfs_callback_tcpport6;
@ -75,10 +80,14 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid); status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
if (status != 0) if (status != 0)
goto out; goto out;
clp->cl_clientid = clid.clientid;
clp->cl_confirm = clid.confirm;
set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
do_confirm:
status = nfs4_proc_setclientid_confirm(clp, &clid, cred); status = nfs4_proc_setclientid_confirm(clp, &clid, cred);
if (status != 0) if (status != 0)
goto out; goto out;
clp->cl_clientid = clid.clientid; clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
nfs4_schedule_state_renewal(clp); nfs4_schedule_state_renewal(clp);
out: out:
return status; return status;
@ -230,13 +239,18 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
{ {
int status; int status;
if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
goto do_confirm;
nfs4_begin_drain_session(clp); nfs4_begin_drain_session(clp);
status = nfs4_proc_exchange_id(clp, cred); status = nfs4_proc_exchange_id(clp, cred);
if (status != 0) if (status != 0)
goto out; goto out;
set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
do_confirm:
status = nfs4_proc_create_session(clp); status = nfs4_proc_create_session(clp);
if (status != 0) if (status != 0)
goto out; goto out;
clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
nfs41_setup_state_renewal(clp); nfs41_setup_state_renewal(clp);
nfs_mark_client_ready(clp, NFS_CS_READY); nfs_mark_client_ready(clp, NFS_CS_READY);
out: out:
@ -1584,20 +1598,23 @@ static int nfs4_recall_slot(struct nfs_client *clp) { return 0; }
*/ */
static void nfs4_set_lease_expired(struct nfs_client *clp, int status) static void nfs4_set_lease_expired(struct nfs_client *clp, int status)
{ {
if (nfs4_has_session(clp)) { switch (status) {
switch (status) { case -NFS4ERR_CLID_INUSE:
case -NFS4ERR_DELAY: case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_CLID_INUSE: clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
case -EAGAIN: break;
break; case -NFS4ERR_DELAY:
case -ETIMEDOUT:
case -EAGAIN:
ssleep(1);
break;
case -EKEYEXPIRED: case -EKEYEXPIRED:
nfs4_warn_keyexpired(clp->cl_hostname); nfs4_warn_keyexpired(clp->cl_hostname);
case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
* in nfs4_exchange_id */ * in nfs4_exchange_id */
default: default:
return; return;
}
} }
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
} }
@ -1607,7 +1624,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
int status = 0; int status = 0;
/* Ensure exclusive access to NFSv4 state */ /* Ensure exclusive access to NFSv4 state */
for(;;) { do {
if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
/* We're going to have to re-establish a clientid */ /* We're going to have to re-establish a clientid */
status = nfs4_reclaim_lease(clp); status = nfs4_reclaim_lease(clp);
@ -1691,7 +1708,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
break; break;
if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
break; break;
} } while (atomic_read(&clp->cl_count) > 1);
return; return;
out_error: out_error:
printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"

View File

@ -1452,26 +1452,25 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
{ {
uint32_t attrs[2] = {0, 0}; uint32_t attrs[2] = {
FATTR4_WORD0_RDATTR_ERROR,
FATTR4_WORD1_MOUNTED_ON_FILEID,
};
uint32_t dircount = readdir->count >> 1; uint32_t dircount = readdir->count >> 1;
__be32 *p; __be32 *p;
if (readdir->plus) { if (readdir->plus) {
attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE; FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE|FATTR4_WORD0_FILEID;
attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER| attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV| FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS| FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
dircount >>= 1; dircount >>= 1;
} }
attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID; /* Use mounted_on_fileid only if the server supports it */
attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID; if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
/* Switch to mounted_on_fileid if the server supports it */ attrs[0] |= FATTR4_WORD0_FILEID;
if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
attrs[0] &= ~FATTR4_WORD0_FILEID;
else
attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
*p++ = cpu_to_be32(OP_READDIR); *p++ = cpu_to_be32(OP_READDIR);
@ -3140,7 +3139,7 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma
goto out_overflow; goto out_overflow;
xdr_decode_hyper(p, fileid); xdr_decode_hyper(p, fileid);
bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
ret = NFS_ATTR_FATTR_FILEID; ret = NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
} }
dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
return ret; return ret;
@ -4002,7 +4001,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
{ {
int status; int status;
umode_t fmode = 0; umode_t fmode = 0;
uint64_t fileid;
uint32_t type; uint32_t type;
status = decode_attr_type(xdr, bitmap, &type); status = decode_attr_type(xdr, bitmap, &type);
@ -4101,13 +4099,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
goto xdr_error; goto xdr_error;
fattr->valid |= status; fattr->valid |= status;
status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid); status = decode_attr_mounted_on_fileid(xdr, bitmap, &fattr->mounted_on_fileid);
if (status < 0) if (status < 0)
goto xdr_error; goto xdr_error;
if (status != 0 && !(fattr->valid & status)) { fattr->valid |= status;
fattr->fileid = fileid;
fattr->valid |= status;
}
xdr_error: xdr_error:
dprintk("%s: xdr returned %d\n", __func__, -status); dprintk("%s: xdr returned %d\n", __func__, -status);
@ -4838,17 +4833,21 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
struct nfs4_secinfo_flavor *sec_flavor; struct nfs4_secinfo_flavor *sec_flavor;
int status; int status;
__be32 *p; __be32 *p;
int i; int i, num_flavors;
status = decode_op_hdr(xdr, OP_SECINFO); status = decode_op_hdr(xdr, OP_SECINFO);
if (status)
goto out;
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(!p)) if (unlikely(!p))
goto out_overflow; goto out_overflow;
res->flavors->num_flavors = be32_to_cpup(p);
for (i = 0; i < res->flavors->num_flavors; i++) { res->flavors->num_flavors = 0;
num_flavors = be32_to_cpup(p);
for (i = 0; i < num_flavors; i++) {
sec_flavor = &res->flavors->flavors[i]; sec_flavor = &res->flavors->flavors[i];
if ((char *)&sec_flavor[1] - (char *)res > PAGE_SIZE) if ((char *)&sec_flavor[1] - (char *)res->flavors > PAGE_SIZE)
break; break;
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
@ -4857,13 +4856,15 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
sec_flavor->flavor = be32_to_cpup(p); sec_flavor->flavor = be32_to_cpup(p);
if (sec_flavor->flavor == RPC_AUTH_GSS) { if (sec_flavor->flavor == RPC_AUTH_GSS) {
if (decode_secinfo_gss(xdr, sec_flavor)) status = decode_secinfo_gss(xdr, sec_flavor);
break; if (status)
goto out;
} }
res->flavors->num_flavors++;
} }
return 0; out:
return status;
out_overflow: out_overflow:
print_overflow_msg(__func__, xdr); print_overflow_msg(__func__, xdr);
return -EIO; return -EIO;
@ -6408,7 +6409,9 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
entry->server, 1) < 0) entry->server, 1) < 0)
goto out_overflow; goto out_overflow;
if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
entry->ino = entry->fattr->mounted_on_fileid;
else if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
entry->ino = entry->fattr->fileid; entry->ino = entry->fattr->fileid;
entry->d_type = DT_UNKNOWN; entry->d_type = DT_UNKNOWN;

View File

@ -1004,6 +1004,7 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
{ {
struct nfs_inode *nfsi = NFS_I(wdata->inode); struct nfs_inode *nfsi = NFS_I(wdata->inode);
loff_t end_pos = wdata->args.offset + wdata->res.count; loff_t end_pos = wdata->args.offset + wdata->res.count;
bool mark_as_dirty = false;
spin_lock(&nfsi->vfs_inode.i_lock); spin_lock(&nfsi->vfs_inode.i_lock);
if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
@ -1011,13 +1012,18 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
get_lseg(wdata->lseg); get_lseg(wdata->lseg);
wdata->lseg->pls_lc_cred = wdata->lseg->pls_lc_cred =
get_rpccred(wdata->args.context->state->owner->so_cred); get_rpccred(wdata->args.context->state->owner->so_cred);
mark_inode_dirty_sync(wdata->inode); mark_as_dirty = true;
dprintk("%s: Set layoutcommit for inode %lu ", dprintk("%s: Set layoutcommit for inode %lu ",
__func__, wdata->inode->i_ino); __func__, wdata->inode->i_ino);
} }
if (end_pos > wdata->lseg->pls_end_pos) if (end_pos > wdata->lseg->pls_end_pos)
wdata->lseg->pls_end_pos = end_pos; wdata->lseg->pls_end_pos = end_pos;
spin_unlock(&nfsi->vfs_inode.i_lock); spin_unlock(&nfsi->vfs_inode.i_lock);
/* if pnfs_layoutcommit_inode() runs between inode locks, the next one
* will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */
if (mark_as_dirty)
mark_inode_dirty_sync(wdata->inode);
} }
EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit); EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit);

View File

@ -1004,6 +1004,7 @@ static int nfs_parse_security_flavors(char *value,
return 0; return 0;
} }
mnt->flags |= NFS_MOUNT_SECFLAVOUR;
mnt->auth_flavor_len = 1; mnt->auth_flavor_len = 1;
return 1; return 1;
} }
@ -1976,6 +1977,15 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
if (error < 0) if (error < 0)
goto out; goto out;
/*
* noac is a special case. It implies -o sync, but that's not
* necessarily reflected in the mtab options. do_remount_sb
* will clear MS_SYNCHRONOUS if -o sync wasn't specified in the
* remount options, so we have to explicitly reset it.
*/
if (data->flags & NFS_MOUNT_NOAC)
*flags |= MS_SYNCHRONOUS;
/* compare new mount options with old ones */ /* compare new mount options with old ones */
error = nfs_compare_remount_data(nfss, data); error = nfs_compare_remount_data(nfss, data);
out: out:
@ -2235,8 +2245,7 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
if (!s->s_root) { if (!s->s_root) {
/* initial superblock/root creation */ /* initial superblock/root creation */
nfs_fill_super(s, data); nfs_fill_super(s, data);
nfs_fscache_get_super_cookie( nfs_fscache_get_super_cookie(s, data->fscache_uniq, NULL);
s, data ? data->fscache_uniq : NULL, NULL);
} }
mntroot = nfs_get_root(s, mntfh, dev_name); mntroot = nfs_get_root(s, mntfh, dev_name);

View File

@ -680,7 +680,6 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
req = nfs_setup_write_request(ctx, page, offset, count); req = nfs_setup_write_request(ctx, page, offset, count);
if (IS_ERR(req)) if (IS_ERR(req))
return PTR_ERR(req); return PTR_ERR(req);
nfs_mark_request_dirty(req);
/* Update file length */ /* Update file length */
nfs_grow_file(page, offset, count); nfs_grow_file(page, offset, count);
nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
@ -1418,8 +1417,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
task->tk_pid, task->tk_status); task->tk_pid, task->tk_status);
/* Call the NFS version-specific code */ /* Call the NFS version-specific code */
if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) NFS_PROTO(data->inode)->commit_done(task, data);
return;
} }
void nfs_commit_release_pages(struct nfs_write_data *data) void nfs_commit_release_pages(struct nfs_write_data *data)

View File

@ -47,6 +47,7 @@ struct nfs_client {
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
u64 cl_clientid; /* constant */ u64 cl_clientid; /* constant */
nfs4_verifier cl_confirm; /* Clientid verifier */
unsigned long cl_state; unsigned long cl_state;
spinlock_t cl_lock; spinlock_t cl_lock;

View File

@ -50,6 +50,7 @@ struct nfs_fattr {
} du; } du;
struct nfs_fsid fsid; struct nfs_fsid fsid;
__u64 fileid; __u64 fileid;
__u64 mounted_on_fileid;
struct timespec atime; struct timespec atime;
struct timespec mtime; struct timespec mtime;
struct timespec ctime; struct timespec ctime;
@ -83,6 +84,7 @@ struct nfs_fattr {
#define NFS_ATTR_FATTR_PRECHANGE (1U << 18) #define NFS_ATTR_FATTR_PRECHANGE (1U << 18)
#define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */ #define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */
#define NFS_ATTR_FATTR_MOUNTPOINT (1U << 20) /* Treat as mountpoint */ #define NFS_ATTR_FATTR_MOUNTPOINT (1U << 20) /* Treat as mountpoint */
#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 21)
#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \ #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
| NFS_ATTR_FATTR_MODE \ | NFS_ATTR_FATTR_MODE \

View File

@ -127,13 +127,16 @@ struct rpc_task_setup {
#define RPC_TASK_KILLED 0x0100 /* task was killed */ #define RPC_TASK_KILLED 0x0100 /* task was killed */
#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */ #define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */
#define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */ #define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */
#define RPC_TASK_SENT 0x0800 /* message was sent */
#define RPC_TASK_TIMEOUT 0x1000 /* fail with ETIMEDOUT on timeout */
#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) #define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC)
#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
#define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS)
#define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) #define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED)
#define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT) #define RPC_IS_SOFT(t) ((t)->tk_flags & (RPC_TASK_SOFT|RPC_TASK_TIMEOUT))
#define RPC_IS_SOFTCONN(t) ((t)->tk_flags & RPC_TASK_SOFTCONN) #define RPC_IS_SOFTCONN(t) ((t)->tk_flags & RPC_TASK_SOFTCONN)
#define RPC_WAS_SENT(t) ((t)->tk_flags & RPC_TASK_SENT)
#define RPC_TASK_RUNNING 0 #define RPC_TASK_RUNNING 0
#define RPC_TASK_QUEUED 1 #define RPC_TASK_QUEUED 1

View File

@ -18,14 +18,13 @@ config SUNRPC_XPRT_RDMA
If unsure, say N. If unsure, say N.
config RPCSEC_GSS_KRB5 config RPCSEC_GSS_KRB5
tristate tristate "Secure RPC: Kerberos V mechanism"
depends on SUNRPC && CRYPTO depends on SUNRPC && CRYPTO
prompt "Secure RPC: Kerberos V mechanism" if !(NFS_V4 || NFSD_V4) depends on CRYPTO_MD5 && CRYPTO_DES && CRYPTO_CBC && CRYPTO_CTS
depends on CRYPTO_ECB && CRYPTO_HMAC && CRYPTO_SHA1 && CRYPTO_AES
depends on CRYPTO_ARC4
default y default y
select SUNRPC_GSS select SUNRPC_GSS
select CRYPTO_MD5
select CRYPTO_DES
select CRYPTO_CBC
help help
Choose Y here to enable Secure RPC using the Kerberos version 5 Choose Y here to enable Secure RPC using the Kerberos version 5
GSS-API mechanism (RFC 1964). GSS-API mechanism (RFC 1964).

View File

@ -520,7 +520,7 @@ gss_refresh_upcall(struct rpc_task *task)
warn_gssd(); warn_gssd();
task->tk_timeout = 15*HZ; task->tk_timeout = 15*HZ;
rpc_sleep_on(&pipe_version_rpc_waitqueue, task, NULL); rpc_sleep_on(&pipe_version_rpc_waitqueue, task, NULL);
return 0; return -EAGAIN;
} }
if (IS_ERR(gss_msg)) { if (IS_ERR(gss_msg)) {
err = PTR_ERR(gss_msg); err = PTR_ERR(gss_msg);
@ -563,10 +563,12 @@ retry:
if (PTR_ERR(gss_msg) == -EAGAIN) { if (PTR_ERR(gss_msg) == -EAGAIN) {
err = wait_event_interruptible_timeout(pipe_version_waitqueue, err = wait_event_interruptible_timeout(pipe_version_waitqueue,
pipe_version >= 0, 15*HZ); pipe_version >= 0, 15*HZ);
if (pipe_version < 0) {
warn_gssd();
err = -EACCES;
}
if (err) if (err)
goto out; goto out;
if (pipe_version < 0)
warn_gssd();
goto retry; goto retry;
} }
if (IS_ERR(gss_msg)) { if (IS_ERR(gss_msg)) {

View File

@ -1508,7 +1508,10 @@ call_timeout(struct rpc_task *task)
if (clnt->cl_chatty) if (clnt->cl_chatty)
printk(KERN_NOTICE "%s: server %s not responding, timed out\n", printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
clnt->cl_protname, clnt->cl_server); clnt->cl_protname, clnt->cl_server);
rpc_exit(task, -EIO); if (task->tk_flags & RPC_TASK_TIMEOUT)
rpc_exit(task, -ETIMEDOUT);
else
rpc_exit(task, -EIO);
return; return;
} }

View File

@ -906,6 +906,7 @@ void xprt_transmit(struct rpc_task *task)
} }
dprintk("RPC: %5u xmit complete\n", task->tk_pid); dprintk("RPC: %5u xmit complete\n", task->tk_pid);
task->tk_flags |= RPC_TASK_SENT;
spin_lock_bh(&xprt->transport_lock); spin_lock_bh(&xprt->transport_lock);
xprt->ops->set_retrans_timeout(task); xprt->ops->set_retrans_timeout(task);