diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fuse/dev.c | 51 | ||||
-rw-r--r-- | fs/fuse/dir.c | 31 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 2 | ||||
-rw-r--r-- | fs/fuse/inode.c | 5 | ||||
-rw-r--r-- | fs/kernfs/dir.c | 12 | ||||
-rw-r--r-- | fs/lockd/svc.c | 8 | ||||
-rw-r--r-- | fs/locks.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4client.c | 42 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 21 |
9 files changed, 115 insertions, 59 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index ba1107977f2e..ed19a7d622fa 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -131,6 +131,13 @@ static void fuse_req_init_context(struct fuse_req *req) req->in.h.pid = current->pid; } +void fuse_set_initialized(struct fuse_conn *fc) +{ + /* Make sure stores before this are seen on another CPU */ + smp_wmb(); + fc->initialized = 1; +} + static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background) { return !fc->initialized || (for_background && fc->blocked); @@ -155,6 +162,8 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages, if (intr) goto out; } + /* Matches smp_wmb() in fuse_set_initialized() */ + smp_rmb(); err = -ENOTCONN; if (!fc->connected) @@ -253,6 +262,8 @@ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc, atomic_inc(&fc->num_waiting); wait_event(fc->blocked_waitq, fc->initialized); + /* Matches smp_wmb() in fuse_set_initialized() */ + smp_rmb(); req = fuse_request_alloc(0); if (!req) req = get_reserved_req(fc, file); @@ -511,6 +522,39 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) } EXPORT_SYMBOL_GPL(fuse_request_send); +static void fuse_adjust_compat(struct fuse_conn *fc, struct fuse_args *args) +{ + if (fc->minor < 4 && args->in.h.opcode == FUSE_STATFS) + args->out.args[0].size = FUSE_COMPAT_STATFS_SIZE; + + if (fc->minor < 9) { + switch (args->in.h.opcode) { + case FUSE_LOOKUP: + case FUSE_CREATE: + case FUSE_MKNOD: + case FUSE_MKDIR: + case FUSE_SYMLINK: + case FUSE_LINK: + args->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; + break; + case FUSE_GETATTR: + case FUSE_SETATTR: + args->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; + break; + } + } + if (fc->minor < 12) { + switch (args->in.h.opcode) { + case FUSE_CREATE: + args->in.args[0].size = sizeof(struct fuse_open_in); + break; + case FUSE_MKNOD: + args->in.args[0].size = FUSE_COMPAT_MKNOD_IN_SIZE; + break; + } + } +} + ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args) { struct fuse_req *req; @@ -520,6 +564,9 @@ ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args) if (IS_ERR(req)) return PTR_ERR(req); + /* Needs to be done after fuse_get_req() so that fc->minor is valid */ + fuse_adjust_compat(fc, args); + req->in.h.opcode = args->in.h.opcode; req->in.h.nodeid = args->in.h.nodeid; req->in.numargs = args->in.numargs; @@ -2127,7 +2174,7 @@ void fuse_abort_conn(struct fuse_conn *fc) if (fc->connected) { fc->connected = 0; fc->blocked = 0; - fc->initialized = 1; + fuse_set_initialized(fc); end_io_requests(fc); end_queued_requests(fc); end_polls(fc); @@ -2146,7 +2193,7 @@ int fuse_dev_release(struct inode *inode, struct file *file) spin_lock(&fc->lock); fc->connected = 0; fc->blocked = 0; - fc->initialized = 1; + fuse_set_initialized(fc); end_queued_requests(fc); end_polls(fc); wake_up_all(&fc->blocked_waitq); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 252b8a5de8b5..08e7b1a9d5d0 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -156,10 +156,7 @@ static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args, args->in.args[0].size = name->len + 1; args->in.args[0].value = name->name; args->out.numargs = 1; - if (fc->minor < 9) - args->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; - else - args->out.args[0].size = sizeof(struct fuse_entry_out); + args->out.args[0].size = sizeof(struct fuse_entry_out); args->out.args[0].value = outarg; } @@ -422,16 +419,12 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, args.in.h.opcode = FUSE_CREATE; args.in.h.nodeid = get_node_id(dir); args.in.numargs = 2; - args.in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) : - sizeof(inarg); + args.in.args[0].size = sizeof(inarg); args.in.args[0].value = &inarg; args.in.args[1].size = entry->d_name.len + 1; args.in.args[1].value = entry->d_name.name; args.out.numargs = 2; - if (fc->minor < 9) - args.out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; - else - args.out.args[0].size = sizeof(outentry); + args.out.args[0].size = sizeof(outentry); args.out.args[0].value = &outentry; args.out.args[1].size = sizeof(outopen); args.out.args[1].value = &outopen; @@ -539,10 +532,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args, memset(&outarg, 0, sizeof(outarg)); args->in.h.nodeid = get_node_id(dir); args->out.numargs = 1; - if (fc->minor < 9) - args->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; - else - args->out.args[0].size = sizeof(outarg); + args->out.args[0].size = sizeof(outarg); args->out.args[0].value = &outarg; err = fuse_simple_request(fc, args); if (err) @@ -592,8 +582,7 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode, inarg.umask = current_umask(); args.in.h.opcode = FUSE_MKNOD; args.in.numargs = 2; - args.in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE : - sizeof(inarg); + args.in.args[0].size = sizeof(inarg); args.in.args[0].value = &inarg; args.in.args[1].size = entry->d_name.len + 1; args.in.args[1].value = entry->d_name.name; @@ -899,10 +888,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, args.in.args[0].size = sizeof(inarg); args.in.args[0].value = &inarg; args.out.numargs = 1; - if (fc->minor < 9) - args.out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; - else - args.out.args[0].size = sizeof(outarg); + args.out.args[0].size = sizeof(outarg); args.out.args[0].value = &outarg; err = fuse_simple_request(fc, &args); if (!err) { @@ -1574,10 +1560,7 @@ static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_args *args, args->in.args[0].size = sizeof(*inarg_p); args->in.args[0].value = inarg_p; args->out.numargs = 1; - if (fc->minor < 9) - args->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; - else - args->out.args[0].size = sizeof(*outarg_p); + args->out.args[0].size = sizeof(*outarg_p); args->out.args[0].value = outarg_p; } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index e0fc6725d1d0..1cdfb07c1376 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -906,4 +906,6 @@ int fuse_write_inode(struct inode *inode, struct writeback_control *wbc); int fuse_do_setattr(struct inode *inode, struct iattr *attr, struct file *file); +void fuse_set_initialized(struct fuse_conn *fc); + #endif /* _FS_FUSE_I_H */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 6749109f255d..f38256e4476e 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -424,8 +424,7 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) args.in.h.opcode = FUSE_STATFS; args.in.h.nodeid = get_node_id(dentry->d_inode); args.out.numargs = 1; - args.out.args[0].size = - fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg); + args.out.args[0].size = sizeof(outarg); args.out.args[0].value = &outarg; err = fuse_simple_request(fc, &args); if (!err) @@ -898,7 +897,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) fc->max_write = max_t(unsigned, 4096, fc->max_write); fc->conn_init = 1; } - fc->initialized = 1; + fuse_set_initialized(fc); wake_up_all(&fc->blocked_waitq); } diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 37989f02a226..2d881b381d2b 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -201,10 +201,14 @@ static unsigned int kernfs_name_hash(const char *name, const void *ns) static int kernfs_name_compare(unsigned int hash, const char *name, const void *ns, const struct kernfs_node *kn) { - if (hash != kn->hash) - return hash - kn->hash; - if (ns != kn->ns) - return ns - kn->ns; + if (hash < kn->hash) + return -1; + if (hash > kn->hash) + return 1; + if (ns < kn->ns) + return -1; + if (ns > kn->ns) + return 1; return strcmp(name, kn->name); } diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index e94c887da2d7..55505cbe11af 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -138,10 +138,6 @@ lockd(void *vrqstp) dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); - if (!nlm_timeout) - nlm_timeout = LOCKD_DFLT_TIMEO; - nlmsvc_timeout = nlm_timeout * HZ; - /* * The main request loop. We don't terminate until the last * NFS mount or NFS daemon has gone away. @@ -350,6 +346,10 @@ static struct svc_serv *lockd_create_svc(void) printk(KERN_WARNING "lockd_up: no pid, %d users??\n", nlmsvc_users); + if (!nlm_timeout) + nlm_timeout = LOCKD_DFLT_TIMEO; + nlmsvc_timeout = nlm_timeout * HZ; + serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, svc_rpcb_cleanup); if (!serv) { printk(KERN_WARNING "lockd_up: create service failed\n"); diff --git a/fs/locks.c b/fs/locks.c index 735b8d3fa78c..59e2f905e4ff 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1702,7 +1702,7 @@ static int generic_delete_lease(struct file *filp) break; } trace_generic_delete_lease(inode, fl); - if (fl) + if (fl && IS_LEASE(fl)) error = fl->fl_lmops->lm_change(before, F_UNLCK, &dispose); spin_unlock(&inode->i_lock); locks_dispose_list(&dispose); diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 03311259b0c4..953daa44a282 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -228,6 +228,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp) kfree(clp->cl_serverowner); kfree(clp->cl_serverscope); kfree(clp->cl_implid); + kfree(clp->cl_owner_id); } void nfs4_free_client(struct nfs_client *clp) @@ -452,6 +453,14 @@ static void nfs4_swap_callback_idents(struct nfs_client *keep, spin_unlock(&nn->nfs_client_lock); } +static bool nfs4_match_client_owner_id(const struct nfs_client *clp1, + const struct nfs_client *clp2) +{ + if (clp1->cl_owner_id == NULL || clp2->cl_owner_id == NULL) + return true; + return strcmp(clp1->cl_owner_id, clp2->cl_owner_id) == 0; +} + /** * nfs40_walk_client_list - Find server that recognizes a client ID * @@ -483,9 +492,6 @@ int nfs40_walk_client_list(struct nfs_client *new, if (pos->rpc_ops != new->rpc_ops) continue; - if (pos->cl_proto != new->cl_proto) - continue; - if (pos->cl_minorversion != new->cl_minorversion) continue; @@ -510,6 +516,9 @@ int nfs40_walk_client_list(struct nfs_client *new, if (pos->cl_clientid != new->cl_clientid) continue; + if (!nfs4_match_client_owner_id(pos, new)) + continue; + atomic_inc(&pos->cl_count); spin_unlock(&nn->nfs_client_lock); @@ -566,20 +575,14 @@ static bool nfs4_match_clientids(struct nfs_client *a, struct nfs_client *b) } /* - * Returns true if the server owners match + * Returns true if the server major ids match */ static bool -nfs4_match_serverowners(struct nfs_client *a, struct nfs_client *b) +nfs4_check_clientid_trunking(struct nfs_client *a, struct nfs_client *b) { struct nfs41_server_owner *o1 = a->cl_serverowner; struct nfs41_server_owner *o2 = b->cl_serverowner; - if (o1->minor_id != o2->minor_id) { - dprintk("NFS: --> %s server owner minor IDs do not match\n", - __func__); - return false; - } - if (o1->major_id_sz != o2->major_id_sz) goto out_major_mismatch; if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0) @@ -621,9 +624,6 @@ int nfs41_walk_client_list(struct nfs_client *new, if (pos->rpc_ops != new->rpc_ops) continue; - if (pos->cl_proto != new->cl_proto) - continue; - if (pos->cl_minorversion != new->cl_minorversion) continue; @@ -654,7 +654,19 @@ int nfs41_walk_client_list(struct nfs_client *new, if (!nfs4_match_clientids(pos, new)) continue; - if (!nfs4_match_serverowners(pos, new)) + /* + * Note that session trunking is just a special subcase of + * client id trunking. In either case, we want to fall back + * to using the existing nfs_client. + */ + if (!nfs4_check_clientid_trunking(pos, new)) + continue; + + /* Unlike NFSv4.0, we know that NFSv4.1 always uses the + * uniform string, however someone might switch the + * uniquifier string on us. + */ + if (!nfs4_match_client_owner_id(pos, new)) continue; atomic_inc(&pos->cl_count); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e7f8d5ff2581..c347705b0161 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1117,8 +1117,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode) return 0; if ((delegation->type & fmode) != fmode) return 0; - if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) - return 0; if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) return 0; nfs_mark_delegation_referenced(delegation); @@ -4917,11 +4915,14 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp, } static unsigned int -nfs4_init_nonuniform_client_string(const struct nfs_client *clp, +nfs4_init_nonuniform_client_string(struct nfs_client *clp, char *buf, size_t len) { unsigned int result; + if (clp->cl_owner_id != NULL) + return strlcpy(buf, clp->cl_owner_id, len); + rcu_read_lock(); result = scnprintf(buf, len, "Linux NFSv4.0 %s/%s %s", clp->cl_ipaddr, @@ -4930,24 +4931,32 @@ nfs4_init_nonuniform_client_string(const struct nfs_client *clp, rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_PROTO)); rcu_read_unlock(); + clp->cl_owner_id = kstrdup(buf, GFP_KERNEL); return result; } static unsigned int -nfs4_init_uniform_client_string(const struct nfs_client *clp, +nfs4_init_uniform_client_string(struct nfs_client *clp, char *buf, size_t len) { const char *nodename = clp->cl_rpcclient->cl_nodename; + unsigned int result; + + if (clp->cl_owner_id != NULL) + return strlcpy(buf, clp->cl_owner_id, len); if (nfs4_client_id_uniquifier[0] != '\0') - return scnprintf(buf, len, "Linux NFSv%u.%u %s/%s", + result = scnprintf(buf, len, "Linux NFSv%u.%u %s/%s", clp->rpc_ops->version, clp->cl_minorversion, nfs4_client_id_uniquifier, nodename); - return scnprintf(buf, len, "Linux NFSv%u.%u %s", + else + result = scnprintf(buf, len, "Linux NFSv%u.%u %s", clp->rpc_ops->version, clp->cl_minorversion, nodename); + clp->cl_owner_id = kstrdup(buf, GFP_KERNEL); + return result; } /* |