/* ----------------------------------------------------------------------- * * * Copyright 2012 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available * under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * ----------------------------------------------------------------------- */ /* * earlycpio.c * * Find a specific cpio member; must precede any compressed content. * This is used to locate data items in the initramfs used by the * kernel itself during early boot (before the main initramfs is * decompressed.) It is the responsibility of the initramfs creator * to ensure that these items are uncompressed at the head of the * blob. Depending on the boot loader or package tool that may be a * separate file or part of the same file. */ #include #include #include enum cpio_fields { C_MAGIC, C_INO, C_MODE, C_UID, C_GID, C_NLINK, C_MTIME, C_FILESIZE, C_MAJ, C_MIN, C_RMAJ, C_RMIN, C_NAMESIZE, C_CHKSUM, C_NFIELDS }; /** * cpio_data find_cpio_data - Search for files in an uncompressed cpio * @path: The directory to search for, including a slash at the end * @data: Pointer to the the cpio archive or a header inside * @len: Remaining length of the cpio based on data pointer * @nextoff: When a matching file is found, this is the offset from the * beginning of the cpio to the beginning of the next file, not the * matching file itself. It can be used to iterate through the cpio * to find all files inside of a directory path. * * @return: struct cpio_data containing the address, length and * filename (with the directory path cut off) of the found file. * If you search for a filename and not for files in a directory, * pass the absolute path of the filename in the cpio and make sure * the match returned an empty filename string. */ struct cpio_data find_cpio_data(const char *path, void *data, size_t len, long *nextoff) { const size_t cpio_header_len = 8*C_NFIELDS - 2; struct cpio_data cd = { NULL, 0, "" }; const char *p, *dptr, *nptr; unsigned int ch[C_NFIELDS], *chp, v; unsigned char c, x; size_t mypathsize = strlen(path); int i, j; p = data; while (len > cpio_header_len) { if (!*p) { /* All cpio headers need to be 4-byte aligned */ p += 4; len -= 4; continue; } j = 6; /* The magic field is only 6 characters */ chp = ch; for (i = C_NFIELDS; i; i--) { v = 0; while (j--) { v <<= 4; c = *p++; x = c - '0'; if (x < 10) { v += x; continue; } x = (c | 0x20) - 'a'; if (x < 6) { v += x + 10; continue; } goto quit; /* Invalid hexadecimal */ } *chp++ = v; j = 8; /* All other fields are 8 characters */ } if ((ch[C_MAGIC] - 0x070701) > 1) goto quit; /* Invalid magic */ len -= cpio_header_len; dptr = PTR_ALIGN(p + ch[C_NAMESIZE], 4); nptr = PTR_ALIGN(dptr + ch[C_FILESIZE], 4); if (nptr > p + len || dptr < p || nptr < dptr) goto quit; /* Buffer overrun */ if ((ch[C_MODE] & 0170000) == 0100000 && ch[C_NAMESIZE] >= mypathsize && !memcmp(p, path, mypathsize)) { if (nextoff) *nextoff = (long)nptr - (long)data; if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) { pr_warn( "File %s exceeding MAX_CPIO_FILE_NAME [%d]\n", p, MAX_CPIO_FILE_NAME); } strlcpy(cd.name, p + mypathsize, MAX_CPIO_FILE_NAME); cd.data = (void *)dptr; cd.size = ch[C_FILESIZE]; return cd; /* Found it! */ } len -= (nptr - p); p = nptr; } quit: return cd; } ion value='5'>5space:mode:
Diffstat (limited to 'include/acpi/button.h')
ht'>2017-01-28 07:49:42 -0500
commit966d2b04e070bc040319aaebfec09e0144dc3341 (patch)
tree4b96156e3d1dd4dfd6039b7c219c9dc4616da52d /tools/testing/radix-tree/generated/autoconf.h
parent1b1bc42c1692e9b62756323c675a44cb1a1f9dbd (diff)
percpu-refcount: fix reference leak during percpu-atomic transition
percpu_ref_tryget() and percpu_ref_tryget_live() should return "true" IFF they acquire a reference. But the return value from atomic_long_inc_not_zero() is a long and may have high bits set, e.g. PERCPU_COUNT_BIAS, and the return value of the tryget routines is bool so the reference may actually be acquired but the routines return "false" which results in a reference leak since the caller assumes it does not need to do a corresponding percpu_ref_put(). This was seen when performing CPU hotplug during I/O, as hangs in blk_mq_freeze_queue_wait where percpu_ref_kill (blk_mq_freeze_queue_start) raced with percpu_ref_tryget (blk_mq_timeout_work). Sample stack trace: __switch_to+0x2c0/0x450 __schedule+0x2f8/0x970 schedule+0x48/0xc0 blk_mq_freeze_queue_wait+0x94/0x120 blk_mq_queue_reinit_work+0xb8/0x180 blk_mq_queue_reinit_prepare+0x84/0xa0 cpuhp_invoke_callback+0x17c/0x600 cpuhp_up_callbacks+0x58/0x150 _cpu_up+0xf0/0x1c0 do_cpu_up+0x120/0x150 cpu_subsys_online+0x64/0xe0 device_online+0xb4/0x120 online_store+0xb4/0xc0 dev_attr_store+0x68/0xa0 sysfs_kf_write+0x80/0xb0 kernfs_fop_write+0x17c/0x250 __vfs_write+0x6c/0x1e0 vfs_write+0xd0/0x270 SyS_write+0x6c/0x110 system_call+0x38/0xe0 Examination of the queue showed a single reference (no PERCPU_COUNT_BIAS, and __PERCPU_REF_DEAD, __PERCPU_REF_ATOMIC set) and no requests. However, conditions at the time of the race are count of PERCPU_COUNT_BIAS + 0 and __PERCPU_REF_DEAD and __PERCPU_REF_ATOMIC set. The fix is to make the tryget routines use an actual boolean internally instead of the atomic long result truncated to a int. Fixes: e625305b3907 percpu-refcount: make percpu_ref based on longs instead of ints Link: https://bugzilla.kernel.org/show_bug.cgi?id=190751 Signed-off-by: Douglas Miller <dougmill@linux.vnet.ibm.com> Reviewed-by: Jens Axboe <axboe@fb.com> Signed-off-by: Tejun Heo <tj@kernel.org> Fixes: e625305b3907 ("percpu-refcount: make percpu_ref based on longs instead of ints") Cc: stable@vger.kernel.org # v3.18+
Diffstat (limited to 'tools/testing/radix-tree/generated/autoconf.h')