From 710b7216964d6455cf1b215c43b03a1a79008c7d Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 26 Jul 2011 16:28:29 -0400 Subject: locks: move F_INPROGRESS from fl_type to fl_flags field F_INPROGRESS isn't exposed to userspace. To me it makes more sense in fl_flags.... Reviewed-by: Jeff Layton Signed-off-by: J. Bruce Fields --- include/asm-generic/fcntl.h | 5 ----- include/linux/fs.h | 3 ++- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/asm-generic/fcntl.h b/include/asm-generic/fcntl.h index 84793c7025e..9e5b0356e2b 100644 --- a/include/asm-generic/fcntl.h +++ b/include/asm-generic/fcntl.h @@ -145,11 +145,6 @@ struct f_owner_ex { #define F_SHLCK 8 /* or 4 */ #endif -/* for leases */ -#ifndef F_INPROGRESS -#define F_INPROGRESS 16 -#endif - /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 178cdb4f1d4..327fdd4de85 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1065,6 +1065,7 @@ static inline int file_check_writeable(struct file *filp) #define FL_LEASE 32 /* lease held on this file */ #define FL_CLOSE 64 /* unlock on close */ #define FL_SLEEP 128 /* A blocking lock */ +#define FL_INPROGRESS 256 /* Lease is being broken */ /* * Special return value from posix_lock_file() and vfs_lock_file() for @@ -1111,7 +1112,7 @@ struct file_lock { struct list_head fl_link; /* doubly linked list of all locks */ struct list_head fl_block; /* circular list of blocked processes */ fl_owner_t fl_owner; - unsigned char fl_flags; + unsigned int fl_flags; unsigned char fl_type; unsigned int fl_pid; struct pid *fl_nspid; -- cgit v1.2.3-70-g09d2 From 778fc546f749c588aa2f6cd50215d2715c374252 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 26 Jul 2011 18:25:49 -0400 Subject: locks: fix tracking of inprogress lease breaks We currently use a bit in fl_flags to record whether a lease is being broken, and set fl_type to the type (RDLCK or UNLCK) that it will eventually have. This means that once the lease break starts, we forget what the lease's type *used* to be. Breaking a read lease will then result in blocking read opens, even though there's no conflict--because the lease type is now F_UNLCK and we can no longer tell whether it was previously a read or write lease. So, instead keep fl_type as the original type (the type which we enforce), and keep track of whether we're unlocking or merely downgrading by replacing the single FL_INPROGRESS flag by FL_UNLOCK_PENDING and FL_DOWNGRADE_PENDING flags. To get this right we also need to track separate downgrade and break times, to handle the case where a write-leased file gets conflicting opens first for read, then later for write. (I first considered just eliminating the downgrade behavior completely--nfsv4 doesn't need it, and nobody as far as I can tell actually uses it currently--but Jeremy Allison tells me that Windows oplocks do behave this way, so Samba will probably use this some day.) Reviewed-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/locks.c | 87 ++++++++++++++++++++++++++++++++++-------------------- include/linux/fs.h | 7 +++-- 2 files changed, 60 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/fs/locks.c b/fs/locks.c index c4215418bca..c525aa4de23 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -135,7 +135,16 @@ static bool lease_breaking(struct file_lock *fl) { - return fl->fl_flags & FL_INPROGRESS; + return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING); +} + +static int target_leasetype(struct file_lock *fl) +{ + if (fl->fl_flags & FL_UNLOCK_PENDING) + return F_UNLCK; + if (fl->fl_flags & FL_DOWNGRADE_PENDING) + return F_RDLCK; + return fl->fl_type; } int leases_enable = 1; @@ -1124,6 +1133,17 @@ int locks_mandatory_area(int read_write, struct inode *inode, EXPORT_SYMBOL(locks_mandatory_area); +static void lease_clear_pending(struct file_lock *fl, int arg) +{ + switch (arg) { + case F_UNLCK: + fl->fl_flags &= ~FL_UNLOCK_PENDING; + /* fall through: */ + case F_RDLCK: + fl->fl_flags &= ~FL_DOWNGRADE_PENDING; + } +} + /* We already had a lease on this file; just change its type */ int lease_modify(struct file_lock **before, int arg) { @@ -1132,7 +1152,7 @@ int lease_modify(struct file_lock **before, int arg) if (error) return error; - fl->fl_flags &= ~FL_INPROGRESS; + lease_clear_pending(fl, arg); locks_wake_up_blocks(fl); if (arg == F_UNLCK) locks_delete_lock(before); @@ -1141,6 +1161,14 @@ int lease_modify(struct file_lock **before, int arg) EXPORT_SYMBOL(lease_modify); +static bool past_time(unsigned long then) +{ + if (!then) + /* 0 is a special value meaning "this never expires": */ + return false; + return time_after(jiffies, then); +} + static void time_out_leases(struct inode *inode) { struct file_lock **before; @@ -1148,12 +1176,10 @@ static void time_out_leases(struct inode *inode) before = &inode->i_flock; while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) { - if ((fl->fl_break_time == 0) - || time_before(jiffies, fl->fl_break_time)) { - before = &fl->fl_next; - continue; - } - lease_modify(before, fl->fl_type); + if (past_time(fl->fl_downgrade_time)) + lease_modify(before, F_RDLCK); + if (past_time(fl->fl_break_time)) + lease_modify(before, F_UNLCK); if (fl == *before) /* lease_modify may have freed fl */ before = &fl->fl_next; } @@ -1171,7 +1197,7 @@ static void time_out_leases(struct inode *inode) */ int __break_lease(struct inode *inode, unsigned int mode) { - int error = 0, future; + int error = 0; struct file_lock *new_fl, *flock; struct file_lock *fl; unsigned long break_time; @@ -1188,24 +1214,13 @@ int __break_lease(struct inode *inode, unsigned int mode) if ((flock == NULL) || !IS_LEASE(flock)) goto out; + if (!locks_conflict(flock, new_fl)) + goto out; + for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) if (fl->fl_owner == current->files) i_have_this_lease = 1; - if (want_write) { - /* If we want write access, we have to revoke any lease. */ - future = F_UNLCK; - } else if (lease_breaking(flock)) { - /* If the lease is already being broken, we just leave it */ - future = flock->fl_type; - } else if (flock->fl_type & F_WRLCK) { - /* Downgrade the exclusive lease to a read-only lease. */ - future = F_RDLCK; - } else { - /* the existing lease was read-only, so we can read too. */ - goto out; - } - if (IS_ERR(new_fl) && !i_have_this_lease && ((mode & O_NONBLOCK) == 0)) { error = PTR_ERR(new_fl); @@ -1220,13 +1235,18 @@ int __break_lease(struct inode *inode, unsigned int mode) } for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) { - if (fl->fl_type != future) { - fl->fl_type = future; - fl->fl_flags |= FL_INPROGRESS; + if (want_write) { + if (fl->fl_flags & FL_UNLOCK_PENDING) + continue; + fl->fl_flags |= FL_UNLOCK_PENDING; fl->fl_break_time = break_time; - /* lease must have lmops break callback */ - fl->fl_lmops->lm_break(fl); + } else { + if (lease_breaking(flock)) + continue; + fl->fl_flags |= FL_DOWNGRADE_PENDING; + fl->fl_downgrade_time = break_time; } + fl->fl_lmops->lm_break(fl); } if (i_have_this_lease || (mode & O_NONBLOCK)) { @@ -1250,10 +1270,13 @@ restart: if (error >= 0) { if (error == 0) time_out_leases(inode); - /* Wait for the next lease that has not been broken yet */ + /* + * Wait for the next conflicting lease that has not been + * broken yet + */ for (flock = inode->i_flock; flock && IS_LEASE(flock); flock = flock->fl_next) { - if (lease_breaking(flock)) + if (locks_conflict(new_fl, flock)) goto restart; } error = 0; @@ -1321,7 +1344,7 @@ int fcntl_getlease(struct file *filp) for (fl = filp->f_path.dentry->d_inode->i_flock; fl && IS_LEASE(fl); fl = fl->fl_next) { if (fl->fl_file == filp) { - type = fl->fl_type; + type = target_leasetype(fl); break; } } @@ -1386,7 +1409,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) before = &fl->fl_next) { if (fl->fl_file == filp) my_before = before; - else if ((fl->fl_type == F_UNLCK) && lease_breaking(fl)) + else if (fl->fl_flags & FL_UNLOCK_PENDING) /* * Someone is in the process of opening this * file for writing so we may not take an diff --git a/include/linux/fs.h b/include/linux/fs.h index 327fdd4de85..76460edf164 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1065,7 +1065,8 @@ static inline int file_check_writeable(struct file *filp) #define FL_LEASE 32 /* lease held on this file */ #define FL_CLOSE 64 /* unlock on close */ #define FL_SLEEP 128 /* A blocking lock */ -#define FL_INPROGRESS 256 /* Lease is being broken */ +#define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */ +#define FL_UNLOCK_PENDING 512 /* Lease is being broken */ /* * Special return value from posix_lock_file() and vfs_lock_file() for @@ -1122,7 +1123,9 @@ struct file_lock { loff_t fl_end; struct fasync_struct * fl_fasync; /* for lease break notifications */ - unsigned long fl_break_time; /* for nonblocking lease breaks */ + /* for lease breaks: */ + unsigned long fl_break_time; + unsigned long fl_downgrade_time; const struct file_lock_operations *fl_ops; /* Callbacks for filesystems */ const struct lock_manager_operations *fl_lmops; /* Callbacks for lockmanagers */ -- cgit v1.2.3-70-g09d2 From 11fd165c68b73434ca1273e21f21db5eecc90926 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 28 Jul 2011 20:04:09 +0200 Subject: sunrpc: use better NUMA affinities Use NUMA aware allocations to reduce latencies and increase throughput. sunrpc kthreads can use kthread_create_on_node() if pool_mode is "percpu" or "pernode", and svc_prepare_thread()/svc_init_buffer() can also take into account NUMA node affinity for memory allocations. Signed-off-by: Eric Dumazet CC: "J. Bruce Fields" CC: Neil Brown CC: David Miller Reviewed-by: Greg Banks [bfields@redhat.com: fix up caller nfs41_callback_up] Signed-off-by: J. Bruce Fields --- fs/lockd/svc.c | 2 +- fs/nfs/callback.c | 4 ++-- include/linux/sunrpc/svc.h | 2 +- net/sunrpc/svc.c | 33 ++++++++++++++++++++++++--------- 4 files changed, 28 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index abfff9d7979..c061b9aa7dd 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -282,7 +282,7 @@ int lockd_up(void) /* * Create the kernel thread and wait for it to start. */ - nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); + nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE); if (IS_ERR(nlmsvc_rqst)) { error = PTR_ERR(nlmsvc_rqst); nlmsvc_rqst = NULL; diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index e3d29426905..516f3375e06 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -125,7 +125,7 @@ nfs4_callback_up(struct svc_serv *serv) else goto out_err; - return svc_prepare_thread(serv, &serv->sv_pools[0]); + return svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE); out_err: if (ret == 0) @@ -199,7 +199,7 @@ nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) INIT_LIST_HEAD(&serv->sv_cb_list); spin_lock_init(&serv->sv_cb_lock); init_waitqueue_head(&serv->sv_cb_waitq); - rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); + rqstp = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE); if (IS_ERR(rqstp)) { svc_xprt_put(serv->sv_bc_xprt); serv->sv_bc_xprt = NULL; diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 223588a976a..a78a51e9337 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -404,7 +404,7 @@ struct svc_procedure { struct svc_serv *svc_create(struct svc_program *, unsigned int, void (*shutdown)(struct svc_serv *)); struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, - struct svc_pool *pool); + struct svc_pool *pool, int node); void svc_exit_thread(struct svc_rqst *); struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, void (*shutdown)(struct svc_serv *), diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 6a69a1131fb..30d70abb4e2 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -295,6 +295,18 @@ svc_pool_map_put(void) } +static int svc_pool_map_get_node(unsigned int pidx) +{ + const struct svc_pool_map *m = &svc_pool_map; + + if (m->count) { + if (m->mode == SVC_POOL_PERCPU) + return cpu_to_node(m->pool_to[pidx]); + if (m->mode == SVC_POOL_PERNODE) + return m->pool_to[pidx]; + } + return NUMA_NO_NODE; +} /* * Set the given thread's cpus_allowed mask so that it * will only run on cpus in the given pool. @@ -499,7 +511,7 @@ EXPORT_SYMBOL_GPL(svc_destroy); * We allocate pages and place them in rq_argpages. */ static int -svc_init_buffer(struct svc_rqst *rqstp, unsigned int size) +svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node) { unsigned int pages, arghi; @@ -513,7 +525,7 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size) arghi = 0; BUG_ON(pages > RPCSVC_MAXPAGES); while (pages) { - struct page *p = alloc_page(GFP_KERNEL); + struct page *p = alloc_pages_node(node, GFP_KERNEL, 0); if (!p) break; rqstp->rq_pages[arghi++] = p; @@ -536,11 +548,11 @@ svc_release_buffer(struct svc_rqst *rqstp) } struct svc_rqst * -svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool) +svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node) { struct svc_rqst *rqstp; - rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL); + rqstp = kzalloc_node(sizeof(*rqstp), GFP_KERNEL, node); if (!rqstp) goto out_enomem; @@ -554,15 +566,15 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool) rqstp->rq_server = serv; rqstp->rq_pool = pool; - rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL); + rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node); if (!rqstp->rq_argp) goto out_thread; - rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL); + rqstp->rq_resp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node); if (!rqstp->rq_resp) goto out_thread; - if (!svc_init_buffer(rqstp, serv->sv_max_mesg)) + if (!svc_init_buffer(rqstp, serv->sv_max_mesg, node)) goto out_thread; return rqstp; @@ -647,6 +659,7 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) struct svc_pool *chosen_pool; int error = 0; unsigned int state = serv->sv_nrthreads-1; + int node; if (pool == NULL) { /* The -1 assumes caller has done a svc_get() */ @@ -662,14 +675,16 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) nrservs--; chosen_pool = choose_pool(serv, pool, &state); - rqstp = svc_prepare_thread(serv, chosen_pool); + node = svc_pool_map_get_node(chosen_pool->sp_id); + rqstp = svc_prepare_thread(serv, chosen_pool, node); if (IS_ERR(rqstp)) { error = PTR_ERR(rqstp); break; } __module_get(serv->sv_module); - task = kthread_create(serv->sv_function, rqstp, serv->sv_name); + task = kthread_create_on_node(serv->sv_function, rqstp, + node, serv->sv_name); if (IS_ERR(task)) { error = PTR_ERR(task); module_put(serv->sv_module); -- cgit v1.2.3-70-g09d2 From 8cfb79134027e96bc11067da00d7ca73e58e69ce Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 8 Aug 2011 07:09:03 -0400 Subject: nfsd: remove unused defines At least one of these is actually wrong anyway. Signed-off-by: J. Bruce Fields --- include/linux/nfsd/const.h | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'include') diff --git a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h index 323f8cfa060..feb3764617a 100644 --- a/include/linux/nfsd/const.h +++ b/include/linux/nfsd/const.h @@ -14,11 +14,6 @@ #include #include -/* - * Maximum protocol version supported by knfsd - */ -#define NFSSVC_MAXVERS 3 - /* * Maximum blocksizes supported by daemon under various circumstances. */ @@ -42,14 +37,6 @@ */ #define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE) -#ifdef CONFIG_NFSD_V4 -# define NFSSVC_XDRSIZE NFS4_SVC_XDRSIZE -#elif defined(CONFIG_NFSD_V3) -# define NFSSVC_XDRSIZE NFS3_SVC_XDRSIZE -#else -# define NFSSVC_XDRSIZE NFS2_SVC_XDRSIZE -#endif - #endif /* __KERNEL__ */ #endif /* _LINUX_NFSD_CONST_H */ -- cgit v1.2.3-70-g09d2 From c10bd39d800d42adef55ed9016f802677cd0ab5f Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 19 Aug 2011 11:38:52 -0400 Subject: Remove include/linux/nfsd/const.h Userspace shouldn't have a use for these constants. Nothing here is used outside fs/nfsd. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsd.h | 26 ++++++++++++++++++++++++++ include/linux/nfsd/Kbuild | 1 - include/linux/nfsd/const.h | 42 ------------------------------------------ include/linux/nfsd/nfsfh.h | 7 +++++-- 4 files changed, 31 insertions(+), 45 deletions(-) delete mode 100644 include/linux/nfsd/const.h (limited to 'include') diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 7ecfa242030..8da03e16ab3 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -11,13 +11,39 @@ #include #include +#include +#include +#include +#include +#include + #include #include #include + /* * nfsd version */ #define NFSD_SUPPORTED_MINOR_VERSION 1 +/* + * Maximum blocksizes supported by daemon under various circumstances. + */ +#define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD +/* NFSv2 is limited by the protocol specification, see RFC 1094 */ +#define NFSSVC_MAXBLKSIZE_V2 (8*1024) + + +/* + * Largest number of bytes we need to allocate for an NFS + * call or reply. Used to control buffer sizes. We use + * the length of v3 WRITE, READDIR and READDIR replies + * which are an RPC header, up to 26 XDR units of reply + * data, and some page data. + * + * Note that accuracy here doesn't matter too much as the + * size is rounded up to a page size when allocating space. + */ +#define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE) struct readdir_cd { __be32 err; /* 0, nfserr, or nfserr_eof */ diff --git a/include/linux/nfsd/Kbuild b/include/linux/nfsd/Kbuild index 55d1467de3c..0e528606d46 100644 --- a/include/linux/nfsd/Kbuild +++ b/include/linux/nfsd/Kbuild @@ -1,4 +1,3 @@ -header-y += const.h header-y += debug.h header-y += export.h header-y += nfsfh.h diff --git a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h deleted file mode 100644 index feb3764617a..00000000000 --- a/include/linux/nfsd/const.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * include/linux/nfsd/const.h - * - * Various constants related to NFS. - * - * Copyright (C) 1995-1997 Olaf Kirch - */ - -#ifndef _LINUX_NFSD_CONST_H -#define _LINUX_NFSD_CONST_H - -#include -#include -#include -#include - -/* - * Maximum blocksizes supported by daemon under various circumstances. - */ -#define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD -/* NFSv2 is limited by the protocol specification, see RFC 1094 */ -#define NFSSVC_MAXBLKSIZE_V2 (8*1024) - -#ifdef __KERNEL__ - -#include - -/* - * Largest number of bytes we need to allocate for an NFS - * call or reply. Used to control buffer sizes. We use - * the length of v3 WRITE, READDIR and READDIR replies - * which are an RPC header, up to 26 XDR units of reply - * data, and some page data. - * - * Note that accuracy here doesn't matter too much as the - * size is rounded up to a page size when allocating space. - */ -#define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE) - -#endif /* __KERNEL__ */ - -#endif /* _LINUX_NFSD_CONST_H */ diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index f76d80ccec1..ce4743a2601 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -14,11 +14,14 @@ #ifndef _LINUX_NFSD_FH_H #define _LINUX_NFSD_FH_H -# include +#include +#include +#include +#include +#include #ifdef __KERNEL__ # include #endif -#include /* * This is the old "dentry style" Linux NFSv2 file handle. -- cgit v1.2.3-70-g09d2 From a9004abc34239705840eaf6fe3d6cc9cb7656cba Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 23 Aug 2011 15:43:04 -0400 Subject: nfsd4: cleanup and consolidate seqid_mutating_err Signed-off-by: J. Bruce Fields --- fs/nfs/nfs4_fs.h | 24 ------------------------ fs/nfsd/nfs4xdr.c | 14 +------------- include/linux/nfs4.h | 16 ++++++++++++++++ 3 files changed, 17 insertions(+), 37 deletions(-) (limited to 'include') diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 1ec1a85fa71..1a652a0bd7d 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -13,30 +13,6 @@ struct idmap; -/* - * In a seqid-mutating op, this macro controls which error return - * values trigger incrementation of the seqid. - * - * from rfc 3010: - * The client MUST monotonically increment the sequence number for the - * CLOSE, LOCK, LOCKU, OPEN, OPEN_CONFIRM, and OPEN_DOWNGRADE - * operations. This is true even in the event that the previous - * operation that used the sequence number received an error. The only - * exception to this rule is if the previous operation received one of - * the following errors: NFSERR_STALE_CLIENTID, NFSERR_STALE_STATEID, - * NFSERR_BAD_STATEID, NFSERR_BAD_SEQID, NFSERR_BADXDR, - * NFSERR_RESOURCE, NFSERR_NOFILEHANDLE. - * - */ -#define seqid_mutating_err(err) \ -(((err) != NFSERR_STALE_CLIENTID) && \ - ((err) != NFSERR_STALE_STATEID) && \ - ((err) != NFSERR_BAD_STATEID) && \ - ((err) != NFSERR_BAD_SEQID) && \ - ((err) != NFSERR_BAD_XDR) && \ - ((err) != NFSERR_RESOURCE) && \ - ((err) != NFSERR_NOFILEHANDLE)) - enum nfs4_client_state { NFS4CLNT_MANAGER_RUNNING = 0, NFS4CLNT_CHECK_LEASE, diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 78c792fb59a..04ad9a2ca3d 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1623,18 +1623,6 @@ static void write_cinfo(__be32 **p, struct nfsd4_change_info *c) \ save = resp->p; -static bool seqid_mutating_err(__be32 err) -{ - /* rfc 3530 section 8.1.5: */ - return err != nfserr_stale_clientid && - err != nfserr_stale_stateid && - err != nfserr_bad_stateid && - err != nfserr_bad_seqid && - err != nfserr_bad_xdr && - err != nfserr_resource && - err != nfserr_nofilehandle; -} - /* * Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This * is where sequence id's are incremented, and the replay cache is filled. @@ -1643,7 +1631,7 @@ static bool seqid_mutating_err(__be32 err) */ #define ENCODE_SEQID_OP_TAIL(stateowner) do { \ - if (seqid_mutating_err(nfserr) && stateowner) { \ + if (seqid_mutating_err(ntohl(nfserr)) && stateowner) { \ stateowner->so_seqid++; \ stateowner->so_replay.rp_status = nfserr; \ stateowner->so_replay.rp_buflen = \ diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 76f99e8714f..b875b0324fc 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -373,6 +373,22 @@ enum nfsstat4 { NFS4ERR_DELEG_REVOKED = 10087, /* deleg./layout revoked */ }; +static inline bool seqid_mutating_err(u32 err) +{ + /* rfc 3530 section 8.1.5: */ + switch (err) { + case NFS4ERR_STALE_CLIENTID: + case NFS4ERR_STALE_STATEID: + case NFS4ERR_BAD_STATEID: + case NFS4ERR_BAD_SEQID: + case NFS4ERR_BADXDR: + case NFS4ERR_RESOURCE: + case NFS4ERR_NOFILEHANDLE: + return false; + }; + return true; +} + /* * Note: NF4BAD is not actually part of the protocol; it is just used * internally by nfsd. -- cgit v1.2.3-70-g09d2 From c152292f9ee7eb4ed30edc0bd5027a5beef5f5e8 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 26 Aug 2011 17:22:06 -0400 Subject: nfsd: remove include/linux/nfsd/syscall.h We don't need this any more. Signed-off-by: J. Bruce Fields --- fs/compat.c | 1 - fs/nfsd/export.c | 1 - fs/nfsd/nfsctl.c | 1 - include/linux/nfsd/Kbuild | 1 - include/linux/nfsd/syscall.h | 116 ------------------------------------------- 5 files changed, 120 deletions(-) delete mode 100644 include/linux/nfsd/syscall.h (limited to 'include') diff --git a/fs/compat.c b/fs/compat.c index 0b48d018e38..f2b36d472c7 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index f4cc1e2bfc5..d491421cd70 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -16,7 +16,6 @@ #include #include -#include #include #include "nfsd.h" diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index c7716143cbd..db34a585e11 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/include/linux/nfsd/Kbuild b/include/linux/nfsd/Kbuild index 0e528606d46..b8d4001212b 100644 --- a/include/linux/nfsd/Kbuild +++ b/include/linux/nfsd/Kbuild @@ -2,4 +2,3 @@ header-y += debug.h header-y += export.h header-y += nfsfh.h header-y += stats.h -header-y += syscall.h diff --git a/include/linux/nfsd/syscall.h b/include/linux/nfsd/syscall.h deleted file mode 100644 index 812bc1e160d..00000000000 --- a/include/linux/nfsd/syscall.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * include/linux/nfsd/syscall.h - * - * This file holds all declarations for the knfsd syscall interface. - * - * Copyright (C) 1995-1997 Olaf Kirch - */ - -#ifndef NFSD_SYSCALL_H -#define NFSD_SYSCALL_H - -#include -#include - -/* - * Version of the syscall interface - */ -#define NFSCTL_VERSION 0x0201 - -/* - * These are the commands understood by nfsctl(). - */ -#define NFSCTL_SVC 0 /* This is a server process. */ -#define NFSCTL_ADDCLIENT 1 /* Add an NFS client. */ -#define NFSCTL_DELCLIENT 2 /* Remove an NFS client. */ -#define NFSCTL_EXPORT 3 /* export a file system. */ -#define NFSCTL_UNEXPORT 4 /* unexport a file system. */ -/*#define NFSCTL_UGIDUPDATE 5 / * update a client's uid/gid map. DISCARDED */ -/*#define NFSCTL_GETFH 6 / * get an fh by ino DISCARDED */ -#define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */ -#define NFSCTL_GETFS 8 /* get an fh by path with max FH len */ - -/* SVC */ -struct nfsctl_svc { - unsigned short svc_port; - int svc_nthreads; -}; - -/* ADDCLIENT/DELCLIENT */ -struct nfsctl_client { - char cl_ident[NFSCLNT_IDMAX+1]; - int cl_naddr; - struct in_addr cl_addrlist[NFSCLNT_ADDRMAX]; - int cl_fhkeytype; - int cl_fhkeylen; - unsigned char cl_fhkey[NFSCLNT_KEYMAX]; -}; - -/* EXPORT/UNEXPORT */ -struct nfsctl_export { - char ex_client[NFSCLNT_IDMAX+1]; - char ex_path[NFS_MAXPATHLEN+1]; - __kernel_old_dev_t ex_dev; - __kernel_ino_t ex_ino; - int ex_flags; - __kernel_uid_t ex_anon_uid; - __kernel_gid_t ex_anon_gid; -}; - -/* GETFD */ -struct nfsctl_fdparm { - struct sockaddr gd_addr; - char gd_path[NFS_MAXPATHLEN+1]; - int gd_version; -}; - -/* GETFS - GET Filehandle with Size */ -struct nfsctl_fsparm { - struct sockaddr gd_addr; - char gd_path[NFS_MAXPATHLEN+1]; - int gd_maxlen; -}; - -/* - * This is the argument union. - */ -struct nfsctl_arg { - int ca_version; /* safeguard */ - union { - struct nfsctl_svc u_svc; - struct nfsctl_client u_client; - struct nfsctl_export u_export; - struct nfsctl_fdparm u_getfd; - struct nfsctl_fsparm u_getfs; - /* - * The following dummy member is needed to preserve binary compatibility - * on platforms where alignof(void*)>alignof(int). It's needed because - * this union used to contain a member (u_umap) which contained a - * pointer. - */ - void *u_ptr; - } u; -#define ca_svc u.u_svc -#define ca_client u.u_client -#define ca_export u.u_export -#define ca_getfd u.u_getfd -#define ca_getfs u.u_getfs -}; - -union nfsctl_res { - __u8 cr_getfh[NFS_FHSIZE]; - struct knfsd_fh cr_getfs; -}; - -#ifdef __KERNEL__ -/* - * Kernel syscall implementation. - */ -extern int exp_addclient(struct nfsctl_client *ncp); -extern int exp_delclient(struct nfsctl_client *ncp); -extern int exp_export(struct nfsctl_export *nxp); -extern int exp_unexport(struct nfsctl_export *nxp); - -#endif /* __KERNEL__ */ - -#endif /* NFSD_SYSCALL_H */ -- cgit v1.2.3-70-g09d2 From ed748aacb8e3318fa2cf24e1c197d35b5fd29605 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 12 Sep 2011 19:37:06 -0400 Subject: NFSD: Cleanup for nfsd4_path() The current code is sort of hackish in that it assumes a referral is always matched to an export. When we add support for junctions that may not be the case. We can replace nfsd4_path() with a function that encodes the components directly from the dentries. Since nfsd4_path is currently the only user of the 'ex_pathname' field in struct svc_export, this has the added benefit of allowing us to get rid of that. Signed-off-by: Trond Myklebust Reviewed-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/export.c | 4 +- fs/nfsd/nfs4xdr.c | 106 ++++++++++++++++++++++++++++++++------------ include/linux/nfsd/export.h | 1 + 3 files changed, 81 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index d491421cd70..99229b0c153 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -1009,7 +1009,7 @@ rqst_exp_parent(struct svc_rqst *rqstp, struct path *path) return exp; } -static struct svc_export *find_fsidzero_export(struct svc_rqst *rqstp) +struct svc_export *rqst_find_fsidzero_export(struct svc_rqst *rqstp) { u32 fsidv[2]; @@ -1029,7 +1029,7 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) struct svc_export *exp; __be32 rv; - exp = find_fsidzero_export(rqstp); + exp = rqst_find_fsidzero_export(rqstp); if (IS_ERR(exp)) return nfserrno(PTR_ERR(exp)); rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 182570bed47..5252d668196 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1696,36 +1696,89 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, } /* - * Return the path to an export point in the pseudo filesystem namespace - * Returned string is safe to use as long as the caller holds a reference - * to @exp. + * Encode a path in RFC3530 'pathname4' format */ -static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat) +static __be32 nfsd4_encode_path(const struct path *root, + const struct path *path, __be32 **pp, int *buflen) { - struct svc_fh tmp_fh; - char *path = NULL, *rootpath; - size_t rootlen; + struct path cur = { + .mnt = path->mnt, + .dentry = path->dentry, + }; + __be32 *p = *pp; + struct dentry **components = NULL; + unsigned int ncomponents = 0; + __be32 err = nfserr_jukebox; - fh_init(&tmp_fh, NFS4_FHSIZE); - *stat = exp_pseudoroot(rqstp, &tmp_fh); - if (*stat) - return NULL; - rootpath = tmp_fh.fh_export->ex_pathname; + dprintk("nfsd4_encode_components("); - path = exp->ex_pathname; + path_get(&cur); + /* First walk the path up to the nfsd root, and store the + * dentries/path components in an array. + */ + for (;;) { + if (cur.dentry == root->dentry && cur.mnt == root->mnt) + break; + if (cur.dentry == cur.mnt->mnt_root) { + if (follow_up(&cur)) + continue; + goto out_free; + } + if ((ncomponents & 15) == 0) { + struct dentry **new; + new = krealloc(components, + sizeof(*new) * (ncomponents + 16), + GFP_KERNEL); + if (!new) + goto out_free; + components = new; + } + components[ncomponents++] = cur.dentry; + cur.dentry = dget_parent(cur.dentry); + } - rootlen = strlen(rootpath); - if (strncmp(path, rootpath, rootlen)) { - dprintk("nfsd: fs_locations failed;" - "%s is not contained in %s\n", path, rootpath); - *stat = nfserr_notsupp; - path = NULL; - goto out; + *buflen -= 4; + if (*buflen < 0) + goto out_free; + WRITE32(ncomponents); + + while (ncomponents) { + struct dentry *dentry = components[ncomponents - 1]; + unsigned int len = dentry->d_name.len; + + *buflen -= 4 + (XDR_QUADLEN(len) << 2); + if (*buflen < 0) + goto out_free; + WRITE32(len); + WRITEMEM(dentry->d_name.name, len); + dprintk("/%s", dentry->d_name.name); + dput(dentry); + ncomponents--; } - path += rootlen; -out: - fh_put(&tmp_fh); - return path; + + *pp = p; + err = 0; +out_free: + dprintk(")\n"); + while (ncomponents) + dput(components[--ncomponents]); + kfree(components); + path_put(&cur); + return err; +} + +static __be32 nfsd4_encode_fsloc_fsroot(struct svc_rqst *rqstp, + const struct path *path, __be32 **pp, int *buflen) +{ + struct svc_export *exp_ps; + __be32 res; + + exp_ps = rqst_find_fsidzero_export(rqstp); + if (IS_ERR(exp_ps)) + return nfserrno(PTR_ERR(exp_ps)); + res = nfsd4_encode_path(&exp_ps->ex_path, path, pp, buflen); + exp_put(exp_ps); + return res; } /* @@ -1739,11 +1792,8 @@ static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp, int i; __be32 *p = *pp; struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; - char *root = nfsd4_path(rqstp, exp, &status); - if (status) - return status; - status = nfsd4_encode_components('/', root, &p, buflen); + status = nfsd4_encode_fsloc_fsroot(rqstp, &exp->ex_path, &p, buflen); if (status) return status; if ((*buflen -= 4) < 0) diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 8a31a20efe7..7ba3fd43f31 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -137,6 +137,7 @@ struct svc_export * rqst_exp_get_by_name(struct svc_rqst *, struct path *); struct svc_export * rqst_exp_parent(struct svc_rqst *, struct path *); +struct svc_export * rqst_find_fsidzero_export(struct svc_rqst *); int exp_rootfh(struct auth_domain *, char *path, struct knfsd_fh *, int maxsize); __be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *); -- cgit v1.2.3-70-g09d2 From 2f1ddda1749a223d1a05e16dc6ea28632b9ec570 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 12 Sep 2011 19:37:16 -0400 Subject: NFSD: Remove the ex_pathname field from struct svc_export There are no more users... Signed-off-by: Trond Myklebust Reviewed-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/export.c | 11 ----------- include/linux/nfsd/export.h | 1 - 2 files changed, 12 deletions(-) (limited to 'include') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 99229b0c153..62f3b9074e8 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -317,7 +317,6 @@ static void svc_export_put(struct kref *ref) struct svc_export *exp = container_of(ref, struct svc_export, h.ref); path_put(&exp->ex_path); auth_domain_put(exp->ex_client); - kfree(exp->ex_pathname); nfsd4_fslocs_free(&exp->ex_fslocs); kfree(exp); } @@ -527,11 +526,6 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) exp.ex_client = dom; - err = -ENOMEM; - exp.ex_pathname = kstrdup(buf, GFP_KERNEL); - if (!exp.ex_pathname) - goto out2; - /* expiry */ err = -EINVAL; exp.h.expiry_time = get_expiry(&mesg); @@ -612,8 +606,6 @@ out4: nfsd4_fslocs_free(&exp.ex_fslocs); kfree(exp.ex_uuid); out3: - kfree(exp.ex_pathname); -out2: path_put(&exp.ex_path); out1: auth_domain_put(dom); @@ -677,7 +669,6 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem) new->ex_client = item->ex_client; new->ex_path.dentry = dget(item->ex_path.dentry); new->ex_path.mnt = mntget(item->ex_path.mnt); - new->ex_pathname = NULL; new->ex_fslocs.locations = NULL; new->ex_fslocs.locations_count = 0; new->ex_fslocs.migrated = 0; @@ -695,8 +686,6 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) new->ex_fsid = item->ex_fsid; new->ex_uuid = item->ex_uuid; item->ex_uuid = NULL; - new->ex_pathname = item->ex_pathname; - item->ex_pathname = NULL; new->ex_fslocs.locations = item->ex_fslocs.locations; item->ex_fslocs.locations = NULL; new->ex_fslocs.locations_count = item->ex_fslocs.locations_count; diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 7ba3fd43f31..f85308e688f 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -96,7 +96,6 @@ struct svc_export { struct auth_domain * ex_client; int ex_flags; struct path ex_path; - char *ex_pathname; uid_t ex_anon_uid; gid_t ex_anon_gid; int ex_fsid; -- cgit v1.2.3-70-g09d2 From 849a1cf13d4394d398d91752166e92e9ecd64f8d Mon Sep 17 00:00:00 2001 From: Mi Jinlong Date: Tue, 30 Aug 2011 17:18:41 +0800 Subject: SUNRPC: Replace svc_addr_u by sockaddr_storage For IPv6 local address, lockd can not callback to client for missing scope id when binding address at inet6_bind: 324 if (addr_type & IPV6_ADDR_LINKLOCAL) { 325 if (addr_len >= sizeof(struct sockaddr_in6) && 326 addr->sin6_scope_id) { 327 /* Override any existing binding, if another one 328 * is supplied by user. 329 */ 330 sk->sk_bound_dev_if = addr->sin6_scope_id; 331 } 332 333 /* Binding to link-local address requires an interface */ 334 if (!sk->sk_bound_dev_if) { 335 err = -EINVAL; 336 goto out_unlock; 337 } Replacing svc_addr_u by sockaddr_storage, let rqstp->rq_daddr contains more info besides address. Reviewed-by: Jeff Layton Reviewed-by: Chuck Lever Signed-off-by: Mi Jinlong Signed-off-by: J. Bruce Fields --- fs/lockd/host.c | 25 ++----------------------- fs/nfsd/nfs4state.c | 16 +--------------- include/linux/sunrpc/svc.h | 30 +++++++++++++++++++++--------- net/sunrpc/svc_xprt.c | 13 ++----------- net/sunrpc/svcsock.c | 23 +++++++++++++++++------ 5 files changed, 43 insertions(+), 64 deletions(-) (limited to 'include') diff --git a/fs/lockd/host.c b/fs/lockd/host.c index b7c99bfb3da..6f29836ec0c 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -316,14 +316,8 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, struct hlist_node *pos; struct nlm_host *host = NULL; struct nsm_handle *nsm = NULL; - struct sockaddr_in sin = { - .sin_family = AF_INET, - }; - struct sockaddr_in6 sin6 = { - .sin6_family = AF_INET6, - }; - struct sockaddr *src_sap; - size_t src_len = rqstp->rq_addrlen; + struct sockaddr *src_sap = svc_daddr(rqstp); + size_t src_len = rqstp->rq_daddrlen; struct nlm_lookup_host_info ni = { .server = 1, .sap = svc_addr(rqstp), @@ -340,21 +334,6 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, mutex_lock(&nlm_host_mutex); - switch (ni.sap->sa_family) { - case AF_INET: - sin.sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr; - src_sap = (struct sockaddr *)&sin; - break; - case AF_INET6: - ipv6_addr_copy(&sin6.sin6_addr, &rqstp->rq_daddr.addr6); - src_sap = (struct sockaddr *)&sin6; - break; - default: - dprintk("lockd: %s failed; unrecognized address family\n", - __func__); - goto out; - } - if (time_after_eq(jiffies, next_gc)) nlm_gc_hosts(); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0cd346477f2..e7f83bd9b4a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1257,20 +1257,6 @@ find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) return NULL; } -static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr) -{ - switch (family) { - case AF_INET: - ((struct sockaddr_in *)sa)->sin_family = AF_INET; - ((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr; - return; - case AF_INET6: - ((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6; - ((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6; - return; - } -} - static void gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) { @@ -1302,7 +1288,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r conn->cb_prog = se->se_callback_prog; conn->cb_ident = se->se_callback_ident; - rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr); + memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); return; out_err: conn->cb_addr.ss_family = AF_UNSPEC; diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index a78a51e9337..d8d5d93071b 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -212,11 +212,6 @@ static inline void svc_putu32(struct kvec *iov, __be32 val) iov->iov_len += sizeof(__be32); } -union svc_addr_u { - struct in_addr addr; - struct in6_addr addr6; -}; - /* * The context of a single thread, including the request currently being * processed. @@ -225,8 +220,12 @@ struct svc_rqst { struct list_head rq_list; /* idle list */ struct list_head rq_all; /* all threads list */ struct svc_xprt * rq_xprt; /* transport ptr */ + struct sockaddr_storage rq_addr; /* peer address */ size_t rq_addrlen; + struct sockaddr_storage rq_daddr; /* dest addr of request + * - reply from here */ + size_t rq_daddrlen; struct svc_serv * rq_server; /* RPC service definition */ struct svc_pool * rq_pool; /* thread pool */ @@ -255,9 +254,6 @@ struct svc_rqst { unsigned short rq_secure : 1; /* secure port */ - union svc_addr_u rq_daddr; /* dest addr of request - * - reply from here */ - void * rq_argp; /* decoded arguments */ void * rq_resp; /* xdr'd results */ void * rq_auth_data; /* flavor-specific data */ @@ -300,6 +296,21 @@ static inline struct sockaddr *svc_addr(const struct svc_rqst *rqst) return (struct sockaddr *) &rqst->rq_addr; } +static inline struct sockaddr_in *svc_daddr_in(const struct svc_rqst *rqst) +{ + return (struct sockaddr_in *) &rqst->rq_daddr; +} + +static inline struct sockaddr_in6 *svc_daddr_in6(const struct svc_rqst *rqst) +{ + return (struct sockaddr_in6 *) &rqst->rq_daddr; +} + +static inline struct sockaddr *svc_daddr(const struct svc_rqst *rqst) +{ + return (struct sockaddr *) &rqst->rq_daddr; +} + /* * Check buffer bounds after decoding arguments */ @@ -340,7 +351,8 @@ struct svc_deferred_req { struct svc_xprt *xprt; struct sockaddr_storage addr; /* where reply must go */ size_t addrlen; - union svc_addr_u daddr; /* where reply must come from */ + struct sockaddr_storage daddr; /* where reply must come from */ + size_t daddrlen; struct cache_deferred_req handle; size_t xprt_hlen; int argslen; diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index bd31208bbb6..d86bb673e1f 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -254,8 +254,6 @@ EXPORT_SYMBOL_GPL(svc_create_xprt); */ void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt) { - struct sockaddr *sin; - memcpy(&rqstp->rq_addr, &xprt->xpt_remote, xprt->xpt_remotelen); rqstp->rq_addrlen = xprt->xpt_remotelen; @@ -263,15 +261,8 @@ void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt) * Destination address in request is needed for binding the * source address in RPC replies/callbacks later. */ - sin = (struct sockaddr *)&xprt->xpt_local; - switch (sin->sa_family) { - case AF_INET: - rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr; - break; - case AF_INET6: - rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr; - break; - } + memcpy(&rqstp->rq_daddr, &xprt->xpt_local, xprt->xpt_locallen); + rqstp->rq_daddrlen = xprt->xpt_locallen; } EXPORT_SYMBOL_GPL(svc_xprt_copy_addrs); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 767d494de7a..dfd686eb0b7 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -143,19 +143,20 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh) cmh->cmsg_level = SOL_IP; cmh->cmsg_type = IP_PKTINFO; pki->ipi_ifindex = 0; - pki->ipi_spec_dst.s_addr = rqstp->rq_daddr.addr.s_addr; + pki->ipi_spec_dst.s_addr = + svc_daddr_in(rqstp)->sin_addr.s_addr; cmh->cmsg_len = CMSG_LEN(sizeof(*pki)); } break; case AF_INET6: { struct in6_pktinfo *pki = CMSG_DATA(cmh); + struct sockaddr_in6 *daddr = svc_daddr_in6(rqstp); cmh->cmsg_level = SOL_IPV6; cmh->cmsg_type = IPV6_PKTINFO; - pki->ipi6_ifindex = 0; - ipv6_addr_copy(&pki->ipi6_addr, - &rqstp->rq_daddr.addr6); + pki->ipi6_ifindex = daddr->sin6_scope_id; + ipv6_addr_copy(&pki->ipi6_addr, &daddr->sin6_addr); cmh->cmsg_len = CMSG_LEN(sizeof(*pki)); } break; @@ -498,9 +499,13 @@ static int svc_udp_get_dest_address4(struct svc_rqst *rqstp, struct cmsghdr *cmh) { struct in_pktinfo *pki = CMSG_DATA(cmh); + struct sockaddr_in *daddr = svc_daddr_in(rqstp); + if (cmh->cmsg_type != IP_PKTINFO) return 0; - rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr; + + daddr->sin_family = AF_INET; + daddr->sin_addr.s_addr = pki->ipi_spec_dst.s_addr; return 1; } @@ -511,9 +516,14 @@ static int svc_udp_get_dest_address6(struct svc_rqst *rqstp, struct cmsghdr *cmh) { struct in6_pktinfo *pki = CMSG_DATA(cmh); + struct sockaddr_in6 *daddr = svc_daddr_in6(rqstp); + if (cmh->cmsg_type != IPV6_PKTINFO) return 0; - ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr); + + daddr->sin6_family = AF_INET6; + ipv6_addr_copy(&daddr->sin6_addr, &pki->ipi6_addr); + daddr->sin6_scope_id = pki->ipi6_ifindex; return 1; } @@ -614,6 +624,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) skb_free_datagram_locked(svsk->sk_sk, skb); return 0; } + rqstp->rq_daddrlen = svc_addr_len(svc_daddr(rqstp)); if (skb_is_nonlinear(skb)) { /* we have to copy */ -- cgit v1.2.3-70-g09d2 From 038c01598e728cda5b2996c4bf883e8485b2fe50 Mon Sep 17 00:00:00 2001 From: Mi Jinlong Date: Tue, 30 Aug 2011 17:22:49 +0800 Subject: SUNRPC: compare scopeid for link-local addresses For ipv6 link-local addresses, sunrpc do not compare those scope id. This patch let sunrpc compares scope id only on link-local addresses. Signed-off-by: Mi Jinlong Reviewed-by: Chuck Lever Reviewed-by: Jeff Layton Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/clnt.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index db7bcaf7c5b..ee1bb67f525 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -218,7 +218,13 @@ static inline bool __rpc_cmp_addr6(const struct sockaddr *sap1, { const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1; const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2; - return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr); + + if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr)) + return false; + else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL) + return sin1->sin6_scope_id == sin2->sin6_scope_id; + + return true; } static inline bool __rpc_copy_addr6(struct sockaddr *dst, -- cgit v1.2.3-70-g09d2 From 8b289b2c2355c3bea75f3e499b4aa251a3191382 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 19 Oct 2011 11:52:12 -0400 Subject: nfsd4: implement new 4.1 open reclaim types Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 15 +++------------ fs/nfsd/nfs4state.c | 10 ++++++++-- fs/nfsd/nfs4xdr.c | 13 +++++++++++++ include/linux/nfs4.h | 5 ++++- 4 files changed, 28 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 710b97b7a2f..458ebb6b59c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -366,12 +366,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, switch (open->op_claim_type) { case NFS4_OPEN_CLAIM_DELEGATE_CUR: case NFS4_OPEN_CLAIM_NULL: - /* - * (1) set CURRENT_FH to the file being opened, - * creating it if necessary, (2) set open->op_cinfo, - * (3) set open->op_truncate if the file is to be - * truncated after opening, (4) do permission checking. - */ status = do_open_lookup(rqstp, &cstate->current_fh, open); if (status) @@ -379,17 +373,14 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, break; case NFS4_OPEN_CLAIM_PREVIOUS: open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; - /* - * The CURRENT_FH is already set to the file being - * opened. (1) set open->op_cinfo, (2) set - * open->op_truncate if the file is to be truncated - * after opening, (3) do permission checking. - */ + case NFS4_OPEN_CLAIM_FH: + case NFS4_OPEN_CLAIM_DELEG_CUR_FH: status = do_open_fhandle(rqstp, &cstate->current_fh, open); if (status) goto out; break; + case NFS4_OPEN_CLAIM_DELEG_PREV_FH: case NFS4_OPEN_CLAIM_DELEGATE_PREV: open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; dprintk("NFSD: unsupported OPEN claim type %d\n", diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 15e0db14040..e8c2a3ec0e6 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2587,6 +2587,12 @@ static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, statei return delegstateid(ret); } +static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) +{ + return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || + open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; +} + static __be32 nfs4_check_deleg(struct nfs4_client *cl, struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_delegation **dp) @@ -2602,7 +2608,7 @@ nfs4_check_deleg(struct nfs4_client *cl, struct nfs4_file *fp, struct nfsd4_open if (status) *dp = NULL; out: - if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR) + if (!nfsd4_is_deleg_cur(open)) return nfs_ok; if (status) return status; @@ -2879,7 +2885,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf goto out; } else { status = nfserr_bad_stateid; - if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) + if (nfsd4_is_deleg_cur(open)) goto out; status = nfserr_jukebox; fp = open->op_file; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 645a0a9d807..fdc09a52cd8 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -803,6 +803,19 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) return status; break; + case NFS4_OPEN_CLAIM_FH: + case NFS4_OPEN_CLAIM_DELEG_PREV_FH: + if (argp->minorversion < 1) + goto xdr_error; + /* void */ + break; + case NFS4_OPEN_CLAIM_DELEG_CUR_FH: + if (argp->minorversion < 1) + goto xdr_error; + status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid); + if (status) + return status; + break; default: goto xdr_error; } diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index b875b0324fc..32345c2805c 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -410,7 +410,10 @@ enum open_claim_type4 { NFS4_OPEN_CLAIM_NULL = 0, NFS4_OPEN_CLAIM_PREVIOUS = 1, NFS4_OPEN_CLAIM_DELEGATE_CUR = 2, - NFS4_OPEN_CLAIM_DELEGATE_PREV = 3 + NFS4_OPEN_CLAIM_DELEGATE_PREV = 3, + NFS4_OPEN_CLAIM_FH = 4, /* 4.1 */ + NFS4_OPEN_CLAIM_DELEG_CUR_FH = 5, /* 4.1 */ + NFS4_OPEN_CLAIM_DELEG_PREV_FH = 6, /* 4.1 */ }; enum opentype4 { -- cgit v1.2.3-70-g09d2