The following patches have been committed to branch nfs-for-2.6.32
Subsystems (4)
cover The following patches have been committed to branch nfs-for-2.6.32
Bartlomiej Zolnierkiewicz (1):
nfs: remove superfluous BUG_ON()s
Peter Staubach (1):
NFS: read-modify-write page updating
Roel Kluin (1):
nfs: Keep index within mnt_errtbl[]
Trond Myklebust (29):
NFSv4: Don't loop forever on state recovery failure...
NFSv4: Add 'server capability' flags for NFSv4 recommended attributes
NFSv4: Don't do idmapper upcalls for asynchronous RPC calls
SUNRPC: convert some sysctls into module parameters
NFSv4: Clean up the nfs.callback_tcpport option
SUNRPC: Constify rpc_pipe_ops...
SUNRPC: Allow rpc_pipefs_ops to have null values for upcall and downcall
SUNRPC: Clean up rpc_pipefs lookup code...
SUNRPC: Clean up file creation code in rpc_pipefs
SUNRPC: Clean up rpc_unlink()
SUNRPC: Clean up rpc_lookup_create
SUNRPC: Clean up rpc_populate/depopulate
SUNRPC: rpc_pipefs cleanup
SUNRPC: Rename rpc_mkdir to rpc_create_client_dir()
SUNRPC: Clean up rpc_create_client_dir()
SUNRPC: Replace rpc_client->cl_dentry and cl_mnt, with a cl_path
SUNRPC: clean up rpc_setup_pipedir()
SUNRPC: One more clean up for rpc_create_client_dir()
NFSD: Clean up the idmapper warning...
SUNRPC: Ensure we initialise the cache_detail before creating procfs files
SUNRPC: Remove the global temporary write buffer in net/sunrpc/cache.c
SUNRPC: Allow the cache_detail to specify alternative upcall mechanisms
SUNRPC: Move procfs-specific stuff out of the generic sunrpc cache code
SUNRPC: Add an rpc_pipefs front end for the sunrpc cache code
NFS: Add a ->migratepage() aop for NFS
SUNRPC: Fix a typo in cache_pipefs_files
NFS: Add a dns resolver for use with NFSv4 referrals and migration
NFS: Use the DNS resolver in the mount code.
SUNRPC: cache must take a reference to the cache detail's module on open()
Documentation/filesystems/nfs.txt | 98 +++++ Documentation/kernel-parameters.txt | 29 ++ fs/nfs/Makefile | 3 +- fs/nfs/cache_lib.c | 140 +++++++ fs/nfs/cache_lib.h | 27 ++ fs/nfs/callback.c | 26 +- fs/nfs/client.c | 15 +- fs/nfs/dns_resolve.c | 335 +++++++++++++++++ fs/nfs/dns_resolve.h | 14 + fs/nfs/file.c | 49 +++- fs/nfs/idmap.c | 6 +- fs/nfs/inode.c | 100 +++++- fs/nfs/internal.h | 6 + fs/nfs/mount_clnt.c | 4 +- fs/nfs/nfs4namespace.c | 18 +- fs/nfs/nfs4proc.c | 40 ++- fs/nfs/nfs4xdr.c | 86 +++-- fs/nfs/write.c | 91 ++++-- fs/nfsd/export.c | 14 +- fs/nfsd/nfs4idmap.c | 20 +- include/linux/nfs_fs_sb.h | 9 + include/linux/sunrpc/cache.h | 40 ++- include/linux/sunrpc/clnt.h | 5 +- include/linux/sunrpc/rpc_pipe_fs.h | 18 +- net/sunrpc/auth_gss/auth_gss.c | 12 +- net/sunrpc/auth_gss/svcauth_gss.c | 7 +- net/sunrpc/cache.c | 622 ++++++++++++++++++++++++-------- net/sunrpc/clnt.c | 60 ++- net/sunrpc/rpc_pipe.c | 685 ++++++++++++++++++++--------------- net/sunrpc/svcauth_unix.c | 14 +- net/sunrpc/xprtsock.c | 52 +++ 31 files changed, 2065 insertions(+), 580 deletions(-)
PATCH 1/32 nfs: Keep index within mnt_errtbl[]
From: Roel Kluin <[email protected]>
Ensure that index i remains within array mnt_errtbl[] and mnt3_errtbl[].
--- fs/nfs/mount_clnt.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
fs/nfs/mount_clnt.c +2 -2
@@ -258,7 +258,7 @@ static int decode_status(struct xdr_stream *xdr, struct mountres *res)return -EIO ; status =ntohl (*p); -for (i =0 ; i <=ARRAY_SIZE (mnt_errtbl); i++) { +for (i =0 ; i <ARRAY_SIZE (mnt_errtbl); i++) {if (mnt_errtbl[i].status == status) { res->errno = mnt_errtbl[i].errno;return 0 ;
@@ -309,7 +309,7 @@ static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res)return -EIO ; status =ntohl (*p); -for (i =0 ; i <=ARRAY_SIZE (mnt3_errtbl); i++) { +for (i =0 ; i <ARRAY_SIZE (mnt3_errtbl); i++) {if (mnt3_errtbl[i].status == status) { res->errno = mnt3_errtbl[i].errno;return 0 ;
Signature · 1 line
1.6.0.4
PATCH 2/32 NFSv4: Don't loop forever on state recovery failure...
If the server is broken, then retrying forever won't fix it. We should just give up after a while, and return an error to the user. We set the number of retries to 10 for now...
--- fs/nfs/nfs4proc.c | 18 ++++++++++++------ 1 files changed, 12 insertions(+), 6 deletions(-)
fs/nfs/nfs4proc.c +12 -6
@@ -61,6 +61,8 @@#define NFS4_POLL_RETRY_MIN (HZ/10)#define NFS4_POLL_RETRY_MAX (15*HZ) +#define NFS4_MAX_LOOP_ON_RECOVER (10) +struct nfs4_opendata ;static int _nfs4_proc_open (struct nfs4_opendata *data);static int nfs4_do_fsinfo (struct nfs_server *,struct nfs_fh *,struct nfs_fsinfo *);
@@ -426,17 +428,19 @@ out:static int nfs4_recover_session (struct nfs4_session *session) {struct nfs_client *clp = session->clp; +unsigned int loop;int ret; -for (;;) { +for (loop =NFS4_MAX_LOOP_ON_RECOVER ; loop !=0 ; loop--) { ret =nfs4_wait_clnt_recover (clp);if (ret !=0 ) -return ret; +break ;if (!test_bit (NFS4CLNT_SESSION_SETUP , &clp->cl_state))break ;nfs4_schedule_state_manager (clp); + ret = -EIO ; } -return 0 ; +return ret; } static int nfs41_setup_sequence(struct nfs4_session *session,
@@ -1444,18 +1448,20 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)static int nfs4_recover_expired_lease (struct nfs_server *server) {struct nfs_client *clp = server->nfs_client; +unsigned int loop;int ret; -for (;;) { +for (loop =NFS4_MAX_LOOP_ON_RECOVER ; loop !=0 ; loop--) { ret =nfs4_wait_clnt_recover (clp);if (ret !=0 ) -return ret; +break ;if (!test_bit (NFS4CLNT_LEASE_EXPIRED , &clp->cl_state) && !test_bit (NFS4CLNT_CHECK_LEASE ,&clp->cl_state))break ;nfs4_schedule_state_recovery (clp); + ret = -EIO ; } -return 0 ; +return ret; }/*
Signature · 1 line
1.6.0.4
PATCH 3/32 NFSv4: Add 'server capability' flags for NFSv4 recommended attributes
If the NFSv4 server doesn't support a POSIX attribute, the generic NFS code needs to know that, so that it don't keep trying to poll for it.
However, by the same count, if the NFSv4 server does support that attribute, then we should ensure that the inode metadata is appropriately labelled as being untrusted. For instance, if we don't know the correct value of the file's uid, we should certainly not be caching ACLs or ACCESS results.
--- fs/nfs/client.c | 7 ++- fs/nfs/inode.c | 92 ++++++++++++++++++++++++++++++++++++++------- fs/nfs/nfs4proc.c | 22 +++++++++++ include/linux/nfs_fs_sb.h | 9 ++++ 4 files changed, 114 insertions(+), 16 deletions(-)
fs/nfs/client.c +5 -2
@@ -809,6 +809,9 @@ static int nfs_init_server(struct nfs_server *server,/* Initialise the client representation from the mount data */ server->flags = data->flags; server->options = data->options; + server->caps |=NFS_CAP_HARDLINKS |NFS_CAP_SYMLINKS |NFS_CAP_FILEID | +NFS_CAP_MODE |NFS_CAP_NLINK |NFS_CAP_OWNER |NFS_CAP_OWNER_GROUP | +NFS_CAP_ATIME |NFS_CAP_CTIME |NFS_CAP_MTIME ;if (data->rsize) server->rsize =nfs_block_size (data->rsize,NULL );
@@ -1274,7 +1277,7 @@ static int nfs4_init_server(struct nfs_server *server,/* Initialise the client representation from the mount data */ server->flags = data->flags; - server->caps |=NFS_CAP_ATOMIC_OPEN ; + server->caps |=NFS_CAP_ATOMIC_OPEN |NFS_CAP_CHANGE_ATTR ; server->options = data->options;/* Get a client record */
@@ -1400,7 +1403,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,/* Initialise the client representation from the parent server */ nfs_server_copy_userdata (server, parent_server); - server->caps |=NFS_CAP_ATOMIC_OPEN ; + server->caps |=NFS_CAP_ATOMIC_OPEN |NFS_CAP_CHANGE_ATTR ;/* Get a client representation. * Note: NFSv4 always uses TCP, */
fs/nfs/inode.c +78 -14
187 lines not on this page · raw message
fs/nfs/nfs4proc.c +22 -0
@@ -2003,12 +2003,34 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f status =nfs4_call_sync (server, &msg, &args, &res,0 );if (status ==0 ) {memcpy (server->attr_bitmask, res.attr_bitmask,sizeof (server->attr_bitmask)); + server->caps &= ~(NFS_CAP_ACLS |NFS_CAP_HARDLINKS | +NFS_CAP_SYMLINKS |NFS_CAP_FILEID | +NFS_CAP_MODE |NFS_CAP_NLINK |NFS_CAP_OWNER | +NFS_CAP_OWNER_GROUP |NFS_CAP_ATIME | +NFS_CAP_CTIME |NFS_CAP_MTIME );if (res.attr_bitmask[0 ] &FATTR4_WORD0_ACL ) server->caps |=NFS_CAP_ACLS ;if (res.has_links !=0 ) server->caps |=NFS_CAP_HARDLINKS ;if (res.has_symlinks !=0 ) server->caps |=NFS_CAP_SYMLINKS ; +if (res.attr_bitmask[0 ] &FATTR4_WORD0_FILEID ) + server->caps |=NFS_CAP_FILEID ; +if (res.attr_bitmask[1 ] &FATTR4_WORD1_MODE ) + server->caps |=NFS_CAP_MODE ; +if (res.attr_bitmask[1 ] &FATTR4_WORD1_NUMLINKS ) + server->caps |=NFS_CAP_NLINK ; +if (res.attr_bitmask[1 ] &FATTR4_WORD1_OWNER ) + server->caps |=NFS_CAP_OWNER ; +if (res.attr_bitmask[1 ] &FATTR4_WORD1_OWNER_GROUP ) + server->caps |=NFS_CAP_OWNER_GROUP ; +if (res.attr_bitmask[1 ] &FATTR4_WORD1_TIME_ACCESS ) + server->caps |=NFS_CAP_ATIME ; +if (res.attr_bitmask[1 ] &FATTR4_WORD1_TIME_METADATA ) + server->caps |=NFS_CAP_CTIME ; +if (res.attr_bitmask[1 ] &FATTR4_WORD1_TIME_MODIFY ) + server->caps |=NFS_CAP_MTIME ; +memcpy (server->cache_consistency_bitmask, res.attr_bitmask,sizeof (server->cache_consistency_bitmask)); server->cache_consistency_bitmask[0 ] &=FATTR4_WORD0_CHANGE |FATTR4_WORD0_SIZE ; server->cache_consistency_bitmask[1 ] &=FATTR4_WORD1_TIME_METADATA |FATTR4_WORD1_TIME_MODIFY ;
include/linux/nfs_fs_sb.h +9 -0
@@ -167,6 +167,15 @@ struct nfs_server {#define NFS_CAP_SYMLINKS (1U << 2)#define NFS_CAP_ACLS (1U << 3)#define NFS_CAP_ATOMIC_OPEN (1U << 4) +#define NFS_CAP_CHANGE_ATTR (1U << 5) +#define NFS_CAP_FILEID (1U << 6) +#define NFS_CAP_MODE (1U << 7) +#define NFS_CAP_NLINK (1U << 8) +#define NFS_CAP_OWNER (1U << 9) +#define NFS_CAP_OWNER_GROUP (1U << 10) +#define NFS_CAP_ATIME (1U << 11) +#define NFS_CAP_CTIME (1U << 12) +#define NFS_CAP_MTIME (1U << 13)/* maximum number of slots to use */
Signature · 1 line
1.6.0.4
PATCH 4/32 NFSv4: Don't do idmapper upcalls for asynchronous RPC calls
We don't want to cause rpciod to hang...
--- fs/nfs/nfs4xdr.c | 86 ++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 58 insertions(+), 28 deletions(-)
fs/nfs/nfs4xdr.c +58 -28
@@ -3075,7 +3075,8 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_treturn ret; } -static int decode_attr_owner (struct xdr_stream *xdr,uint32_t *bitmap,struct nfs_client *clp,uint32_t *uid) +static int decode_attr_owner (struct xdr_stream *xdr,uint32_t *bitmap, +struct nfs_client *clp,uint32_t *uid,int may_sleep) {uint32_t len;__be32 *p;
@@ -3088,7 +3089,9 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfREAD_BUF (4 );READ32 (len);READ_BUF (len); -if (len <XDR_MAX_NETOBJ ) { +if (!may_sleep) { +/* do nothing */ + }else if (len <XDR_MAX_NETOBJ ) {if (nfs_map_name_to_uid (clp, (char *)p, len, uid) ==0 ) ret =NFS_ATTR_FATTR_OWNER ;else
@@ -3103,7 +3106,8 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfreturn ret; } -static int decode_attr_group (struct xdr_stream *xdr,uint32_t *bitmap,struct nfs_client *clp,uint32_t *gid) +static int decode_attr_group (struct xdr_stream *xdr,uint32_t *bitmap, +struct nfs_client *clp,uint32_t *gid,int may_sleep) {uint32_t len;__be32 *p;
@@ -3116,7 +3120,9 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfREAD_BUF (4 );READ32 (len);READ_BUF (len); -if (len <XDR_MAX_NETOBJ ) { +if (!may_sleep) { +/* do nothing */ + }else if (len <XDR_MAX_NETOBJ ) {if (nfs_map_group_to_gid (clp, (char *)p, len, gid) ==0 ) ret =NFS_ATTR_FATTR_GROUP ;else
@@ -3466,7 +3472,8 @@ xdr_error:return status; } -static int decode_getfattr (struct xdr_stream *xdr,struct nfs_fattr *fattr,const struct nfs_server *server) +static int decode_getfattr (struct xdr_stream *xdr,struct nfs_fattr *fattr, +const struct nfs_server *server,int may_sleep) {__be32 *savep; uint32_t attrlen,
@@ -3538,12 +3545,14 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons goto xdr_error; fattr->valid |= status; - status =decode_attr_owner (xdr, bitmap, server->nfs_client, &fattr->uid); + status =decode_attr_owner (xdr, bitmap, server->nfs_client, + &fattr->uid, may_sleep);if (status <0 ) goto xdr_error; fattr->valid |= status; - status =decode_attr_group (xdr, bitmap, server->nfs_client, &fattr->gid); + status =decode_attr_group (xdr, bitmap, server->nfs_client, + &fattr->gid, may_sleep);if (status <0 ) goto xdr_error; fattr->valid |= status;
@@ -4370,7 +4379,8 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct status =decode_open_downgrade (&xdr, res);if (status !=0 ) goto out; -decode_getfattr (&xdr, res->fattr, res->server); +decode_getfattr (&xdr, res->fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -4397,7 +4407,8 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac status =decode_access (&xdr, res);if (status !=0 ) goto out; -decode_getfattr (&xdr, res->fattr, res->server); +decode_getfattr (&xdr, res->fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -4424,7 +4435,8 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo goto out;if ((status =decode_getfh (&xdr, res->fh)) !=0 ) goto out; - status =decode_getfattr (&xdr, res->fattr, res->server); + status =decode_getfattr (&xdr, res->fattr, res->server + ,!RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -4448,7 +4460,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfif ((status =decode_putrootfh (&xdr)) !=0 ) goto out;if ((status =decode_getfh (&xdr, res->fh)) ==0 ) - status =decode_getfattr (&xdr, res->fattr, res->server); + status =decode_getfattr (&xdr, res->fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -4473,7 +4486,8 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem goto out;if ((status =decode_remove (&xdr, &res->cinfo)) !=0 ) goto out; -decode_getfattr (&xdr, &res->dir_attr, res->server); +decode_getfattr (&xdr, &res->dir_attr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -4503,11 +4517,13 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_reif ((status =decode_rename (&xdr, &res->old_cinfo, &res->new_cinfo)) !=0 ) goto out;/* Current FH is target directory */ -if (decode_getfattr (&xdr, res->new_fattr, res->server) !=0 ) +if (decode_getfattr (&xdr, res->new_fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)) !=0 ) goto out;if ((status =decode_restorefh (&xdr)) !=0 ) goto out; -decode_getfattr (&xdr, res->old_fattr, res->server); +decode_getfattr (&xdr, res->old_fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -4540,11 +4556,13 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link* Note order: OP_LINK leaves the directory as the current * filehandle. */ -if (decode_getfattr (&xdr, res->dir_attr, res->server) !=0 ) +if (decode_getfattr (&xdr, res->dir_attr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)) !=0 ) goto out;if ((status =decode_restorefh (&xdr)) !=0 ) goto out; -decode_getfattr (&xdr, res->fattr, res->server); +decode_getfattr (&xdr, res->fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -4573,11 +4591,13 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr goto out;if ((status =decode_getfh (&xdr, res->fh)) !=0 ) goto out; -if (decode_getfattr (&xdr, res->fattr, res->server) !=0 ) +if (decode_getfattr (&xdr, res->fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)) !=0 ) goto out;if ((status =decode_restorefh (&xdr)) !=0 ) goto out; -decode_getfattr (&xdr, res->dir_fattr, res->server); +decode_getfattr (&xdr, res->dir_fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -4609,7 +4629,8 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g status =decode_putfh (&xdr);if (status) goto out; - status =decode_getfattr (&xdr, res->fattr, res->server); + status =decode_getfattr (&xdr, res->fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -4716,7 +4737,8 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos* an ESTALE error. Shouldn't be a problem, * though, since fattr->valid will remain unset. */ -decode_getfattr (&xdr, res->fattr, res->server); +decode_getfattr (&xdr, res->fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -4748,11 +4770,13 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr goto out;if (decode_getfh (&xdr, &res->fh) !=0 ) goto out; -if (decode_getfattr (&xdr, res->f_attr, res->server) !=0 ) +if (decode_getfattr (&xdr, res->f_attr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)) !=0 ) goto out;if (decode_restorefh (&xdr) !=0 ) goto out; -decode_getfattr (&xdr, res->dir_attr, res->server); +decode_getfattr (&xdr, res->dir_attr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -4800,7 +4824,8 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nf status =decode_open (&xdr, res);if (status) goto out; -decode_getfattr (&xdr, res->f_attr, res->server); +decode_getfattr (&xdr, res->f_attr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -4827,7 +4852,8 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se status =decode_setattr (&xdr);if (status) goto out; -decode_getfattr (&xdr, res->fattr, res->server); +decode_getfattr (&xdr, res->fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -5001,7 +5027,8 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writ status =decode_write (&xdr, res);if (status) goto out; -decode_getfattr (&xdr, res->fattr, res->server); +decode_getfattr (&xdr, res->fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task));if (!status) status = res->count; out:
@@ -5030,7 +5057,8 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_wri status =decode_commit (&xdr, res);if (status) goto out; -decode_getfattr (&xdr, res->fattr, res->server); +decode_getfattr (&xdr, res->fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -5194,7 +5222,8 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfif (status !=0 ) goto out; status =decode_delegreturn (&xdr); -decode_getfattr (&xdr, res->fattr, res->server); +decode_getfattr (&xdr, res->fattr, res->server, + !RPC_IS_ASYNC (rqstp->rq_task)); out:return status; }
@@ -5222,7 +5251,8 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, goto out;xdr_enter_page (&xdr,PAGE_SIZE ); status =decode_getfattr (&xdr, &res->fs_locations->fattr, - res->fs_locations->server); + res->fs_locations->server, + !RPC_IS_ASYNC (req->rq_task)); out:return status; }
Signature · 1 line
1.6.0.4
PATCH 5/32 SUNRPC: convert some sysctls into module parameters
Parameters like the minimum reserved port, and the number of slot entries should really be module parameters rather than sysctls.
--- Documentation/kernel-parameters.txt | 21 ++++++++++++++ net/sunrpc/xprtsock.c | 52 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 0 deletions(-)
Documentation/kernel-parameters.txt +21 -0
@@ -2391,6 +2391,18 @@ and is between 256 and 4096 characters. It is defined in the file stifb= [HW] Format: bpp:<bpp1>[:<bpp2>[:<bpp3>...]] + sunrpc.min_resvport= + sunrpc.max_resvport= + [NFS,SUNRPC] + SunRPC servers often require that client requests + originate from a privileged port (i.e. a port in the + range 0 < portnr < 1024). + An administrator who wishes to reserve some of these + ports for other uses may adjust the range that the + kernel's sunrpc client considers to be privileged + using these two parameters to set the minimum and + maximum port values. + sunrpc.pool_mode= [NFS] Control how the NFS server code allocates CPUs to
@@ -2407,6 +2419,15 @@ and is between 256 and 4096 characters. It is defined in the file pernode one pool for each NUMA node (equivalent to global on non-NUMA machines) + sunrpc.tcp_slot_table_entries= + sunrpc.udp_slot_table_entries= + [NFS,SUNRPC] + Sets the upper limit on the number of simultaneous + RPC calls that can be sent from the client to a + server. Increasing these values may allow you to + improve throughput, but will also increase the + amount of memory reserved for use by the client. + swiotlb= [IA-64] Number of I/O TLB slabs switches= [HW,M68k]
net/sunrpc/xprtsock.c +52 -0
55 lines not on this page · raw message
Signature · 1 line
1.6.0.4
PATCH 6/32 NFSv4: Clean up the nfs.callback_tcpport option
Tighten up the validity checking in param_set_port: check for NULL pointers. Ensure that the option shows up on 'modinfo' output.
--- fs/nfs/callback.c | 26 +++++++++++++++++--------- 1 files changed, 17 insertions(+), 9 deletions(-)
fs/nfs/callback.c +17 -9
@@ -43,21 +43,29 @@ static struct svc_program nfs4_callback_program;unsigned int nfs_callback_set_tcpport;unsigned short nfs_callback_tcpport;unsigned short nfs_callback_tcpport6; -static const int nfs_set_port_min =0 ; -static const int nfs_set_port_max =65535 ; +#define NFS_CALLBACK_MAXPORTNR (65535U) -static int param_set_port (const char *val,struct kernel_param *kp) +static int param_set_portnr (const char *val,struct kernel_param *kp) { -char *endp; -int num =simple_strtol (val, &endp,0 ); -if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max) +unsigned long num; +int ret; + +if (!val) +return -EINVAL ; + ret =strict_strtoul (val,0 , &num); +if (ret == -EINVAL || num >NFS_CALLBACK_MAXPORTNR )return -EINVAL ; - *((int *)kp->arg) = num; + *((unsigned int *)kp->arg) = num;return 0 ; } -module_param_call (callback_tcpport, param_set_port, param_get_int, - &nfs_callback_set_tcpport,0644 ); +static int param_get_portnr (char *buffer,struct kernel_param *kp) +{ +return param_get_uint (buffer, kp); +} +#define param_check_portnr (name, p) __param_check(name, p, unsigned int); + +module_param_named (callback_tcpport, nfs_callback_set_tcpport, portnr,0644 );/* * This is the NFSv4 callback kernel thread.
Signature · 1 line
1.6.0.4
PATCH 7/32 SUNRPC: Constify rpc_pipe_ops...
--- fs/nfs/idmap.c | 2 +- include/linux/sunrpc/rpc_pipe_fs.h | 5 +++-- net/sunrpc/auth_gss/auth_gss.c | 8 ++++---- net/sunrpc/rpc_pipe.c | 7 ++++--- 4 files changed, 12 insertions(+), 10 deletions(-)
fs/nfs/idmap.c +1 -1
@@ -101,7 +101,7 @@ static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);static unsigned int fnvhash32 (const void *,size_t ); -static struct rpc_pipe_ops idmap_upcall_ops = { +static const struct rpc_pipe_ops idmap_upcall_ops = { .upcall = idmap_pipe_upcall, .downcall = idmap_pipe_downcall, .destroy_msg = idmap_pipe_destroy_msg,
include/linux/sunrpc/rpc_pipe_fs.h +3 -2
@@ -32,8 +32,8 @@ struct rpc_inode {wait_queue_head_t waitq;#define RPC_PIPE_WAIT_FOR_OPEN 1int flags; -struct rpc_pipe_ops *ops;struct delayed_work queue_timeout; +const struct rpc_pipe_ops *ops; }; static inline struct rpc_inode *
@@ -46,7 +46,8 @@ extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);extern struct dentry *rpc_mkdir (char *,struct rpc_clnt *);extern int rpc_rmdir (struct dentry *); -extern struct dentry *rpc_mkpipe (struct dentry *,const char *,void *,struct rpc_pipe_ops *,int flags); +extern struct dentry *rpc_mkpipe (struct dentry *,const char *,void *, +const struct rpc_pipe_ops *,int flags);extern int rpc_unlink (struct dentry *);extern struct vfsmount *rpc_get_mount (void );extern void rpc_put_mount (void );
net/sunrpc/auth_gss/auth_gss.c +4 -4
@@ -89,8 +89,8 @@ static struct rpc_wait_queue pipe_version_rpc_waitqueue;static DECLARE_WAIT_QUEUE_HEAD (pipe_version_waitqueue);static void gss_free_ctx (struct gss_cl_ctx *); -static struct rpc_pipe_ops gss_upcall_ops_v0; -static struct rpc_pipe_ops gss_upcall_ops_v1; +static const struct rpc_pipe_ops gss_upcall_ops_v0; +static const struct rpc_pipe_ops gss_upcall_ops_v1;static inline struct gss_cl_ctx *gss_get_ctx (struct gss_cl_ctx *ctx)
@@ -1507,7 +1507,7 @@ static const struct rpc_credops gss_nullops = { .crunwrap_resp = gss_unwrap_resp, }; -static struct rpc_pipe_ops gss_upcall_ops_v0 = { +static const struct rpc_pipe_ops gss_upcall_ops_v0 = { .upcall = gss_pipe_upcall, .downcall = gss_pipe_downcall, .destroy_msg = gss_pipe_destroy_msg,
@@ -1515,7 +1515,7 @@ static struct rpc_pipe_ops gss_upcall_ops_v0 = { .release_pipe = gss_pipe_release, }; -static struct rpc_pipe_ops gss_upcall_ops_v1 = { +static const struct rpc_pipe_ops gss_upcall_ops_v1 = { .upcall = gss_pipe_upcall, .downcall = gss_pipe_downcall, .destroy_msg = gss_pipe_destroy_msg,
net/sunrpc/rpc_pipe.c +4 -3
@@ -125,7 +125,7 @@ static void rpc_close_pipes(struct inode *inode) {struct rpc_inode *rpci =RPC_I (inode); -struct rpc_pipe_ops *ops; +const struct rpc_pipe_ops *ops;int need_release;mutex_lock (&inode->i_mutex);
@@ -776,8 +776,9 @@ rpc_rmdir(struct dentry *dentry)* The @private argument passed here will be available to all these methods * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. */ -struct dentry * -rpc_mkpipe (struct dentry *parent,const char *name,void *private,struct rpc_pipe_ops *ops,int flags) +struct dentry *rpc_mkpipe (struct dentry *parent,const char *name, +void *private,const struct rpc_pipe_ops *ops, +int flags) {struct dentry *dentry;struct inode *dir, *inode;
Signature · 1 line
1.6.0.4
PATCH 8/32 SUNRPC: Allow rpc_pipefs_ops to have null values for upcall and downcall
Also ensure that we use the umode_t type when appropriate...
--- net/sunrpc/rpc_pipe.c | 15 +++++++++++---- 1 files changed, 11 insertions(+), 4 deletions(-)
net/sunrpc/rpc_pipe.c +11 -4
@@ -417,7 +417,7 @@ enum {struct rpc_filelist {char *name;const struct file_operations *i_fop; -int mode; +umode_t mode; };static struct rpc_filelist files[] = {
@@ -516,7 +516,7 @@ rpc_release_path(struct nameidata *nd) }static struct inode * -rpc_get_inode (struct super_block *sb,int mode) +rpc_get_inode (struct super_block *sb,umode_t mode) {struct inode *inode =new_inode (sb);if (!inode)
@@ -589,7 +589,8 @@ rpc_populate(struct dentry *parent,struct inode *inode, *dir = parent->d_inode;void *private =RPC_I (dir)->private;struct dentry *dentry; -int mode, i; +umode_t mode; +int i;mutex_lock (&dir->i_mutex);for (i = start; i < eof; i++) {
@@ -783,6 +784,12 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name,struct dentry *dentry;struct inode *dir, *inode;struct rpc_inode *rpci; +umode_t umode =S_IFIFO |S_IRUSR |S_IWUSR ; + +if (ops->upcall ==NULL ) + umode &= ~S_IRUGO ; +if (ops->downcall ==NULL ) + umode &= ~S_IWUGO ; dentry =rpc_lookup_create (parent, name,strlen (name),0 );if (IS_ERR (dentry))
@@ -799,7 +806,7 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, rpci->nkern_readwriters++; goto out; } - inode =rpc_get_inode (dir->i_sb,S_IFIFO |S_IRUSR |S_IWUSR ); + inode =rpc_get_inode (dir->i_sb, umode);if (!inode) goto err_dput; inode->i_ino =iunique (dir->i_sb,100 );
Signature · 1 line
1.6.0.4
PATCH 9/32 SUNRPC: Clean up rpc_pipefs lookup code...
--- net/sunrpc/rpc_pipe.c | 15 ++++++++++----- 1 files changed, 10 insertions(+), 5 deletions(-)
net/sunrpc/rpc_pipe.c +10 -5
@@ -484,12 +484,12 @@ static const struct dentry_operations rpc_dentry_operations = { .d_delete = rpc_delete_dentry, }; -static int -rpc_lookup_parent (char *path,struct nameidata *nd) +static int __rpc_lookup_path (const char *pathname,unsigned flags, +struct nameidata *nd) {struct vfsmount *mnt; -if (path[0 ] =='\0' ) +if (pathname[0 ] =='\0' )return -ENOENT ; mnt =rpc_get_mount ();
@@ -499,15 +499,20 @@ rpc_lookup_parent(char *path, struct nameidata *nd)return PTR_ERR (mnt); } -if (vfs_path_lookup (mnt->mnt_root, mnt, path,LOOKUP_PARENT , nd)) { +if (vfs_path_lookup (mnt->mnt_root, mnt, pathname, flags, nd)) {printk (KERN_WARNING "%s: %s failed to find path %s\n" , - __FILE__, __func__, path); + __FILE__, __func__, pathname);rpc_put_mount ();return -ENOENT ; }return 0 ; } +static int rpc_lookup_parent (const char *pathname,struct nameidata *nd) +{ +return __rpc_lookup_path (pathname,LOOKUP_PARENT , nd); +} +static void rpc_release_path (struct nameidata *nd) {
Signature · 1 line
1.6.0.4
PATCH 10/32 SUNRPC: Clean up file creation code in rpc_pipefs
--- net/sunrpc/rpc_pipe.c | 120 +++++++++++++++++++++++++++++++----------------- 1 files changed, 77 insertions(+), 43 deletions(-)
net/sunrpc/rpc_pipe.c +77 -43
@@ -539,6 +539,68 @@ rpc_get_inode(struct super_block *sb, umode_t mode)return inode; } +static int __rpc_create_common (struct inode *dir,struct dentry *dentry, +umode_t mode, +const struct file_operations *i_fop, +void *private) +{ +struct inode *inode; + +BUG_ON (!d_unhashed (dentry)); + inode =rpc_get_inode (dir->i_sb, mode); +if (!inode) + goto out_err; + inode->i_ino =iunique (dir->i_sb,100 ); +if (i_fop) + inode->i_fop = i_fop; +if (private) +rpc_inode_setowner (inode, private); +d_add (dentry, inode); +return 0 ; +out_err: +printk (KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n" , + __FILE__, __func__, dentry->d_name.name); +dput (dentry); +return -ENOMEM ; +} + +static int __rpc_mkdir (struct inode *dir,struct dentry *dentry, +umode_t mode, +const struct file_operations *i_fop, +void *private) +{ +int err; + + err =__rpc_create_common (dir, dentry,S_IFDIR | mode, i_fop, private); +if (err) +return err; +inc_nlink (dir); +fsnotify_mkdir (dir, dentry); +return 0 ; +} + +static int __rpc_mkpipe (struct inode *dir,struct dentry *dentry, +umode_t mode, +const struct file_operations *i_fop, +void *private, +const struct rpc_pipe_ops *ops, +int flags) +{ +struct rpc_inode *rpci; +int err; + + err =__rpc_create_common (dir, dentry,S_IFIFO | mode, i_fop, private); +if (err) +return err; + rpci =RPC_I (dentry->d_inode); + rpci->nkern_readwriters =1 ; + rpci->private = private; + rpci->flags = flags; + rpci->ops = ops; +fsnotify_create (dir, dentry); +return 0 ; +} +/* * FIXME: This probably has races. */
@@ -629,25 +691,6 @@ out_bad: }static int -__rpc_mkdir (struct inode *dir,struct dentry *dentry) -{ -struct inode *inode; - - inode =rpc_get_inode (dir->i_sb,S_IFDIR |S_IRUGO |S_IXUGO ); -if (!inode) - goto out_err; - inode->i_ino =iunique (dir->i_sb,100 ); -d_instantiate (dentry, inode); -inc_nlink (dir); -fsnotify_mkdir (dir, dentry); -return 0 ; -out_err: -printk (KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n" , - __FILE__, __func__, dentry->d_name.name); -return -ENOMEM ; -} - -static int __rpc_rmdir (struct inode *dir,struct dentry *dentry) {int error;
@@ -717,9 +760,9 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client)if (IS_ERR (dentry))return dentry; dir = nd.path.dentry->d_inode; -if ((error =__rpc_mkdir (dir, dentry)) !=0 ) - goto err_dput; -RPC_I (dentry->d_inode)->private = rpc_client; + error =__rpc_mkdir (dir, dentry,S_IRUGO |S_IXUGO ,NULL , rpc_client); +if (error !=0 ) + goto out_err; error =rpc_populate (dentry, authfiles, RPCAUTH_info,RPCAUTH_EOF );if (error)
@@ -732,8 +775,7 @@ out: err_depopulate:rpc_depopulate (dentry, RPCAUTH_info,RPCAUTH_EOF );__rpc_rmdir (dir, dentry); -err_dput: -dput (dentry); +out_err:printk (KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n" , __FILE__, __func__, path, error); dentry =ERR_PTR (error);
@@ -787,9 +829,9 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, int flags) {struct dentry *dentry; -struct inode *dir, *inode; -struct rpc_inode *rpci; +struct inode *dir = parent->d_inode;umode_t umode =S_IFIFO |S_IRUSR |S_IWUSR ; +int err;if (ops->upcall ==NULL ) umode &= ~S_IRUGO ;
@@ -801,7 +843,7 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name,return dentry; dir = parent->d_inode;if (dentry->d_inode) { - rpci =RPC_I (dentry->d_inode); +struct rpc_inode *rpci =RPC_I (dentry->d_inode);if (rpci->private != private || rpci->ops != ops || rpci->flags != flags) {
@@ -811,28 +853,20 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, rpci->nkern_readwriters++; goto out; } - inode =rpc_get_inode (dir->i_sb, umode); -if (!inode) - goto err_dput; - inode->i_ino =iunique (dir->i_sb,100 ); - inode->i_fop = &rpc_pipe_fops; -d_instantiate (dentry, inode); - rpci =RPC_I (inode); - rpci->private = private; - rpci->flags = flags; - rpci->ops = ops; - rpci->nkern_readwriters =1 ; -fsnotify_create (dir, dentry); + + err =__rpc_mkpipe (dir, dentry, umode, &rpc_pipe_fops, + private, ops, flags); +if (err) + goto out_err;dget (dentry); out:mutex_unlock (&dir->i_mutex);return dentry; -err_dput: -dput (dentry); - dentry =ERR_PTR (-ENOMEM ); +out_err: + dentry =ERR_PTR (err);printk (KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n" , __FILE__, __func__, parent->d_name.name, name, - -ENOMEM ); + err); goto out; }EXPORT_SYMBOL_GPL (rpc_mkpipe);
Signature · 1 line
1.6.0.4
PATCH 11/32 SUNRPC: Clean up rpc_unlink()
--- net/sunrpc/rpc_pipe.c | 35 +++++++++++++++++++++++++++-------- 1 files changed, 27 insertions(+), 8 deletions(-)
net/sunrpc/rpc_pipe.c +27 -8
@@ -601,6 +601,29 @@ static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry,return 0 ; } +static int __rpc_unlink (struct inode *dir,struct dentry *dentry) +{ +int ret; + +dget (dentry); + ret =simple_unlink (dir, dentry); +d_delete (dentry); +dput (dentry); +return ret; +} + +static int __rpc_rmpipe (struct inode *dir,struct dentry *dentry) +{ +struct inode *inode = dentry->d_inode; +struct rpc_inode *rpci =RPC_I (inode); + + rpci->nkern_readwriters--; +if (rpci->nkern_readwriters !=0 ) +return 0 ; +rpc_close_pipes (inode); +return __rpc_unlink (dir, dentry); +} +/* * FIXME: This probably has races. */
@@ -848,14 +871,15 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, rpci->ops != ops || rpci->flags != flags) {dput (dentry); - dentry =ERR_PTR (-EBUSY ); + err = -EBUSY ; + goto out_err; } rpci->nkern_readwriters++; goto out; } err =__rpc_mkpipe (dir, dentry, umode, &rpc_pipe_fops, - private, ops, flags); + private, ops, flags);if (err) goto out_err;dget (dentry);
@@ -889,12 +913,7 @@ rpc_unlink(struct dentry *dentry) parent =dget_parent (dentry); dir = parent->d_inode;mutex_lock_nested (&dir->i_mutex,I_MUTEX_PARENT ); -if (--RPC_I (dentry->d_inode)->nkern_readwriters ==0 ) { -rpc_close_pipes (dentry->d_inode); - error =simple_unlink (dir, dentry); -if (!error) -d_delete (dentry); - } + error =__rpc_rmpipe (dir, dentry);dput (dentry);mutex_unlock (&dir->i_mutex);dput (parent);
Signature · 1 line
1.6.0.4
PATCH 12/32 SUNRPC: Clean up rpc_lookup_create
--- net/sunrpc/rpc_pipe.c | 100 +++++++++++++++++++++++++++++-------------------- 1 files changed, 59 insertions(+), 41 deletions(-)
net/sunrpc/rpc_pipe.c +59 -41
@@ -624,6 +624,57 @@ static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry)return __rpc_unlink (dir, dentry); } +static struct dentry *__rpc_lookup_create (struct dentry *parent, +struct qstr *name) +{ +struct dentry *dentry; + + dentry =d_lookup (parent, name); +if (!dentry) { + dentry =d_alloc (parent, name); +if (!dentry) { + dentry =ERR_PTR (-ENOMEM ); + goto out_err; + } + } +if (!dentry->d_inode) + dentry->d_op = &rpc_dentry_operations; +out_err: +return dentry; +} + +static struct dentry *__rpc_lookup_create_exclusive (struct dentry *parent, +struct qstr *name) +{ +struct dentry *dentry; + + dentry =__rpc_lookup_create (parent, name); +if (dentry->d_inode ==NULL ) +return dentry; +dput (dentry); +return ERR_PTR (-EEXIST ); +} + +static struct dentry *rpc_lookup_negative (const char *path, +struct nameidata *nd) +{ +struct inode *dir; +struct dentry *dentry; +int error; + + error =rpc_lookup_parent (path, nd); +if (error !=0 ) +return ERR_PTR (error); + dir = nd->path.dentry->d_inode; +mutex_lock_nested (&dir->i_mutex,I_MUTEX_PARENT ); + dentry =__rpc_lookup_create_exclusive (nd->path.dentry, &nd->last); +if (IS_ERR (dentry)) { +mutex_unlock (&dir->i_mutex); +rpc_release_path (nd); + } +return dentry; +} +/* * FIXME: This probably has races. */
@@ -723,44 +774,6 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry)return error; } -static struct dentry * -rpc_lookup_create (struct dentry *parent,const char *name,int len,int exclusive) -{ -struct inode *dir = parent->d_inode; -struct dentry *dentry; - -mutex_lock_nested (&dir->i_mutex,I_MUTEX_PARENT ); - dentry =lookup_one_len (name, parent, len); -if (IS_ERR (dentry)) - goto out_err; -if (!dentry->d_inode) - dentry->d_op = &rpc_dentry_operations; -else if (exclusive) { -dput (dentry); - dentry =ERR_PTR (-EEXIST ); - goto out_err; - } -return dentry; -out_err: -mutex_unlock (&dir->i_mutex); -return dentry; -} - -static struct dentry * -rpc_lookup_negative (char *path,struct nameidata *nd) -{ -struct dentry *dentry; -int error; - -if ((error =rpc_lookup_parent (path, nd)) !=0 ) -return ERR_PTR (error); - dentry =rpc_lookup_create (nd->path.dentry, nd->last.name, nd->last.len, -1 ); -if (IS_ERR (dentry)) -rpc_release_path (nd); -return dentry; -} -/** * rpc_mkdir - Create a new directory in rpc_pipefs * @path: path from the rpc_pipefs root to the new directory
@@ -854,6 +867,7 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name,struct dentry *dentry;struct inode *dir = parent->d_inode;umode_t umode =S_IFIFO |S_IRUSR |S_IWUSR ; +struct qstr q;int err;if (ops->upcall ==NULL )
@@ -861,10 +875,14 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name,if (ops->downcall ==NULL ) umode &= ~S_IWUGO ; - dentry =rpc_lookup_create (parent, name,strlen (name),0 ); + q.name = name; + q.len =strlen (name); + q.hash =full_name_hash (q.name, q.len), + +mutex_lock_nested (&dir->i_mutex,I_MUTEX_PARENT ); + dentry =__rpc_lookup_create (parent, &q);if (IS_ERR (dentry)) -return dentry; - dir = parent->d_inode; + goto out;if (dentry->d_inode) {struct rpc_inode *rpci =RPC_I (dentry->d_inode); if (rpci->private != private ||
Signature · 1 line
1.6.0.4
PATCH 13/32 SUNRPC: Clean up rpc_populate/depopulate
--- net/sunrpc/rpc_pipe.c | 187 ++++++++++++++++++++++++++---------------------- 1 files changed, 101 insertions(+), 86 deletions(-)
net/sunrpc/rpc_pipe.c +101 -86
@@ -401,7 +401,6 @@ static const struct file_operations rpc_info_operations = {* We have a single directory with 1 node in it. */ enum { - RPCAUTH_Root =1 , RPCAUTH_lockd, RPCAUTH_mount, RPCAUTH_nfs,
@@ -415,12 +414,12 @@ enum {* Description of fs contents. */ struct rpc_filelist { -char *name; +const char *name;const struct file_operations *i_fop;umode_t mode; }; -static struct rpc_filelist files[] = { +static const struct rpc_filelist files[] = { [RPCAUTH_lockd] = { .name ="lockd" , .mode =S_IFDIR |S_IRUGO |S_IXUGO ,
@@ -448,11 +447,11 @@ static struct rpc_filelist files[] = { };enum { - RPCAUTH_info =2 , + RPCAUTH_info,RPCAUTH_EOF }; -static struct rpc_filelist authfiles[] = { +static const struct rpc_filelist authfiles[] = { [RPCAUTH_info] = { .name ="info" , .i_fop = &rpc_info_operations,
@@ -564,6 +563,20 @@ out_err:return -ENOMEM ; } +static int __rpc_create (struct inode *dir,struct dentry *dentry, +umode_t mode, +const struct file_operations *i_fop, +void *private) +{ +int err; + + err =__rpc_create_common (dir, dentry,S_IFREG | mode, i_fop, private); +if (err) +return err; +fsnotify_create (dir, dentry); +return 0 ; +} + static int __rpc_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode, const struct file_operations *i_fop,
@@ -601,6 +614,17 @@ static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry,return 0 ; } +static int __rpc_rmdir (struct inode *dir,struct dentry *dentry) +{ +int ret; + +dget (dentry); + ret =simple_rmdir (dir, dentry); +d_delete (dentry); +dput (dentry); +return ret; +} +static int __rpc_unlink (struct inode *dir,struct dentry *dentry) {int ret;
@@ -678,100 +702,96 @@ static struct dentry *rpc_lookup_negative(const char *path,/* * FIXME: This probably has races. */ -static void rpc_depopulate (struct dentry *parent, -unsigned long start,unsigned long eof) +static void __rpc_depopulate (struct dentry *parent, +const struct rpc_filelist *files, +int start,int eof) {struct inode *dir = parent->d_inode; -struct list_head *pos, *next; -struct dentry *dentry, *dvec[10 ]; -int n =0 ; +struct dentry *dentry; +struct qstr name; +int i; -mutex_lock_nested (&dir->i_mutex,I_MUTEX_CHILD ); -repeat: -spin_lock (&dcache_lock); -list_for_each_safe (pos, next, &parent->d_subdirs) { - dentry = list_entry(pos, struct dentry, d_u.d_child); -if (!dentry->d_inode || - dentry->d_inode->i_ino < start || - dentry->d_inode->i_ino >= eof) +for (i = start; i < eof; i++) { + name.name = files[i].name; + name.len =strlen (files[i].name); + name.hash =full_name_hash (name.name, name.len); + dentry =d_lookup (parent, &name); + +if (dentry ==NULL )continue ; -spin_lock (&dentry->d_lock); -if (!d_unhashed (dentry)) { -dget_locked (dentry); -__d_drop (dentry); -spin_unlock (&dentry->d_lock); - dvec[n++] = dentry; -if (n ==ARRAY_SIZE (dvec)) +if (dentry->d_inode ==NULL ) + goto next; +switch (dentry->d_inode->i_mode &S_IFMT ) { +default : +BUG (); +case S_IFREG : +__rpc_unlink (dir, dentry);break ; - }else -spin_unlock (&dentry->d_lock); - } -spin_unlock (&dcache_lock); -if (n) { -do { - dentry = dvec[--n]; -if (S_ISREG (dentry->d_inode->i_mode)) -simple_unlink (dir, dentry); -else if (S_ISDIR (dentry->d_inode->i_mode)) -simple_rmdir (dir, dentry); -d_delete (dentry); -dput (dentry); - }while (n); - goto repeat; +case S_IFDIR : +__rpc_rmdir (dir, dentry); + } +next: +dput (dentry); } +} + +static void rpc_depopulate (struct dentry *parent, +const struct rpc_filelist *files, +int start,int eof) +{ +struct inode *dir = parent->d_inode; + +mutex_lock_nested (&dir->i_mutex,I_MUTEX_CHILD ); +__rpc_depopulate (parent, files, start, eof);mutex_unlock (&dir->i_mutex); } -static int -rpc_populate (struct dentry *parent, -struct rpc_filelist *files, -int start,int eof) +static int rpc_populate (struct dentry *parent, +const struct rpc_filelist *files, +int start,int eof, +void *private) { -struct inode *inode, *dir = parent->d_inode; -void *private =RPC_I (dir)->private; +struct inode *dir = parent->d_inode;struct dentry *dentry; -umode_t mode; -int i; +int i, err;mutex_lock (&dir->i_mutex);for (i = start; i < eof; i++) { - dentry =d_alloc_name (parent, files[i].name); -if (!dentry) - goto out_bad; - dentry->d_op = &rpc_dentry_operations; - mode = files[i].mode; - inode =rpc_get_inode (dir->i_sb, mode); -if (!inode) { -dput (dentry); +struct qstr q; + + q.name = files[i].name; + q.len =strlen (files[i].name); + q.hash =full_name_hash (q.name, q.len); + dentry =__rpc_lookup_create_exclusive (parent, &q); + err =PTR_ERR (dentry); +if (IS_ERR (dentry)) goto out_bad; +switch (files[i].mode &S_IFMT ) { +default : +BUG (); +case S_IFREG : + err =__rpc_create (dir, dentry, + files[i].mode, + files[i].i_fop, + private); +break ; +case S_IFDIR : + err =__rpc_mkdir (dir, dentry, + files[i].mode, +NULL , + private); } - inode->i_ino = i; -if (files[i].i_fop) - inode->i_fop = files[i].i_fop; -if (private) -rpc_inode_setowner (inode, private); -if (S_ISDIR (mode)) -inc_nlink (dir); -d_add (dentry, inode); -fsnotify_create (dir, dentry); +if (err !=0 ) + goto out_bad; }mutex_unlock (&dir->i_mutex);return 0 ; out_bad: +__rpc_depopulate (parent, files, start, eof);mutex_unlock (&dir->i_mutex);printk (KERN_WARNING "%s: %s failed to populate directory %s\n" , __FILE__, __func__, parent->d_name.name); -return -ENOMEM ; -} - -static int -__rpc_rmdir (struct inode *dir,struct dentry *dentry) -{ -int error; - error =simple_rmdir (dir, dentry); -if (!error) -d_delete (dentry); -return error; +return err; }/**
@@ -800,16 +820,14 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client)if (error !=0 ) goto out_err; error =rpc_populate (dentry, authfiles, - RPCAUTH_info,RPCAUTH_EOF ); + RPCAUTH_info,RPCAUTH_EOF , rpc_client);if (error) - goto err_depopulate; -dget (dentry); + goto err_rmdir; out:mutex_unlock (&dir->i_mutex);rpc_release_path (&nd);return dentry; -err_depopulate: -rpc_depopulate (dentry, RPCAUTH_info,RPCAUTH_EOF ); +err_rmdir:__rpc_rmdir (dir, dentry); out_err: printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n",
@@ -832,9 +850,8 @@ rpc_rmdir(struct dentry *dentry) parent =dget_parent (dentry); dir = parent->d_inode;mutex_lock_nested (&dir->i_mutex,I_MUTEX_PARENT ); -rpc_depopulate (dentry, RPCAUTH_info,RPCAUTH_EOF ); +rpc_depopulate (dentry, authfiles, RPCAUTH_info,RPCAUTH_EOF ); error =__rpc_rmdir (dir, dentry); -dput (dentry);mutex_unlock (&dir->i_mutex);dput (parent);return error;
@@ -900,7 +917,6 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, private, ops, flags);if (err) goto out_err; -dget (dentry); out:mutex_unlock (&dir->i_mutex);return dentry;
@@ -932,7 +948,6 @@ rpc_unlink(struct dentry *dentry) dir = parent->d_inode;mutex_lock_nested (&dir->i_mutex,I_MUTEX_PARENT ); error =__rpc_rmpipe (dir, dentry); -dput (dentry);mutex_unlock (&dir->i_mutex);dput (parent);return error;
@@ -970,7 +985,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)iput (inode);return -ENOMEM ; } -if (rpc_populate (root, files, RPCAUTH_Root +1 , RPCAUTH_RootEOF)) +if (rpc_populate (root, files, RPCAUTH_lockd, RPCAUTH_RootEOF,NULL )) goto out; sb->s_root = root;return 0 ;
Signature · 1 line
1.6.0.4
PATCH 14/32 SUNRPC: rpc_pipefs cleanup
Move the files[] array closer to rpc_fill_super()
--- net/sunrpc/rpc_pipe.c | 80 ++++++++++++++++++++++++------------------------ 1 files changed, 40 insertions(+), 40 deletions(-)
net/sunrpc/rpc_pipe.c +40 -40
@@ -398,19 +398,6 @@ static const struct file_operations rpc_info_operations = {/* -* We have a single directory with 1 node in it. -*/ -enum { - RPCAUTH_lockd, - RPCAUTH_mount, - RPCAUTH_nfs, - RPCAUTH_portmap, - RPCAUTH_statd, - RPCAUTH_nfsd4_cb, - RPCAUTH_RootEOF -}; - -/* * Description of fs contents. */ struct rpc_filelist {
@@ -419,33 +406,6 @@ struct rpc_filelist {umode_t mode; }; -static const struct rpc_filelist files[] = { - [RPCAUTH_lockd] = { - .name ="lockd" , - .mode =S_IFDIR |S_IRUGO |S_IXUGO , - }, - [RPCAUTH_mount] = { - .name ="mount" , - .mode =S_IFDIR |S_IRUGO |S_IXUGO , - }, - [RPCAUTH_nfs] = { - .name ="nfs" , - .mode =S_IFDIR |S_IRUGO |S_IXUGO , - }, - [RPCAUTH_portmap] = { - .name ="portmap" , - .mode =S_IFDIR |S_IRUGO |S_IXUGO , - }, - [RPCAUTH_statd] = { - .name ="statd" , - .mode =S_IFDIR |S_IRUGO |S_IXUGO , - }, - [RPCAUTH_nfsd4_cb] = { - .name ="nfsd4_cb" , - .mode =S_IFDIR |S_IRUGO |S_IXUGO , - }, -}; -enum { RPCAUTH_info,RPCAUTH_EOF
@@ -965,6 +925,46 @@ static struct super_operations s_ops = {#define RPCAUTH_GSSMAGIC 0x67596969 +/* +* We have a single directory with 1 node in it. +*/ +enum { + RPCAUTH_lockd, + RPCAUTH_mount, + RPCAUTH_nfs, + RPCAUTH_portmap, + RPCAUTH_statd, + RPCAUTH_nfsd4_cb, + RPCAUTH_RootEOF +}; + +static const struct rpc_filelist files[] = { + [RPCAUTH_lockd] = { + .name ="lockd" , + .mode =S_IFDIR |S_IRUGO |S_IXUGO , + }, + [RPCAUTH_mount] = { + .name ="mount" , + .mode =S_IFDIR |S_IRUGO |S_IXUGO , + }, + [RPCAUTH_nfs] = { + .name ="nfs" , + .mode =S_IFDIR |S_IRUGO |S_IXUGO , + }, + [RPCAUTH_portmap] = { + .name ="portmap" , + .mode =S_IFDIR |S_IRUGO |S_IXUGO , + }, + [RPCAUTH_statd] = { + .name ="statd" , + .mode =S_IFDIR |S_IRUGO |S_IXUGO , + }, + [RPCAUTH_nfsd4_cb] = { + .name ="nfsd4_cb" , + .mode =S_IFDIR |S_IRUGO |S_IXUGO , + }, +}; +static int rpc_fill_super (struct super_block *sb,void *data,int silent) {
Signature · 1 line
1.6.0.4
PATCH 15/32 SUNRPC: Rename rpc_mkdir to rpc_create_client_dir()
This reflects the fact that rpc_mkdir() as it stands today, can only create a RPC client type directory.
--- include/linux/sunrpc/rpc_pipe_fs.h | 5 +++-- net/sunrpc/clnt.c | 6 +++--- net/sunrpc/rpc_pipe.c | 11 +++++------ 3 files changed, 11 insertions(+), 11 deletions(-)
include/linux/sunrpc/rpc_pipe_fs.h +3 -2
@@ -44,8 +44,9 @@ RPC_I(struct inode *inode)extern int rpc_queue_upcall (struct inode *,struct rpc_pipe_msg *); -extern struct dentry *rpc_mkdir (char *,struct rpc_clnt *); -extern int rpc_rmdir (struct dentry *); +struct rpc_clnt ; +extern struct dentry *rpc_create_client_dir (const char *,struct rpc_clnt *); +extern int rpc_remove_client_dir (struct dentry *);extern struct dentry *rpc_mkpipe (struct dentry *,const char *,void *,const struct rpc_pipe_ops *,int flags);extern int rpc_unlink (struct dentry *);
net/sunrpc/clnt.c +3 -3
@@ -113,7 +113,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)"%s/clnt%x" , dir_name, (unsigned int)clntid++); clnt->cl_pathname[sizeof (clnt->cl_pathname) -1 ] ='\0' ; - clnt->cl_dentry =rpc_mkdir (clnt->cl_pathname, clnt); + clnt->cl_dentry =rpc_create_client_dir (clnt->cl_pathname, clnt);if (!IS_ERR (clnt->cl_dentry))return 0 ; error =PTR_ERR (clnt->cl_dentry);
@@ -232,7 +232,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru out_no_auth:if (!IS_ERR (clnt->cl_dentry)) { -rpc_rmdir (clnt->cl_dentry); +rpc_remove_client_dir (clnt->cl_dentry);rpc_put_mount (); } out_no_path:
@@ -424,7 +424,7 @@ rpc_free_client(struct kref *kref)dprintk ("RPC: destroying %s client for %s\n" , clnt->cl_protname, clnt->cl_server);if (!IS_ERR (clnt->cl_dentry)) { -rpc_rmdir (clnt->cl_dentry); +rpc_remove_client_dir (clnt->cl_dentry);rpc_put_mount (); }if (clnt->cl_parent != clnt) {
net/sunrpc/rpc_pipe.c +5 -6
@@ -755,7 +755,7 @@ out_bad: }/** -* rpc_mkdir - Create a new directory in rpc_pipefs +* rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs * @path: path from the rpc_pipefs root to the new directory * @rpc_client: rpc client to associate with this directory *
@@ -764,8 +764,8 @@ out_bad:* information about the client, together with any "pipes" that may * later be created using rpc_mkpipe(). */ -struct dentry * -rpc_mkdir (char *path,struct rpc_clnt *rpc_client) +struct dentry *rpc_create_client_dir (const char *path, +struct rpc_clnt *rpc_client) {struct nameidata nd;struct dentry *dentry;
@@ -797,11 +797,10 @@ out_err: }/** -* rpc_rmdir - Remove a directory created with rpc_mkdir() +* rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() * @dentry: directory to remove */ -int -rpc_rmdir (struct dentry *dentry) +int rpc_remove_client_dir (struct dentry *dentry) {struct dentry *parent;struct inode *dir;
Signature · 1 line
1.6.0.4
PATCH 16/32 SUNRPC: Clean up rpc_create_client_dir()
Factor out the code that does lookups from the code that actually creates the directory.
--- net/sunrpc/rpc_pipe.c | 83 ++++++++++++++++++++++++------------------------- 1 files changed, 41 insertions(+), 42 deletions(-)
net/sunrpc/rpc_pipe.c +41 -42
@@ -639,26 +639,6 @@ static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,return ERR_PTR (-EEXIST ); } -static struct dentry *rpc_lookup_negative (const char *path, -struct nameidata *nd) -{ -struct inode *dir; -struct dentry *dentry; -int error; - - error =rpc_lookup_parent (path, nd); -if (error !=0 ) -return ERR_PTR (error); - dir = nd->path.dentry->d_inode; -mutex_lock_nested (&dir->i_mutex,I_MUTEX_PARENT ); - dentry =__rpc_lookup_create_exclusive (nd->path.dentry, &nd->last); -if (IS_ERR (dentry)) { -mutex_unlock (&dir->i_mutex); -rpc_release_path (nd); - } -return dentry; -} -/* * FIXME: This probably has races. */
@@ -754,44 +734,30 @@ out_bad:return err; } -/** -* rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs -* @path: path from the rpc_pipefs root to the new directory -* @rpc_client: rpc client to associate with this directory -* -* This creates a directory at the given @path associated with -* @rpc_clnt, which will contain a file named "info" with some basic -* information about the client, together with any "pipes" that may -* later be created using rpc_mkpipe(). -*/ -struct dentry *rpc_create_client_dir (const char *path, -struct rpc_clnt *rpc_client) +struct dentry *rpc_mkdir_populate (struct dentry *parent, +struct qstr *name,umode_t mode,void *private) { -struct nameidata nd;struct dentry *dentry; -struct inode *dir; +struct inode *dir = parent->d_inode;int error; - dentry =rpc_lookup_negative (path, &nd); +mutex_lock_nested (&dir->i_mutex,I_MUTEX_PARENT ); + dentry =__rpc_lookup_create_exclusive (parent, name);if (IS_ERR (dentry)) -return dentry; - dir = nd.path.dentry->d_inode; - error =__rpc_mkdir (dir, dentry,S_IRUGO |S_IXUGO ,NULL , rpc_client); + goto out; + error =__rpc_mkdir (dir, dentry, mode,NULL , private);if (error !=0 ) goto out_err; error =rpc_populate (dentry, authfiles, - RPCAUTH_info,RPCAUTH_EOF , rpc_client); + RPCAUTH_info,RPCAUTH_EOF , private);if (error) goto err_rmdir; out:mutex_unlock (&dir->i_mutex); -rpc_release_path (&nd);return dentry; err_rmdir:__rpc_rmdir (dir, dentry); out_err: -printk (KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n" , - __FILE__, __func__, path, error); dentry =ERR_PTR (error); goto out; }
@@ -913,6 +879,39 @@ rpc_unlink(struct dentry *dentry) }EXPORT_SYMBOL_GPL (rpc_unlink); +/** +* rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs +* @path: path from the rpc_pipefs root to the new directory +* @rpc_client: rpc client to associate with this directory +* +* This creates a directory at the given @path associated with +* @rpc_clnt, which will contain a file named "info" with some basic +* information about the client, together with any "pipes" that may +* later be created using rpc_mkpipe(). +*/ +struct dentry *rpc_create_client_dir (const char *path, +struct rpc_clnt *rpc_client) +{ +struct nameidata nd; +struct dentry *ret; +struct inode *dir; + + ret =ERR_PTR (rpc_lookup_parent (path, &nd)); +if (IS_ERR (ret)) + goto out_err; + dir = nd.path.dentry->d_inode; + + ret =rpc_mkdir_populate (nd.path.dentry, &nd.last, +S_IRUGO |S_IXUGO , rpc_client); +rpc_release_path (&nd); +if (!IS_ERR (ret)) +return ret; +out_err: +printk (KERN_WARNING "%s: %s() failed to create directory %s (errno = %ld)\n" , + __FILE__, __func__, path,PTR_ERR (ret)); +return ret; +} +/* * populate the filesystem */
Signature · 1 line
1.6.0.4
PATCH 17/32 SUNRPC: Replace rpc_client->cl_dentry and cl_mnt, with a cl_path
--- fs/nfs/idmap.c | 4 ++-- include/linux/sunrpc/clnt.h | 4 ++-- net/sunrpc/auth_gss/auth_gss.c | 4 ++-- net/sunrpc/clnt.c | 24 ++++++++++++------------ 4 files changed, 18 insertions(+), 18 deletions(-)
fs/nfs/idmap.c +2 -2
@@ -119,8 +119,8 @@ nfs_idmap_new(struct nfs_client *clp)if (idmap ==NULL )return -ENOMEM ; - idmap->idmap_dentry =rpc_mkpipe (clp->cl_rpcclient->cl_dentry,"idmap" , - idmap, &idmap_upcall_ops,0 ); + idmap->idmap_dentry =rpc_mkpipe (clp->cl_rpcclient->cl_path.dentry, +"idmap" , idmap, &idmap_upcall_ops,0 );if (IS_ERR (idmap->idmap_dentry)) { error =PTR_ERR (idmap->idmap_dentry);kfree (idmap);
include/linux/sunrpc/clnt.h +2 -2
@@ -17,6 +17,7 @@#include <linux/sunrpc/xdr.h> #include <linux/sunrpc/timer.h> #include <asm/signal.h> +#include <linux/path.h> struct rpc_inode ;
@@ -51,8 +52,7 @@ struct rpc_clnt {int cl_nodelen;/* nodename length */ char cl_nodename[UNX_MAXNODENAME ];char cl_pathname[30 ];/* Path in rpc_pipe_fs */ -struct vfsmount * cl_vfsmnt; -struct dentry * cl_dentry;/* inode */ +struct path cl_path;struct rpc_clnt * cl_parent;/* Points to parent of clones */ struct rpc_rtt cl_rtt_default;struct rpc_timeout cl_timeout_default;
net/sunrpc/auth_gss/auth_gss.c +2 -2
@@ -777,7 +777,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)* that we supported only the old pipe. So we instead create * the new pipe first. */ - gss_auth->dentry[1 ] =rpc_mkpipe (clnt->cl_dentry, + gss_auth->dentry[1 ] =rpc_mkpipe (clnt->cl_path.dentry,"gssd" , clnt, &gss_upcall_ops_v1,RPC_PIPE_WAIT_FOR_OPEN );
@@ -786,7 +786,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) goto err_put_mech; } - gss_auth->dentry[0 ] =rpc_mkpipe (clnt->cl_dentry, + gss_auth->dentry[0 ] =rpc_mkpipe (clnt->cl_path.dentry, gss_auth->mech->gm_name, clnt, &gss_upcall_ops_v0,RPC_PIPE_WAIT_FOR_OPEN );
net/sunrpc/clnt.c +12 -12
@@ -99,24 +99,24 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)static uint32_t clntid;int error; - clnt->cl_vfsmnt =ERR_PTR (-ENOENT ); - clnt->cl_dentry =ERR_PTR (-ENOENT ); + clnt->cl_path.mnt =ERR_PTR (-ENOENT ); + clnt->cl_path.dentry =ERR_PTR (-ENOENT );if (dir_name ==NULL )return 0 ; - clnt->cl_vfsmnt =rpc_get_mount (); -if (IS_ERR (clnt->cl_vfsmnt)) -return PTR_ERR (clnt->cl_vfsmnt); + clnt->cl_path.mnt =rpc_get_mount (); +if (IS_ERR (clnt->cl_path.mnt)) +return PTR_ERR (clnt->cl_path.mnt);for (;;) {snprintf (clnt->cl_pathname,sizeof (clnt->cl_pathname),"%s/clnt%x" , dir_name, (unsigned int )clntid++); clnt->cl_pathname[sizeof (clnt->cl_pathname) -1 ] ='\0' ; - clnt->cl_dentry =rpc_create_client_dir (clnt->cl_pathname, clnt); -if (!IS_ERR (clnt->cl_dentry)) + clnt->cl_path.dentry =rpc_create_client_dir (clnt->cl_pathname, clnt); +if (!IS_ERR (clnt->cl_path.dentry))return 0 ; - error =PTR_ERR (clnt->cl_dentry); + error =PTR_ERR (clnt->cl_path.dentry);if (error != -EEXIST ) {printk (KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n" , clnt->cl_pathname, error);
@@ -231,8 +231,8 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, strureturn clnt; out_no_auth: -if (!IS_ERR (clnt->cl_dentry)) { -rpc_remove_client_dir (clnt->cl_dentry); +if (!IS_ERR (clnt->cl_path.dentry)) { +rpc_remove_client_dir (clnt->cl_path.dentry);rpc_put_mount (); } out_no_path:
@@ -423,8 +423,8 @@ rpc_free_client(struct kref *kref)dprintk ("RPC: destroying %s client for %s\n" , clnt->cl_protname, clnt->cl_server); -if (!IS_ERR (clnt->cl_dentry)) { -rpc_remove_client_dir (clnt->cl_dentry); +if (!IS_ERR (clnt->cl_path.dentry)) { +rpc_remove_client_dir (clnt->cl_path.dentry);rpc_put_mount (); }if (clnt->cl_parent != clnt) {
Signature · 1 line
1.6.0.4
PATCH 18/32 SUNRPC: clean up rpc_setup_pipedir()
There is still a little wart or two there: Since we've already got a vfsmount, we might as well pass that in to rpc_create_client_dir. Another point is that if we open code __rpc_lookup_path() here, then we can avoid looking up the entire parent directory path over and over again: it doesn't change.
Also get rid of rpc_clnt->cl_pathname, since it has no users...
--- include/linux/sunrpc/clnt.h | 1 - include/linux/sunrpc/rpc_pipe_fs.h | 2 +- net/sunrpc/clnt.c | 48 ++++++++++++++++++++--------- net/sunrpc/rpc_pipe.c | 58 ++---------------------------------- 4 files changed, 37 insertions(+), 72 deletions(-)
include/linux/sunrpc/clnt.h +0 -1
@@ -51,7 +51,6 @@ struct rpc_clnt {int cl_nodelen;/* nodename length */ char cl_nodename[UNX_MAXNODENAME ]; -char cl_pathname[30 ];/* Path in rpc_pipe_fs */ struct path cl_path;struct rpc_clnt * cl_parent;/* Points to parent of clones */ struct rpc_rtt cl_rtt_default;
include/linux/sunrpc/rpc_pipe_fs.h +1 -1
@@ -45,7 +45,7 @@ RPC_I(struct inode *inode)extern int rpc_queue_upcall (struct inode *,struct rpc_pipe_msg *);struct rpc_clnt ; -extern struct dentry *rpc_create_client_dir (const char *,struct rpc_clnt *); +extern struct dentry *rpc_create_client_dir (struct dentry *,struct qstr *,struct rpc_clnt *);extern int rpc_remove_client_dir (struct dentry *);extern struct dentry *rpc_mkpipe (struct dentry *,const char *,void *,const struct rpc_pipe_ops *,int flags);
net/sunrpc/clnt.c +33 -15
71 lines not on this page · raw message
net/sunrpc/rpc_pipe.c +3 -55
72 lines not on this page · raw message
Signature · 1 line
1.6.0.4
PATCH 19/32 SUNRPC: One more clean up for rpc_create_client_dir()
In order to allow rpc_pipefs to create directories with different types of subtrees, it is useful to allow the caller to customise the subtree filling process.
In order to do so, we separate out the parts which are specific to making an RPC client directory, and put them in a separate helper, then we convert the process of filling the directory contents into a callback.
--- net/sunrpc/rpc_pipe.c | 78 +++++++++++++++++++++++++++++++----------------- 1 files changed, 50 insertions(+), 28 deletions(-)
net/sunrpc/rpc_pipe.c +50 -28
@@ -406,19 +406,6 @@ struct rpc_filelist {umode_t mode; }; -enum { - RPCAUTH_info, -RPCAUTH_EOF -}; - -static const struct rpc_filelist authfiles[] = { - [RPCAUTH_info] = { - .name ="info" , - .i_fop = &rpc_info_operations, - .mode =S_IFREG |S_IRUSR , - }, -}; -struct vfsmount *rpc_get_mount (void ) {int err;
@@ -698,8 +685,9 @@ out_bad:return err; } -struct dentry *rpc_mkdir_populate (struct dentry *parent, -struct qstr *name,umode_t mode,void *private) +static struct dentry *rpc_mkdir_populate (struct dentry *parent, +struct qstr *name,umode_t mode,void *private, +int (*populate)(struct dentry *,void *),void *args_populate) {struct dentry *dentry;struct inode *dir = parent->d_inode;
@@ -712,10 +700,11 @@ struct dentry *rpc_mkdir_populate(struct dentry *parent, error =__rpc_mkdir (dir, dentry, mode,NULL , private);if (error !=0 ) goto out_err; - error =rpc_populate (dentry, authfiles, - RPCAUTH_info,RPCAUTH_EOF , private); -if (error) - goto err_rmdir; +if (populate !=NULL ) { + error =populate (dentry, args_populate); +if (error) + goto err_rmdir; + } out:mutex_unlock (&dir->i_mutex);return dentry;
@@ -726,11 +715,8 @@ out_err: goto out; } -/** -* rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() -* @dentry: directory to remove -*/ -int rpc_remove_client_dir (struct dentry *dentry) +static int rpc_rmdir_depopulate (struct dentry *dentry, +void (*depopulate)(struct dentry *)) {struct dentry *parent;struct inode *dir;
@@ -739,7 +725,8 @@ int rpc_remove_client_dir(struct dentry *dentry) parent =dget_parent (dentry); dir = parent->d_inode;mutex_lock_nested (&dir->i_mutex,I_MUTEX_PARENT ); -rpc_depopulate (dentry, authfiles, RPCAUTH_info,RPCAUTH_EOF ); +if (depopulate !=NULL ) +depopulate (dentry); error =__rpc_rmdir (dir, dentry);mutex_unlock (&dir->i_mutex);dput (parent);
@@ -843,6 +830,31 @@ rpc_unlink(struct dentry *dentry) }EXPORT_SYMBOL_GPL (rpc_unlink); +enum { + RPCAUTH_info, +RPCAUTH_EOF +}; + +static const struct rpc_filelist authfiles[] = { + [RPCAUTH_info] = { + .name ="info" , + .i_fop = &rpc_info_operations, + .mode =S_IFREG |S_IRUSR , + }, +}; + +static int rpc_clntdir_populate (struct dentry *dentry,void *private) +{ +return rpc_populate (dentry, + authfiles, RPCAUTH_info,RPCAUTH_EOF , + private); +} + +static void rpc_clntdir_depopulate (struct dentry *dentry) +{ +rpc_depopulate (dentry, authfiles, RPCAUTH_info,RPCAUTH_EOF ); +} +/** * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs * @path: path from the rpc_pipefs root to the new directory
@@ -854,10 +866,20 @@ EXPORT_SYMBOL_GPL(rpc_unlink);* later be created using rpc_mkpipe(). */ struct dentry *rpc_create_client_dir (struct dentry *dentry, -struct qstr *name, -struct rpc_clnt *rpc_client) +struct qstr *name, +struct rpc_clnt *rpc_client) +{ +return rpc_mkdir_populate (dentry, name,S_IRUGO |S_IXUGO ,NULL , + rpc_clntdir_populate, rpc_client); +} + +/** +* rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() +* @dentry: directory to remove +*/ +int rpc_remove_client_dir (struct dentry *dentry) { -return rpc_mkdir_populate (dentry, name,S_IRUGO |S_IXUGO , rpc_client); +return rpc_rmdir_depopulate (dentry, rpc_clntdir_depopulate); }/*
Signature · 1 line
1.6.0.4
PATCH 20/32 NFSD: Clean up the idmapper warning...
What part of 'internal use' is so hard to understand?
--- fs/nfsd/nfs4idmap.c | 4 ++-- include/linux/sunrpc/cache.h | 3 ++- net/sunrpc/cache.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-)
fs/nfsd/nfs4idmap.c +2 -2
@@ -175,10 +175,10 @@ idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) }static void -warn_no_idmapd (struct cache_detail *detail) +warn_no_idmapd (struct cache_detail *detail,int has_died) {printk ("nfsd: nfsv4 idmapping failing: has idmapd %s?\n" , - detail->last_close?"died" :"not been started" ); + has_died ?"died" :"not been started" ); }
include/linux/sunrpc/cache.h +2 -1
@@ -79,6 +79,8 @@ struct cache_detail {int (*cache_show)(struct seq_file *m,struct cache_detail *cd,struct cache_head *h); +void (*warn_no_listener)(struct cache_detail *cd, +int has_died);struct cache_head * (*alloc)(void );int (*match)(struct cache_head *orig,struct cache_head *new);
@@ -102,7 +104,6 @@ struct cache_detail {atomic_t readers;/* how many time is /chennel open */ time_t last_close;/* if no readers, when did last close */ time_t last_warn;/* when we last warned about no readers */ -void (*warn_no_listener)(struct cache_detail *cd); };
net/sunrpc/cache.c +1 -1
@@ -1020,7 +1020,7 @@ static void warn_no_listener(struct cache_detail *detail)if (detail->last_warn != detail->last_close) { detail->last_warn = detail->last_close;if (detail->warn_no_listener) - detail->warn_no_listener (detail); + detail->warn_no_listener (detail, detail->last_close !=0 ); } }
Signature · 1 line
1.6.0.4
PATCH 21/32 SUNRPC: Ensure we initialise the cache_detail before creating procfs files
Also ensure that we destroy those files before we destroy the cache_detail. Otherwise, user processes might attempt to write into uninitialised caches.
--- net/sunrpc/cache.c | 30 ++++++++++++++++++++---------- 1 files changed, 20 insertions(+), 10 deletions(-)
net/sunrpc/cache.c +20 -10
@@ -347,13 +347,8 @@ static int create_cache_proc_entries(struct cache_detail *cd) }#endif -int cache_register (struct cache_detail *cd) +static void sunrpc_init_cache_detail (struct cache_detail *cd) { -int ret; - - ret =create_cache_proc_entries (cd); -if (ret) -return ret;rwlock_init (&cd->hash_lock);INIT_LIST_HEAD (&cd->queue);spin_lock (&cache_list_lock);
@@ -367,11 +362,9 @@ int cache_register(struct cache_detail *cd)/* start the cleaning process */ schedule_delayed_work (&cache_cleaner,0 ); -return 0 ; } -EXPORT_SYMBOL_GPL (cache_register); -void cache_unregister (struct cache_detail *cd) +static void sunrpc_destroy_cache_detail (struct cache_detail *cd) {cache_purge (cd);spin_lock (&cache_list_lock);
@@ -386,7 +379,6 @@ void cache_unregister(struct cache_detail *cd)list_del_init (&cd->others);write_unlock (&cd->hash_lock);spin_unlock (&cache_list_lock); -remove_cache_proc_entries (cd);if (list_empty (&cache_list)) {/* module must be being unloaded so its safe to kill the worker */ cancel_delayed_work_sync (&cache_cleaner);
@@ -395,6 +387,24 @@ void cache_unregister(struct cache_detail *cd) out:printk (KERN_ERR "nfsd: failed to unregister %s cache\n" , cd->name); } + +int cache_register (struct cache_detail *cd) +{ +int ret; + +sunrpc_init_cache_detail (cd); + ret =create_cache_proc_entries (cd); +if (ret) +sunrpc_destroy_cache_detail (cd); +return ret; +} +EXPORT_SYMBOL_GPL (cache_register); + +void cache_unregister (struct cache_detail *cd) +{ +remove_cache_proc_entries (cd); +sunrpc_destroy_cache_detail (cd); +}EXPORT_SYMBOL_GPL (cache_unregister);/* clean cache tries to find something to clean
Signature · 1 line
1.6.0.4
PATCH 22/32 SUNRPC: Remove the global temporary write buffer in net/sunrpc/cache.c
While we do want to protect against multiple concurrent readers and writers on each upcall/downcall pipe, we don't want to limit concurrent reading and writing to separate caches.
This patch therefore replaces the static buffer 'write_buf', which can only be used by one writer at a time, with use of the page cache as the temporary buffer for downcalls. We still fall back to using the the old global buffer if the downcall is larger than PAGE_CACHE_SIZE, since this is apparently needed by the SPKM security context initialisation.
It then replaces the use of the global 'queue_io_mutex' with the inode->i_mutex in cache_read() and cache_write().
--- net/sunrpc/cache.c | 95 ++++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 70 insertions(+), 25 deletions(-)
net/sunrpc/cache.c +70 -25
@@ -27,6 +27,7 @@#include <linux/net.h> #include <linux/workqueue.h> #include <linux/mutex.h> +#include <linux/pagemap.h> #include <asm/ioctls.h> #include <linux/sunrpc/types.h> #include <linux/sunrpc/cache.h>
@@ -702,13 +703,14 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) {struct cache_reader *rp = filp->private_data;struct cache_request *rq; -struct cache_detail *cd =PDE (filp->f_path.dentry->d_inode)->data; +struct inode *inode = filp->f_path.dentry->d_inode; +struct cache_detail *cd =PDE (inode)->data;int err;if (count ==0 )return 0 ; -mutex_lock (&queue_io_mutex);/* protect against multiple concurrent +mutex_lock (&inode->i_mutex);/* protect against multiple concurrent * readers on this file */ again:spin_lock (&queue_lock);
@@ -721,7 +723,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) }if (rp->q.list.next == &cd->queue) {spin_unlock (&queue_lock); -mutex_unlock (&queue_io_mutex); +mutex_unlock (&inode->i_mutex);BUG_ON (rp->offset);return 0 ; }
@@ -768,38 +770,81 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) }if (err == -EAGAIN ) goto again; -mutex_unlock (&queue_io_mutex); +mutex_unlock (&inode->i_mutex);return err ? err : count; } -static char write_buf[8192 ];/* protected by queue_io_mutex */ +static ssize_t cache_do_downcall (char *kaddr,const char __user *buf, +size_t count,struct cache_detail *cd) +{ +ssize_t ret; -static ssize_t -cache_write (struct file *filp,const char __user *buf,size_t count, -loff_t *ppos) +if (copy_from_user (kaddr, buf, count)) +return -EFAULT ; + kaddr[count] ='\0' ; + ret = cd->cache_parse (cd, kaddr, count); +if (!ret) + ret = count; +return ret; +} + +static ssize_t cache_slow_downcall (const char __user *buf, +size_t count,struct cache_detail *cd) { -int err; -struct cache_detail *cd =PDE (filp->f_path.dentry->d_inode)->data; +static char write_buf[8192 ];/* protected by queue_io_mutex */ +ssize_t ret = -EINVAL ; -if (count ==0 ) -return 0 ;if (count >=sizeof (write_buf)) -return -EINVAL ; - + goto out;mutex_lock (&queue_io_mutex); + ret =cache_do_downcall (write_buf, buf, count, cd); +mutex_unlock (&queue_io_mutex); +out: +return ret; +} -if (copy_from_user (write_buf, buf, count)) { -mutex_unlock (&queue_io_mutex); -return -EFAULT ; - } - write_buf[count] ='\0' ; -if (cd->cache_parse) - err = cd->cache_parse (cd, write_buf, count); -else - err = -EINVAL ; +static ssize_t cache_downcall (struct address_space *mapping, +const char __user *buf, +size_t count,struct cache_detail *cd) +{ +struct page *page; +char *kaddr; +ssize_t ret = -ENOMEM ; + +if (count >=PAGE_CACHE_SIZE ) + goto out_slow; + + page =find_or_create_page (mapping,0 ,GFP_KERNEL ); +if (!page) + goto out_slow; + + kaddr =kmap (page); + ret =cache_do_downcall (kaddr, buf, count, cd); +kunmap (page); +unlock_page (page); +page_cache_release (page); +return ret; +out_slow: +return cache_slow_downcall (buf, count, cd); +} -mutex_unlock (&queue_io_mutex); -return err ? err : count; +static ssize_t +cache_write (struct file *filp,const char __user *buf,size_t count, +loff_t *ppos) +{ +struct address_space *mapping = filp->f_mapping; +struct inode *inode = filp->f_path.dentry->d_inode; +struct cache_detail *cd =PDE (inode)->data; +ssize_t ret = -EINVAL ; + +if (!cd->cache_parse) + goto out; + +mutex_lock (&inode->i_mutex); + ret =cache_downcall (mapping, buf, count, cd); +mutex_unlock (&inode->i_mutex); +out: +return ret; }static DECLARE_WAIT_QUEUE_HEAD (queue_wait);
Signature · 1 line
1.6.0.4
PATCH 23/32 SUNRPC: Allow the cache_detail to specify alternative upcall mechanisms
For events that are rare, such as referral DNS lookups, it makes limited sense to have a daemon constantly listening for upcalls on a channel. An alternative in those cases might simply be to run the app that fills the cache using call_usermodehelper_exec() and friends.
The following patch allows the cache_detail to specify alternative upcall mechanisms for these particular cases.
--- fs/nfsd/export.c | 14 ++++++++++++-- fs/nfsd/nfs4idmap.c | 16 ++++++++++++++-- include/linux/sunrpc/cache.h | 13 ++++++++++--- net/sunrpc/auth_gss/svcauth_gss.c | 7 ++++++- net/sunrpc/cache.c | 26 ++++++++++++++++++-------- net/sunrpc/svcauth_unix.c | 14 ++++++++++++-- 6 files changed, 72 insertions(+), 18 deletions(-)
fs/nfsd/export.c +12 -2
@@ -85,6 +85,11 @@ static void expkey_request(struct cache_detail *cd, (*bpp)[-1 ] ='\n' ; } +static int expkey_upcall (struct cache_detail *cd,struct cache_head *h) +{ +return sunrpc_cache_pipe_upcall (cd, h, expkey_request); +} +static struct svc_expkey *svc_expkey_update (struct svc_expkey *new,struct svc_expkey *old);static struct svc_expkey *svc_expkey_lookup (struct svc_expkey *);static struct cache_detail svc_expkey_cache;
@@ -259,7 +264,7 @@ static struct cache_detail svc_expkey_cache = { .hash_table = expkey_table, .name = "nfsd.fh", .cache_put = expkey_put, - .cache_request = expkey_request, + .cache_upcall = expkey_upcall, .cache_parse = expkey_parse, .cache_show = expkey_show, .match = expkey_match,
@@ -355,6 +360,11 @@ static void svc_export_request(struct cache_detail *cd, (*bpp)[-1 ] ='\n' ; } +static int svc_export_upcall (struct cache_detail *cd,struct cache_head *h) +{ +return sunrpc_cache_pipe_upcall (cd, h, svc_export_request); +} +static struct svc_export *svc_export_update (struct svc_export *new,struct svc_export *old);static struct svc_export *svc_export_lookup (struct svc_export *);
@@ -724,7 +734,7 @@ struct cache_detail svc_export_cache = { .hash_table = export_table, .name = "nfsd.export", .cache_put = svc_export_put, - .cache_request = svc_export_request, + .cache_upcall = svc_export_upcall, .cache_parse = svc_export_parse, .cache_show = svc_export_show, .match = svc_export_match,
fs/nfsd/nfs4idmap.c +14 -2
@@ -146,6 +146,12 @@ idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, }static int +idtoname_upcall (struct cache_detail *cd,struct cache_head *ch) +{ +return sunrpc_cache_pipe_upcall (cd, ch, idtoname_request); +} + +static int idtoname_match (struct cache_head *ca,struct cache_head *cb) { struct ent *a = container_of(ca, struct ent, h);
@@ -192,7 +198,7 @@ static struct cache_detail idtoname_cache = { .hash_table = idtoname_table, .name = "nfs4.idtoname", .cache_put = ent_put, - .cache_request = idtoname_request, + .cache_upcall = idtoname_upcall, .cache_parse = idtoname_parse, .cache_show = idtoname_show, .warn_no_listener = warn_no_idmapd,
@@ -325,6 +331,12 @@ nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, }static int +nametoid_upcall (struct cache_detail *cd,struct cache_head *ch) +{ +return sunrpc_cache_pipe_upcall (cd, ch, nametoid_request); +} + +static int nametoid_match (struct cache_head *ca,struct cache_head *cb) { struct ent *a = container_of(ca, struct ent, h);
@@ -363,7 +375,7 @@ static struct cache_detail nametoid_cache = { .hash_table = nametoid_table, .name = "nfs4.nametoid", .cache_put = ent_put, - .cache_request = nametoid_request, + .cache_upcall = nametoid_upcall, .cache_parse = nametoid_parse, .cache_show = nametoid_show, .warn_no_listener = warn_no_idmapd,
include/linux/sunrpc/cache.h +10 -3
@@ -70,9 +70,9 @@ struct cache_detail {char *name;void (*cache_put)(struct kref *); -void (*cache_request)(struct cache_detail *cd, -struct cache_head *h, -char **bpp,int *blen); +int (*cache_upcall)(struct cache_detail *, +struct cache_head *); +int (*cache_parse)(struct cache_detail *,char *buf,int len);
@@ -135,6 +135,13 @@ extern struct cache_head * sunrpc_cache_update(struct cache_detail *detail, struct cache_head *new, struct cache_head *old, int hash); +extern int +sunrpc_cache_pipe_upcall (struct cache_detail *detail,struct cache_head *h, +void (*cache_request)(struct cache_detail *, +struct cache_head *, +char **, +int *)); +extern void cache_clean_deferred (void *owner);
net/sunrpc/auth_gss/svcauth_gss.c +6 -1
@@ -181,6 +181,11 @@ static void rsi_request(struct cache_detail *cd, (*bpp)[-1 ] ='\n' ; } +static int rsi_upcall (struct cache_detail *cd,struct cache_head *h) +{ +return sunrpc_cache_pipe_upcall (cd, h, rsi_request); +} +static int rsi_parse (struct cache_detail *cd,char *mesg,int mlen)
@@ -270,7 +275,7 @@ static struct cache_detail rsi_cache = { .hash_table = rsi_table, .name = "auth.rpcsec.init", .cache_put = rsi_put, - .cache_request = rsi_request, + .cache_upcall = rsi_upcall, .cache_parse = rsi_parse, .match = rsi_match, .init = rsi_init,
net/sunrpc/cache.c +18 -8
@@ -176,7 +176,13 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, }EXPORT_SYMBOL_GPL (sunrpc_cache_update); -static int cache_make_upcall (struct cache_detail *detail,struct cache_head *h); +static int cache_make_upcall (struct cache_detail *cd,struct cache_head *h) +{ +if (!cd->cache_upcall) +return -EINVAL ; +return cd->cache_upcall (cd, h); +} +/* * This is the generic cache management routine for all * the authentication caches.
@@ -322,7 +328,7 @@ static int create_cache_proc_entries(struct cache_detail *cd)if (p ==NULL ) goto out_nomem; -if (cd->cache_request || cd->cache_parse) { +if (cd->cache_upcall || cd->cache_parse) { p =proc_create_data ("channel" ,S_IFREG |S_IRUSR |S_IWUSR , cd->proc_ent, &cache_file_operations, cd); cd->channel_ent = p;
@@ -1080,10 +1086,16 @@ static void warn_no_listener(struct cache_detail *detail) }/* -* register an upcall request to user-space. +* register an upcall request to user-space and queue it up for read() by the +* upcall daemon. +* * Each request is at most one page long. */ -static int cache_make_upcall (struct cache_detail *detail,struct cache_head *h) +int sunrpc_cache_pipe_upcall (struct cache_detail *detail,struct cache_head *h, +void (*cache_request)(struct cache_detail *, +struct cache_head *, +char **, +int *)) {char *buf;
@@ -1091,9 +1103,6 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h)char *bp;int len; -if (detail->cache_request ==NULL ) -return -EINVAL ; -if (atomic_read (&detail->readers) ==0 && detail->last_close <get_seconds () -30 ) {warn_no_listener (detail);
@@ -1112,7 +1121,7 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h) bp = buf; len =PAGE_SIZE ; - detail->cache_request (detail, h, &bp, &len); +cache_request (detail, h, &bp, &len);if (len <0 ) {kfree (buf);
@@ -1130,6 +1139,7 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h)wake_up (&queue_wait);return 0 ; } +EXPORT_SYMBOL_GPL (sunrpc_cache_pipe_upcall);/* * parse a message from user-space and pass it
net/sunrpc/svcauth_unix.c +12 -2
@@ -171,6 +171,11 @@ static void ip_map_request(struct cache_detail *cd, (*bpp)[-1 ] ='\n' ; } +static int ip_map_upcall (struct cache_detail *cd,struct cache_head *h) +{ +return sunrpc_cache_pipe_upcall (cd, h, ip_map_request); +} +static struct ip_map *ip_map_lookup (char *class,struct in6_addr *addr);static int ip_map_update (struct ip_map *ipm,struct unix_domain *udom,time_t expiry);
@@ -289,7 +294,7 @@ struct cache_detail ip_map_cache = { .hash_table = ip_table, .name = "auth.unix.ip", .cache_put = ip_map_put, - .cache_request = ip_map_request, + .cache_upcall = ip_map_upcall, .cache_parse = ip_map_parse, .cache_show = ip_map_show, .match = ip_map_match,
@@ -523,6 +528,11 @@ static void unix_gid_request(struct cache_detail *cd, (*bpp)[-1 ] ='\n' ; } +static int unix_gid_upcall (struct cache_detail *cd,struct cache_head *h) +{ +return sunrpc_cache_pipe_upcall (cd, h, unix_gid_request); +} +static struct unix_gid *unix_gid_lookup (uid_t uid);extern struct cache_detail unix_gid_cache;
@@ -622,7 +632,7 @@ struct cache_detail unix_gid_cache = { .hash_table = gid_table, .name = "auth.unix.gid", .cache_put = unix_gid_put, - .cache_request = unix_gid_request, + .cache_upcall = unix_gid_upcall, .cache_parse = unix_gid_parse, .cache_show = unix_gid_show, .match = unix_gid_match,
Signature · 1 line
1.6.0.4
PATCH 24/32 SUNRPC: Move procfs-specific stuff out of the generic sunrpc cache code
--- include/linux/sunrpc/cache.h | 11 ++- net/sunrpc/cache.c | 319 +++++++++++++++++++++++++----------------- 2 files changed, 199 insertions(+), 131 deletions(-)
include/linux/sunrpc/cache.h +9 -2
@@ -59,6 +59,11 @@ struct cache_head {#define CACHE_NEW_EXPIRY 120/* keep new things pending confirmation for 120 seconds */ +struct cache_detail_procfs { +struct proc_dir_entry *proc_ent; +struct proc_dir_entry *flush_ent, *channel_ent, *content_ent; +}; +struct cache_detail {struct module * owner;int hash_size;
@@ -98,12 +103,14 @@ struct cache_detail {/* fields for communication over channel */ struct list_head queue; -struct proc_dir_entry *proc_ent; -struct proc_dir_entry *flush_ent, *channel_ent, *content_ent;atomic_t readers;/* how many time is /chennel open */ time_t last_close;/* if no readers, when did last close */ time_t last_warn;/* when we last warned about no readers */ + +union { +struct cache_detail_procfs procfs; + } u; };
net/sunrpc/cache.c +190 -129
426 lines not on this page · raw message
Signature · 1 line
1.6.0.4
PATCH 25/32 SUNRPC: Add an rpc_pipefs front end for the sunrpc cache code
--- include/linux/sunrpc/cache.h | 13 ++++ include/linux/sunrpc/rpc_pipe_fs.h | 8 ++ net/sunrpc/cache.c | 126 ++++++++++++++++++++++++++++++++++++ net/sunrpc/rpc_pipe.c | 43 ++++++++++++ 4 files changed, 190 insertions(+), 0 deletions(-)
include/linux/sunrpc/cache.h +13 -0
@@ -64,6 +64,10 @@ struct cache_detail_procfs {struct proc_dir_entry *flush_ent, *channel_ent, *content_ent; }; +struct cache_detail_pipefs { +struct dentry *dir; +}; +struct cache_detail {struct module * owner;int hash_size;
@@ -110,6 +114,7 @@ struct cache_detail {union {struct cache_detail_procfs procfs; +struct cache_detail_pipefs pipefs; } u; };
@@ -135,6 +140,10 @@ struct cache_deferred_req { }; +extern const struct file_operations cache_file_operations_pipefs; +extern const struct file_operations content_file_operations_pipefs; +extern const struct file_operations cache_flush_operations_pipefs; +extern struct cache_head *sunrpc_cache_lookup (struct cache_detail *detail,struct cache_head *key,int hash);
@@ -186,6 +195,10 @@ extern void cache_purge(struct cache_detail *detail);extern int cache_register (struct cache_detail *cd);extern void cache_unregister (struct cache_detail *cd); +extern int sunrpc_cache_register_pipefs (struct dentry *parent,const char *, +mode_t ,struct cache_detail *); +extern void sunrpc_cache_unregister_pipefs (struct cache_detail *); +extern void qword_add (char **bpp,int *lp,char *str);extern void qword_addhex (char **bpp,int *lp,char *buf,int blen);extern int qword_get (char **bpp,char *dest,int bufsize);
include/linux/sunrpc/rpc_pipe_fs.h +8 -0
@@ -47,6 +47,14 @@ extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);struct rpc_clnt ;extern struct dentry *rpc_create_client_dir (struct dentry *,struct qstr *,struct rpc_clnt *);extern int rpc_remove_client_dir (struct dentry *); + +struct cache_detail ; +extern struct dentry *rpc_create_cache_dir (struct dentry *, +struct qstr *, +mode_t umode, +struct cache_detail *); +extern void rpc_remove_cache_dir (struct dentry *); +extern struct dentry *rpc_mkpipe (struct dentry *,const char *,void *,const struct rpc_pipe_ops *,int flags);extern int rpc_unlink (struct dentry *);
net/sunrpc/cache.c +126 -0
135 lines not on this page · raw message
net/sunrpc/rpc_pipe.c +43 -0
55 lines not on this page · raw message
Signature · 1 line
1.6.0.4
PATCH 26/32 NFS: Add a ->migratepage() aop for NFS
Make NFS a bit more friendly to NUMA and memory hot removal...
--- fs/nfs/file.c | 1 + fs/nfs/internal.h | 6 +++ fs/nfs/write.c | 91 ++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 76 insertions(+), 22 deletions(-)
fs/nfs/file.c +1 -0
@@ -479,6 +479,7 @@ const struct address_space_operations nfs_file_aops = { .invalidatepage = nfs_invalidate_page, .releasepage = nfs_release_page, .direct_IO = nfs_direct_IO, + .migratepage = nfs_migrate_page, .launder_page = nfs_launder_page, };
fs/nfs/internal.h +6 -0
@@ -248,6 +248,12 @@ extern void nfs_read_prepare(struct rpc_task *task, void *calldata);/* write.c */ extern void nfs_write_prepare (struct rpc_task *task,void *calldata); +#ifdef CONFIG_MIGRATION +extern int nfs_migrate_page (struct address_space *, +struct page *,struct page *); +#else +#define nfs_migrate_page NULL +#endif /* nfs4proc.c */ extern int _nfs4_call_sync(struct nfs_server *server,
fs/nfs/write.c +69 -22
134 lines not on this page · raw message
Signature · 1 line
1.6.0.4
PATCH 27/32 NFS: read-modify-write page updating
From: Peter Staubach <[email protected]>
Hi.
I have a proposal for possibly resolving this issue.
I believe that this situation occurs due to the way that the Linux NFS client handles writes which modify partial pages.
The Linux NFS client handles partial page modifications by allocating a page from the page cache, copying the data from the user level into the page, and then keeping track of the offset and length of the modified portions of the page. The page is not marked as up to date because there are portions of the page which do not contain valid file contents.
When a read call comes in for a portion of the page, the contents of the page must be read in the from the server. However, since the page may already contain some modified data, that modified data must be written to the server before the file contents can be read back in the from server. And, since the writing and reading can not be done atomically, the data must be written and committed to stable storage on the server for safety purposes. This means either a FILE_SYNC WRITE or a UNSTABLE WRITE followed by a COMMIT. This has been discussed at length previously.
This algorithm could be described as modify-write-read. It is most efficient when the application only updates pages and does not read them.
My proposed solution is to add a heuristic to decide whether to do this modify-write-read algorithm or switch to a read- modify-write algorithm when initially allocating the page in the write system call path. The heuristic uses the modes that the file was opened with, the offset in the page to read from, and the size of the region to read.
If the file was opened for reading in addition to writing and the page would not be filled completely with data from the user level, then read in the old contents of the page and mark it as Uptodate before copying in the new data. If the page would be completely filled with data from the user level, then there would be no reason to read in the old contents because they would just be copied over.
This would optimize for applications which randomly access and update portions of files. The linkage editor for the C compiler is an example of such a thing.
I tested the attached patch by using rpmbuild to build the current Fedora rawhide kernel. The kernel without the patch generated about 269,500 WRITE requests. The modified kernel containing the patch generated about 261,000 WRITE requests. Thus, about 8,500 fewer WRITE requests were generated. I suspect that many of these additional WRITE requests were probably FILE_SYNC requests to WRITE a single page, but I didn't test this theory.
The difference between this patch and the previous one was to remove the unneeded PageDirty() test. I then retested to ensure that the resulting system continued to behave as desired.
Thanx... ps
--- fs/nfs/file.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 46 insertions(+), 2 deletions(-)
fs/nfs/file.c +46 -2
@@ -328,6 +328,42 @@ nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync) }/* +* Decide whether a read/modify/write cycle may be more efficient +* then a modify/write/read cycle when writing to a page in the +* page cache. +* +* The modify/write/read cycle may occur if a page is read before +* being completely filled by the writer. In this situation, the +* page must be completely written to stable storage on the server +* before it can be refilled by reading in the page from the server. +* This can lead to expensive, small, FILE_SYNC mode writes being +* done. +* +* It may be more efficient to read the page first if the file is +* open for reading in addition to writing, the page is not marked +* as Uptodate, it is not dirty or waiting to be committed, +* indicating that it was previously allocated and then modified, +* that there were valid bytes of data in that range of the file, +* and that the new data won't completely replace the old data in +* that range of the file. +*/ +static int nfs_want_read_modify_write (struct file *file,struct page *page, +loff_t pos,unsigned len) +{ +unsigned int pglen =nfs_page_length (page); +unsigned int offset = pos & (PAGE_CACHE_SIZE -1 ); +unsigned int end = offset + len; + +if ((file->f_mode &FMODE_READ ) &&/* open for read? */ + !PageUptodate (page) &&/* Uptodate? */ + !PagePrivate (page) &&/* i/o request already? */ + pglen &&/* valid bytes of file? */ + (end < pglen || offset))/* replace all valid bytes? */ +return 1 ; +return 0 ; +} + +/* * This does the "real" work of the write. We must allocate and lock the * page to be sent back to the generic routine, which then copies the * data from user space.
@@ -340,15 +376,16 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, struct page **pagep, void **fsdata) { int ret; -pgoff_t index; +pgoff_t index = pos >>PAGE_CACHE_SHIFT ;struct page *page; - index = pos >>PAGE_CACHE_SHIFT ; +int once_thru =0 ;dfprintk (PAGECACHE ,"NFS: write_begin(%s/%s(%ld), %u@%lld)\n" , file->f_path.dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name, mapping->host->i_ino, len, (long long ) pos); +start:/* * Prevent starvation issues if someone is doing a consistency * sync-to-disk
@@ -367,6 +404,13 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,if (ret) {unlock_page (page);page_cache_release (page); + }else if (!once_thru && +nfs_want_read_modify_write (file, page, pos, len)) { + once_thru =1 ; + ret =nfs_readpage (file, page); +page_cache_release (page); +if (!ret) + goto start; }return ret; }
Signature · 1 line
1.6.0.4
PATCH 28/32 nfs: remove superfluous BUG_ON()s
From: Bartlomiej Zolnierkiewicz <[email protected]>
Remove duplicated BUG_ON()s from nfs[4]_create_server() (we make the same checks earlier in both functions).
This takes care of the following entries from Dan's list:
fs/nfs/client.c +1078 nfs_create_server(47) warning: variable derefenced before check 'server->nfs_client' fs/nfs/client.c +1079 nfs_create_server(48) warning: variable derefenced before check 'server->nfs_client->rpc_ops' fs/nfs/client.c +1363 nfs4_create_server(43) warning: variable derefenced before check 'server->nfs_client' fs/nfs/client.c +1364 nfs4_create_server(44) warning: variable derefenced before check 'server->nfs_
--- fs/nfs/client.c | 8 -------- 1 files changed, 0 insertions(+), 8 deletions(-)
fs/nfs/client.c +0 -8
@@ -1077,10 +1077,6 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, (unsigned long long ) server->fsid.major, (unsigned long long) server->fsid.minor); -BUG_ON (!server->nfs_client); -BUG_ON (!server->nfs_client->rpc_ops); -BUG_ON (!server->nfs_client->rpc_ops->file_inode_ops); -spin_lock (&nfs_client_lock);list_add_tail (&server->client_link, &server->nfs_client->cl_superblocks);list_add_tail (&server->master_link, &nfs_volume_list);
@@ -1362,10 +1358,6 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,if (server->namelen ==0 || server->namelen >NFS4_MAXNAMLEN ) server->namelen =NFS4_MAXNAMLEN ; -BUG_ON (!server->nfs_client); -BUG_ON (!server->nfs_client->rpc_ops); -BUG_ON (!server->nfs_client->rpc_ops->file_inode_ops); -spin_lock (&nfs_client_lock);list_add_tail (&server->client_link, &server->nfs_client->cl_superblocks);list_add_tail (&server->master_link, &nfs_volume_list);
Signature · 1 line
1.6.0.4
PATCH 29/32 SUNRPC: Fix a typo in cache_pipefs_files
We want the channel to be a regular file, so that we don't need to supply rpc_pipe_ops.
--- net/sunrpc/rpc_pipe.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
net/sunrpc/rpc_pipe.c +1 -1
@@ -887,7 +887,7 @@ static const struct rpc_filelist cache_pipefs_files[3] = { [0] = { .name = "channel", .i_fop = &cache_file_operations_pipefs, - .mode = S_IFIFO|S_IRUSR|S_IWUSR, + .mode = S_IFREG|S_IRUSR|S_IWUSR, }, [1] = { .name = "content",
Signature · 1 line
1.6.0.4
PATCH 30/32 NFS: Add a dns resolver for use with NFSv4 referrals and migration
The NFSv4 and NFSv4.1 protocols both allow for the redirection of a client from one server to another in order to support filesystem migration and replication. For full protocol support, we need to add the ability to convert a DNS host name into an IP address that we can feed to the RPC client.
We'll reuse the sunrpc cache, now that it has been converted to work with rpc_pipefs.
--- Documentation/filesystems/nfs.txt | 98 ++++++++++ Documentation/kernel-parameters.txt | 8 + fs/nfs/Makefile | 3 +- fs/nfs/cache_lib.c | 140 +++++++++++++++ fs/nfs/cache_lib.h | 27 +++ fs/nfs/dns_resolve.c | 335 +++++++++++++++++++++++++++++++++++ fs/nfs/dns_resolve.h | 14 ++ fs/nfs/inode.c | 8 + net/sunrpc/rpc_pipe.c | 7 + 9 files changed, 639 insertions(+), 1 deletions(-) create mode 100644 Documentation/filesystems/nfs.txt create mode 100644 fs/nfs/cache_lib.c create mode 100644 fs/nfs/cache_lib.h create mode 100644 fs/nfs/dns_resolve.c create mode 100644 fs/nfs/dns_resolve.h
Documentation/filesystems/nfs.txt new file +98 -0
@@ -0,0 +1,98 @@ + +The NFS client +============== + +The NFS version 2 protocol was first documented in RFC1094 (March 1989). +Since then two more major releases of NFS have been published, with NFSv3 +being documented in RFC1813 (June 1995), and NFSv4 in RFC3530 (April +2003). + +The Linux NFS client currently supports all the above published versions, +and work is in progress on adding support for minor version 1 of the NFSv4 +protocol. + +The purpose of this document is to provide information on some of the +upcall interfaces that are used in order to provide the NFS client with +some of the information that it requires in order to fully comply with +the NFS spec. + +The DNS resolver +================ + +NFSv4 allows for one server to refer the NFS client to data that has been +migrated onto another server by means of the special "fs_locations" +attribute. See + http://tools.ietf.org/html/rfc3530#section-6 +and + http://tools.ietf.org/html/draft-ietf-nfsv4-referrals-00 + +The fs_locations information can take the form of either an ip address and +a path, or a DNS hostname and a path. The latter requires the NFS client to +do a DNS lookup in order to mount the new volume, and hence the need for an +upcall to allow userland to provide this service. + +Assuming that the user has the 'rpc_pipefs' filesystem mounted in the usual +/var/lib/nfs/rpc_pipefs, the upcall consists of the following steps: + + (1) The process checks the dns_resolve cache to see if it contains a + valid entry. If so, it returns that entry and exits. + + (2) If no valid entry exists, the helper script '/sbin/nfs_cache_getent' + (may be changed using the 'nfs.cache_getent' kernel boot parameter) + is run, with two arguments: + - the cache name, "dns_resolve" + - the hostname to resolve + + (3) After looking up the corresponding ip address, the helper script + writes the result into the rpc_pipefs pseudo-file + '/var/lib/nfs/rpc_pipefs/cache/dns_resolve/channel' + in the following (text) format: + + "<ip address> <hostname> <ttl>\n" + + Where <ip address> is in the usual IPv4 (123.456.78.90) or IPv6 + (ffee:ddcc:bbaa:9988:7766:5544:3322:1100, ffee::1100, ...) format. + <hostname> is identical to the second argument of the helper + script, and <ttl> is the 'time to live' of this cache entry (in + units of seconds). + + Note: If <ip address> is invalid, say the string "0", then a negative + entry is created, which will cause the kernel to treat the hostname + as having no valid DNS translation. + + + + +A basic sample /sbin/nfs_cache_getent +===================================== + +#!/bin/bash +# +ttl=600 +# +cut=/usr/bin/cut +getent=/usr/bin/getent +rpc_pipefs=/var/lib/nfs/rpc_pipefs +# +die() +{ + echo "Usage: $0 cache_name entry_name" + exit 1 +} + +[ $# -lt 2 ] && die +cachename="$1" +cache_path=${rpc_pipefs}/cache/${cachename}/channel + +case "${cachename}" in + dns_resolve) + name="$2" + result="$(${getent} hosts ${name} | ${cut} -f1 -d\ )" + [ -z "${result}" ] && result="0" + ;; + *) + die + ;; +esac +echo "${result} ${name} ${ttl}" >${cache_path} +
Documentation/kernel-parameters.txt +8 -0
@@ -1499,6 +1499,14 @@ and is between 256 and 4096 characters. It is defined in the file [NFS] set the TCP port on which the NFSv4 callback channel should listen. + nfs.cache_getent= + [NFS] sets the pathname to the program which is used + to update the NFS client cache entries. + + nfs.cache_getent_timeout= + [NFS] sets the timeout after which an attempt to + update a cache entry is deemed to have failed. + nfs.idmap_cache_timeout= [NFS] set the maximum lifetime for idmapper cache entries.
fs/nfs/Makefile +2 -1
@@ -6,7 +6,8 @@ obj-$(CONFIG_NFS_FS) += nfs.o nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ direct.o pagelist.o proc.o read.o symlink.o unlink.o \ - write.o namespace.o mount_clnt.o + write.o namespace.o mount_clnt.o \ + dns_resolve.o cache_lib.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.o nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
fs/nfs/cache_lib.c new file +140 -0
140 lines not on this page · raw message
fs/nfs/cache_lib.h new file +27 -0
@@ -0,0 +1,27 @@ +/* +* Helper routines for the NFS client caches +* +* Copyright (c) 2009 Trond Myklebust <[email protected]> +*/ + +#include <linux/completion.h> +#include <linux/sunrpc/cache.h> +#include <asm/atomic.h> + +/* +* Deferred request handling +*/ +struct nfs_cache_defer_req { +struct cache_req req; +struct cache_deferred_req deferred_req; +struct completion completion; +atomic_t count; +}; + +extern int nfs_cache_upcall (struct cache_detail *cd,char *entry_name); +extern struct nfs_cache_defer_req *nfs_cache_defer_req_alloc (void ); +extern void nfs_cache_defer_req_put (struct nfs_cache_defer_req *dreq); +extern int nfs_cache_wait_for_upcall (struct nfs_cache_defer_req *dreq); + +extern int nfs_cache_register (struct cache_detail *cd); +extern void nfs_cache_unregister (struct cache_detail *cd);
fs/nfs/dns_resolve.c new file +335 -0
335 lines not on this page · raw message
fs/nfs/dns_resolve.h new file +14 -0
@@ -0,0 +1,14 @@ +/* +* Resolve DNS hostnames into valid ip addresses +*/ +#ifndef __LINUX_FS_NFS_DNS_RESOLVE_H +#define __LINUX_FS_NFS_DNS_RESOLVE_H + +#define NFS_DNS_HOSTNAME_MAXLEN (128) + +extern int nfs_dns_resolver_init (void ); +extern void nfs_dns_resolver_destroy (void ); +extern ssize_t nfs_dns_resolve_name (char *name,size_t namelen, +struct sockaddr *sa,size_t salen); + +#endif
fs/nfs/inode.c +8 -0
@@ -46,6 +46,7 @@#include "iostat.h" #include "internal.h" #include "fscache.h" +#include "dns_resolve.h" #define NFSDBG_FACILITY NFSDBG_VFS
@@ -1506,6 +1507,10 @@ static int __init init_nfs_fs(void) {int err; + err =nfs_dns_resolver_init (); +if (err <0 ) + goto out8; + err =nfs_fscache_register ();if (err <0 ) goto out7;
@@ -1564,6 +1569,8 @@ out5: out6:nfs_fscache_unregister (); out7: +nfs_dns_resolver_destroy (); +out8:return err; }
@@ -1575,6 +1582,7 @@ static void __exit exit_nfs_fs(void)nfs_destroy_inodecache ();nfs_destroy_nfspagecache ();nfs_fscache_unregister (); +nfs_dns_resolver_destroy ();#ifdef CONFIG_PROC_FS rpc_proc_unregister ("nfs" );#endif
net/sunrpc/rpc_pipe.c +7 -0
@@ -416,11 +416,13 @@ struct vfsmount *rpc_get_mount(void)return ERR_PTR (err);return rpc_mount; } +EXPORT_SYMBOL_GPL (rpc_get_mount);void rpc_put_mount (void ) {simple_release_fs (&rpc_mount, &rpc_mount_count); } +EXPORT_SYMBOL_GPL (rpc_put_mount);static int rpc_delete_dentry (struct dentry *dentry) {
@@ -946,6 +948,7 @@ enum { RPCAUTH_portmap, RPCAUTH_statd, RPCAUTH_nfsd4_cb, + RPCAUTH_cache, RPCAUTH_RootEOF };
@@ -974,6 +977,10 @@ static const struct rpc_filelist files[] = { .name = "nfsd4_cb", .mode = S_IFDIR | S_IRUGO | S_IXUGO, }, + [RPCAUTH_cache] = { + .name = "cache", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, }; static int
Signature · 1 line
1.6.0.4
PATCH 31/32 NFS: Use the DNS resolver in the mount code.
In the referral code, use it to look up the new server's ip address if the fs_locations attribute contains a hostname.
--- fs/nfs/nfs4namespace.c | 18 +++++++++++++++++- 1 files changed, 17 insertions(+), 1 deletions(-)
fs/nfs/nfs4namespace.c +17 -1
@@ -17,6 +17,7 @@#include <linux/inet.h> #include "internal.h" #include "nfs4_fs.h" +#include "dns_resolve.h" #define NFSDBG_FACILITY NFSDBG_VFS
@@ -95,6 +96,20 @@ static int nfs4_validate_fspath(const struct vfsmount *mnt_parent,return 0 ; } +static size_t nfs_parse_server_name (char *string,size_t len, +struct sockaddr *sa,size_t salen) +{ +ssize_t ret; + + ret =rpc_pton (string, len, sa, salen); +if (ret ==0 ) { + ret =nfs_dns_resolve_name (string, len, sa, salen); +if (ret <0 ) + ret =0 ; + } +return ret; +} +static struct vfsmount *try_location (struct nfs_clone_mount *mountdata,char *page,char *page2,const struct nfs4_fs_location *location)
@@ -121,7 +136,8 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,if (memchr (buf->data,IPV6_SCOPE_DELIMITER , buf->len))continue ; - mountdata->addrlen =rpc_pton (buf->data, buf->len, + mountdata->addrlen =nfs_parse_server_name (buf->data, + buf->len, mountdata->addr, mountdata->addrlen);if (mountdata->addrlen ==0 )continue ;
Signature · 1 line
1.6.0.4
PATCH 32/32 SUNRPC: cache must take a reference to the cache detail's module on open()
Otherwise we Oops if the module containing the cache detail is removed before all cache readers have closed the file.
--- net/sunrpc/cache.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 76 insertions(+), 4 deletions(-)
net/sunrpc/cache.c +76 -4
@@ -836,6 +836,8 @@ static int cache_open(struct inode *inode, struct file *filp, {struct cache_reader *rp =NULL ; +if (!cd || !try_module_get (cd->owner)) +return -EACCES ;nonseekable_open (inode, filp);if (filp->f_mode &FMODE_READ ) { rp =kmalloc (sizeof (*rp),GFP_KERNEL );
@@ -879,6 +881,7 @@ static int cache_release(struct inode *inode, struct file *filp, cd->last_close =get_seconds ();atomic_dec (&cd->readers); } +module_put (cd->owner);return 0 ; }
@@ -1215,6 +1218,8 @@ static int content_open(struct inode *inode, struct file *file, {struct handle *han; +if (!cd || !try_module_get (cd->owner)) +return -EACCES ; han =__seq_open_private (file, &cache_content_op,sizeof (*han));if (han ==NULL )return -ENOMEM ;
@@ -1223,6 +1228,29 @@ static int content_open(struct inode *inode, struct file *file,return 0 ; } +static int content_release (struct inode *inode,struct file *file, +struct cache_detail *cd) +{ +int ret =seq_release_private (inode, file); +module_put (cd->owner); +return ret; +} + +static int open_flush (struct inode *inode,struct file *file, +struct cache_detail *cd) +{ +if (!cd || !try_module_get (cd->owner)) +return -EACCES ; +return nonseekable_open (inode, file); +} + +static int release_flush (struct inode *inode,struct file *file, +struct cache_detail *cd) +{ +module_put (cd->owner); +return 0 ; +} +static ssize_t read_flush (struct file *file,char __user *buf,size_t count,loff_t *ppos,struct cache_detail *cd)
@@ -1331,13 +1359,34 @@ static int content_open_procfs(struct inode *inode, struct file *filp)return content_open (inode, filp, cd); } +static int content_release_procfs (struct inode *inode,struct file *filp) +{ +struct cache_detail *cd =PDE (inode)->data; + +return content_release (inode, filp, cd); +} +static const struct file_operations content_file_operations_procfs = { .open = content_open_procfs, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = content_release_procfs, }; +static int open_flush_procfs (struct inode *inode,struct file *filp) +{ +struct cache_detail *cd =PDE (inode)->data; + +return open_flush (inode, filp, cd); +} + +static int release_flush_procfs (struct inode *inode,struct file *filp) +{ +struct cache_detail *cd =PDE (inode)->data; + +return release_flush (inode, filp, cd); +} +static ssize_t read_flush_procfs (struct file *filp,char __user *buf,size_t count,loff_t *ppos) {
@@ -1356,9 +1405,10 @@ static ssize_t write_flush_procfs(struct file *filp, }static const struct file_operations cache_flush_operations_procfs = { - .open = nonseekable_open, + .open = open_flush_procfs, .read = read_flush_procfs, .write = write_flush_procfs, + .release = release_flush_procfs, };static void remove_cache_proc_entries (struct cache_detail *cd)
@@ -1503,13 +1553,34 @@ static int content_open_pipefs(struct inode *inode, struct file *filp)return content_open (inode, filp, cd); } +static int content_release_pipefs (struct inode *inode,struct file *filp) +{ +struct cache_detail *cd =RPC_I (inode)->private; + +return content_release (inode, filp, cd); +} +const struct file_operations content_file_operations_pipefs = { .open = content_open_pipefs, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = content_release_pipefs, }; +static int open_flush_pipefs (struct inode *inode,struct file *filp) +{ +struct cache_detail *cd =RPC_I (inode)->private; + +return open_flush (inode, filp, cd); +} + +static int release_flush_pipefs (struct inode *inode,struct file *filp) +{ +struct cache_detail *cd =RPC_I (inode)->private; + +return release_flush (inode, filp, cd); +} +static ssize_t read_flush_pipefs (struct file *filp,char __user *buf,size_t count,loff_t *ppos) {
@@ -1528,9 +1599,10 @@ static ssize_t write_flush_pipefs(struct file *filp, }const struct file_operations cache_flush_operations_pipefs = { - .open = nonseekable_open, + .open = open_flush_pipefs, .read = read_flush_pipefs, .write = write_flush_pipefs, + .release = release_flush_pipefs, }; int sunrpc_cache_register_pipefs(struct dentry *parent,
Signature · 1 line
1.6.0.4
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
In reply to Trond MyklebustQuoted 8 lines · Trond Myklebust
The NFSv4 and NFSv4.1 protocols both allow for the redirection of a client from one server to another in order to support filesystem migration and replication. For full protocol support, we need to add the ability to convert a DNS host name into an IP address that we can feed to the RPC client.
We'll reuse the sunrpc cache, now that it has been converted to work with
rpc_pipefs.
Should I merge this too?
From: Trond Myklebust <[email protected]>
Subject: NFS: Testcase for the DNS resolver
---
fs/nfs/Kconfig | 11 ++++++++++ fs/nfs/Makefile | 4 +++ fs/nfs/cache_testcases.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ fs/nfs/dns_resolve.c | 1 + 4 files changed, 69 insertions(+), 0 deletions(-) create mode 100644 fs/nfs/cache_testcases.c
fs/nfs/Kconfig +11 -0
@@ -101,3 +101,14 @@ config NFS_FSCACHE help Say Y here if you want NFS data to be cached locally on disc through the general filesystem cache manager + +config NFS_CACHETEST + tristate "Test the NFS client DNS cache upcalls" + depends on NFS_FS + default N + help + Choose M if you want to build a module that can be used to test + the NFS client DNS cache upcall mechanism. + + Most people will want to say N +
fs/nfs/Makefile +4 -0
@@ -17,3 +17,7 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ nfs4namespace.o nfs-$(CONFIG_SYSCTL) += sysctl.o nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o + +obj-$(CONFIG_NFS_CACHETEST) += nfs_cachetest.o +nfs_cachetest-objs := cache_testcases.o +
fs/nfs/cache_testcases.c new file +53 -0
53 lines not on this page · raw message
fs/nfs/dns_resolve.c +1 -0
@@ -322,6 +322,7 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen, ret = -ESRCH ;return ret; } +EXPORT_SYMBOL_GPL (nfs_dns_resolve_name);int nfs_dns_resolver_init (void ) {
Signature · 6 lines
Trond Myklebust Linux NFS client maintainer NetApp [email protected] www.netapp.com
A message that is not in the archive (sent off-list or not yet received): 1250725916.12555.1.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
Quoted 11 lines · Trond Myklebust
Quoted 8 lines · Trond Myklebust
The NFSv4 and NFSv4.1 protocols both allow for the redirection of a client from one server to another in order to support filesystem migration and replication. For full protocol support, we need to add the ability to convert a DNS host name into an IP address that we can feed to the RPC client.
We'll reuse the sunrpc cache, now that it has been converted to work with
rpc_pipefs.Should I merge this too?
It's cute. If it's expected that more people may want to write nfs_cache_getent scripts, maybe it would be useful to them. But then, it's not that hard for them just to call the script by hand.
I guess I probably wouldn't....
--b.
Quoted 129 lines
From: Trond Myklebust <[email protected]>
Subject: NFS: Testcase for the DNS resolverSigned-off-by Trond Myklebust <[email protected]>---
fs/nfs/Kconfig | 11 ++++++++++ fs/nfs/Makefile | 4 +++ fs/nfs/cache_testcases.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ fs/nfs/dns_resolve.c | 1 + 4 files changed, 69 insertions(+), 0 deletions(-) create mode 100644 fs/nfs/cache_testcases.cfs/nfs/Kconfig +11
-0@@ -101,3 +101,14 @@ config NFS_FSCACHE help Say Y here if you want NFS data to be cached locally on disc through the general filesystem cache manager + +config NFS_CACHETEST + tristate "Test the NFS client DNS cache upcalls" + depends on NFS_FS + default N + help + Choose M if you want to build a module that can be used to test + the NFS client DNS cache upcall mechanism. + + Most people will want to say N +fs/nfs/Makefile +4
-0@@ -17,3 +17,7 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ nfs4namespace.o nfs-$(CONFIG_SYSCTL) += sysctl.o nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o + +obj-$(CONFIG_NFS_CACHETEST) += nfs_cachetest.o +nfs_cachetest-objs := cache_testcases.o +fs/nfs/cache_testcases.c new file +53
-0@@ -0,0 +1,53 @@ +/* +* linux/fs/nfs/cache_testcases.c +* +* Testcases for the NFS client cache upcalls +* +* Copyright (c) 2009 Trond Myklebust <[email protected]> +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/sunrpc/clnt.h> + +#include "dns_resolve.h" + +static char hostname[NFS_DNS_HOSTNAME_MAXLEN ] ="" ; +module_param_string (hostname, hostname,sizeof (hostname),0600 ); +MODULE_PARM_DESC (hostname,"DNS hostname to look up" ); + +static int nfs_lookup_hostname (char *name) +{ +struct sockaddr_storage sa; +ssize_t salen; + +if (!name || *name =='\0' ) + goto out; + salen =nfs_dns_resolve_name (name,strlen (name), + (struct sockaddr *)&sa,sizeof (sa)); +if (salen >0 ) { +char buf[INET6_ADDRSTRLEN +IPV6_SCOPE_ID_LEN +1 ]; + +rpc_ntop ((struct sockaddr *)&sa, buf,sizeof (buf)); +printk (KERN_NOTICE "%15s " , buf); + }else +printk (KERN_NOTICE "%15zd " , salen); +printk ("%15s\n" , name); +out: +return 0 ; +} + +static int nfs_dnstest_init (void ) +{ +return nfs_lookup_hostname (hostname); +} + +static void nfs_dnstest_exit (void ) +{ +} + +MODULE_AUTHOR ("Trond Myklebust <[email protected]>" ); +MODULE_LICENSE ("GPL" ); + +module_init (nfs_dnstest_init) +module_exit (nfs_dnstest_exit)fs/nfs/dns_resolve.c +1
-0@@ -322,6 +322,7 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen, ret = -ESRCH ;return ret; } +EXPORT_SYMBOL_GPL (nfs_dns_resolve_name);int nfs_dns_resolver_init (void ) {Signature · 11 lines
-- Trond Myklebust Linux NFS client maintainer NetApp [email protected] www.netapp.com -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
Quoted 11 lines · J. Bruce Fields
Quoted 10 lines · Trond Myklebust
Quoted 8 lines · Trond Myklebust
The NFSv4 and NFSv4.1 protocols both allow for the redirection of a client from one server to another in order to support filesystem migration and replication. For full protocol support, we need to add the ability to convert a DNS host name into an IP address that we can feed to the RPC client.
We'll reuse the sunrpc cache, now that it has been converted to work with
rpc_pipefs.
Quoted 7 lines
Quoted 1 line
Should I merge this too?
It's cute. If it's expected that more people may want to write
nfs_cache_getentscripts, maybe it would be useful to them. But then, it's not that hard for them just to call the script by hand.I guess I probably wouldn't....
I like the idea of including test code, but this looks like it would almost never be run. If the tests were run automatically somehow, it might be worth adding.
Quoted 129 lines
--b.
Quoted 126 lines
From: Trond Myklebust <[email protected]>
Subject: NFS: Testcase for the DNS resolverSigned-off-by Trond Myklebust <[email protected]>---
fs/nfs/Kconfig | 11 ++++++++++ fs/nfs/Makefile | 4 +++ fs/nfs/cache_testcases.c | 53 ++++++++++++++++++++++++++++++++++++ ++++++++++ fs/nfs/dns_resolve.c | 1 + 4 files changed, 69 insertions(+), 0 deletions(-)create mode 100644
fs/nfs/cache_testcases.cfs/nfs/Kconfig +0
-0@@ -101,3 +101,14 @@ config NFS_FSCACHE help Say Y here if you want NFS data to be cached locally on discthrough
the general filesystem cache managerfs/nfs/Kconfig +11
-0+ +config NFS_CACHETEST + tristate "Test the NFS client DNS cache upcalls" + depends on NFS_FS + default N + help + Choose M if you want to build a module that can be used to test + the NFS client DNS cache upcall mechanism. + + Most people will want to say N +fs/nfs/Makefile +0
-0@@ -17,3 +17,7 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ nfs4namespace.onfs-$(CONFIG_SYSCTL) += sysctl.o nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
fs/nfs/Makefile +4
-0+ +obj-$(CONFIG_NFS_CACHETEST) += nfs_cachetest.o +nfs_cachetest-objs := cache_testcases.o +fs/nfs/cache_testcases.c new file +53
-0@@ -0,0 +1,53 @@ +/* +* linux/fs/nfs/cache_testcases.c +* +* Testcases for the NFS client cache upcalls +* +* Copyright (c) 2009 Trond Myklebust <[email protected]> +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/sunrpc/clnt.h> + +#include "dns_resolve.h" + +static char hostname[NFS_DNS_HOSTNAME_MAXLEN ] ="" ; +module_param_string (hostname, hostname,sizeof (hostname),0600 ); +MODULE_PARM_DESC (hostname,"DNS hostname to look up" ); + +static int nfs_lookup_hostname (char *name) +{ +struct sockaddr_storage sa; +ssize_t salen; + +if (!name || *name =='\0' ) + goto out; + salen =nfs_dns_resolve_name (name,strlen (name), + (struct sockaddr *)&sa,sizeof (sa)); +if (salen >0 ) { +char buf[INET6_ADDRSTRLEN +IPV6_SCOPE_ID_LEN +1 ]; + +rpc_ntop ((struct sockaddr *)&sa, buf,sizeof (buf)); +printk (KERN_NOTICE "%15s " , buf); + }else +printk (KERN_NOTICE "%15zd " , salen); +printk ("%15s\n" , name); +out: +return 0 ; +} + +static int nfs_dnstest_init (void ) +{ +return nfs_lookup_hostname (hostname); +} + +static void nfs_dnstest_exit (void ) +{ +} + +MODULE_AUTHOR ("Trond Myklebust <[email protected]>" ); +MODULE_LICENSE ("GPL" ); + +module_init (nfs_dnstest_init) +module_exit (nfs_dnstest_exit)fs/nfs/dns_resolve.c +1
-0@@ -322,6 +322,7 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen, ret = -ESRCH ;return ret; } +EXPORT_SYMBOL_GPL (nfs_dns_resolve_name);int nfs_dns_resolver_init (void ){
Signature · 2 lines
Trond Myklebust Linux NFS client maintainer
Quoted 11 lines
Quoted 7 lines
NetApp
[email protected]
www.netapp.com
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
In reply to Trond MyklebustRandom thoughts.
Quoted 142 lines · Trond Myklebust
The NFSv4 and NFSv4.1 protocols both allow for the redirection of a client from one server to another in order to support filesystem migration and replication. For full protocol support, we need to add the ability to convert a DNS host name into an IP address that we can feed to the RPC client.
We'll reuse the sunrpc cache, now that it has been converted to work with
rpc_pipefs.Signed-off-by Trond Myklebust <[email protected]>---
Documentation/filesystems/nfs.txt | 98 ++++++++++ Documentation/kernel-parameters.txt | 8 + fs/nfs/Makefile | 3 +- fs/nfs/cache_lib.c | 140 +++++++++++++++ fs/nfs/cache_lib.h | 27 +++ fs/nfs/dns_resolve.c | 335 ++++++++++++++++++++++++++ +++++++++ fs/nfs/dns_resolve.h | 14 ++ fs/nfs/inode.c | 8 + net/sunrpc/rpc_pipe.c | 7 + 9 files changed, 639 insertions(+), 1 deletions(-)create mode 100644
Documentation/filesystems/nfs.txtcreate mode 100644fs/nfs/cache_lib.c
create mode 100644fs/nfs/cache_lib.h
create mode 100644fs/nfs/dns_resolve.ccreate mode 100644fs/nfs/dns_resolve.hDocumentation/filesystems/nfs.txt new file +5
-0@@ -0,0 +1,98 @@ + +The NFS client +============== + +The NFS version 2 protocol was first documented in RFC1094 (March1989).
+Since then two more major releases of NFS have been published, with NFSv3Documentation/filesystems/nfs.txt new file +4
-0+being documented in RFC1813 (June 1995), and NFSv4 in RFC3530 (April +2003). + +The Linux NFS client currently supports all the above publishedversions,
+and work is in progress on adding support for minor version 1 of the NFSv4Documentation/filesystems/nfs.txt new file +4
-0+protocol. + +The purpose of this document is to provide information on some of the +upcall interfaces that are used in order to provide the NFS clientwith
+some of the information that it requires in order to fully comply withDocumentation/filesystems/nfs.txt new file +6
-0+the NFS spec. + +The DNS resolver +================ + +NFSv4 allows for one server to refer the NFS client to data thathas been
Documentation/filesystems/nfs.txt new file +7
-0+migrated onto another server by means of the special "fs_locations" +attribute. See + http://tools.ietf.org/html/rfc3530#section-6 +and + http://tools.ietf.org/html/draft-ietf-nfsv4-referrals-00 + +The fs_locations information can take the form of either an ipaddress and
+a path, or a DNS hostname and a path. The latter requires the NFS client to
+do a DNS lookup in order to mount the new volume, and hence the need for anDocumentation/filesystems/nfs.txt new file +3
-0+upcall to allow userland to provide this service. + +Assuming that the user has the 'rpc_pipefs' filesystem mounted inthe usual
Documentation/filesystems/nfs.txt new file +3
-0+/var/lib/nfs/rpc_pipefs, the upcall consists of the following steps: + + (1) The process checks the dns_resolve cache to see if itcontains a
Documentation/filesystems/nfs.txt new file +3
-0+ valid entry. If so, it returns that entry and exits. + + (2) If no valid entry exists, the helper script '/sbin/
nfs_cache_getent'
+ (may be changed using the 'nfs.cache_getent' kernel boot
parameter)Documentation/filesystems/nfs.txt new file +5
-0+ is run, with two arguments: + - the cache name, "dns_resolve" + - the hostname to resolve + + (3) After looking up the corresponding ip address, the helperscript
Documentation/filesystems/nfs.txt new file +7
-0+ writes the result into the rpc_pipefs pseudo-file + '/var/lib/nfs/rpc_pipefs/cache/dns_resolve/channel' + in the following (text) format: + + "<ip address> <hostname> <ttl>\n" + + Where <ip address> is in the usual IPv4 (123.456.78.90) orIPv6
+ (ffee:ddcc:bbaa:9988:7766:5544:3322:1100, ffee::1100, ...)
format.Documentation/filesystems/nfs.txt new file +2
-0+ <hostname> is identical to the second argument of the helper + script, and <ttl> is the 'time to live' of this cache entry(in
Documentation/filesystems/nfs.txt new file +3
-0+ units of seconds). + + Note: If <ip address> is invalid, say the string "0", then anegative
+ entry is created, which will cause the kernel to treat the
hostnameDocumentation/filesystems/nfs.txt new file +28
-0+ as having no valid DNS translation. + + + + +A basic sample /sbin/nfs_cache_getent +===================================== + +#!/bin/bash +# +ttl=600 +# +cut=/usr/bin/cut +getent=/usr/bin/getent +rpc_pipefs=/var/lib/nfs/rpc_pipefs +# +die() +{ + echo "Usage: $0 cache_name entry_name" + exit 1 +} + +[ $# -lt 2 ] && die +cachename="$1" +cache_path=${rpc_pipefs}/cache/${cachename}/channel + +case "${cachename}" in + dns_resolve)
Documentation/filesystems/nfs.txt line 98
Quoted 10 lines
Documentation/filesystems/nfs.txt new file +10
-0+ name="$2" + result="$(${getent} hosts ${name} | ${cut} -f1 -d\ )" + [ -z "${result}" ] && result="0" + ;; + *) + die + ;; +esac +echo "${result} ${name} ${ttl}" >${cache_path} +
Instead of having a single script with a big case statement in it, why not have a directory containing a bunch of smaller, more specific, scripts? Common code can be "sourced" from a separate file. Some of these scripts may want to do more (or less) than writing into an rpc_pipefs file.
Quoted 91 lines
Documentation/kernel-parameters.txt +0
-0@@ -1499,6 +1499,14 @@ and is between 256 and 4096 characters. It isdefined in the file
[NFS] set the TCP port on which the NFSv4 callback channel should listen.Documentation/kernel-parameters.txt +8
-0+ nfs.cache_getent= + [NFS] sets the pathname to the program which is used + to update the NFS client cache entries. + + nfs.cache_getent_timeout= + [NFS] sets the timeout after which an attempt to + update a cache entry is deemed to have failed. +nfs.idmap_cache_timeout=
[NFS] set the maximum lifetime for idmapper cache entries.fs/nfs/Makefile +2
-1@@ -6,7 +6,8 @@ obj-$(CONFIG_NFS_FS) += nfs.o nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ direct.o pagelist.o proc.o read.o symlink.o unlink.o \ - write.o namespace.o mount_clnt.o + write.o namespace.o mount_clnt.o \ + dns_resolve.o cache_lib.onfs-$(CONFIG_ROOT_NFS) += nfsroot.o
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.ofs/nfs/cache_lib.c new file +23
-0@@ -0,0 +1,140 @@ +/* +* linux/fs/nfs/cache_lib.c +* +* Helper routines for the NFS client caches +* +* Copyright (c) 2009 Trond Myklebust <[email protected]> +*/ +#include <linux/kmod.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/mount.h> +#include <linux/namei.h> +#include <linux/sunrpc/cache.h> +#include <linux/sunrpc/rpc_pipe_fs.h> + +#include "cache_lib.h" + +#define NFS_CACHE_UPCALL_PATHLEN 256 +#define NFS_CACHE_UPCALL_TIMEOUT 15 + +static char nfs_cache_getent_prog[NFS_CACHE_UPCALL_PATHLEN ] = +"/sbin/nfs_cache_getent" ; +static unsigned long nfs_cache_getent_timeout =
NFS_CACHE_UPCALL_TIMEOUT;fs/nfs/cache_lib.c new file +4
-0+ +module_param_string (cache_getent, nfs_cache_getent_prog, +sizeof (nfs_cache_getent_prog),0600 ); +MODULE_PARM_DESC(cache_getent, "Path to the client cache upcallprogram");
+module_param_named(cache_getent_timeout,nfs_cache_getent_timeout, ulong, 0600);
+MODULE_PARM_DESC(cache_getent_timeout, "Timeout (in seconds) after which "fs/nfs/cache_lib.c new file +18
-0+ "the cache upcall is assumed to have failed"); + +int nfs_cache_upcall (struct cache_detail *cd,char *entry_name) +{ +static char *envp[] = {"HOME=/" , +"TERM=linux" , +"PATH=/sbin:/usr/sbin:/bin:/usr/bin" , +NULL + }; +char *argv[] = { + nfs_cache_getent_prog, + cd->name, + entry_name, +NULL + }; +int ret = -EACCES ; + +if (nfs_cache_getent_prog[0 ] =='\0' )
fs/nfs/cache_lib.c line 57
Quoted 10 lines
fs/nfs/cache_lib.c new file +10
-0+ goto out; + ret =call_usermodehelper (argv[0 ], argv, envp,UMH_WAIT_EXEC ); +/* +* Disable the upcall mechanism if we're getting an ENOENT or +* EACCES error. The admin can re-enable it on the fly by using +* sysfs to set the 'cache_getent' parameter once the problem +* has been fixed. +*/ +if (ret == -ENOENT || ret == -EACCES ) + nfs_cache_getent_prog[0 ] ='\0' ;
What's the risk of continuing to invoke the upcall script if it doesn't exist? If it's happening frequently I would expect that the lack of the file would be cached, so it would still be a quick failure.
Quoted 141 lines
fs/nfs/cache_lib.c new file +14
-0+out: +return ret >0 ?0 : ret; +} + +/* +* Deferred request handling +*/ +void nfs_cache_defer_req_put (struct nfs_cache_defer_req *dreq) +{ +if (atomic_dec_and_test (&dreq->count)) +kfree (dreq); +} + +static void nfs_dns_cache_revisit(struct cache_deferred_req *d, inttoomany)
fs/nfs/cache_lib.c new file +10
-0+{ +struct nfs_cache_defer_req *dreq; + + dreq = container_of(d, struct nfs_cache_defer_req, deferred_req); + +complete_all (&dreq->completion); +nfs_cache_defer_req_put (dreq); +} + +static struct cache_deferred_req *nfs_dns_cache_defer(struct
cache_req*req)fs/nfs/cache_lib.c new file +59
-0+{ +struct nfs_cache_defer_req *dreq; + + dreq = container_of(req, struct nfs_cache_defer_req, req); + dreq->deferred_req.revisit = nfs_dns_cache_revisit; +atomic_inc (&dreq->count); + +return &dreq->deferred_req; +} + +struct nfs_cache_defer_req *nfs_cache_defer_req_alloc (void ) +{ +struct nfs_cache_defer_req *dreq; + + dreq =kzalloc (sizeof (*dreq),GFP_KERNEL ); +if (dreq) { +init_completion (&dreq->completion); +atomic_set (&dreq->count,1 ); + dreq->req.defer = nfs_dns_cache_defer; + } +return dreq; +} + +int nfs_cache_wait_for_upcall (struct nfs_cache_defer_req *dreq) +{ +if (wait_for_completion_timeout (&dreq->completion, + nfs_cache_getent_timeout *HZ ) ==0 ) +return -ETIMEDOUT ; +return 0 ; +} + +int nfs_cache_register (struct cache_detail *cd) +{ +struct nameidata nd; +struct vfsmount *mnt; +int ret; + + mnt =rpc_get_mount (); +if (IS_ERR (mnt)) +return PTR_ERR (mnt); + ret =vfs_path_lookup (mnt->mnt_root, mnt,"/cache" ,0 , &nd); +if (ret) + goto err; + ret =sunrpc_cache_register_pipefs (nd.path.dentry, + cd->name,0600 , cd); +path_put (&nd.path); +if (!ret) +return ret; +err: +rpc_put_mount (); +return ret; +} + +void nfs_cache_unregister (struct cache_detail *cd) +{ +sunrpc_cache_unregister_pipefs (cd); +rpc_put_mount (); +} +fs/nfs/cache_lib.h new file +21
-0@@ -0,0 +1,27 @@ +/* +* Helper routines for the NFS client caches +* +* Copyright (c) 2009 Trond Myklebust <[email protected]> +*/ + +#include <linux/completion.h> +#include <linux/sunrpc/cache.h> +#include <asm/atomic.h> + +/* +* Deferred request handling +*/ +struct nfs_cache_defer_req { +struct cache_req req; +struct cache_deferred_req deferred_req; +struct completion completion; +atomic_t count; +}; + +extern int nfs_cache_upcall(struct cache_detail *cd, char
*entry_name);fs/nfs/cache_lib.h new file +2
-0+extern struct nfs_cache_defer_req *nfs_cache_defer_req_alloc (void ); +extern void nfs_cache_defer_req_put(struct nfs_cache_defer_req*dreq);
+extern intnfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq);fs/nfs/cache_lib.h new file +3
-0+ +extern int nfs_cache_register (struct cache_detail *cd); +extern void nfs_cache_unregister (struct cache_detail *cd);fs/nfs/dns_resolve.c new file +14
-0@@ -0,0 +1,335 @@ +/* +* linux/fs/nfs/dns_resolve.c +* +* Copyright (c) 2009 Trond Myklebust <[email protected]> +* +* Resolves DNS hostnames into valid ip addresses +*/ + +#include <linux/hash.h> +#include <linux/string.h> +#include <linux/kmod.h> +#include <linux/module.h> +#include <linux/socket.h> +#include <linux/seq_file.h>
fs/nfs/dns_resolve.c line 24
Quoted 10 lines
fs/nfs/dns_resolve.c new file +10
-0+#include <linux/inet.h> +#include <linux/sunrpc/clnt.h> +#include <linux/sunrpc/cache.h> +#include <linux/sunrpc/svcauth.h> + +#include "dns_resolve.h" +#include "cache_lib.h" + +#define NFS_DNS_HASHBITS 4 +#define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS)
So the hash table is only 16 buckets. Is it really worth the trouble of keeping a small cache of hostname lookups in the kernel? I guess I don't have a clear idea of how often you need to handle DNS resolution for FS_LOCATIONS.
The garbage collection mechanism for expired entries isn't obvious. Without one I would expect this cache to grow enough that inserting and looking up valid entries might become expensive.
Quoted 51 lines
fs/nfs/dns_resolve.c new file +51
-0+ +static struct cache_head *nfs_dns_table[NFS_DNS_HASHTBL_SIZE ]; + +struct nfs_dns_ent { +struct cache_head h; + +char *hostname; +size_t namelen; + +struct sockaddr_storage addr; +size_t addrlen; +}; + + +static void nfs_dns_ent_init (struct cache_head *cnew, +struct cache_head *ckey) +{ +struct nfs_dns_ent *new; +struct nfs_dns_ent *key; + + new = container_of(cnew, struct nfs_dns_ent, h); + key = container_of(ckey, struct nfs_dns_ent, h); + +kfree (new->hostname); + new->hostname =kstrndup (key->hostname, key->namelen,GFP_KERNEL ); +if (new->hostname) { + new->namelen = key->namelen; +memcpy (&new->addr, &key->addr, key->addrlen); + new->addrlen = key->addrlen; + }else { + new->namelen =0 ; + new->addrlen =0 ; + } +} + +static void nfs_dns_ent_put (struct kref *ref) +{ +struct nfs_dns_ent *item; + + item = container_of(ref, struct nfs_dns_ent, h.ref); +kfree (item->hostname); +kfree (item); +} + +static struct cache_head *nfs_dns_ent_alloc (void ) +{ +struct nfs_dns_ent *item =kmalloc (sizeof (*item),GFP_KERNEL ); + +if (item !=NULL ) { + item->hostname =NULL ; + item->namelen =0 ;
fs/nfs/dns_resolve.c line 85
Quoted 10 lines
fs/nfs/dns_resolve.c new file +10
-0+ item->addrlen =0 ; +return &item->h; + } +return NULL ; +}; + +static unsigned int nfs_dns_hash (const struct nfs_dns_ent *key) +{ +return hash_str (key->hostname,NFS_DNS_HASHBITS ); +}
Any idea how well this hash function works for hostnames?
Quoted 257 lines
fs/nfs/dns_resolve.c new file +91
-0+ +static void nfs_dns_request (struct cache_detail *cd, +struct cache_head *ch, +char **bpp,int *blen) +{ + struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); + +qword_add (bpp, blen, key->hostname); + (*bpp)[-1 ] ='\n' ; +} + +static int nfs_dns_upcall (struct cache_detail *cd, +struct cache_head *ch) +{ + struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); +int ret; + + ret =nfs_cache_upcall (cd, key->hostname); +if (ret) + ret =sunrpc_cache_pipe_upcall (cd, ch, nfs_dns_request); +return ret; +} + +static int nfs_dns_match (struct cache_head *ca, +struct cache_head *cb) +{ +struct nfs_dns_ent *a; +struct nfs_dns_ent *b; + + a = container_of(ca, struct nfs_dns_ent, h); + b = container_of(cb, struct nfs_dns_ent, h); + +if (a->namelen ==0 || a->namelen != b->namelen) +return 0 ; +return memcmp (a->hostname, b->hostname, a->namelen) ==0 ; +} + +static int nfs_dns_show (struct seq_file *m,struct cache_detail *cd, +struct cache_head *h) +{ +struct nfs_dns_ent *item; +long ttl; + +if (h ==NULL ) { +seq_puts (m,"# ip address hostname ttl\n" ); +return 0 ; + } + item = container_of(h, struct nfs_dns_ent, h); + ttl = (long )item->h.expiry_time - (long )get_seconds (); +if (ttl <0 ) + ttl =0 ; + +if (!test_bit (CACHE_NEGATIVE , &h->flags)) { +char buf[INET6_ADDRSTRLEN +IPV6_SCOPE_ID_LEN +1 ]; + +rpc_ntop ((struct sockaddr *)&item->addr, buf,sizeof (buf)); +seq_printf (m,"%15s " , buf); + }else +seq_puts (m,"<none> " ); +seq_printf (m,"%15s %ld\n" , item->hostname, ttl); +return 0 ; +} + +struct nfs_dns_ent *nfs_dns_lookup (struct cache_detail *cd, +struct nfs_dns_ent *key) +{ +struct cache_head *ch; + + ch =sunrpc_cache_lookup (cd, + &key->h, +nfs_dns_hash (key)); +if (!ch) +return NULL ; + return container_of(ch, struct nfs_dns_ent, h); +} + +struct nfs_dns_ent *nfs_dns_update (struct cache_detail *cd, +struct nfs_dns_ent *new, +struct nfs_dns_ent *key) +{ +struct cache_head *ch; + + ch =sunrpc_cache_update (cd, + &new->h, &key->h, +nfs_dns_hash (key)); +if (!ch) +return NULL ; + return container_of(ch, struct nfs_dns_ent, h); +} + +static int nfs_dns_parse(struct cache_detail *cd, char *buf, intbuflen)
fs/nfs/dns_resolve.c new file +159
-0+{ +char buf1[NFS_DNS_HOSTNAME_MAXLEN +1 ]; +struct nfs_dns_ent key, *item; +unsigned long ttl; +ssize_t len; +int ret = -EINVAL ; + +if (buf[buflen-1 ] !='\n' ) + goto out; + buf[buflen-1 ] ='\0' ; + + len =qword_get (&buf, buf1,sizeof (buf1)); +if (len <=0 ) + goto out; + key.addrlen =rpc_pton (buf1, len, + (struct sockaddr *)&key.addr, +sizeof (key.addr)); + + len =qword_get (&buf, buf1,sizeof (buf1)); +if (len <=0 ) + goto out; + + key.hostname = buf1; + key.namelen = len; +memset (&key.h,0 ,sizeof (key.h)); + + ttl =get_expiry (&buf); +if (ttl ==0 ) + goto out; + key.h.expiry_time = ttl +get_seconds (); + + ret = -ENOMEM ; + item =nfs_dns_lookup (cd, &key); +if (item ==NULL ) + goto out; + +if (key.addrlen ==0 ) +set_bit (CACHE_NEGATIVE , &key.h.flags); + + item =nfs_dns_update (cd, &key, item); +if (item ==NULL ) + goto out; + + ret =0 ; +cache_put (&item->h, cd); +out: +return ret; +} + +static struct cache_detail nfs_dns_resolve = { + .owner =THIS_MODULE , + .hash_size =NFS_DNS_HASHTBL_SIZE , + .hash_table = nfs_dns_table, + .name ="dns_resolve" , + .cache_put = nfs_dns_ent_put, + .cache_upcall = nfs_dns_upcall, + .cache_parse = nfs_dns_parse, + .cache_show = nfs_dns_show, + .match = nfs_dns_match, + .init = nfs_dns_ent_init, + .update = nfs_dns_ent_init, + .alloc = nfs_dns_ent_alloc, +}; + +static int do_cache_lookup (struct cache_detail *cd, +struct nfs_dns_ent *key, +struct nfs_dns_ent **item, +struct nfs_cache_defer_req *dreq) +{ +int ret = -ENOMEM ; + + *item =nfs_dns_lookup (cd, key); +if (*item) { + ret =cache_check (cd, &(*item)->h, &dreq->req); +if (ret) + *item =NULL ; + } +return ret; +} + +static int do_cache_lookup_nowait (struct cache_detail *cd, +struct nfs_dns_ent *key, +struct nfs_dns_ent **item) +{ +int ret = -ENOMEM ; + + *item =nfs_dns_lookup (cd, key); +if (!*item) + goto out_err; + ret = -ETIMEDOUT ; +if (!test_bit (CACHE_VALID , &(*item)->h.flags) + || (*item)->h.expiry_time <get_seconds () + || cd->flush_time > (*item)->h.last_refresh) + goto out_put; + ret = -ENOENT ; +if (test_bit (CACHE_NEGATIVE , &(*item)->h.flags)) + goto out_put; +return 0 ; +out_put: +cache_put (&(*item)->h, cd); +out_err: + *item =NULL ; +return ret; +} + +static int do_cache_lookup_wait (struct cache_detail *cd, +struct nfs_dns_ent *key, +struct nfs_dns_ent **item) +{ +struct nfs_cache_defer_req *dreq; +int ret = -ENOMEM ; + + dreq =nfs_cache_defer_req_alloc (); +if (!dreq) + goto out; + ret =do_cache_lookup (cd, key, item, dreq); +if (ret == -EAGAIN ) { + ret =nfs_cache_wait_for_upcall (dreq); +if (!ret) + ret =do_cache_lookup_nowait (cd, key, item); + } +nfs_cache_defer_req_put (dreq); +out: +return ret; +} + +ssize_t nfs_dns_resolve_name (char *name,size_t namelen, +struct sockaddr *sa,size_t salen) +{ +struct nfs_dns_ent key = { + .hostname = name, + .namelen = namelen, + }; +struct nfs_dns_ent *item =NULL ; +ssize_t ret; + + ret =do_cache_lookup_wait (&nfs_dns_resolve, &key, &item); +if (ret ==0 ) { +if (salen >= item->addrlen) { +memcpy (sa, &item->addr, item->addrlen); + ret = item->addrlen; + }else + ret = -EOVERFLOW ; +cache_put (&item->h, &nfs_dns_resolve); + }else if (ret == -ENOENT ) + ret = -ESRCH ; +return ret; +} + +int nfs_dns_resolver_init (void ) +{ +return nfs_cache_register (&nfs_dns_resolve); +} + +void nfs_dns_resolver_destroy (void ) +{ +nfs_cache_unregister (&nfs_dns_resolve); +} +fs/nfs/dns_resolve.h new file +0
-0
fs/nfs/dns_resolve.h line 7
Quoted 7 lines
fs/nfs/dns_resolve.h new file +7
-0@@ -0,0 +1,14 @@ +/* +* Resolve DNS hostnames into valid ip addresses +*/ +#ifndef __LINUX_FS_NFS_DNS_RESOLVE_H +#define __LINUX_FS_NFS_DNS_RESOLVE_H + +#define NFS_DNS_HOSTNAME_MAXLEN (128)
It looks like you are using this to size the target buffer for a presentation address, not a hostname. Perhaps you should use INET6_ADDRSTRLEN+IPV6_SCOPEID_LEN+1 here instead, and/or change the name of the macro.
Quoted 34 lines
fs/nfs/dns_resolve.h new file +7
-0+ +extern int nfs_dns_resolver_init (void ); +extern void nfs_dns_resolver_destroy (void ); +extern ssize_t nfs_dns_resolve_name (char *name,size_t namelen, +struct sockaddr *sa,size_t salen); + +#endif fs/nfs/inode.c +5
-0@@ -46,6 +46,7 @@#include "iostat.h" #include "internal.h" #include "fscache.h" +#include "dns_resolve.h" #define NFSDBG_FACILITY NFSDBG_VFS@@ -1506,6 +1507,10 @@ static int __init init_nfs_fs(void) {int err; + err =nfs_dns_resolver_init (); +if (err <0 ) + goto out8; + err =nfs_fscache_register ();if (err <0 ) goto out7;@@ -1564,6 +1569,8 @@ out5:out6:
nfs_fscache_unregister();out7:
fs/nfs/inode.c out5: · line 1573
Quoted 2 lines
fs/nfs/inode.c +2
-0+nfs_dns_resolver_destroy (); +out8:
This init routine is getting cumbersome. Eventually could we provide an array of function pointers and call them in a loop?
Quoted 47 lines
return err; }fs/nfs/inode.c +1
-0@@ -1575,6 +1582,7 @@ static void __exit exit_nfs_fs(void)nfs_destroy_inodecache ();nfs_destroy_nfspagecache ();nfs_fscache_unregister (); +nfs_dns_resolver_destroy ();#ifdef CONFIG_PROC_FS rpc_proc_unregister ("nfs" );#endif net/sunrpc/rpc_pipe.c +7
-0@@ -416,11 +416,13 @@ struct vfsmount *rpc_get_mount(void)return ERR_PTR (err);return rpc_mount; } +EXPORT_SYMBOL_GPL (rpc_get_mount);void rpc_put_mount (void ) {simple_release_fs (&rpc_mount, &rpc_mount_count); } +EXPORT_SYMBOL_GPL (rpc_put_mount);static int rpc_delete_dentry (struct dentry *dentry) {@@ -946,6 +948,7 @@ enum { RPCAUTH_portmap, RPCAUTH_statd, RPCAUTH_nfsd4_cb, + RPCAUTH_cache, RPCAUTH_RootEOF };@@ -974,6 +977,10 @@ static const struct rpc_filelist files[] = { .name = "nfsd4_cb", .mode = S_IFDIR | S_IRUGO | S_IXUGO, }, + [RPCAUTH_cache] = { + .name = "cache", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, };
Quoted 7 lines
static int
Signature · 5 lines
1.6.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
Quoted 31 lines · Chuck Lever
Quoted 31 lines
Documentation/filesystems/nfs.txt new file +31
-0+A basic sample /sbin/nfs_cache_getent +===================================== + +#!/bin/bash +# +ttl=600 +# +cut=/usr/bin/cut +getent=/usr/bin/getent +rpc_pipefs=/var/lib/nfs/rpc_pipefs +# +die() +{ + echo "Usage: $0 cache_name entry_name" + exit 1 +} + +[ $# -lt 2 ] && die +cachename="$1" +cache_path=${rpc_pipefs}/cache/${cachename}/channel + +case "${cachename}" in + dns_resolve) + name="$2" + result="$(${getent} hosts ${name} | ${cut} -f1 -d\ )" + [ -z "${result}" ] && result="0" + ;; + *) + die + ;; +esac
Quoted 8 lines
Documentation/filesystems/nfs.txt line 98
Quoted 2 lines
Documentation/filesystems/nfs.txt new file +2
-0+echo "${result} ${name} ${ttl}" >${cache_path} +Instead of having a single script with a big case statement in it, why not have a directory containing a bunch of smaller, more specific, scripts? Common code can be "sourced" from a separate file. Some of these scripts may want to do more (or less) than writing into an
rpc_pipefsfile.
I'm not too concerned. As it says above, this is a sample that illustrates how you could do it. It does work, though, so people can definitely use it to test the functionality.
Quoted 11 lines
fs/nfs/cache_lib.c line 57
Quoted 7 lines
fs/nfs/cache_lib.c new file +7
-0+* Disable the upcall mechanism if we're getting an ENOENT or +* EACCES error. The admin can re-enable it on the fly by using +* sysfs to set the 'cache_getent' parameter once the problem +* has been fixed. +*/ +if (ret == -ENOENT || ret == -EACCES ) + nfs_cache_getent_prog[0 ] ='\0' ;What's the risk of continuing to invoke the upcall script if it doesn't exist? If it's happening frequently I would expect that the lack of the file would be cached, so it would still be a quick failure.
Yes, but if the upcall script fails, we want to fall back to trying the pipe upcall mechanism.
Quoted 7 lines
fs/nfs/dns_resolve.c line 24
Quoted 2 lines
fs/nfs/dns_resolve.c new file +2
-0+#define NFS_DNS_HASHBITS 4 +#define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS)So the hash table is only 16 buckets. Is it really worth the trouble of keeping a small cache of hostname lookups in the kernel? I guess I don't have a clear idea of how often you need to handle DNS resolution for
FS_LOCATIONS.
At the moment, the number of referrals out there are few, but we're expecting that to grow when the whole federated fs management infrastructure develops.
Quoted 3 lines
The garbage collection mechanism for expired entries isn't obvious. Without one I would expect this cache to grow enough that inserting and looking up valid entries might become expensive.
It uses the same garbage collection mechanisms that the nfsd caches use. Try it...
Quoted 6 lines
fs/nfs/dns_resolve.c line 85
Quoted 4 lines
fs/nfs/dns_resolve.c new file +4
-0+static unsigned int nfs_dns_hash (const struct nfs_dns_ent *key) +{ +return hash_str (key->hostname,NFS_DNS_HASHBITS ); +}Any idea how well this hash function works for hostnames?
No, but it is the same one nfsd uses for its version of the same cache, so I assume that it is appropriate.
Quoted 6 lines
Quoted 1 line
+#define
NFS_DNS_HOSTNAME_MAXLEN(128)It looks like you are using this to size the target buffer for a presentation address, not a hostname. Perhaps you should use INET6_ADDRSTRLEN+IPV6_SCOPEID_LEN+1 here instead, and/or change the name of the macro.
No. I'm using it primarily to store the hostname. See nfs_dns_parse().
Quoted 4 lines
Quoted 4 lines
fs/nfs/inode.c +0
-0@@ -1506,6 +1507,10 @@ static int __init init_nfs_fs(void) {int err;
Quoted 16 lines
fs/nfs/inode.c out5: · line 1573
Quoted 13 lines
fs/nfs/inode.c +4
-0+ err =nfs_dns_resolver_init (); +if (err <0 ) + goto out8; + err =nfs_fscache_register ();if (err <0 ) goto out7;@@ -1564,6 +1569,8 @@ out5:out6:
nfs_fscache_unregister();out7:
fs/nfs/inode.c +2
-0+nfs_dns_resolver_destroy (); +out8:This init routine is getting cumbersome. Eventually could we provide an array of function pointers and call them in a loop?
The annoyance comes primarily from the need to call the *_destroy() functions on error. It would be better to just call exit_nfs_fs().
Signature · 6 lines
Trond Myklebust Linux NFS client maintainer NetApp [email protected] www.netapp.com
A message that is not in the archive (sent off-list or not yet received): 1250785542.19156.12.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
Quoted 41 lines · Trond Myklebust
Quoted 31 lines · Chuck Lever
Quoted 31 lines
Documentation/filesystems/nfs.txt new file +31
-0+A basic sample /sbin/nfs_cache_getent +===================================== + +#!/bin/bash +# +ttl=600 +# +cut=/usr/bin/cut +getent=/usr/bin/getent +rpc_pipefs=/var/lib/nfs/rpc_pipefs +# +die() +{ + echo "Usage: $0 cache_name entry_name" + exit 1 +} + +[ $# -lt 2 ] && die +cachename="$1" +cache_path=${rpc_pipefs}/cache/${cachename}/channel + +case "${cachename}" in + dns_resolve) + name="$2" + result="$(${getent} hosts ${name} | ${cut} -f1 -d\ )" + [ -z "${result}" ] && result="0" + ;; + *) + die + ;; +esacQuoted 8 lines
Documentation/filesystems/nfs.txt line 98
Quoted 2 lines
Documentation/filesystems/nfs.txt new file +2
-0+echo "${result} ${name} ${ttl}" >${cache_path} +Instead of having a single script with a big case statement in it, why not have a directory containing a bunch of smaller, more specific, scripts? Common code can be "sourced" from a separate file. Some of these scripts may want to do more (or less) than writing into an
rpc_pipefsfile.
Quoted 3 lines
I'm not too concerned. As it says above, this is a sample that illustrates how you could do it. It does work, though, so people can definitely use it to test the functionality.
I'm thinking of when we want to add new upcalls, since you went to some length to generalize this facility. It would be easier to manage adding a new script than it would to update an existing one, and an admin or distributor could control what scripts are present, or provide their own.
The act of editing a single script is easy enough, but then you have to worry about updates from the distributor possibly overwriting the local modifications, and so on, and so on.
A model like /etc/init.d might be easier to manage in the long run.
Quoted 12 lines
Quoted 11 lines
fs/nfs/cache_lib.c line 57
Quoted 7 lines
fs/nfs/cache_lib.c new file +7
-0+* Disable the upcall mechanism if we're getting an ENOENT or +* EACCES error. The admin can re-enable it on the fly by using +* sysfs to set the 'cache_getent' parameter once the problem +* has been fixed. +*/ +if (ret == -ENOENT || ret == -EACCES ) + nfs_cache_getent_prog[0 ] ='\0' ;What's the risk of continuing to invoke the upcall script if it doesn't exist? If it's happening frequently I would expect that the lack of the file would be cached, so it would still be a quick failure.
Quoted 2 lines
Yes, but if the upcall script fails, we want to fall back to trying the pipe upcall mechanism.
Makes sense, but that important detail is not clear from the documenting comment.
Quoted 11 lines
Quoted 7 lines
fs/nfs/dns_resolve.c line 24
Quoted 2 lines
fs/nfs/dns_resolve.c new file +2
-0+#define NFS_DNS_HASHBITS 4 +#define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS)So the hash table is only 16 buckets. Is it really worth the trouble of keeping a small cache of hostname lookups in the kernel? I guess I don't have a clear idea of how often you need to handle DNS resolution for
FS_LOCATIONS.At the moment, the number of referrals out there are few, but we're expecting that to grow when the whole federated fs management infrastructure develops.
OK. Can you give some sense of quantity?
Quoted 9 lines
Quoted 6 lines
fs/nfs/dns_resolve.c line 85
Quoted 4 lines
fs/nfs/dns_resolve.c new file +4
-0+static unsigned int nfs_dns_hash (const struct nfs_dns_ent *key) +{ +return hash_str (key->hostname,NFS_DNS_HASHBITS ); +}Any idea how well this hash function works for hostnames?
No, but it is the same one nfsd uses for its version of the same cache, so I assume that it is appropriate.
A brief scan shows that it's hashing for username@host for idmapping, but not for hostnames only (which might be missing randomness of the username@ part). A detail, for sure, but it would be reasonable to verify at some point as the size of the cache increases.
Quoted 8 lines
Quoted 6 lines
Quoted 1 line
+#define
NFS_DNS_HOSTNAME_MAXLEN(128)It looks like you are using this to size the target buffer for a presentation address, not a hostname. Perhaps you should use INET6_ADDRSTRLEN+IPV6_SCOPEID_LEN+1 here instead, and/or change the name of the macro.
No. I'm using it primarily to store the hostname. See
nfs_dns_parse().
OK, you store the presentation address in buf1 first, and now I see that farther down you are storing the hostname too. But note that the maximum size of a hostname is 1024 (see the definition of NI_MAXHOST in user space).
If there is a protocol specified limit on the hostname string returned via FS_LOCATION, perhaps that should be noted here. Otherwise, 128 is too small, I think.
--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
Quoted 10 lines · Chuck Lever
Quoted 3 lines
I'm not too concerned. As it says above, this is a sample that illustrates how you could do it. It does work, though, so people can definitely use it to test the functionality.
I'm thinking of when we want to add new upcalls, since you went to some length to generalize this facility. It would be easier to manage adding a new script than it would to update an existing one, and an admin or distributor could control what scripts are present, or provide their own.
Quoted 5 lines
The act of editing a single script is easy enough, but then you have to worry about updates from the distributor possibly overwriting the local modifications, and so on, and so on.
A model like
/etc/init.dmight be easier to manage in the long run.
True, and we might want to consider adding something like that into nfs-utils.
Yes, I did generalise the facility: I'm planning on redoing the NFSv4 idmapper at some point soon.
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
fs/nfs/dns_resolve.c line 24
Quoted 2 lines
fs/nfs/dns_resolve.c new file +2
-0+#define NFS_DNS_HASHBITS 4 +#define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS)So the hash table is only 16 buckets. Is it really worth the trouble of keeping a small cache of hostname lookups in the kernel? I guess I
don't have a clear idea of how often you need to handle DNS resolution
forFS_LOCATIONS.
Quoted 5 lines
Quoted 3 lines
At the moment, the number of referrals out there are few, but we're expecting that to grow when the whole federated fs management infrastructure develops.
OK. Can you give some sense of quantity?
Could be in the hundreds in a large organisation. Then again, if we go do the equivalent of /afs, it could be in the thousands. We'll see how that turns out.
Quoted 9 lines
Quoted 8 lines
Quoted 6 lines
Quoted 1 line
+#define
NFS_DNS_HOSTNAME_MAXLEN(128)It looks like you are using this to size the target buffer for a presentation address, not a hostname. Perhaps you should use INET6_ADDRSTRLEN+IPV6_SCOPEID_LEN+1 here instead, and/or change the name of the macro.
No. I'm using it primarily to store the hostname. See
nfs_dns_parse().
Quoted 8 lines
OK, you store the presentation address in buf1 first, and now I see that farther down you are storing the hostname too. But note that the maximum size of a hostname is 1024 (see the definition of
NI_MAXHOSTin user space).If there is a protocol specified limit on the hostname string returned via
FS_LOCATION, perhaps that should be noted here. Otherwise, 128 is too small, I think.
There is no limit in the protocol, but DNS names that are larger than 64 bytes will not fit into a Linux utsname structure. For that reason, I think 128 characters is sufficient.
Anybody who has to type www.<122 characters>.com has my sympathy, and deepest regrets...
Signature · 6 lines
Trond Myklebust Linux NFS client maintainer NetApp [email protected] www.netapp.com
A message that is not in the archive (sent off-list or not yet received): 1250795483.26904.6.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
Quoted 15 lines · Trond Myklebust
Quoted 14 lines · Chuck Lever
Quoted 3 lines
I'm not too concerned. As it says above, this is a sample that illustrates how you could do it. It does work, though, so people can definitely use it to test the functionality.
I'm thinking of when we want to add new upcalls, since you went to some length to generalize this facility. It would be easier to manage adding a new script than it would to update an existing one, and an admin or distributor could control what scripts are present, or provide their own.
The act of editing a single script is easy enough, but then you have to worry about updates from the distributor possibly overwriting the local modifications, and so on, and so on.
Quoted 7 lines
Quoted 1 line
A model like
/etc/init.dmight be easier to manage in the long run.True, and we might want to consider adding something like that into nfs-utils.
Yes, I did generalise the facility: I'm planning on redoing the NFSv4 idmapper at some point soon.
It might also work well for an in-kernel statd implementation. The user script component could manage the persistent monitored host database, and everything else would live in the kernel.
--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
In reply to Trond MyklebustQuoted 1 line · Trond Myklebust
The NFSv4 and NFSv4.1 protocols both allow for the redirection of a c=
lient
Quoted 1 line
from one server to another in order to support filesystem migration a=
nd
Quoted 2 lines
replication. For full protocol support, we need to add the ability to convert a DNS host name into an IP address that we can feed to the RP=
C
Quoted 1 line
client.
Your current nfs-for-2.6.32 doesn't compile for me:
In file included from fs/nfs/cache_lib.c:14: include/linux/sunrpc/rpc_pipe_fs.h:35: error: field =E2=80=98queue_tim=
eout=E2=80=99 has incomplete type
(I wonder why you weren't seeing this?)
--b.
Quoted 2 lines
=20
We'll reuse the sunrpc cache, now that it has been converted to work =
with
Quoted 10 lines
rpc_pipefs.
=20Signed-off-by Trond Myklebust <[email protected]>--- Documentation/filesystems/nfs.txt | 98 ++++++++++ Documentation/kernel-parameters.txt | 8 + fs/nfs/Makefile | 3 +- fs/nfs/cache_lib.c | 140 +++++++++++++++ fs/nfs/cache_lib.h | 27 +++
fs/nfs/dns_resolve.c| 335 +++++++++++++++++++++++++=
++++++++++
Documentation/filesy=
Quoted 11 lines
fs/nfs/dns_resolve.h | 14 ++ fs/nfs/inode.c | 8 + net/sunrpc/rpc_pipe.c | 7 + 9 files changed, 639 insertions(+), 1 deletions(-) create mode 100644 Documentation/filesystems/nfs.txt create mode 100644 fs/nfs/cache_lib.c create mode 100644 fs/nfs/cache_lib.h create mode 100644 fs/nfs/dns_resolve.c create mode 100644 fs/nfs/dns_resolve.h=20
Documentation/filesy= renamed from Documentation/filesystems/nfs.txt +0
-0
stems/nfs.txt
Documentation/filesystems/nfs.txt line 5
Quoted 10 lines
new file mode 100644
index 0000000..f50f26cDocumentation/filesystems/nfs.txt new file +5
-0@@ -0,0 +1,98 @@ + +The NFS client +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The NFS version 2 protocol was first documented in RFC1094 (March 19=
89).
Documentation/filesystems/nfs.txt line 6
Quoted 1 line
Documentation/filesystems/nfs.txt new file +1
-0+Since then two more major releases of NFS have been published, with =
NFSv3
Documentation/filesystems/nfs.txt
Quoted 4 lines
Documentation/filesystems/nfs.txt new file +4
-0+being documented in RFC1813 (June 1995), and NFSv4 in RFC3530 (April +2003). + +The Linux NFS client currently supports all the above published vers=
ions,
Documentation/filesystems/nfs.txt line 11
Quoted 1 line
Documentation/filesystems/nfs.txt new file +1
-0+and work is in progress on adding support for minor version 1 of the=
NFSv4
Documentation/filesystems/nfs.txt
Quoted 3 lines
Documentation/filesystems/nfs.txt new file +3
-0+protocol. + +The purpose of this document is to provide information on some of th=
e
Documentation/filesystems/nfs.txt line 15
Quoted 1 line
Documentation/filesystems/nfs.txt new file +1
-0+upcall interfaces that are used in order to provide the NFS client w=
ith
Documentation/filesystems/nfs.txt line 16
Quoted 1 line
Documentation/filesystems/nfs.txt new file +1
-0+some of the information that it requires in order to fully comply wi=
th
Documentation/filesystems/nfs.txt
Quoted 6 lines
Documentation/filesystems/nfs.txt new file +6
-0+the NFS spec. + +The DNS resolver +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +NFSv4 allows for one server to refer the NFS client to data that has=
been
Documentation/filesystems/nfs.txt
Quoted 7 lines
Documentation/filesystems/nfs.txt new file +7
-0+migrated onto another server by means of the special "fs_locations" +attribute. See + http://tools.ietf.org/html/rfc3530#section-6 +and + http://tools.ietf.org/html/draft-ietf-nfsv4-referrals-00 + +The fs_locations information can take the form of either an ip addre=
ss and
Documentation/filesystems/nfs.txt line 30
Quoted 1 line
Documentation/filesystems/nfs.txt new file +1
-0+a path, or a DNS hostname and a path. The latter requires the NFS cl=
ient to
Documentation/filesystems/nfs.txt line 31
Quoted 1 line
Documentation/filesystems/nfs.txt new file +1
-0+do a DNS lookup in order to mount the new volume, and hence the need=
for an
Documentation/filesystems/nfs.txt
Quoted 3 lines
Documentation/filesystems/nfs.txt new file +3
-0+upcall to allow userland to provide this service. + +Assuming that the user has the 'rpc_pipefs' filesystem mounted in th=
e usual
Documentation/filesystems/nfs.txt
Quoted 3 lines
Documentation/filesystems/nfs.txt new file +3
-0+/var/lib/nfs/rpc_pipefs, the upcall consists of the following steps: + + (1) The process checks the dns_resolve cache to see if it contain=
s a
Documentation/filesystems/nfs.txt
Quoted 3 lines
Documentation/filesystems/nfs.txt new file +3
-0+ valid entry. If so, it returns that entry and exits. + + (2) If no valid entry exists, the helper script '/sbin/nfs_cache_=
getent'
Documentation/filesystems/nfs.txt line 41
Quoted 1 line
Documentation/filesystems/nfs.txt new file +1
-0+ (may be changed using the 'nfs.cache_getent' kernel boot para=
meter)
Documentation/filesystems/nfs.txt
Quoted 5 lines
Documentation/filesystems/nfs.txt new file +5
-0+ is run, with two arguments: + - the cache name, "dns_resolve" + - the hostname to resolve + + (3) After looking up the corresponding ip address, the helper scr=
ipt
Documentation/filesystems/nfs.txt
Quoted 7 lines
Documentation/filesystems/nfs.txt new file +7
-0+ writes the result into the rpc_pipefs pseudo-file + '/var/lib/nfs/rpc_pipefs/cache/dns_resolve/channel' + in the following (text) format: + + "<ip address> <hostname> <ttl>\n" + + Where <ip address> is in the usual IPv4 (123.456.78.90) or IP=
v6
Documentation/filesystems/nfs.txt line 54
Quoted 1 line
Documentation/filesystems/nfs.txt new file +1
-0+ (ffee:ddcc:bbaa:9988:7766:5544:3322:1100, ffee::1100, ...) fo=
rmat.
Documentation/filesystems/nfs.txt line 56
Quoted 2 lines
Documentation/filesystems/nfs.txt new file +2
-0+ <hostname> is identical to the second argument of the helper + script, and <ttl> is the 'time to live' of this cache entry (=
in
Documentation/filesystems/nfs.txt
Quoted 3 lines
Documentation/filesystems/nfs.txt new file +3
-0+ units of seconds). + + Note: If <ip address> is invalid, say the string "0", then a =
negative
Documentation/filesystems/nfs.txt line 60
Quoted 1 line
Documentation/filesystems/nfs.txt new file +1
-0+ entry is created, which will cause the kernel to treat the ho=
stname
Documentation/filesystems/nfs.txt
Quoted 7 lines
Documentation/filesystems/nfs.txt new file +7
-0+ as having no valid DNS translation. + + + + +A basic sample /sbin/nfs_cache_getent +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
Documentation/kern=
Quoted 32 lines
Documentation/filesystems/nfs.txt new file +31
-0+ +#!/bin/bash +# +ttl=3D600 +# +cut=3D/usr/bin/cut +getent=3D/usr/bin/getent +rpc_pipefs=3D/var/lib/nfs/rpc_pipefs +# +die() +{ + echo "Usage: $0 cache_name entry_name" + exit 1 +} + +[ $# -lt 2 ] && die +cachename=3D"$1" +cache_path=3D${rpc_pipefs}/cache/${cachename}/channel + +case "${cachename}" in + dns_resolve) + name=3D"$2" + result=3D"$(${getent} hosts ${name} | ${cut} -f1 -d\ )" + [ -z "${result}" ] && result=3D"0" + ;; + *) + die + ;; +esac +echo "${result} ${name} ${ttl}" >${cache_path} +Documentation/kern= renamed from Documentation/kernel-parameters.txt +0
-0
el-parameters.txt
Documentation/kernel-parameters.txt and is between 256 and 4096 characters. It is =
Quoted 4 lines
index 2f18206..4d0ed96 100644
Documentation/kernel-parameters.txt +0
-0@@ -1499,6 +1499,14 @@ and is between 256 and 4096 characters. It is =
defined in the file
Quoted 19 lines
Documentation/kernel-parameters.txt +0
-0[NFS] set the TCP port on which the NFSv4 callback channel should listen.=20
Documentation/kernel-parameters.txt +8
-0+ nfs.cache_getent=3D + [NFS] sets the pathname to the program which is used + to update the NFS client cache entries. + + nfs.cache_getent_timeout=3D + [NFS] sets the timeout after which an attempt to + update a cache entry is deemed to have failed. + nfs.idmap_cache_timeout=3D [NFS] set the maximum lifetime for idmapper cache entries.fs/nfs/Makefile +0
-0@@ -6,7 +6,8 @@ obj-$(CONFIG_NFS_FS) +=3D nfs.o
Quoted 2 lines
=20
nfs-y :=3D client.o dir.o file.o getroot.o inode.o super.o nfs2xd=
r.o \
Quoted 26 lines
fs/nfs/Makefile +2
-1direct.o pagelist.o proc.o read.o symlink.o unlink.o \ - write.o namespace.o mount_clnt.o + write.o namespace.o mount_clnt.o \ + dns_resolve.o cache_lib.o nfs-$(CONFIG_ROOT_NFS) +=3D nfsroot.o nfs-$(CONFIG_NFS_V3) +=3D nfs3proc.o nfs3xdr.o nfs-$(CONFIG_NFS_V3_ACL) +=3D nfs3acl.ofs/nfs/cache_lib.c new file +13
-0@@ -0,0 +1,140 @@ +/* +* linux/fs/nfs/cache_lib.c +* +* Helper routines for the NFS client caches +* +* Copyright (c) 2009 Trond Myklebust <[email protected]> +*/ +#include <linux/kmod.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/mount.h> +#include <linux/namei.h> +#include <linux/sunrpc/cache.h>
fs/nfs/cache_lib.c line 23
Quoted 10 lines
fs/nfs/cache_lib.c new file +10
-0+#include <linux/sunrpc/rpc_pipe_fs.h> + +#include "cache_lib.h" + +#define NFS_CACHE_UPCALL_PATHLEN 256 +#define NFS_CACHE_UPCALL_TIMEOUT 15 + +static char nfs_cache_getent_prog[NFS_CACHE_UPCALL_PATHLEN] =3D +"/sbin/nfs_cache_getent" ; +static unsigned long nfs_cache_getent_timeout =3D NFS_CACHE_UPCALL_T=
IMEOUT;
fs/nfs/cache_lib.c
Quoted 4 lines
fs/nfs/cache_lib.c new file +4
-0+ +module_param_string (cache_getent, nfs_cache_getent_prog, +sizeof (nfs_cache_getent_prog),0600 ); +MODULE_PARM_DESC(cache_getent, "Path to the client cache upcall prog=
ram");
fs/nfs/cache_lib.c line 28
Quoted 1 line
fs/nfs/cache_lib.c new file +1
-0+module_param_named(cache_getent_timeout, nfs_cache_getent_timeout, u=
long, 0600);
fs/nfs/cache_lib.c line 29
Quoted 1 line
fs/nfs/cache_lib.c new file +1
-0+MODULE_PARM_DESC(cache_getent_timeout, "Timeout (in seconds) after w=
hich "
Quoted 32 lines
fs/nfs/cache_lib.c new file +32
-0+ "the cache upcall is assumed to have failed"); + +int nfs_cache_upcall (struct cache_detail *cd,char *entry_name) +{ + static char *envp[] =3D { "HOME=3D/", +"TERM=3Dlinux" , +"PATH=3D/sbin:/usr/sbin:/bin:/usr/bin" , +NULL + }; + char *argv[] =3D { + nfs_cache_getent_prog, + cd->name, + entry_name, +NULL + }; +int ret =3D -EACCES ; + + if (nfs_cache_getent_prog[0] =3D=3D '\0') + goto out; + ret =3D call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); +/* +* Disable the upcall mechanism if we're getting an ENOENT or +* EACCES error. The admin can re-enable it on the fly by using +* sysfs to set the 'cache_getent' parameter once the problem +* has been fixed. +*/ + if (ret =3D=3D -ENOENT || ret =3D=3D -EACCES) + nfs_cache_getent_prog[0] =3D '\0'; +out: +return ret >0 ?0 : ret; +} +
fs/nfs/cache_lib.c
Quoted 10 lines
fs/nfs/cache_lib.c new file +10
-0+/* +* Deferred request handling +*/ +void nfs_cache_defer_req_put (struct nfs_cache_defer_req *dreq) +{ +if (atomic_dec_and_test (&dreq->count)) +kfree (dreq); +} + +static void nfs_dns_cache_revisit(struct cache_deferred_req *d, int =
toomany)
fs/nfs/cache_lib.c
Quoted 10 lines
fs/nfs/cache_lib.c new file +10
-0+{ +struct nfs_cache_defer_req *dreq; + + dreq =3D container_of(d, struct nfs_cache_defer_req, deferred_req); + +complete_all (&dreq->completion); +nfs_cache_defer_req_put (dreq); +} + +static struct cache_deferred_req *nfs_dns_cache_defer(struct cache_r=
eq *req)
Quoted 76 lines
fs/nfs/cache_lib.c new file +59
-0+{ +struct nfs_cache_defer_req *dreq; + + dreq =3D container_of(req, struct nfs_cache_defer_req, req); + dreq->deferred_req.revisit =3D nfs_dns_cache_revisit; +atomic_inc (&dreq->count); + +return &dreq->deferred_req; +} + +struct nfs_cache_defer_req *nfs_cache_defer_req_alloc (void ) +{ +struct nfs_cache_defer_req *dreq; + + dreq =3D kzalloc(sizeof(*dreq), GFP_KERNEL); +if (dreq) { +init_completion (&dreq->completion); +atomic_set (&dreq->count,1 ); + dreq->req.defer =3D nfs_dns_cache_defer; + } +return dreq; +} + +int nfs_cache_wait_for_upcall (struct nfs_cache_defer_req *dreq) +{ +if (wait_for_completion_timeout (&dreq->completion, + nfs_cache_getent_timeout * HZ) =3D=3D 0) +return -ETIMEDOUT ; +return 0 ; +} + +int nfs_cache_register (struct cache_detail *cd) +{ +struct nameidata nd; +struct vfsmount *mnt; +int ret; + + mnt =3D rpc_get_mount(); +if (IS_ERR (mnt)) +return PTR_ERR (mnt); + ret =3D vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &nd); +if (ret) + goto err; + ret =3D sunrpc_cache_register_pipefs(nd.path.dentry, + cd->name,0600 , cd); +path_put (&nd.path); +if (!ret) +return ret; +err: +rpc_put_mount (); +return ret; +} + +void nfs_cache_unregister (struct cache_detail *cd) +{ +sunrpc_cache_unregister_pipefs (cd); +rpc_put_mount (); +} +fs/nfs/cache_lib.h new file +11
-0@@ -0,0 +1,27 @@ +/* +* Helper routines for the NFS client caches +* +* Copyright (c) 2009 Trond Myklebust <[email protected]> +*/ + +#include <linux/completion.h> +#include <linux/sunrpc/cache.h> +#include <asm/atomic.h> + +/*
fs/nfs/cache_lib.h line 21
Quoted 10 lines
fs/nfs/cache_lib.h new file +10
-0+* Deferred request handling +*/ +struct nfs_cache_defer_req { +struct cache_req req; +struct cache_deferred_req deferred_req; +struct completion completion; +atomic_t count; +}; + +extern int nfs_cache_upcall(struct cache_detail *cd, char *entry_nam=
e);
fs/nfs/cache_lib.h line 23
Quoted 2 lines
fs/nfs/cache_lib.h new file +2
-0+extern struct nfs_cache_defer_req *nfs_cache_defer_req_alloc (void ); +extern void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq=
);
fs/nfs/cache_lib.h line 24
Quoted 1 line
fs/nfs/cache_lib.h new file +1
-0+extern int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dre=
q);
Quoted 48 lines
fs/nfs/cache_lib.h new file +3
-0+ +extern int nfs_cache_register (struct cache_detail *cd); +extern void nfs_cache_unregister (struct cache_detail *cd);fs/nfs/dns_resolve.c new file +39
-0@@ -0,0 +1,335 @@ +/* +* linux/fs/nfs/dns_resolve.c +* +* Copyright (c) 2009 Trond Myklebust <[email protected]> +* +* Resolves DNS hostnames into valid ip addresses +*/ + +#include <linux/hash.h> +#include <linux/string.h> +#include <linux/kmod.h> +#include <linux/module.h> +#include <linux/socket.h> +#include <linux/seq_file.h> +#include <linux/inet.h> +#include <linux/sunrpc/clnt.h> +#include <linux/sunrpc/cache.h> +#include <linux/sunrpc/svcauth.h> + +#include "dns_resolve.h" +#include "cache_lib.h" + +#define NFS_DNS_HASHBITS 4 +#define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS) + +static struct cache_head *nfs_dns_table[NFS_DNS_HASHTBL_SIZE ]; + +struct nfs_dns_ent { +struct cache_head h; + +char *hostname; +size_t namelen; + +struct sockaddr_storage addr; +size_t addrlen; +}; + + +static void nfs_dns_ent_init(struct cache_head *cnew,
fs/nfs/dns_resolve.c line 49
Quoted 10 lines
fs/nfs/dns_resolve.c new file +10
-0+ struct cache_head *ckey) +{ +struct nfs_dns_ent *new; +struct nfs_dns_ent *key; + + new =3D container_of(cnew, struct nfs_dns_ent, h); + key =3D container_of(ckey, struct nfs_dns_ent, h); + +kfree (new->hostname); + new->hostname =3D kstrndup(key->hostname, key->namelen, GFP_KERNEL)=
;
Quoted 32 lines
fs/nfs/dns_resolve.c new file +32
-0+if (new->hostname) { + new->namelen =3D key->namelen; +memcpy (&new->addr, &key->addr, key->addrlen); + new->addrlen =3D key->addrlen; + }else { + new->namelen =3D 0; + new->addrlen =3D 0; + } +} + +static void nfs_dns_ent_put (struct kref *ref) +{ +struct nfs_dns_ent *item; + + item =3D container_of(ref, struct nfs_dns_ent, h.ref); +kfree (item->hostname); +kfree (item); +} + +static struct cache_head *nfs_dns_ent_alloc (void ) +{ + struct nfs_dns_ent *item =3D kmalloc(sizeof(*item), GFP_KERNEL); + + if (item !=3D NULL) { + item->hostname =3D NULL; + item->namelen =3D 0; + item->addrlen =3D 0; +return &item->h; + } +return NULL ; +}; +
fs/nfs/dns_resolve.c
Quoted 10 lines
fs/nfs/dns_resolve.c new file +10
-0+static unsigned int nfs_dns_hash (const struct nfs_dns_ent *key) +{ +return hash_str (key->hostname,NFS_DNS_HASHBITS ); +} + +static void nfs_dns_request (struct cache_detail *cd, +struct cache_head *ch, +char **bpp,int *blen) +{ + struct nfs_dns_ent *key =3D container_of(ch, struct nfs_dns_ent, h)=
;
fs/nfs/dns_resolve.c
Quoted 9 lines
fs/nfs/dns_resolve.c new file +9
-0+ +qword_add (bpp, blen, key->hostname); + (*bpp)[-1] =3D '\n'; +} + +static int nfs_dns_upcall (struct cache_detail *cd, +struct cache_head *ch) +{ + struct nfs_dns_ent *key =3D container_of(ch, struct nfs_dns_ent, h)=
;
Quoted 66 lines
fs/nfs/dns_resolve.c new file +66
-0+int ret; + + ret =3D nfs_cache_upcall(cd, key->hostname); +if (ret) + ret =3D sunrpc_cache_pipe_upcall(cd, ch, nfs_dns_request); +return ret; +} + +static int nfs_dns_match (struct cache_head *ca, +struct cache_head *cb) +{ +struct nfs_dns_ent *a; +struct nfs_dns_ent *b; + + a =3D container_of(ca, struct nfs_dns_ent, h); + b =3D container_of(cb, struct nfs_dns_ent, h); + + if (a->namelen =3D=3D 0 || a->namelen !=3D b->namelen) +return 0 ; + return memcmp(a->hostname, b->hostname, a->namelen) =3D=3D 0; +} + +static int nfs_dns_show (struct seq_file *m,struct cache_detail *cd, +struct cache_head *h) +{ +struct nfs_dns_ent *item; +long ttl; + + if (h =3D=3D NULL) { +seq_puts (m,"# ip address hostname ttl\n" ); +return 0 ; + } + item =3D container_of(h, struct nfs_dns_ent, h); + ttl =3D (long)item->h.expiry_time - (long)get_seconds(); +if (ttl <0 ) + ttl =3D 0; + +if (!test_bit (CACHE_NEGATIVE , &h->flags)) { +char buf[INET6_ADDRSTRLEN +IPV6_SCOPE_ID_LEN +1 ]; + +rpc_ntop ((struct sockaddr *)&item->addr, buf,sizeof (buf)); +seq_printf (m,"%15s " , buf); + }else +seq_puts (m,"<none> " ); +seq_printf (m,"%15s %ld\n" , item->hostname, ttl); +return 0 ; +} + +struct nfs_dns_ent *nfs_dns_lookup (struct cache_detail *cd, +struct nfs_dns_ent *key) +{ +struct cache_head *ch; + + ch =3D sunrpc_cache_lookup(cd, + &key->h, +nfs_dns_hash (key)); +if (!ch) +return NULL ; + return container_of(ch, struct nfs_dns_ent, h); +} + +struct nfs_dns_ent *nfs_dns_update (struct cache_detail *cd, +struct nfs_dns_ent *new, +struct nfs_dns_ent *key) +{ +struct cache_head *ch;
fs/nfs/dns_resolve.c
Quoted 10 lines
fs/nfs/dns_resolve.c new file +10
-0+ + ch =3D sunrpc_cache_update(cd, + &new->h, &key->h, +nfs_dns_hash (key)); +if (!ch) +return NULL ; + return container_of(ch, struct nfs_dns_ent, h); +} + +static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buf=
len)
Quoted 254 lines
fs/nfs/dns_resolve.c new file +159
-0+{ +char buf1[NFS_DNS_HOSTNAME_MAXLEN +1 ]; +struct nfs_dns_ent key, *item; +unsigned long ttl; +ssize_t len; +int ret =3D -EINVAL ; + + if (buf[buflen-1] !=3D '\n') + goto out; + buf[buflen-1] =3D '\0'; + + len =3D qword_get(&buf, buf1, sizeof(buf1)); + if (len <=3D 0) + goto out; + key.addrlen =3D rpc_pton(buf1, len, + (struct sockaddr *)&key.addr, +sizeof (key.addr)); + + len =3D qword_get(&buf, buf1, sizeof(buf1)); + if (len <=3D 0) + goto out; + + key.hostname =3D buf1; + key.namelen =3D len; +memset (&key.h,0 ,sizeof (key.h)); + + ttl =3D get_expiry(&buf); + if (ttl =3D=3D 0) + goto out; + key.h.expiry_time =3D ttl + get_seconds(); + + ret =3D -ENOMEM ; + item =3D nfs_dns_lookup(cd, &key); + if (item =3D=3D NULL) + goto out; + + if (key.addrlen =3D=3D 0) +set_bit (CACHE_NEGATIVE , &key.h.flags); + + item =3D nfs_dns_update(cd, &key, item); + if (item =3D=3D NULL) + goto out; + + ret =3D 0; +cache_put (&item->h, cd); +out: +return ret; +} + +static struct cache_detail nfs_dns_resolve =3D { + .owner =3D THIS_MODULE, + .hash_size =3D NFS_DNS_HASHTBL_SIZE, + .hash_table =3D nfs_dns_table, + .name =3D "dns_resolve", + .cache_put =3D nfs_dns_ent_put, + .cache_upcall =3D nfs_dns_upcall, + .cache_parse =3D nfs_dns_parse, + .cache_show =3D nfs_dns_show, + .match =3D nfs_dns_match, + .init =3D nfs_dns_ent_init, + .update =3D nfs_dns_ent_init, + .alloc =3D nfs_dns_ent_alloc, +}; + +static int do_cache_lookup (struct cache_detail *cd, +struct nfs_dns_ent *key, +struct nfs_dns_ent **item, +struct nfs_cache_defer_req *dreq) +{ +int ret =3D -ENOMEM ; + + *item =3D nfs_dns_lookup(cd, key); +if (*item) { + ret =3D cache_check(cd, &(*item)->h, &dreq->req); +if (ret) + *item =3D NULL; + } +return ret; +} + +static int do_cache_lookup_nowait (struct cache_detail *cd, +struct nfs_dns_ent *key, +struct nfs_dns_ent **item) +{ +int ret =3D -ENOMEM ; + + *item =3D nfs_dns_lookup(cd, key); +if (!*item) + goto out_err; + ret =3D -ETIMEDOUT ; +if (!test_bit (CACHE_VALID , &(*item)->h.flags) + || (*item)->h.expiry_time <get_seconds () + || cd->flush_time > (*item)->h.last_refresh) + goto out_put; + ret =3D -ENOENT ; +if (test_bit (CACHE_NEGATIVE , &(*item)->h.flags)) + goto out_put; +return 0 ; +out_put: +cache_put (&(*item)->h, cd); +out_err: + *item =3D NULL; +return ret; +} + +static int do_cache_lookup_wait (struct cache_detail *cd, +struct nfs_dns_ent *key, +struct nfs_dns_ent **item) +{ +struct nfs_cache_defer_req *dreq; +int ret =3D -ENOMEM ; + + dreq =3D nfs_cache_defer_req_alloc(); +if (!dreq) + goto out; + ret =3D do_cache_lookup(cd, key, item, dreq); + if (ret =3D=3D -EAGAIN) { + ret =3D nfs_cache_wait_for_upcall(dreq); +if (!ret) + ret =3D do_cache_lookup_nowait(cd, key, item); + } +nfs_cache_defer_req_put (dreq); +out: +return ret; +} + +ssize_t nfs_dns_resolve_name (char *name,size_t namelen, +struct sockaddr *sa,size_t salen) +{ + struct nfs_dns_ent key =3D { + .hostname =3D name, + .namelen =3D namelen, + }; + struct nfs_dns_ent *item =3D NULL; +ssize_t ret; + + ret =3D do_cache_lookup_wait(&nfs_dns_resolve, &key, &item); + if (ret =3D=3D 0) { + if (salen >=3D item->addrlen) { +memcpy (sa, &item->addr, item->addrlen); + ret =3D item->addrlen; + }else + ret =3D -EOVERFLOW ; +cache_put (&item->h, &nfs_dns_resolve); + } else if (ret =3D=3D -ENOENT) + ret =3D -ESRCH ; +return ret; +} + +int nfs_dns_resolver_init (void ) +{ +return nfs_cache_register (&nfs_dns_resolve); +} + +void nfs_dns_resolver_destroy (void ) +{ +nfs_cache_unregister (&nfs_dns_resolve); +} +fs/nfs/dns_resolve.h new file +14
-0@@ -0,0 +1,14 @@ +/* +* Resolve DNS hostnames into valid ip addresses +*/ +#ifndef __LINUX_FS_NFS_DNS_RESOLVE_H +#define __LINUX_FS_NFS_DNS_RESOLVE_H + +#define NFS_DNS_HOSTNAME_MAXLEN (128) + +extern int nfs_dns_resolver_init (void ); +extern void nfs_dns_resolver_destroy (void ); +extern ssize_t nfs_dns_resolve_name (char *name,size_t namelen, +struct sockaddr *sa,size_t salen); + +#endif fs/nfs/inode.c +1
-0@@ -46,6 +46,7 @@#include "iostat.h" #include "internal.h" #include "fscache.h" +#include "dns_resolve.h" =20
#defineNFSDBG_FACILITYNFSDBG_VFS
=20fs/nfs/inode.c +0
-0@@ -1506,6 +1507,10 @@ static int __init init_nfs_fs(void) {int err;=20
fs/nfs/inode.c +6
-0+ err =3D nfs_dns_resolver_init(); +if (err <0 ) + goto out8; + err =3D nfs_fscache_register();if (err <0 ) goto out7;@@ -1564,6 +1569,8 @@ out5: out6:nfs_fscache_unregister (); out7: +nfs_dns_resolver_destroy (); +out8:return err; }=20
fs/nfs/inode.c +1
-0@@ -1575,6 +1582,7 @@ static void __exit exit_nfs_fs(void)nfs_destroy_inodecache ();nfs_destroy_nfspagecache ();nfs_fscache_unregister (); +nfs_dns_resolver_destroy ();#ifdef CONFIG_PROC_FS rpc_proc_unregister ("nfs" );#endif net/sunrpc/rpc_pipe.c +1
-0@@ -416,11 +416,13 @@ struct vfsmount *rpc_get_mount(void)return ERR_PTR (err);return rpc_mount; } +EXPORT_SYMBOL_GPL (rpc_get_mount);=20
voidrpc_put_mount(void)
{net/sunrpc/rpc_pipe.c +1
-0simple_release_fs (&rpc_mount, &rpc_mount_count); } +EXPORT_SYMBOL_GPL (rpc_put_mount);=20
static intrpc_delete_dentry(struct dentry *dentry){net/sunrpc/rpc_pipe.c +1
-0@@ -946,6 +948,7 @@ enum { RPCAUTH_portmap, RPCAUTH_statd, RPCAUTH_nfsd4_cb, + RPCAUTH_cache, RPCAUTH_RootEOF };=20
net/sunrpc/rpc_pipe.c +4
-0@@ -974,6 +977,10 @@ static const struct rpc_filelist files[] =3D { .name =3D "nfsd4_cb", .mode =3D S_IFDIR | S_IRUGO | S_IXUGO, }, + [RPCAUTH_cache] =3D { + .name =3D "cache", + .mode =3D S_IFDIR | S_IRUGO | S_IXUGO, + }, };
Quoted 6 lines
=20
static int
--=20
1.6.0.4
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" =
in
Quoted 2 lines
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 nfs: fix compile error in rpc_pipefs.h
From: J. Bruce Fields <[email protected]>
This include is needed for the definition of delayed_work.
--- include/linux/sunrpc/rpc_pipe_fs.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
One possible fix. Works for me, anyway.
include/linux/sunrpc/rpc_pipe_fs.h +2 -0
@@ -3,6 +3,8 @@ #ifdef __KERNEL__ +#include <linux/workqueue.h> + struct rpc_pipe_msg { struct list_head list; void *data;
Signature · 1 line
1.6.0.4
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
In reply to J. Bruce FieldsQuoted 2 lines · J. Bruce Fields
Quoted 1 line · Trond Myklebust
The NFSv4 and NFSv4.1 protocols both allow for the redirection of a=
client
Quoted 1 line
Quoted 1 line
from one server to another in order to support filesystem migration=
and
Quoted 1 line
Quoted 1 line
replication. For full protocol support, we need to add the ability =
to
Quoted 1 line
Quoted 1 line
convert a DNS host name into an IP address that we can feed to the =
RPC
Quoted 6 lines
Quoted 1 line
client.
=20
Your current nfs-for-2.6.32 doesn't compile for me:
=20In file included from fs/nfs/cache_lib.c:14: include/linux/sunrpc/rpc_pipe_fs.h:35: error: field =E2=80=98queue_t=
imeout=E2=80=99 has incomplete type
Quoted 2 lines
=20
(I wonder why you weren't seeing this?)
Odd. Neither Ubuntu 9.04 nor Fedora 11 flagged the above error when I compiled it.
A few days ago I had the same issue with some of Benny's stuff. He swor= e
he couldn't reproduce the error with his copy of gcc, whereas mine flagged it immediately.
Anyhow, I'm committing your fix. Thanks for reporting it.
--=20
Trond Myklebust
Linux NFS client maintainer
NetApp
[email protected]
www.netapp.com
A message that is not in the archive (sent off-list or not yet received): 1250807011.6514.8.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
Quoted 3 lines · Trond Myklebust
Quoted 2 lines · J. Bruce Fields
Quoted 1 line · Trond Myklebust
The NFSv4 and NFSv4.1 protocols both allow for the redirection of=
a client
Quoted 1 line
Quoted 1 line
Quoted 1 line
from one server to another in order to support filesystem migrati=
on and
Quoted 1 line
Quoted 1 line
Quoted 1 line
replication. For full protocol support, we need to add the abilit=
y to
Quoted 1 line
Quoted 1 line
Quoted 1 line
convert a DNS host name into an IP address that we can feed to th=
e RPC
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
client.
=20
Your current nfs-for-2.6.32 doesn't compile for me:
=20In file included from fs/nfs/cache_lib.c:14: include/linux/sunrpc/rpc_pipe_fs.h:35: error: field =E2=80=98queue=
_timeout=E2=80=99 has incomplete type
Quoted 6 lines
Quoted 2 lines
=20
(I wonder why you weren't seeing this?)=20
Odd. Neither Ubuntu 9.04 nor Fedora 11 flagged the above error when I compiled it.
A few days ago I had the same issue with some of Benny's stuff. He sw=
ore
Quoted 4 lines
he couldn't reproduce the error with his copy of gcc, whereas mine flagged it immediately.
=20
Anyhow, I'm committing your fix. Thanks for reporting it.
Maybe there's an include of linux/workqueue.h (hidden somewhere deep in the includes from cache_lib.c) that's under a config option?
--b.
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
Quoted 2 lines · J. Bruce Fields
Maybe there's an include of
linux/workqueue.h(hidden somewhere deep in the includes fromcache_lib.c) that's under a config option?
Yeah, that's the danger of nesting #includes...
Signature · 6 lines
Trond Myklebust Linux NFS client maintainer NetApp [email protected] www.netapp.com
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
In reply to Trond MyklebustQuoted 10 lines · On Wed, 19 Aug 2009 19:38:53 -0400 Trond Myklebust…
The NFSv4 and NFSv4.1 protocols both allow for the redirection of a client from one server to another in order to support filesystem migration and replication. For full protocol support, we need to add the ability to convert a DNS host name into an IP address that we can feed to the RPC client.
We'll reuse the sunrpc cache, now that it has been converted to work with
rpc_pipefs.Signed-off-by Trond Myklebust <[email protected]>
I'm happy to see this problem get resolved. Much of this functionality however is already provided by the keys API. While it's more geared toward dealing with auth tokens, it's still a fairly decent generic upcall implementation and could easily have been used here with a lot less new code added. Why did you decide to roll your own implementation instead?
Signature · 1 line
Jeff Layton <[email protected]>
A message that is not in the archive (sent off-list or not yet received): 20090821094248.23bc54f1-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org
Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration
Quoted 12 lines · Jeff Layton
Quoted 9 lines · On Wed, 19 Aug 2009 19:38:53 -0400 Trond Myklebust…
The NFSv4 and NFSv4.1 protocols both allow for the redirection of a client from one server to another in order to support filesystem migration and replication. For full protocol support, we need to add the ability to convert a DNS host name into an IP address that we can feed to the RPC client.
We'll reuse the sunrpc cache, now that it has been converted to work with
rpc_pipefs.
Quoted 8 lines
Quoted 1 line
Signed-off-by Trond Myklebust <[email protected]>I'm happy to see this problem get resolved. Much of this functionality however is already provided by the keys API. While it's more geared toward dealing with auth tokens, it's still a fairly decent generic upcall implementation and could easily have been used here with a lot less new code added. Why did you decide to roll your own implementation instead?
As I told you at Connectathon, I don't trust the keyring mechanism at all for this.
The user is free to inject anything they want into their keyring caches. Trusting that information when doing a mount onto a shared namespace is inappropriate.
The point then is that if you can't trust the caching mechanism, then you have to build a new cache. I chose to reuse Neil's rpc-cache stuff, because it has some nice properties:
* Write access is restricted to privileged processes using standard filesystem techniques.
* The cache contents can be easily verified using the 'contents' pseudofile.
* The contents can be easily cleared using the 'flush' pseudofile.
The only property I really didn't like about his cache mechanism (that it uses procfs), I easily worked around.
As I said to Chuck, the plan is to also rewrite the idmapper to use a similar mechanism. The current idmapper has scalability problems that we need to address in order to make NFSv4 perform in environments with lots of users.
Cheers
Trond
Signature · 6 lines
Trond Myklebust Linux NFS client maintainer NetApp [email protected] www.netapp.com