/* * FUSE: Filesystem in Userspace * Copyright (C) 2001-2016 Miklos Szeredi * * This program can be distributed under the terms of the GNU GPL. * See the file COPYING. */ #include "fuse_i.h" #include #include int fuse_setxattr(struct inode *inode, const char *name, const void *value, size_t size, int flags) { struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); struct fuse_setxattr_in inarg; int err; if (fc->no_setxattr) return -EOPNOTSUPP; memset(&inarg, 0, sizeof(inarg)); inarg.size = size; inarg.flags = flags; args.in.h.opcode = FUSE_SETXATTR; args.in.h.nodeid = get_node_id(inode); args.in.numargs = 3; args.in.args[0].size = sizeof(inarg); args.in.args[0].value = &inarg; args.in.args[1].size = strlen(name) + 1; args.in.args[1].value = name; args.in.args[2].size = size; args.in.args[2].value = value; err = fuse_simple_request(fc, &args); if (err == -ENOSYS) { fc->no_setxattr = 1; err = -EOPNOTSUPP; } if (!err) { fuse_invalidate_attr(inode); fuse_update_ctime(inode); } return err; } ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value, size_t size) { struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); struct fuse_getxattr_in inarg; struct fuse_getxattr_out outarg; ssize_t ret; if (fc->no_getxattr) return -EOPNOTSUPP; memset(&inarg, 0, sizeof(inarg)); inarg.size = size; args.in.h.opcode = FUSE_GETXATTR; args.in.h.nodeid = get_node_id(inode); args.in.numargs = 2; args.in.args[0].size = sizeof(inarg); args.in.args[0].value = &inarg; args.in.args[1].size = strlen(name) + 1; args.in.args[1].value = name; /* This is really two different operations rolled into one */ args.out.numargs = 1; if (size) { args.out.argvar = 1; args.out.args[0].size = size; args.out.args[0].value = value; } else { args.out.args[0].size = sizeof(outarg); args.out.args[0].value = &outarg; } ret = fuse_simple_request(fc, &args); if (!ret && !size) ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX); if (ret == -ENOSYS) { fc->no_getxattr = 1; ret = -EOPNOTSUPP; } return ret; } static int fuse_verify_xattr_list(char *list, size_t size) { size_t origsize = size; while (size) { size_t thislen = strnlen(list, size); if (!thislen || thislen == size) return -EIO; size -= thislen + 1; list += thislen + 1; } return origsize; } ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) { struct inode *inode = d_inode(entry); struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); struct fuse_getxattr_in inarg; struct fuse_getxattr_out outarg; ssize_t ret; if (!fuse_allow_current_process(fc)) return -EACCES; if (fc->no_listxattr) return -EOPNOTSUPP; memset(&inarg, 0, sizeof(inarg)); inarg.size = size; args.in.h.opcode = FUSE_LISTXATTR; args.in.h.nodeid = get_node_id(inode); args.in.numargs = 1; args.in.args[0].size = sizeof(inarg); args.in.args[0].value = &inarg; /* This is really two different operations rolled into one */ args.out.numargs = 1; if (size) { args.out.argvar = 1; args.out.args[0].size = size; args.out.args[0].value = list; } else { args.out.args[0].size = sizeof(outarg); args.out.args[0].value = &outarg; } ret = fuse_simple_request(fc, &args); if (!ret && !size) ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX); if (ret > 0 && size) ret = fuse_verify_xattr_list(list, ret); if (ret == -ENOSYS) { fc->no_listxattr = 1; ret = -EOPNOTSUPP; } return ret; } int fuse_removexattr(struct inode *inode, const char *name) { struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); int err; if (fc->no_removexattr) return -EOPNOTSUPP; args.in.h.opcode = FUSE_REMOVEXATTR; args.in.h.nodeid = get_node_id(inode); args.in.numargs = 1; args.in.args[0].size = strlen(name) + 1; args.in.args[0].value = name; err = fuse_simple_request(fc, &args); if (err == -ENOSYS) { fc->no_removexattr = 1; err = -EOPNOTSUPP; } if (!err) { fuse_invalidate_attr(inode); fuse_update_ctime(inode); } return err; } static int fuse_xattr_get(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, const char *name, void *value, size_t size) { return fuse_getxattr(inode, name, value, size); } static int fuse_xattr_set(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, const char *name, const void *value, size_t size, int flags) { if (!value) return fuse_removexattr(inode, name); return fuse_setxattr(inode, name, value, size, flags); } static const struct xattr_handler fuse_xattr_handler = { .prefix = "", .get = fuse_xattr_get, .set = fuse_xattr_set, }; const struct xattr_handler *fuse_xattr_handlers[] = { &fuse_xattr_handler, NULL }; const struct xattr_handler *fuse_acl_xattr_handlers[] = { &posix_acl_access_xattr_handler, &posix_acl_default_xattr_handler, &fuse_xattr_handler, NULL }; r> commit79c6f448c8b79c321e4a1f31f98194e4f6b6cae7 (patch) tree370efda701f03cccf21e02bb1fdd3b852547d75c /drivers/usb/storage/usual-tables.c parent0c744ea4f77d72b3dcebb7a8f2684633ec79be88 (diff)
tracing: Fix hwlat kthread migration
The hwlat tracer creates a kernel thread at start of the tracer. It is pinned to a single CPU and will move to the next CPU after each period of running. If the user modifies the migration thread's affinity, it will not change after that happens. The original code created the thread at the first instance it was called, but later was changed to destroy the thread after the tracer was finished, and would not be created until the next instance of the tracer was established. The code that initialized the affinity was only called on the initial instantiation of the tracer. After that, it was not initialized, and the previous affinity did not match the current newly created one, making it appear that the user modified the thread's affinity when it did not, and the thread failed to migrate again. Cc: stable@vger.kernel.org Fixes: 0330f7aa8ee6 ("tracing: Have hwlat trace migrate across tracing_cpumask CPUs") Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Diffstat (limited to 'drivers/usb/storage/usual-tables.c')