* [PATCH 00/32] The following patches have been committed to branch nfs-for-2.6.32
@ 2009-08-19 23:38 Trond Myklebust
2009-08-19 23:38 ` [PATCH 01/32] nfs: Keep index within mnt_errtbl[] Trond Myklebust
0 siblings, 1 reply; 48+ messages in thread
From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw)
To: linux-nfs
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(-)
^ permalink raw reply [flat|nested] 48+ messages in thread* [PATCH 01/32] nfs: Keep index within mnt_errtbl[] 2009-08-19 23:38 [PATCH 00/32] The following patches have been committed to branch nfs-for-2.6.32 Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 02/32] NFSv4: Don't loop forever on state recovery failure Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Roel Kluin From: Roel Kluin <roel.kluin@gmail.com> Ensure that index i remains within array mnt_errtbl[] and mnt3_errtbl[]. Signed-off-by: Roel Kluin <roel.kluin@gmail.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- fs/nfs/mount_clnt.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 38ef9ea..8b9affc 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -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; -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 02/32] NFSv4: Don't loop forever on state recovery failure... 2009-08-19 23:38 ` [PATCH 01/32] nfs: Keep index within mnt_errtbl[] Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 03/32] NFSv4: Add 'server capability' flags for NFSv4 recommended attributes Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust 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... Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- fs/nfs/nfs4proc.c | 18 ++++++++++++------ 1 files changed, 12 insertions(+), 6 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6917311..d95f7f9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -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; } /* -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 03/32] NFSv4: Add 'server capability' flags for NFSv4 recommended attributes 2009-08-19 23:38 ` [PATCH 02/32] NFSv4: Don't loop forever on state recovery failure Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 04/32] NFSv4: Don't do idmapper upcalls for asynchronous RPC calls Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust 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. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- 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(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 8d25ccb..8f34fd8 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -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, */ diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index bd7938e..fe5a8b4 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -286,6 +286,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) /* We can't support update_atime(), since the server will reset it */ inode->i_flags |= S_NOATIME|S_NOCMTIME; inode->i_mode = fattr->mode; + if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0 + && nfs_server_capable(inode, NFS_CAP_MODE)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL; /* Why so? Because we want revalidate for devices/FIFOs, and * that's precisely what we have in nfs_file_inode_operations. */ @@ -330,20 +335,46 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) nfsi->attr_gencount = fattr->gencount; if (fattr->valid & NFS_ATTR_FATTR_ATIME) inode->i_atime = fattr->atime; + else if (nfs_server_capable(inode, NFS_CAP_ATIME)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR; if (fattr->valid & NFS_ATTR_FATTR_MTIME) inode->i_mtime = fattr->mtime; + else if (nfs_server_capable(inode, NFS_CAP_MTIME)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_DATA; if (fattr->valid & NFS_ATTR_FATTR_CTIME) inode->i_ctime = fattr->ctime; + else if (nfs_server_capable(inode, NFS_CAP_CTIME)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL; if (fattr->valid & NFS_ATTR_FATTR_CHANGE) nfsi->change_attr = fattr->change_attr; + else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_DATA; if (fattr->valid & NFS_ATTR_FATTR_SIZE) inode->i_size = nfs_size_to_loff_t(fattr->size); + else + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_DATA + | NFS_INO_REVAL_PAGECACHE; if (fattr->valid & NFS_ATTR_FATTR_NLINK) inode->i_nlink = fattr->nlink; + else if (nfs_server_capable(inode, NFS_CAP_NLINK)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR; if (fattr->valid & NFS_ATTR_FATTR_OWNER) inode->i_uid = fattr->uid; + else if (nfs_server_capable(inode, NFS_CAP_OWNER)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL; if (fattr->valid & NFS_ATTR_FATTR_GROUP) inode->i_gid = fattr->gid; + else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL; if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) inode->i_blocks = fattr->du.nfs2.blocks; if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { @@ -1145,6 +1176,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) loff_t cur_isize, new_isize; unsigned long invalid = 0; unsigned long now = jiffies; + unsigned long save_cache_validity; dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", __func__, inode->i_sb->s_id, inode->i_ino, @@ -1171,10 +1203,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) */ nfsi->read_cache_jiffies = fattr->time_start; - if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) || (fattr->valid & (NFS_ATTR_FATTR_MTIME|NFS_ATTR_FATTR_CTIME))) - nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR - | NFS_INO_INVALID_ATIME - | NFS_INO_REVAL_PAGECACHE); + save_cache_validity = nfsi->cache_validity; + nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ATIME + | NFS_INO_REVAL_FORCED + | NFS_INO_REVAL_PAGECACHE); /* Do atomic weak cache consistency updates */ nfs_wcc_update_inode(inode, fattr); @@ -1189,7 +1222,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) nfs_force_lookup_revalidate(inode); nfsi->change_attr = fattr->change_attr; } - } + } else if (server->caps & NFS_CAP_CHANGE_ATTR) + invalid |= save_cache_validity; if (fattr->valid & NFS_ATTR_FATTR_MTIME) { /* NFSv2/v3: Check if the mtime agrees */ @@ -1201,7 +1235,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) nfs_force_lookup_revalidate(inode); memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); } - } + } else if (server->caps & NFS_CAP_MTIME) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_DATA + | NFS_INO_REVAL_PAGECACHE + | NFS_INO_REVAL_FORCED); + if (fattr->valid & NFS_ATTR_FATTR_CTIME) { /* If ctime has changed we should definitely clear access+acl caches */ if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { @@ -1215,7 +1254,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) } memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); } - } + } else if (server->caps & NFS_CAP_CTIME) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL + | NFS_INO_REVAL_FORCED); /* Check if our cached file size is stale */ if (fattr->valid & NFS_ATTR_FATTR_SIZE) { @@ -1231,30 +1274,50 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) dprintk("NFS: isize change on server for file %s/%ld\n", inode->i_sb->s_id, inode->i_ino); } - } + } else + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_REVAL_PAGECACHE + | NFS_INO_REVAL_FORCED); if (fattr->valid & NFS_ATTR_FATTR_ATIME) memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); + else if (server->caps & NFS_CAP_ATIME) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATIME + | NFS_INO_REVAL_FORCED); if (fattr->valid & NFS_ATTR_FATTR_MODE) { if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; inode->i_mode = fattr->mode; } - } + } else if (server->caps & NFS_CAP_MODE) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL + | NFS_INO_REVAL_FORCED); + if (fattr->valid & NFS_ATTR_FATTR_OWNER) { if (inode->i_uid != fattr->uid) { invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; inode->i_uid = fattr->uid; } - } + } else if (server->caps & NFS_CAP_OWNER) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL + | NFS_INO_REVAL_FORCED); + if (fattr->valid & NFS_ATTR_FATTR_GROUP) { if (inode->i_gid != fattr->gid) { invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; inode->i_gid = fattr->gid; } - } + } else if (server->caps & NFS_CAP_OWNER_GROUP) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL + | NFS_INO_REVAL_FORCED); if (fattr->valid & NFS_ATTR_FATTR_NLINK) { if (inode->i_nlink != fattr->nlink) { @@ -1263,7 +1326,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) invalid |= NFS_INO_INVALID_DATA; inode->i_nlink = fattr->nlink; } - } + } else if (server->caps & NFS_CAP_NLINK) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_REVAL_FORCED); if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { /* @@ -1293,9 +1358,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) || S_ISLNK(inode->i_mode))) invalid &= ~NFS_INO_INVALID_DATA; if (!nfs_have_delegation(inode, FMODE_READ) || - (nfsi->cache_validity & NFS_INO_REVAL_FORCED)) + (save_cache_validity & NFS_INO_REVAL_FORCED)) nfsi->cache_validity |= invalid; - nfsi->cache_validity &= ~NFS_INO_REVAL_FORCED; return 0; out_changed: diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d95f7f9..be6544a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -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; diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 19fe15d..320569e 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -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 */ -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 04/32] NFSv4: Don't do idmapper upcalls for asynchronous RPC calls 2009-08-19 23:38 ` [PATCH 03/32] NFSv4: Add 'server capability' flags for NFSv4 recommended attributes Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 05/32] SUNRPC: convert some sysctls into module parameters Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust We don't want to cause rpciod to hang... Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- fs/nfs/nfs4xdr.c | 86 ++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 58 insertions(+), 28 deletions(-) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 617273e..e65cc2e 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -3075,7 +3075,8 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t return 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 nf READ_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 nf return 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 nf READ_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 nf if ((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_re if ((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 nf if (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; } -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 05/32] SUNRPC: convert some sysctls into module parameters 2009-08-19 23:38 ` [PATCH 04/32] NFSv4: Don't do idmapper upcalls for asynchronous RPC calls Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 06/32] NFSv4: Clean up the nfs.callback_tcpport option Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Parameters like the minimum reserved port, and the number of slot entries should really be module parameters rather than sysctls. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- Documentation/kernel-parameters.txt | 21 ++++++++++++++ net/sunrpc/xprtsock.c | 52 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 0 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index dd1a6d4..2f18206 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -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] diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 83c73c4..585a864 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2412,3 +2412,55 @@ void cleanup_socket_xprt(void) xprt_unregister_transport(&xs_udp_transport); xprt_unregister_transport(&xs_tcp_transport); } + +static int param_set_uint_minmax(const char *val, struct kernel_param *kp, + unsigned int min, unsigned int max) +{ + unsigned long num; + int ret; + + if (!val) + return -EINVAL; + ret = strict_strtoul(val, 0, &num); + if (ret == -EINVAL || num < min || num > max) + return -EINVAL; + *((unsigned int *)kp->arg) = num; + return 0; +} + +static int param_set_portnr(const char *val, struct kernel_param *kp) +{ + return param_set_uint_minmax(val, kp, + RPC_MIN_RESVPORT, + RPC_MAX_RESVPORT); +} + +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(min_resvport, xprt_min_resvport, portnr, 0644); +module_param_named(max_resvport, xprt_max_resvport, portnr, 0644); + +static int param_set_slot_table_size(const char *val, struct kernel_param *kp) +{ + return param_set_uint_minmax(val, kp, + RPC_MIN_SLOT_TABLE, + RPC_MAX_SLOT_TABLE); +} + +static int param_get_slot_table_size(char *buffer, struct kernel_param *kp) +{ + return param_get_uint(buffer, kp); +} +#define param_check_slot_table_size(name, p) \ + __param_check(name, p, unsigned int); + +module_param_named(tcp_slot_table_entries, xprt_tcp_slot_table_entries, + slot_table_size, 0644); +module_param_named(udp_slot_table_entries, xprt_udp_slot_table_entries, + slot_table_size, 0644); + -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 06/32] NFSv4: Clean up the nfs.callback_tcpport option 2009-08-19 23:38 ` [PATCH 05/32] SUNRPC: convert some sysctls into module parameters Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 07/32] SUNRPC: Constify rpc_pipe_ops Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Tighten up the validity checking in param_set_port: check for NULL pointers. Ensure that the option shows up on 'modinfo' output. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- fs/nfs/callback.c | 26 +++++++++++++++++--------- 1 files changed, 17 insertions(+), 9 deletions(-) diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 7f604c7..293fa05 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -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. -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 07/32] SUNRPC: Constify rpc_pipe_ops... 2009-08-19 23:38 ` [PATCH 06/32] NFSv4: Clean up the nfs.callback_tcpport option Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 08/32] SUNRPC: Allow rpc_pipefs_ops to have null values for upcall and downcall Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- 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(-) diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 86147b0..fae0d3e 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -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, diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index cea764c..91f5b13 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -32,8 +32,8 @@ struct rpc_inode { wait_queue_head_t waitq; #define RPC_PIPE_WAIT_FOR_OPEN 1 int 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); diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 66d458f..23eb386 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -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, diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 9ced062..f6f60f6 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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; -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 08/32] SUNRPC: Allow rpc_pipefs_ops to have null values for upcall and downcall 2009-08-19 23:38 ` [PATCH 07/32] SUNRPC: Constify rpc_pipe_ops Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 09/32] SUNRPC: Clean up rpc_pipefs lookup code Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Also ensure that we use the umode_t type when appropriate... Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/rpc_pipe.c | 15 +++++++++++---- 1 files changed, 11 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index f6f60f6..8fa7182 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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); -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 09/32] SUNRPC: Clean up rpc_pipefs lookup code... 2009-08-19 23:38 ` [PATCH 08/32] SUNRPC: Allow rpc_pipefs_ops to have null values for upcall and downcall Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 10/32] SUNRPC: Clean up file creation code in rpc_pipefs Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/rpc_pipe.c | 15 ++++++++++----- 1 files changed, 10 insertions(+), 5 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 8fa7182..2940b92 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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) { -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 10/32] SUNRPC: Clean up file creation code in rpc_pipefs 2009-08-19 23:38 ` [PATCH 09/32] SUNRPC: Clean up rpc_pipefs lookup code Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 11/32] SUNRPC: Clean up rpc_unlink() Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/rpc_pipe.c | 120 +++++++++++++++++++++++++++++++----------------- 1 files changed, 77 insertions(+), 43 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 2940b92..d8c7815 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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); -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 11/32] SUNRPC: Clean up rpc_unlink() 2009-08-19 23:38 ` [PATCH 10/32] SUNRPC: Clean up file creation code in rpc_pipefs Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 12/32] SUNRPC: Clean up rpc_lookup_create Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/rpc_pipe.c | 35 +++++++++++++++++++++++++++-------- 1 files changed, 27 insertions(+), 8 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index d8c7815..cf30bf5 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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); -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 12/32] SUNRPC: Clean up rpc_lookup_create 2009-08-19 23:38 ` [PATCH 11/32] SUNRPC: Clean up rpc_unlink() Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 13/32] SUNRPC: Clean up rpc_populate/depopulate Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/rpc_pipe.c | 100 +++++++++++++++++++++++++++++-------------------- 1 files changed, 59 insertions(+), 41 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index cf30bf5..3633851 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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 || -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 13/32] SUNRPC: Clean up rpc_populate/depopulate 2009-08-19 23:38 ` [PATCH 12/32] SUNRPC: Clean up rpc_lookup_create Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 14/32] SUNRPC: rpc_pipefs cleanup Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/rpc_pipe.c | 187 ++++++++++++++++++++++++++---------------------- 1 files changed, 101 insertions(+), 86 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 3633851..e5f37de 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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; -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 14/32] SUNRPC: rpc_pipefs cleanup 2009-08-19 23:38 ` [PATCH 13/32] SUNRPC: Clean up rpc_populate/depopulate Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 15/32] SUNRPC: Rename rpc_mkdir to rpc_create_client_dir() Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Move the files[] array closer to rpc_fill_super() Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/rpc_pipe.c | 80 ++++++++++++++++++++++++------------------------ 1 files changed, 40 insertions(+), 40 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index e5f37de..2a4e6eb 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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) { -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 15/32] SUNRPC: Rename rpc_mkdir to rpc_create_client_dir() 2009-08-19 23:38 ` [PATCH 14/32] SUNRPC: rpc_pipefs cleanup Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 16/32] SUNRPC: Clean up rpc_create_client_dir() Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust This reflects the fact that rpc_mkdir() as it stands today, can only create a RPC client type directory. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- 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(-) diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 91f5b13..8de0ac2 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -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 *); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index ebfcf9b..6ec3770 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -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) { diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 2a4e6eb..08580be 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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; -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 16/32] SUNRPC: Clean up rpc_create_client_dir() 2009-08-19 23:38 ` [PATCH 15/32] SUNRPC: Rename rpc_mkdir to rpc_create_client_dir() Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 17/32] SUNRPC: Replace rpc_client->cl_dentry and cl_mnt, with a cl_path Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Factor out the code that does lookups from the code that actually creates the directory. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/rpc_pipe.c | 83 ++++++++++++++++++++++++------------------------- 1 files changed, 41 insertions(+), 42 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 08580be..6d152f6 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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 */ -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 17/32] SUNRPC: Replace rpc_client->cl_dentry and cl_mnt, with a cl_path 2009-08-19 23:38 ` [PATCH 16/32] SUNRPC: Clean up rpc_create_client_dir() Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 18/32] SUNRPC: clean up rpc_setup_pipedir() Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- 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(-) diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index fae0d3e..21a84d4 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -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); diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 37881f1..38ad162 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -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; diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 23eb386..fc6a43c 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -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); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 6ec3770..b3f8633 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -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, stru return 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) { -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 18/32] SUNRPC: clean up rpc_setup_pipedir() 2009-08-19 23:38 ` [PATCH 17/32] SUNRPC: Replace rpc_client->cl_dentry and cl_mnt, with a cl_path Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 19/32] SUNRPC: One more clean up for rpc_create_client_dir() Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust 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... Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- 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(-) diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 38ad162..1848d44 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -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; diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 8de0ac2..88332ef 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -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); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index b3f8633..c1e467e 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -27,6 +27,8 @@ #include <linux/types.h> #include <linux/kallsyms.h> #include <linux/mm.h> +#include <linux/namei.h> +#include <linux/mount.h> #include <linux/slab.h> #include <linux/utsname.h> #include <linux/workqueue.h> @@ -97,6 +99,12 @@ static int rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) { static uint32_t clntid; + struct nameidata nd; + struct path path; + char name[15]; + struct qstr q = { + .name = name, + }; int error; clnt->cl_path.mnt = ERR_PTR(-ENOENT); @@ -104,26 +112,36 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) if (dir_name == NULL) return 0; - clnt->cl_path.mnt = rpc_get_mount(); - if (IS_ERR(clnt->cl_path.mnt)) - return PTR_ERR(clnt->cl_path.mnt); + path.mnt = rpc_get_mount(); + if (IS_ERR(path.mnt)) + return PTR_ERR(path.mnt); + error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &nd); + if (error) + goto err; 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_path.dentry = rpc_create_client_dir(clnt->cl_pathname, clnt); - if (!IS_ERR(clnt->cl_path.dentry)) - return 0; - error = PTR_ERR(clnt->cl_path.dentry); + q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++); + name[sizeof(name) - 1] = '\0'; + q.hash = full_name_hash(q.name, q.len); + path.dentry = rpc_create_client_dir(nd.path.dentry, &q, clnt); + if (!IS_ERR(path.dentry)) + break; + error = PTR_ERR(path.dentry); if (error != -EEXIST) { - printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n", - clnt->cl_pathname, error); - rpc_put_mount(); - return error; + printk(KERN_INFO "RPC: Couldn't create pipefs entry" + " %s/%s, error %d\n", + dir_name, name, error); + goto err_path_put; } } + path_put(&nd.path); + clnt->cl_path = path; + return 0; +err_path_put: + path_put(&nd.path); +err: + rpc_put_mount(); + return error; } static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 6d152f6..1613d85 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -443,42 +443,6 @@ static const struct dentry_operations rpc_dentry_operations = { .d_delete = rpc_delete_dentry, }; -static int __rpc_lookup_path(const char *pathname, unsigned flags, - struct nameidata *nd) -{ - struct vfsmount *mnt; - - if (pathname[0] == '\0') - return -ENOENT; - - mnt = rpc_get_mount(); - if (IS_ERR(mnt)) { - printk(KERN_WARNING "%s: %s failed to mount " - "pseudofilesystem \n", __FILE__, __func__); - return PTR_ERR(mnt); - } - - if (vfs_path_lookup(mnt->mnt_root, mnt, pathname, flags, nd)) { - printk(KERN_WARNING "%s: %s failed to find path %s\n", - __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) -{ - path_put(&nd->path); - rpc_put_mount(); -} - static struct inode * rpc_get_inode(struct super_block *sb, umode_t mode) { @@ -889,27 +853,11 @@ EXPORT_SYMBOL_GPL(rpc_unlink); * 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 dentry *rpc_create_client_dir(struct dentry *dentry, + struct qstr *name, 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; + return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, rpc_client); } /* -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 19/32] SUNRPC: One more clean up for rpc_create_client_dir() 2009-08-19 23:38 ` [PATCH 18/32] SUNRPC: clean up rpc_setup_pipedir() Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 20/32] NFSD: Clean up the idmapper warning Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust 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. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/rpc_pipe.c | 78 +++++++++++++++++++++++++++++++----------------- 1 files changed, 50 insertions(+), 28 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 1613d85..57e9cd3 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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); } /* -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 20/32] NFSD: Clean up the idmapper warning... 2009-08-19 23:38 ` [PATCH 19/32] SUNRPC: One more clean up for rpc_create_client_dir() Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 21/32] SUNRPC: Ensure we initialise the cache_detail before creating procfs files Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust What part of 'internal use' is so hard to understand? Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- fs/nfsd/nfs4idmap.c | 4 ++-- include/linux/sunrpc/cache.h | 3 ++- net/sunrpc/cache.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 5b39842..e9012ad 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -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"); } diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 2d8b211..3d1fad2 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -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); }; diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index ff0c230..8ede4a6 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -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); } } -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 21/32] SUNRPC: Ensure we initialise the cache_detail before creating procfs files 2009-08-19 23:38 ` [PATCH 20/32] NFSD: Clean up the idmapper warning Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 22/32] SUNRPC: Remove the global temporary write buffer in net/sunrpc/cache.c Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Also ensure that we destroy those files before we destroy the cache_detail. Otherwise, user processes might attempt to write into uninitialised caches. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/cache.c | 30 ++++++++++++++++++++---------- 1 files changed, 20 insertions(+), 10 deletions(-) diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 8ede4a6..062d4f4 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -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 -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 22/32] SUNRPC: Remove the global temporary write buffer in net/sunrpc/cache.c 2009-08-19 23:38 ` [PATCH 21/32] SUNRPC: Ensure we initialise the cache_detail before creating procfs files Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 23/32] SUNRPC: Allow the cache_detail to specify alternative upcall mechanisms Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust 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(). Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/cache.c | 95 ++++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 70 insertions(+), 25 deletions(-) diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 062d4f4..c8e7d2d 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -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); -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 23/32] SUNRPC: Allow the cache_detail to specify alternative upcall mechanisms 2009-08-19 23:38 ` [PATCH 22/32] SUNRPC: Remove the global temporary write buffer in net/sunrpc/cache.c Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 24/32] SUNRPC: Move procfs-specific stuff out of the generic sunrpc cache code Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust 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. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- 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(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index b92a276..d946264 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -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, diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index e9012ad..cdfa86f 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -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, diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 3d1fad2..23ee259 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -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); diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 2278a50..2e6a148 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -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, diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index c8e7d2d..e438352 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -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 diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 5c865e2..6caffa3 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -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, -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 24/32] SUNRPC: Move procfs-specific stuff out of the generic sunrpc cache code 2009-08-19 23:38 ` [PATCH 23/32] SUNRPC: Allow the cache_detail to specify alternative upcall mechanisms Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 25/32] SUNRPC: Add an rpc_pipefs front end for the " Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- include/linux/sunrpc/cache.h | 11 ++- net/sunrpc/cache.c | 319 +++++++++++++++++++++++++----------------- 2 files changed, 199 insertions(+), 131 deletions(-) diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 23ee259..8e5bf30 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -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; }; diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index e438352..1cd82ed 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -291,69 +291,9 @@ static DEFINE_SPINLOCK(cache_list_lock); static struct cache_detail *current_detail; static int current_index; -static const struct file_operations cache_file_operations; -static const struct file_operations content_file_operations; -static const struct file_operations cache_flush_operations; - static void do_cache_clean(struct work_struct *work); static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean); -static void remove_cache_proc_entries(struct cache_detail *cd) -{ - if (cd->proc_ent == NULL) - return; - if (cd->flush_ent) - remove_proc_entry("flush", cd->proc_ent); - if (cd->channel_ent) - remove_proc_entry("channel", cd->proc_ent); - if (cd->content_ent) - remove_proc_entry("content", cd->proc_ent); - cd->proc_ent = NULL; - remove_proc_entry(cd->name, proc_net_rpc); -} - -#ifdef CONFIG_PROC_FS -static int create_cache_proc_entries(struct cache_detail *cd) -{ - struct proc_dir_entry *p; - - cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc); - if (cd->proc_ent == NULL) - goto out_nomem; - cd->channel_ent = cd->content_ent = NULL; - - p = proc_create_data("flush", S_IFREG|S_IRUSR|S_IWUSR, - cd->proc_ent, &cache_flush_operations, cd); - cd->flush_ent = p; - if (p == NULL) - goto out_nomem; - - 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; - if (p == NULL) - goto out_nomem; - } - if (cd->cache_show) { - p = proc_create_data("content", S_IFREG|S_IRUSR|S_IWUSR, - cd->proc_ent, &content_file_operations, cd); - cd->content_ent = p; - if (p == NULL) - goto out_nomem; - } - return 0; -out_nomem: - remove_cache_proc_entries(cd); - return -ENOMEM; -} -#else /* CONFIG_PROC_FS */ -static int create_cache_proc_entries(struct cache_detail *cd) -{ - return 0; -} -#endif - static void sunrpc_init_cache_detail(struct cache_detail *cd) { rwlock_init(&cd->hash_lock); @@ -395,25 +335,6 @@ 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 * and cleans it. * It returns 1 if it cleaned something, @@ -704,13 +625,12 @@ struct cache_reader { int offset; /* if non-0, we have a refcnt on next request */ }; -static ssize_t -cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) +static ssize_t cache_read(struct file *filp, char __user *buf, size_t count, + loff_t *ppos, struct cache_detail *cd) { struct cache_reader *rp = filp->private_data; struct cache_request *rq; struct inode *inode = filp->f_path.dentry->d_inode; - struct cache_detail *cd = PDE(inode)->data; int err; if (count == 0) @@ -834,13 +754,12 @@ out_slow: return cache_slow_downcall(buf, count, cd); } -static ssize_t -cache_write(struct file *filp, const char __user *buf, size_t count, - loff_t *ppos) +static ssize_t cache_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos, + struct cache_detail *cd) { 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) @@ -855,13 +774,12 @@ out: static DECLARE_WAIT_QUEUE_HEAD(queue_wait); -static unsigned int -cache_poll(struct file *filp, poll_table *wait) +static unsigned int cache_poll(struct file *filp, poll_table *wait, + struct cache_detail *cd) { unsigned int mask; struct cache_reader *rp = filp->private_data; struct cache_queue *cq; - struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; poll_wait(filp, &queue_wait, wait); @@ -883,14 +801,13 @@ cache_poll(struct file *filp, poll_table *wait) return mask; } -static int -cache_ioctl(struct inode *ino, struct file *filp, - unsigned int cmd, unsigned long arg) +static int cache_ioctl(struct inode *ino, struct file *filp, + unsigned int cmd, unsigned long arg, + struct cache_detail *cd) { int len = 0; struct cache_reader *rp = filp->private_data; struct cache_queue *cq; - struct cache_detail *cd = PDE(ino)->data; if (cmd != FIONREAD || !rp) return -EINVAL; @@ -913,15 +830,13 @@ cache_ioctl(struct inode *ino, struct file *filp, return put_user(len, (int __user *)arg); } -static int -cache_open(struct inode *inode, struct file *filp) +static int cache_open(struct inode *inode, struct file *filp, + struct cache_detail *cd) { struct cache_reader *rp = NULL; nonseekable_open(inode, filp); if (filp->f_mode & FMODE_READ) { - struct cache_detail *cd = PDE(inode)->data; - rp = kmalloc(sizeof(*rp), GFP_KERNEL); if (!rp) return -ENOMEM; @@ -936,11 +851,10 @@ cache_open(struct inode *inode, struct file *filp) return 0; } -static int -cache_release(struct inode *inode, struct file *filp) +static int cache_release(struct inode *inode, struct file *filp, + struct cache_detail *cd) { struct cache_reader *rp = filp->private_data; - struct cache_detail *cd = PDE(inode)->data; if (rp) { spin_lock(&queue_lock); @@ -969,18 +883,6 @@ cache_release(struct inode *inode, struct file *filp) -static const struct file_operations cache_file_operations = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = cache_read, - .write = cache_write, - .poll = cache_poll, - .ioctl = cache_ioctl, /* for FIONREAD */ - .open = cache_open, - .release = cache_release, -}; - - static void queue_loose(struct cache_detail *detail, struct cache_head *ch) { struct cache_queue *cq; @@ -1307,10 +1209,10 @@ static const struct seq_operations cache_content_op = { .show = c_show, }; -static int content_open(struct inode *inode, struct file *file) +static int content_open(struct inode *inode, struct file *file, + struct cache_detail *cd) { struct handle *han; - struct cache_detail *cd = PDE(inode)->data; han = __seq_open_private(file, &cache_content_op, sizeof(*han)); if (han == NULL) @@ -1320,17 +1222,10 @@ static int content_open(struct inode *inode, struct file *file) return 0; } -static const struct file_operations content_file_operations = { - .open = content_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_private, -}; - static ssize_t read_flush(struct file *file, char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos, + struct cache_detail *cd) { - struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data; char tbuf[20]; unsigned long p = *ppos; size_t len; @@ -1348,10 +1243,10 @@ static ssize_t read_flush(struct file *file, char __user *buf, return len; } -static ssize_t write_flush(struct file * file, const char __user * buf, - size_t count, loff_t *ppos) +static ssize_t write_flush(struct file *file, const char __user *buf, + size_t count, loff_t *ppos, + struct cache_detail *cd) { - struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data; char tbuf[20]; char *ep; long flushtime; @@ -1372,8 +1267,174 @@ static ssize_t write_flush(struct file * file, const char __user * buf, return count; } -static const struct file_operations cache_flush_operations = { +static ssize_t cache_read_procfs(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; + + return cache_read(filp, buf, count, ppos, cd); +} + +static ssize_t cache_write_procfs(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; + + return cache_write(filp, buf, count, ppos, cd); +} + +static unsigned int cache_poll_procfs(struct file *filp, poll_table *wait) +{ + struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; + + return cache_poll(filp, wait, cd); +} + +static int cache_ioctl_procfs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct cache_detail *cd = PDE(inode)->data; + + return cache_ioctl(inode, filp, cmd, arg, cd); +} + +static int cache_open_procfs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = PDE(inode)->data; + + return cache_open(inode, filp, cd); +} + +static int cache_release_procfs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = PDE(inode)->data; + + return cache_release(inode, filp, cd); +} + +static const struct file_operations cache_file_operations_procfs = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = cache_read_procfs, + .write = cache_write_procfs, + .poll = cache_poll_procfs, + .ioctl = cache_ioctl_procfs, /* for FIONREAD */ + .open = cache_open_procfs, + .release = cache_release_procfs, +}; + +static int content_open_procfs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = PDE(inode)->data; + + return content_open(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, +}; + +static ssize_t read_flush_procfs(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; + + return read_flush(filp, buf, count, ppos, cd); +} + +static ssize_t write_flush_procfs(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; + + return write_flush(filp, buf, count, ppos, cd); +} + +static const struct file_operations cache_flush_operations_procfs = { .open = nonseekable_open, - .read = read_flush, - .write = write_flush, + .read = read_flush_procfs, + .write = write_flush_procfs, }; + +static void remove_cache_proc_entries(struct cache_detail *cd) +{ + if (cd->u.procfs.proc_ent == NULL) + return; + if (cd->u.procfs.flush_ent) + remove_proc_entry("flush", cd->u.procfs.proc_ent); + if (cd->u.procfs.channel_ent) + remove_proc_entry("channel", cd->u.procfs.proc_ent); + if (cd->u.procfs.content_ent) + remove_proc_entry("content", cd->u.procfs.proc_ent); + cd->u.procfs.proc_ent = NULL; + remove_proc_entry(cd->name, proc_net_rpc); +} + +#ifdef CONFIG_PROC_FS +static int create_cache_proc_entries(struct cache_detail *cd) +{ + struct proc_dir_entry *p; + + cd->u.procfs.proc_ent = proc_mkdir(cd->name, proc_net_rpc); + if (cd->u.procfs.proc_ent == NULL) + goto out_nomem; + cd->u.procfs.channel_ent = NULL; + cd->u.procfs.content_ent = NULL; + + p = proc_create_data("flush", S_IFREG|S_IRUSR|S_IWUSR, + cd->u.procfs.proc_ent, + &cache_flush_operations_procfs, cd); + cd->u.procfs.flush_ent = p; + if (p == NULL) + goto out_nomem; + + if (cd->cache_upcall || cd->cache_parse) { + p = proc_create_data("channel", S_IFREG|S_IRUSR|S_IWUSR, + cd->u.procfs.proc_ent, + &cache_file_operations_procfs, cd); + cd->u.procfs.channel_ent = p; + if (p == NULL) + goto out_nomem; + } + if (cd->cache_show) { + p = proc_create_data("content", S_IFREG|S_IRUSR|S_IWUSR, + cd->u.procfs.proc_ent, + &content_file_operations_procfs, cd); + cd->u.procfs.content_ent = p; + if (p == NULL) + goto out_nomem; + } + return 0; +out_nomem: + remove_cache_proc_entries(cd); + return -ENOMEM; +} +#else /* CONFIG_PROC_FS */ +static int create_cache_proc_entries(struct cache_detail *cd) +{ + return 0; +} +#endif + +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); -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 25/32] SUNRPC: Add an rpc_pipefs front end for the sunrpc cache code 2009-08-19 23:38 ` [PATCH 24/32] SUNRPC: Move procfs-specific stuff out of the generic sunrpc cache code Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 26/32] NFS: Add a ->migratepage() aop for NFS Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- 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(-) diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 8e5bf30..6f52b4d 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -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); diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 88332ef..a92571a 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -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 *); diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 1cd82ed..db7720e 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -32,6 +32,7 @@ #include <linux/sunrpc/types.h> #include <linux/sunrpc/cache.h> #include <linux/sunrpc/stats.h> +#include <linux/sunrpc/rpc_pipe_fs.h> #define RPCDBG_FACILITY RPCDBG_CACHE @@ -1438,3 +1439,128 @@ void cache_unregister(struct cache_detail *cd) sunrpc_destroy_cache_detail(cd); } EXPORT_SYMBOL_GPL(cache_unregister); + +static ssize_t cache_read_pipefs(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; + + return cache_read(filp, buf, count, ppos, cd); +} + +static ssize_t cache_write_pipefs(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; + + return cache_write(filp, buf, count, ppos, cd); +} + +static unsigned int cache_poll_pipefs(struct file *filp, poll_table *wait) +{ + struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; + + return cache_poll(filp, wait, cd); +} + +static int cache_ioctl_pipefs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct cache_detail *cd = RPC_I(inode)->private; + + return cache_ioctl(inode, filp, cmd, arg, cd); +} + +static int cache_open_pipefs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = RPC_I(inode)->private; + + return cache_open(inode, filp, cd); +} + +static int cache_release_pipefs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = RPC_I(inode)->private; + + return cache_release(inode, filp, cd); +} + +const struct file_operations cache_file_operations_pipefs = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = cache_read_pipefs, + .write = cache_write_pipefs, + .poll = cache_poll_pipefs, + .ioctl = cache_ioctl_pipefs, /* for FIONREAD */ + .open = cache_open_pipefs, + .release = cache_release_pipefs, +}; + +static int content_open_pipefs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = RPC_I(inode)->private; + + return content_open(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, +}; + +static ssize_t read_flush_pipefs(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; + + return read_flush(filp, buf, count, ppos, cd); +} + +static ssize_t write_flush_pipefs(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; + + return write_flush(filp, buf, count, ppos, cd); +} + +const struct file_operations cache_flush_operations_pipefs = { + .open = nonseekable_open, + .read = read_flush_pipefs, + .write = write_flush_pipefs, +}; + +int sunrpc_cache_register_pipefs(struct dentry *parent, + const char *name, mode_t umode, + struct cache_detail *cd) +{ + struct qstr q; + struct dentry *dir; + int ret = 0; + + sunrpc_init_cache_detail(cd); + q.name = name; + q.len = strlen(name); + q.hash = full_name_hash(q.name, q.len); + dir = rpc_create_cache_dir(parent, &q, umode, cd); + if (!IS_ERR(dir)) + cd->u.pipefs.dir = dir; + else { + sunrpc_destroy_cache_detail(cd); + ret = PTR_ERR(dir); + } + return ret; +} +EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs); + +void sunrpc_cache_unregister_pipefs(struct cache_detail *cd) +{ + rpc_remove_cache_dir(cd->u.pipefs.dir); + cd->u.pipefs.dir = NULL; + sunrpc_destroy_cache_detail(cd); +} +EXPORT_SYMBOL_GPL(sunrpc_cache_unregister_pipefs); + diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 57e9cd3..8dd8153 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -26,6 +26,7 @@ #include <linux/sunrpc/clnt.h> #include <linux/workqueue.h> #include <linux/sunrpc/rpc_pipe_fs.h> +#include <linux/sunrpc/cache.h> static struct vfsmount *rpc_mount __read_mostly; static int rpc_mount_count; @@ -882,6 +883,48 @@ int rpc_remove_client_dir(struct dentry *dentry) return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate); } +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, + }, + [1] = { + .name = "content", + .i_fop = &content_file_operations_pipefs, + .mode = S_IFREG|S_IRUSR, + }, + [2] = { + .name = "flush", + .i_fop = &cache_flush_operations_pipefs, + .mode = S_IFREG|S_IRUSR|S_IWUSR, + }, +}; + +static int rpc_cachedir_populate(struct dentry *dentry, void *private) +{ + return rpc_populate(dentry, + cache_pipefs_files, 0, 3, + private); +} + +static void rpc_cachedir_depopulate(struct dentry *dentry) +{ + rpc_depopulate(dentry, cache_pipefs_files, 0, 3); +} + +struct dentry *rpc_create_cache_dir(struct dentry *parent, struct qstr *name, + mode_t umode, struct cache_detail *cd) +{ + return rpc_mkdir_populate(parent, name, umode, NULL, + rpc_cachedir_populate, cd); +} + +void rpc_remove_cache_dir(struct dentry *dentry) +{ + rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate); +} + /* * populate the filesystem */ -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 26/32] NFS: Add a ->migratepage() aop for NFS 2009-08-19 23:38 ` [PATCH 25/32] SUNRPC: Add an rpc_pipefs front end for the " Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 27/32] NFS: read-modify-write page updating Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Make NFS a bit more friendly to NUMA and memory hot removal... Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- fs/nfs/file.c | 1 + fs/nfs/internal.h | 6 +++ fs/nfs/write.c | 91 ++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 76 insertions(+), 22 deletions(-) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 0506232..dfc8967 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -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, }; diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 7dd90a6..e2ccb4a 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -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, diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 0a0a2ff..6240e64 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -13,6 +13,7 @@ #include <linux/file.h> #include <linux/writeback.h> #include <linux/swap.h> +#include <linux/migrate.h> #include <linux/sunrpc/clnt.h> #include <linux/nfs_fs.h> @@ -26,6 +27,7 @@ #include "internal.h" #include "iostat.h" #include "nfs4_fs.h" +#include "fscache.h" #define NFSDBG_FACILITY NFSDBG_PAGECACHE @@ -220,24 +222,17 @@ static void nfs_end_page_writeback(struct page *page) clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); } -/* - * Find an associated nfs write request, and prepare to flush it out - * May return an error if the user signalled nfs_wait_on_request(). - */ -static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, - struct page *page) +static struct nfs_page *nfs_find_and_lock_request(struct page *page) { struct inode *inode = page->mapping->host; struct nfs_page *req; int ret; spin_lock(&inode->i_lock); - for(;;) { + for (;;) { req = nfs_page_find_request_locked(page); - if (req == NULL) { - spin_unlock(&inode->i_lock); - return 0; - } + if (req == NULL) + break; if (nfs_set_page_tag_locked(req)) break; /* Note: If we hold the page lock, as is the case in nfs_writepage, @@ -249,23 +244,40 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, ret = nfs_wait_on_request(req); nfs_release_request(req); if (ret != 0) - return ret; + return ERR_PTR(ret); spin_lock(&inode->i_lock); } - if (test_bit(PG_CLEAN, &req->wb_flags)) { - spin_unlock(&inode->i_lock); - BUG(); - } - if (nfs_set_page_writeback(page) != 0) { - spin_unlock(&inode->i_lock); - BUG(); - } spin_unlock(&inode->i_lock); + return req; +} + +/* + * Find an associated nfs write request, and prepare to flush it out + * May return an error if the user signalled nfs_wait_on_request(). + */ +static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, + struct page *page) +{ + struct nfs_page *req; + int ret = 0; + + req = nfs_find_and_lock_request(page); + if (!req) + goto out; + ret = PTR_ERR(req); + if (IS_ERR(req)) + goto out; + + ret = nfs_set_page_writeback(page); + BUG_ON(ret != 0); + BUG_ON(test_bit(PG_CLEAN, &req->wb_flags)); + if (!nfs_pageio_add_request(pgio, req)) { nfs_redirty_request(req); - return pgio->pg_error; + ret = pgio->pg_error; } - return 0; +out: + return ret; } static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) @@ -1582,6 +1594,41 @@ int nfs_wb_page(struct inode *inode, struct page* page) return nfs_wb_page_priority(inode, page, FLUSH_STABLE); } +#ifdef CONFIG_MIGRATION +int nfs_migrate_page(struct address_space *mapping, struct page *newpage, + struct page *page) +{ + struct nfs_page *req; + int ret; + + if (PageFsCache(page)) + nfs_fscache_release_page(page, GFP_KERNEL); + + req = nfs_find_and_lock_request(page); + ret = PTR_ERR(req); + if (IS_ERR(req)) + goto out; + + ret = migrate_page(mapping, newpage, page); + if (!req) + goto out; + if (ret) + goto out_unlock; + page_cache_get(newpage); + req->wb_page = newpage; + SetPagePrivate(newpage); + set_page_private(newpage, page_private(page)); + ClearPagePrivate(page); + set_page_private(page, 0); + page_cache_release(page); +out_unlock: + nfs_clear_page_tag_locked(req); + nfs_release_request(req); +out: + return ret; +} +#endif + int __init nfs_init_writepagecache(void) { nfs_wdata_cachep = kmem_cache_create("nfs_write_data", -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 27/32] NFS: read-modify-write page updating 2009-08-19 23:38 ` [PATCH 26/32] NFS: Add a ->migratepage() aop for NFS Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 28/32] nfs: remove superfluous BUG_ON()s Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Peter Staubach From: Peter Staubach <staubach@redhat.com> 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 Signed-off-by: Peter Staubach <staubach@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- fs/nfs/file.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 46 insertions(+), 2 deletions(-) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index dfc8967..5021b75 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -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; } -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 28/32] nfs: remove superfluous BUG_ON()s 2009-08-19 23:38 ` [PATCH 27/32] NFS: read-modify-write page updating Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 29/32] SUNRPC: Fix a typo in cache_pipefs_files Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Bartlomiej Zolnierkiewicz From: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> 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_ Reported-by: Dan Carpenter <error27@gmail.com> Cc: corbet-T1hC0tSOHrs@public.gmane.org Cc: eteo@redhat.com Cc: Julia Lawall <julia@diku.dk> Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- fs/nfs/client.c | 8 -------- 1 files changed, 0 insertions(+), 8 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 8f34fd8..d36925f 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -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); -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 29/32] SUNRPC: Fix a typo in cache_pipefs_files 2009-08-19 23:38 ` [PATCH 28/32] nfs: remove superfluous BUG_ON()s Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust [not found] ` <1250725135-14632-31-git-send-email-Trond.Myklebus! t@! ne! tapp.com> ` (2 more replies) 0 siblings, 3 replies; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust We want the channel to be a regular file, so that we don't need to supply rpc_pipe_ops. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/rpc_pipe.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 8dd8153..3fdacaf 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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", -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
[parent not found: <1250725135-14632-31-git-send-email-Trond.Myklebus! t@! ne! tapp.com>]
[parent not found: <1250725135-14632-31-git-send-email-Trond.Myklebust@! ne! tapp.com>]
* [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration 2009-08-19 23:38 ` [PATCH 29/32] SUNRPC: Fix a typo in cache_pipefs_files Trond Myklebust [not found] ` <1250725135-14632-31-git-send-email-Trond.Myklebus! t@! ne! tapp.com> [not found] ` <1250725135-14632-31-git-send-email-Trond.Myklebust@! ne! tapp.com> @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 31/32] NFS: Use the DNS resolver in the mount code Trond Myklebust ` (4 more replies) 2 siblings, 5 replies; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: 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 <Trond.Myklebust@netapp.com> --- 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 diff --git a/Documentation/filesystems/nfs.txt b/Documentation/filesystems/nfs.txt new file mode 100644 index 0000000..f50f26c --- /dev/null +++ b/Documentation/filesystems/nfs.txt @@ -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} + diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 2f18206..4d0ed96 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -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. diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 8451598..da7fda6 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile @@ -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 diff --git a/fs/nfs/cache_lib.c b/fs/nfs/cache_lib.c new file mode 100644 index 0000000..b4ffd01 --- /dev/null +++ b/fs/nfs/cache_lib.c @@ -0,0 +1,140 @@ +/* + * linux/fs/nfs/cache_lib.c + * + * Helper routines for the NFS client caches + * + * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> + */ +#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; + +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 program"); +module_param_named(cache_getent_timeout, nfs_cache_getent_timeout, ulong, 0600); +MODULE_PARM_DESC(cache_getent_timeout, "Timeout (in seconds) after which " + "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') + 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'; +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, int toomany) +{ + 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) +{ + 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(); +} + diff --git a/fs/nfs/cache_lib.h b/fs/nfs/cache_lib.h new file mode 100644 index 0000000..76f856e --- /dev/null +++ b/fs/nfs/cache_lib.h @@ -0,0 +1,27 @@ +/* + * Helper routines for the NFS client caches + * + * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> + */ + +#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); diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c new file mode 100644 index 0000000..f4d54ba --- /dev/null +++ b/fs/nfs/dns_resolve.c @@ -0,0 +1,335 @@ +/* + * linux/fs/nfs/dns_resolve.c + * + * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> + * + * 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, + 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; + 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); +} + +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, int buflen) +{ + 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); +} + diff --git a/fs/nfs/dns_resolve.h b/fs/nfs/dns_resolve.h new file mode 100644 index 0000000..a3f0938 --- /dev/null +++ b/fs/nfs/dns_resolve.h @@ -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 diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index fe5a8b4..060022b 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -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 diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 3fdacaf..7f676bd 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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 -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 31/32] NFS: Use the DNS resolver in the mount code. 2009-08-19 23:38 ` [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 2009-08-19 23:38 ` [PATCH 32/32] SUNRPC: cache must take a reference to the cache detail's module on open() Trond Myklebust 2009-08-19 23:51 ` [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration Trond Myklebust ` (3 subsequent siblings) 4 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust In the referral code, use it to look up the new server's ip address if the fs_locations attribute contains a hostname. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- fs/nfs/nfs4namespace.c | 18 +++++++++++++++++- 1 files changed, 17 insertions(+), 1 deletions(-) diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index ef22ee8..2636c26 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -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; -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH 32/32] SUNRPC: cache must take a reference to the cache detail's module on open() 2009-08-19 23:38 ` [PATCH 31/32] NFS: Use the DNS resolver in the mount code Trond Myklebust @ 2009-08-19 23:38 ` Trond Myklebust 0 siblings, 0 replies; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:38 UTC (permalink / raw) To: linux-nfs; +Cc: Trond Myklebust Otherwise we Oops if the module containing the cache detail is removed before all cache readers have closed the file. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- net/sunrpc/cache.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 76 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index db7720e..45cdaff 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -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, -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration 2009-08-19 23:38 ` [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration Trond Myklebust 2009-08-19 23:38 ` [PATCH 31/32] NFS: Use the DNS resolver in the mount code Trond Myklebust @ 2009-08-19 23:51 ` Trond Myklebust [not found] ` <1250725916.12555.1.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org> 2009-08-20 15:34 ` Chuck Lever ` (2 subsequent siblings) 4 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-19 23:51 UTC (permalink / raw) To: linux-nfs On Wed, 2009-08-19 at 19:38 -0400, Trond Myklebust wrote: > 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 <Trond.Myklebust@netapp.com> Subject: NFS: Testcase for the DNS resolver Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- 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 diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index 2a77bc2..13fc471 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig @@ -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 + diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index da7fda6..4fe5ac2 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile @@ -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 + diff --git a/fs/nfs/cache_testcases.c b/fs/nfs/cache_testcases.c new file mode 100644 index 0000000..2d8810a --- /dev/null +++ b/fs/nfs/cache_testcases.c @@ -0,0 +1,53 @@ +/* + * linux/fs/nfs/cache_testcases.c + * + * Testcases for the NFS client cache upcalls + * + * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> + */ + +#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 <Trond.Myklebust@netapp.com>"); +MODULE_LICENSE("GPL"); + +module_init(nfs_dnstest_init) +module_exit(nfs_dnstest_exit) diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index f4d54ba..572d453 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c @@ -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) { -- Trond Myklebust Linux NFS client maintainer NetApp Trond.Myklebust@netapp.com www.netapp.com ^ permalink raw reply related [flat|nested] 48+ messages in thread
[parent not found: <1250725916.12555.1.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org>]
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration [not found] ` <1250725916.12555.1.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org> @ 2009-08-21 20:47 ` J. Bruce Fields 2009-08-21 20:57 ` Chuck Lever 0 siblings, 1 reply; 48+ messages in thread From: J. Bruce Fields @ 2009-08-21 20:47 UTC (permalink / raw) To: Trond Myklebust; +Cc: linux-nfs On Wed, Aug 19, 2009 at 07:51:56PM -0400, Trond Myklebust wrote: > On Wed, 2009-08-19 at 19:38 -0400, Trond Myklebust wrote: > > 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. > > From: Trond Myklebust <Trond.Myklebust@netapp.com> > Subject: NFS: Testcase for the DNS resolver > > Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> > --- > > 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 > > > diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig > index 2a77bc2..13fc471 100644 > --- a/fs/nfs/Kconfig > +++ b/fs/nfs/Kconfig > @@ -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 > + > diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile > index da7fda6..4fe5ac2 100644 > --- a/fs/nfs/Makefile > +++ b/fs/nfs/Makefile > @@ -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 > + > diff --git a/fs/nfs/cache_testcases.c b/fs/nfs/cache_testcases.c > new file mode 100644 > index 0000000..2d8810a > --- /dev/null > +++ b/fs/nfs/cache_testcases.c > @@ -0,0 +1,53 @@ > +/* > + * linux/fs/nfs/cache_testcases.c > + * > + * Testcases for the NFS client cache upcalls > + * > + * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> > + */ > + > +#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 <Trond.Myklebust@netapp.com>"); > +MODULE_LICENSE("GPL"); > + > +module_init(nfs_dnstest_init) > +module_exit(nfs_dnstest_exit) > diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c > index f4d54ba..572d453 100644 > --- a/fs/nfs/dns_resolve.c > +++ b/fs/nfs/dns_resolve.c > @@ -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) > { > > -- > Trond Myklebust > Linux NFS client maintainer > > NetApp > Trond.Myklebust@netapp.com > www.netapp.com > -- > To unsubscribe from this list: send the line "unsubscribe linux-nfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration 2009-08-21 20:47 ` J. Bruce Fields @ 2009-08-21 20:57 ` Chuck Lever 0 siblings, 0 replies; 48+ messages in thread From: Chuck Lever @ 2009-08-21 20:57 UTC (permalink / raw) To: Trond Myklebust; +Cc: NFS list On Aug 21, 2009, at 4:47 PM, J. Bruce Fields wrote: > On Wed, Aug 19, 2009 at 07:51:56PM -0400, Trond Myklebust wrote: >> On Wed, 2009-08-19 at 19:38 -0400, Trond Myklebust wrote: >>> 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.... 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. > > --b. > >> >> From: Trond Myklebust <Trond.Myklebust@netapp.com> >> Subject: NFS: Testcase for the DNS resolver >> >> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> >> --- >> >> 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 >> >> >> diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig >> index 2a77bc2..13fc471 100644 >> --- a/fs/nfs/Kconfig >> +++ b/fs/nfs/Kconfig >> @@ -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 >> + >> diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile >> index da7fda6..4fe5ac2 100644 >> --- a/fs/nfs/Makefile >> +++ b/fs/nfs/Makefile >> @@ -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 >> + >> diff --git a/fs/nfs/cache_testcases.c b/fs/nfs/cache_testcases.c >> new file mode 100644 >> index 0000000..2d8810a >> --- /dev/null >> +++ b/fs/nfs/cache_testcases.c >> @@ -0,0 +1,53 @@ >> +/* >> + * linux/fs/nfs/cache_testcases.c >> + * >> + * Testcases for the NFS client cache upcalls >> + * >> + * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> >> + */ >> + >> +#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 <Trond.Myklebust@netapp.com>"); >> +MODULE_LICENSE("GPL"); >> + >> +module_init(nfs_dnstest_init) >> +module_exit(nfs_dnstest_exit) >> diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c >> index f4d54ba..572d453 100644 >> --- a/fs/nfs/dns_resolve.c >> +++ b/fs/nfs/dns_resolve.c >> @@ -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) >> { >> >> -- >> Trond Myklebust >> Linux NFS client maintainer >> >> NetApp >> Trond.Myklebust@netapp.com >> www.netapp.com >> -- >> To unsubscribe from this list: send the line "unsubscribe linux- >> nfs" in >> the body of a message to majordomo@vger.kernel.org >> 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 majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Chuck Lever chuck[dot]lever[at]oracle[dot]com ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration 2009-08-19 23:38 ` [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration Trond Myklebust 2009-08-19 23:38 ` [PATCH 31/32] NFS: Use the DNS resolver in the mount code Trond Myklebust 2009-08-19 23:51 ` [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration Trond Myklebust @ 2009-08-20 15:34 ` Chuck Lever 2009-08-20 16:25 ` Trond Myklebust 2009-08-20 21:03 ` J. Bruce Fields 2009-08-21 13:42 ` Jeff Layton 4 siblings, 1 reply; 48+ messages in thread From: Chuck Lever @ 2009-08-20 15:34 UTC (permalink / raw) To: Trond Myklebust; +Cc: linux-nfs Random thoughts. On Aug 19, 2009, at 7:38 PM, Trond Myklebust wrote: > 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 <Trond.Myklebust@netapp.com> > --- > 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 > > diff --git a/Documentation/filesystems/nfs.txt b/Documentation/ > filesystems/nfs.txt > new file mode 100644 > index 0000000..f50f26c > --- /dev/null > +++ b/Documentation/filesystems/nfs.txt > @@ -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} > + 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. > diff --git a/Documentation/kernel-parameters.txt b/Documentation/ > kernel-parameters.txt > index 2f18206..4d0ed96 100644 > --- a/Documentation/kernel-parameters.txt > +++ b/Documentation/kernel-parameters.txt > @@ -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. > diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile > index 8451598..da7fda6 100644 > --- a/fs/nfs/Makefile > +++ b/fs/nfs/Makefile > @@ -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 > diff --git a/fs/nfs/cache_lib.c b/fs/nfs/cache_lib.c > new file mode 100644 > index 0000000..b4ffd01 > --- /dev/null > +++ b/fs/nfs/cache_lib.c > @@ -0,0 +1,140 @@ > +/* > + * linux/fs/nfs/cache_lib.c > + * > + * Helper routines for the NFS client caches > + * > + * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> > + */ > +#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; > + > +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 > program"); > +module_param_named(cache_getent_timeout, nfs_cache_getent_timeout, > ulong, 0600); > +MODULE_PARM_DESC(cache_getent_timeout, "Timeout (in seconds) after > which " > + "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') > + 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. > +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, int > toomany) > +{ > + 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) > +{ > + 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(); > +} > + > diff --git a/fs/nfs/cache_lib.h b/fs/nfs/cache_lib.h > new file mode 100644 > index 0000000..76f856e > --- /dev/null > +++ b/fs/nfs/cache_lib.h > @@ -0,0 +1,27 @@ > +/* > + * Helper routines for the NFS client caches > + * > + * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> > + */ > + > +#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); > diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c > new file mode 100644 > index 0000000..f4d54ba > --- /dev/null > +++ b/fs/nfs/dns_resolve.c > @@ -0,0 +1,335 @@ > +/* > + * linux/fs/nfs/dns_resolve.c > + * > + * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> > + * > + * 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) 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. > + > +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; > + 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? > + > +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, int > buflen) > +{ > + 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); > +} > + > diff --git a/fs/nfs/dns_resolve.h b/fs/nfs/dns_resolve.h > new file mode 100644 > index 0000000..a3f0938 > --- /dev/null > +++ b/fs/nfs/dns_resolve.h > @@ -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. > + > +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 > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c > index fe5a8b4..060022b 100644 > --- a/fs/nfs/inode.c > +++ b/fs/nfs/inode.c > @@ -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: This init routine is getting cumbersome. Eventually could we provide an array of function pointers and call them in a loop? > 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 > diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c > index 3fdacaf..7f676bd 100644 > --- a/net/sunrpc/rpc_pipe.c > +++ b/net/sunrpc/rpc_pipe.c > @@ -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 > -- > 1.6.0.4 > -- > To unsubscribe from this list: send the line "unsubscribe linux-nfs" > in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Chuck Lever chuck[dot]lever[at]oracle[dot]com ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration 2009-08-20 15:34 ` Chuck Lever @ 2009-08-20 16:25 ` Trond Myklebust [not found] ` <1250785542.19156.12.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org> 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-20 16:25 UTC (permalink / raw) To: Chuck Lever; +Cc: linux-nfs On Thu, 2009-08-20 at 11:34 -0400, Chuck Lever wrote: > > +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} > > + > > 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. 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. > > + * 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. > > +#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. > 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... > > +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. > > +#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(). > > @@ -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: > > 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(). -- Trond Myklebust Linux NFS client maintainer NetApp Trond.Myklebust@netapp.com www.netapp.com ^ permalink raw reply [flat|nested] 48+ messages in thread
[parent not found: <1250785542.19156.12.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org>]
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration [not found] ` <1250785542.19156.12.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org> @ 2009-08-20 16:54 ` Chuck Lever 2009-08-20 19:11 ` Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: Chuck Lever @ 2009-08-20 16:54 UTC (permalink / raw) To: Trond Myklebust; +Cc: linux-nfs On Aug 20, 2009, at 12:25 PM, Trond Myklebust wrote: > On Thu, 2009-08-20 at 11:34 -0400, Chuck Lever wrote: >>> +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} >>> + >> >> 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. > > 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. >>> + * 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. Makes sense, but that important detail is not clear from the documenting comment. >>> +#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? >>> +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. >>> +#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 ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration 2009-08-20 16:54 ` Chuck Lever @ 2009-08-20 19:11 ` Trond Myklebust [not found] ` <1250795483.26904.6.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org> 0 siblings, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-20 19:11 UTC (permalink / raw) To: Chuck Lever; +Cc: linux-nfs On Thu, 2009-08-20 at 12:54 -0400, Chuck Lever wrote: > > 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. 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. > >>> +#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? 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. > >>> +#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. 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... -- Trond Myklebust Linux NFS client maintainer NetApp Trond.Myklebust@netapp.com www.netapp.com ^ permalink raw reply [flat|nested] 48+ messages in thread
[parent not found: <1250795483.26904.6.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org>]
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration [not found] ` <1250795483.26904.6.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org> @ 2009-08-20 21:13 ` Chuck Lever 0 siblings, 0 replies; 48+ messages in thread From: Chuck Lever @ 2009-08-20 21:13 UTC (permalink / raw) To: Trond Myklebust; +Cc: linux-nfs On Aug 20, 2009, at 3:11 PM, Trond Myklebust wrote: > On Thu, 2009-08-20 at 12:54 -0400, Chuck Lever wrote: >>> 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. > > 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 ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration 2009-08-19 23:38 ` [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration Trond Myklebust ` (2 preceding siblings ...) 2009-08-20 15:34 ` Chuck Lever @ 2009-08-20 21:03 ` J. Bruce Fields 2009-08-20 21:08 ` [PATCH] nfs: fix compile error in rpc_pipefs.h J. Bruce Fields 2009-08-20 22:23 ` [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration Trond Myklebust 2009-08-21 13:42 ` Jeff Layton 4 siblings, 2 replies; 48+ messages in thread From: J. Bruce Fields @ 2009-08-20 21:03 UTC (permalink / raw) To: Trond Myklebust; +Cc: linux-nfs On Wed, Aug 19, 2009 at 07:38:53PM -0400, Trond Myklebust wrote: > The NFSv4 and NFSv4.1 protocols both allow for the redirection of a c= lient > from one server to another in order to support filesystem migration a= nd > 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 > 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. >=20 > We'll reuse the sunrpc cache, now that it has been converted to work = with > rpc_pipefs. >=20 > Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> > --- > 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 >=20 > diff --git a/Documentation/filesystems/nfs.txt b/Documentation/filesy= stems/nfs.txt > new file mode 100644 > index 0000000..f50f26c > --- /dev/null > +++ b/Documentation/filesystems/nfs.txt > @@ -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). > +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 vers= ions, > +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 th= e > +upcall interfaces that are used in order to provide the NFS client w= ith > +some of the information that it requires in order to fully comply wi= th > +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 > +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 > +a path, or a DNS hostname and a path. The latter requires the NFS cl= ient 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 th= e 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 contain= s 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 para= meter) > + 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 > + 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 > + (ffee:ddcc:bbaa:9988:7766:5544:3322:1100, ffee::1100, ...) fo= rmat. > + <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 ho= stname > + 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 > + > +#!/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} > + > diff --git a/Documentation/kernel-parameters.txt b/Documentation/kern= el-parameters.txt > index 2f18206..4d0ed96 100644 > --- a/Documentation/kernel-parameters.txt > +++ b/Documentation/kernel-parameters.txt > @@ -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. > =20 > + 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. > diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile > index 8451598..da7fda6 100644 > --- a/fs/nfs/Makefile > +++ b/fs/nfs/Makefile > @@ -6,7 +6,8 @@ obj-$(CONFIG_NFS_FS) +=3D nfs.o > =20 > nfs-y :=3D client.o dir.o file.o getroot.o inode.o super.o nfs2xd= r.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) +=3D nfsroot.o > nfs-$(CONFIG_NFS_V3) +=3D nfs3proc.o nfs3xdr.o > nfs-$(CONFIG_NFS_V3_ACL) +=3D nfs3acl.o > diff --git a/fs/nfs/cache_lib.c b/fs/nfs/cache_lib.c > new file mode 100644 > index 0000000..b4ffd01 > --- /dev/null > +++ b/fs/nfs/cache_lib.c > @@ -0,0 +1,140 @@ > +/* > + * linux/fs/nfs/cache_lib.c > + * > + * Helper routines for the NFS client caches > + * > + * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> > + */ > +#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] =3D > + "/sbin/nfs_cache_getent"; > +static unsigned long nfs_cache_getent_timeout =3D NFS_CACHE_UPCALL_T= IMEOUT; > + > +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"); > +module_param_named(cache_getent_timeout, nfs_cache_getent_timeout, u= long, 0600); > +MODULE_PARM_DESC(cache_getent_timeout, "Timeout (in seconds) after w= hich " > + "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; > +} > + > +/* > + * 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) > +{ > + 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) > +{ > + 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(); > +} > + > diff --git a/fs/nfs/cache_lib.h b/fs/nfs/cache_lib.h > new file mode 100644 > index 0000000..76f856e > --- /dev/null > +++ b/fs/nfs/cache_lib.h > @@ -0,0 +1,27 @@ > +/* > + * Helper routines for the NFS client caches > + * > + * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> > + */ > + > +#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_nam= e); > +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 *dre= q); > + > +extern int nfs_cache_register(struct cache_detail *cd); > +extern void nfs_cache_unregister(struct cache_detail *cd); > diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c > new file mode 100644 > index 0000000..f4d54ba > --- /dev/null > +++ b/fs/nfs/dns_resolve.c > @@ -0,0 +1,335 @@ > +/* > + * linux/fs/nfs/dns_resolve.c > + * > + * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> > + * > + * 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, > + 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)= ; > + 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; > +}; > + > +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)= ; > + > + 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)= ; > + 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; > + > + 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) > +{ > + 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); > +} > + > diff --git a/fs/nfs/dns_resolve.h b/fs/nfs/dns_resolve.h > new file mode 100644 > index 0000000..a3f0938 > --- /dev/null > +++ b/fs/nfs/dns_resolve.h > @@ -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 > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c > index fe5a8b4..060022b 100644 > --- a/fs/nfs/inode.c > +++ b/fs/nfs/inode.c > @@ -46,6 +46,7 @@ > #include "iostat.h" > #include "internal.h" > #include "fscache.h" > +#include "dns_resolve.h" > =20 > #define NFSDBG_FACILITY NFSDBG_VFS > =20 > @@ -1506,6 +1507,10 @@ static int __init init_nfs_fs(void) > { > int err; > =20 > + 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 > @@ -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 > diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c > index 3fdacaf..7f676bd 100644 > --- a/net/sunrpc/rpc_pipe.c > +++ b/net/sunrpc/rpc_pipe.c > @@ -416,11 +416,13 @@ struct vfsmount *rpc_get_mount(void) > return ERR_PTR(err); > return rpc_mount; > } > +EXPORT_SYMBOL_GPL(rpc_get_mount); > =20 > void rpc_put_mount(void) > { > simple_release_fs(&rpc_mount, &rpc_mount_count); > } > +EXPORT_SYMBOL_GPL(rpc_put_mount); > =20 > static int rpc_delete_dentry(struct dentry *dentry) > { > @@ -946,6 +948,7 @@ enum { > RPCAUTH_portmap, > RPCAUTH_statd, > RPCAUTH_nfsd4_cb, > + RPCAUTH_cache, > RPCAUTH_RootEOF > }; > =20 > @@ -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, > + }, > }; > =20 > static int > --=20 > 1.6.0.4 > -- > To unsubscribe from this list: send the line "unsubscribe linux-nfs" = in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH] nfs: fix compile error in rpc_pipefs.h 2009-08-20 21:03 ` J. Bruce Fields @ 2009-08-20 21:08 ` J. Bruce Fields 2009-08-20 22:23 ` [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration Trond Myklebust 1 sibling, 0 replies; 48+ messages in thread From: J. Bruce Fields @ 2009-08-20 21:08 UTC (permalink / raw) To: Trond Myklebust; +Cc: linux-nfs From: J. Bruce Fields <bfields@citi.umich.edu> This include is needed for the definition of delayed_work. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> --- include/linux/sunrpc/rpc_pipe_fs.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) One possible fix. Works for me, anyway. diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index a92571a..cf14db9 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -3,6 +3,8 @@ #ifdef __KERNEL__ +#include <linux/workqueue.h> + struct rpc_pipe_msg { struct list_head list; void *data; -- 1.6.0.4 ^ permalink raw reply related [flat|nested] 48+ messages in thread
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration 2009-08-20 21:03 ` J. Bruce Fields 2009-08-20 21:08 ` [PATCH] nfs: fix compile error in rpc_pipefs.h J. Bruce Fields @ 2009-08-20 22:23 ` Trond Myklebust [not found] ` <1250807011.6514.8.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org> 1 sibling, 1 reply; 48+ messages in thread From: Trond Myklebust @ 2009-08-20 22:23 UTC (permalink / raw) To: J. Bruce Fields; +Cc: linux-nfs On Thu, 2009-08-20 at 17:03 -0400, J. Bruce Fields wrote: > On Wed, Aug 19, 2009 at 07:38:53PM -0400, Trond Myklebust wrote: > > 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. >=20 > Your current nfs-for-2.6.32 doesn't compile for me: >=20 > In 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 >=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 Trond.Myklebust@netapp.com www.netapp.com ^ permalink raw reply [flat|nested] 48+ messages in thread
[parent not found: <1250807011.6514.8.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org>]
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration [not found] ` <1250807011.6514.8.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org> @ 2009-08-20 22:33 ` J. Bruce Fields 2009-08-20 22:39 ` Trond Myklebust 0 siblings, 1 reply; 48+ messages in thread From: J. Bruce Fields @ 2009-08-20 22:33 UTC (permalink / raw) To: Trond Myklebust; +Cc: linux-nfs On Thu, Aug 20, 2009 at 06:23:31PM -0400, Trond Myklebust wrote: > On Thu, 2009-08-20 at 17:03 -0400, J. Bruce Fields wrote: > > On Wed, Aug 19, 2009 at 07:38:53PM -0400, Trond Myklebust wrote: > > > The NFSv4 and NFSv4.1 protocols both allow for the redirection of= a client > > > from one server to another in order to support filesystem migrati= on and > > > replication. For full protocol support, we need to add the abilit= y to > > > convert a DNS host name into an IP address that we can feed to th= e RPC > > > client. > >=20 > > Your current nfs-for-2.6.32 doesn't compile for me: > >=20 > > In 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 > >=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 > 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. ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration 2009-08-20 22:33 ` J. Bruce Fields @ 2009-08-20 22:39 ` Trond Myklebust 0 siblings, 0 replies; 48+ messages in thread From: Trond Myklebust @ 2009-08-20 22:39 UTC (permalink / raw) To: J. Bruce Fields; +Cc: linux-nfs On Thu, 2009-08-20 at 18:33 -0400, J. Bruce Fields wrote: > 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? Yeah, that's the danger of nesting #includes... -- Trond Myklebust Linux NFS client maintainer NetApp Trond.Myklebust@netapp.com www.netapp.com ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration 2009-08-19 23:38 ` [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration Trond Myklebust ` (3 preceding siblings ...) 2009-08-20 21:03 ` J. Bruce Fields @ 2009-08-21 13:42 ` Jeff Layton [not found] ` <20090821094248.23bc54f1-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org> 4 siblings, 1 reply; 48+ messages in thread From: Jeff Layton @ 2009-08-21 13:42 UTC (permalink / raw) To: Trond Myklebust; +Cc: linux-nfs, Trond Myklebust On Wed, 19 Aug 2009 19:38:53 -0400 Trond Myklebust <Trond.Myklebust@netapp.com> wrote: > 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 <Trond.Myklebust@netapp.com> 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? -- Jeff Layton <jlayton@redhat.com> ^ permalink raw reply [flat|nested] 48+ messages in thread
[parent not found: <20090821094248.23bc54f1-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>]
* Re: [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration [not found] ` <20090821094248.23bc54f1-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org> @ 2009-08-21 14:21 ` Trond Myklebust 0 siblings, 0 replies; 48+ messages in thread From: Trond Myklebust @ 2009-08-21 14:21 UTC (permalink / raw) To: Jeff Layton; +Cc: linux-nfs On Fri, 2009-08-21 at 09:42 -0400, Jeff Layton wrote: > On Wed, 19 Aug 2009 19:38:53 -0400 > Trond Myklebust <Trond.Myklebust@netapp.com> wrote: > > > 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 <Trond.Myklebust@netapp.com> > > > 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 -- Trond Myklebust Linux NFS client maintainer NetApp Trond.Myklebust@netapp.com www.netapp.com ^ permalink raw reply [flat|nested] 48+ messages in thread
end of thread, other threads:[~2009-08-21 20:57 UTC | newest]
Thread overview: 48+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-19 23:38 [PATCH 00/32] The following patches have been committed to branch nfs-for-2.6.32 Trond Myklebust
2009-08-19 23:38 ` [PATCH 01/32] nfs: Keep index within mnt_errtbl[] Trond Myklebust
2009-08-19 23:38 ` [PATCH 02/32] NFSv4: Don't loop forever on state recovery failure Trond Myklebust
2009-08-19 23:38 ` [PATCH 03/32] NFSv4: Add 'server capability' flags for NFSv4 recommended attributes Trond Myklebust
2009-08-19 23:38 ` [PATCH 04/32] NFSv4: Don't do idmapper upcalls for asynchronous RPC calls Trond Myklebust
2009-08-19 23:38 ` [PATCH 05/32] SUNRPC: convert some sysctls into module parameters Trond Myklebust
2009-08-19 23:38 ` [PATCH 06/32] NFSv4: Clean up the nfs.callback_tcpport option Trond Myklebust
2009-08-19 23:38 ` [PATCH 07/32] SUNRPC: Constify rpc_pipe_ops Trond Myklebust
2009-08-19 23:38 ` [PATCH 08/32] SUNRPC: Allow rpc_pipefs_ops to have null values for upcall and downcall Trond Myklebust
2009-08-19 23:38 ` [PATCH 09/32] SUNRPC: Clean up rpc_pipefs lookup code Trond Myklebust
2009-08-19 23:38 ` [PATCH 10/32] SUNRPC: Clean up file creation code in rpc_pipefs Trond Myklebust
2009-08-19 23:38 ` [PATCH 11/32] SUNRPC: Clean up rpc_unlink() Trond Myklebust
2009-08-19 23:38 ` [PATCH 12/32] SUNRPC: Clean up rpc_lookup_create Trond Myklebust
2009-08-19 23:38 ` [PATCH 13/32] SUNRPC: Clean up rpc_populate/depopulate Trond Myklebust
2009-08-19 23:38 ` [PATCH 14/32] SUNRPC: rpc_pipefs cleanup Trond Myklebust
2009-08-19 23:38 ` [PATCH 15/32] SUNRPC: Rename rpc_mkdir to rpc_create_client_dir() Trond Myklebust
2009-08-19 23:38 ` [PATCH 16/32] SUNRPC: Clean up rpc_create_client_dir() Trond Myklebust
2009-08-19 23:38 ` [PATCH 17/32] SUNRPC: Replace rpc_client->cl_dentry and cl_mnt, with a cl_path Trond Myklebust
2009-08-19 23:38 ` [PATCH 18/32] SUNRPC: clean up rpc_setup_pipedir() Trond Myklebust
2009-08-19 23:38 ` [PATCH 19/32] SUNRPC: One more clean up for rpc_create_client_dir() Trond Myklebust
2009-08-19 23:38 ` [PATCH 20/32] NFSD: Clean up the idmapper warning Trond Myklebust
2009-08-19 23:38 ` [PATCH 21/32] SUNRPC: Ensure we initialise the cache_detail before creating procfs files Trond Myklebust
2009-08-19 23:38 ` [PATCH 22/32] SUNRPC: Remove the global temporary write buffer in net/sunrpc/cache.c Trond Myklebust
2009-08-19 23:38 ` [PATCH 23/32] SUNRPC: Allow the cache_detail to specify alternative upcall mechanisms Trond Myklebust
2009-08-19 23:38 ` [PATCH 24/32] SUNRPC: Move procfs-specific stuff out of the generic sunrpc cache code Trond Myklebust
2009-08-19 23:38 ` [PATCH 25/32] SUNRPC: Add an rpc_pipefs front end for the " Trond Myklebust
2009-08-19 23:38 ` [PATCH 26/32] NFS: Add a ->migratepage() aop for NFS Trond Myklebust
2009-08-19 23:38 ` [PATCH 27/32] NFS: read-modify-write page updating Trond Myklebust
2009-08-19 23:38 ` [PATCH 28/32] nfs: remove superfluous BUG_ON()s Trond Myklebust
2009-08-19 23:38 ` [PATCH 29/32] SUNRPC: Fix a typo in cache_pipefs_files Trond Myklebust
[not found] ` <1250725135-14632-31-git-send-email-Trond.Myklebus! t@! ne! tapp.com>
[not found] ` <1250725135-14632-31-git-send-email-Trond.Myklebust@! ne! tapp.com>
2009-08-19 23:38 ` [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration Trond Myklebust
2009-08-19 23:38 ` [PATCH 31/32] NFS: Use the DNS resolver in the mount code Trond Myklebust
2009-08-19 23:38 ` [PATCH 32/32] SUNRPC: cache must take a reference to the cache detail's module on open() Trond Myklebust
2009-08-19 23:51 ` [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration Trond Myklebust
[not found] ` <1250725916.12555.1.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org>
2009-08-21 20:47 ` J. Bruce Fields
2009-08-21 20:57 ` Chuck Lever
2009-08-20 15:34 ` Chuck Lever
2009-08-20 16:25 ` Trond Myklebust
[not found] ` <1250785542.19156.12.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org>
2009-08-20 16:54 ` Chuck Lever
2009-08-20 19:11 ` Trond Myklebust
[not found] ` <1250795483.26904.6.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org>
2009-08-20 21:13 ` Chuck Lever
2009-08-20 21:03 ` J. Bruce Fields
2009-08-20 21:08 ` [PATCH] nfs: fix compile error in rpc_pipefs.h J. Bruce Fields
2009-08-20 22:23 ` [PATCH 30/32] NFS: Add a dns resolver for use with NFSv4 referrals and migration Trond Myklebust
[not found] ` <1250807011.6514.8.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org>
2009-08-20 22:33 ` J. Bruce Fields
2009-08-20 22:39 ` Trond Myklebust
2009-08-21 13:42 ` Jeff Layton
[not found] ` <20090821094248.23bc54f1-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2009-08-21 14:21 ` Trond Myklebust
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox