mm.git review status for linus..mm-nonmm-stable

Total patches:       134
 Fixes: tags:         86
 cc:stable patches:   52
 Reviews/patch:       0.73
 Reviewed rate:       59%
 
 Summary of patch series in this merge:
 
 - "ocfs2: exit recovery thread on mount error path" (Joseph Qi):
 
   Stop OCFS2 recovery before freeing failed-mount state and replay slots,
   closing use-after-free and double-free races.  Defer suballocator reclaim
   to break a transaction-lock deadlock with dismount.
 
 - "ocfs2: validate suballoc slot and bit of metadata blocks" (Joseph Qi):
 
   Validate OCFS2 metadata suballocator slots, bits and directory index
   block locations.  Reject corrupt metadata with filesystem errors instead
   of BUGs or out-of-bounds accesses.
 
 - "ocfs2: deal with legacy signed name hash values" (Joseph Qi):
 
   Restore OCFS2 lookups for non-ASCII names stored with legacy signed
   hashes.  Use stored xattr hashes during bucket splits to avoid duplicate
   entries and spurious ENOSPC failures.
 
 - "ocfs2: stabilize dentry names in file and setattr traces" (Cen Zhang):
 
   Snapshot OCFS2 names during file and setattr tracing to prevent rename
   races using freed storage or mismatched names and lengths.  Preserve
   trace formats and the locked release open-count sample.
 
 - "panic: fix panic_force_cpu= redirect races and NMI bypass"
   (Bradley Morgan):
 
   Fix panic_force_cpu races and NMI redirection so crash-kernel CPU
   selection is honored.  Preserve variable arguments on failed redirects
   and use a static message buffer.
 
 - "fat: allocate multiple clusters in fallocate"
   (Matheus Alves de Almeida):
 
   Allocate FAT clusters in batches for FALLOC_FL_KEEP_SIZE and batch FAT
   updates.  This removes repeated single-cluster allocation overhead,
   particularly on synchronous mounts.
 
 - "scripts/gdb: fix radix tree lookup and stack depot diagnostic"
   (Ting-Han Hou):
 
   Fix GDB radix-tree lookup and its handling of XArray sibling, retry and
   zero entries.  Also repair the stack-depot diagnostic for an out-of-range
   pool index.
 
 - "hung_task: Improve warning budget handling and task reporting"
   (Aaron Tomlin):
 
   Reset the hung-task warning budget after recovery so later hangs remain
   visible.  Keep the configured limit intact and emit one summary per scan
   when detailed reports exhaust the budget.
 
 - "bootconfig: Reject unexpected data after null character and cleanups"
   (Masami Hiramatsu (Google)):
 
   Reject bootconfig data after an embedded null while accepting trailing
   padding.  Validate the full input in the userspace tool, and retain
   internal tree sanity checks there rather than in the kernel.
 
 - "kbuild: GCOV cleanups following the prefer-atomic fix"
   (Konstantin Khorenko):
 
   Use the actual GCOV build flags in the prefer-atomic compiler probe.
   Move flag setup into scripts/Makefile.gcov and skip the probe when GCOV
   is disabled.
 
 - "ocfs2: xattr bucket validation fixes" (Joseph Qi):
 
   Accept valid OCFS2 xattr buckets spanning 512-byte blocks, avoiding false
   read-only remounts.  Reject misaligned buckets and return errors instead
   of panicking on corrupt defrag metadata.
 
 - "ocfs2: fix metadata reservation for xattr value trees" (Joseph Qi):
 
   Reserve enough OCFS2 metadata for new and relocated xattr value trees.
   Fix shortfalls which could cause ENOSPC, dropped entries and leaked
   clusters on fragmented filesystems; remove duplicate reservations.
 
 - "Introduce arch_do_panic" (Mete Durlu):
 
   Add arch_do_panic() and move s390 and sparc handling out of generic panic
   code.  The architecture-specific actions now follow the end-of-panic
   marker.
 
 - "checkpatch: userspace improvements" (Petr Vorel):
 
   Improve checkpatch's userspace detection and suppress kernel-only checks.
   Recognize standard inttypes macros and add explicit --userspace and
   --no-userspace overrides.
 
 - "ocfs2: validate dr_fs_generation of dir index root blocks" (Joseph Qi):
 
   Check OCFS2 directory index generations and leaf block numbers.  Reject
   stale or misplaced blocks instead of using metadata left by a previously
   formatted filesystem.
 
 - "selftests/membarrier: Skip an unregistered memory barrier test on Musl"
   (Chris Gellermann):
 
   Skip the unregistered membarrier test when libc has already registered
   the command.  Musl does this during thread creation, causing false
   failures in the multithreaded test.
 
 - "init: fix array boundary bugs in boot parameter parsing"
   (Wilson Felipe Pereira):
 
   Fix boot argument boundary cases which leave stale arguments in init's
   command line or panic when replacing the final environment variable.
   Clear the last slot and check duplicates before the limit.
 
 Summary of the 87 singletons in this merge:
 
 The OCFS2 singletons fix deadlocks between xattr updates and inline
 truncation, and during inode reclaim. Corrupt quota and extent metadata
 could also crash the kernel or corrupt memory; these paths now check the
 layout before using it. Other fixes close use-after-free and publication
 races around cluster reconfiguration, node failure, quota remount errors
 and shared refcount trees. New files now retain security labels from all
 stacked LSMs instead of silently dropping all but one. Valid xattr
 insertions also stop tripping FORTIFY on builds with counted arrays.
 
 Elsewhere, a lost wakeup could leave hardware-monitoring reads stuck in
 unkillable sleep and block further I2C traffic. That is fixed, as are
 kernel memory leaks in POSIX message-queue notifications and tmpfs
 casefold setup which could grow until memory is exhausted. A driver
 removal race which could crash the kernel is fixed too. The hibernation
 command through reboot() also stops taking the same mutex twice,
 avoiding a deadlock before suspension.
 
 On the boot side, bzip2 decoding now accepts valid full blocks emitted
 by lbzip2, fixing failures to boot those compressed kernels. Malformed
 bzip2 streams can no longer overflow the decode buffer, and LZ4 initrds
 are checked before the decoder can read past their end. FAT rejects
 geometry which overflows the data-area calculation on 32-bit systems,
 and rolls back entries when inode setup fails, preventing failed
 creations from reappearing after remount. The x86 XOR and RAID6 AVX
 paths also avoid imposing a slowdown on subsequent SSE code.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQTTMBEPP41GrTpTJgfdBJ7gKXxAjgUCat57YgAKCRDdBJ7gKXxA
 jofGAQDBRlA6AI/WIWAuSb9FH4RIMe16EU3klIYoNqgY3eMbLwD/f8J1rm4gBpBl
 eXV7nwZMb8Ackw1+2CuBtbvpLfjQUA4=
 =JLjf
 -----END PGP SIGNATURE-----

Merge tag 'mm-nonmm-stable-2026-10-25-14-57' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull non-MM updates from Andrew Morton:

 - "ocfs2: exit recovery thread on mount error path" (Joseph Qi):

   Stop OCFS2 recovery before freeing failed-mount state and replay
   slots, closing use-after-free and double-free races. Defer
   suballocator reclaim to break a transaction-lock deadlock with
   dismount.

 - "ocfs2: validate suballoc slot and bit of metadata blocks" (Joseph
   Qi):

   Validate OCFS2 metadata suballocator slots, bits and directory index
   block locations. Reject corrupt metadata with filesystem errors
   instead of BUGs or out-of-bounds accesses.

 - "ocfs2: deal with legacy signed name hash values" (Joseph Qi):

   Restore OCFS2 lookups for non-ASCII names stored with legacy signed
   hashes. Use stored xattr hashes during bucket splits to avoid
   duplicate entries and spurious ENOSPC failures.

 - "ocfs2: stabilize dentry names in file and setattr traces" (Cen
   Zhang):

   Snapshot OCFS2 names during file and setattr tracing to prevent
   rename races using freed storage or mismatched names and lengths.
   Preserve trace formats and the locked release open-count sample.

 - "panic: fix panic_force_cpu= redirect races and NMI bypass" (Bradley
   Morgan):

   Fix panic_force_cpu races and NMI redirection so crash-kernel CPU
   selection is honored. Preserve variable arguments on failed redirects
   and use a static message buffer.

 - "fat: allocate multiple clusters in fallocate" (Matheus Alves de
   Almeida):

   Allocate FAT clusters in batches for FALLOC_FL_KEEP_SIZE and batch
   FAT updates. This removes repeated single-cluster allocation
   overhead, particularly on synchronous mounts.

 - "scripts/gdb: fix radix tree lookup and stack depot diagnostic"
   (Ting-Han Hou):

   Fix GDB radix-tree lookup and its handling of XArray sibling, retry
   and zero entries. Also repair the stack-depot diagnostic for an
   out-of-range pool index.

 - "hung_task: Improve warning budget handling and task reporting"
   (Aaron Tomlin):

   Reset the hung-task warning budget after recovery so later hangs
   remain visible. Keep the configured limit intact and emit one summary
   per scan when detailed reports exhaust the budget.

 - "bootconfig: Reject unexpected data after null character and
   cleanups" (Masami Hiramatsu):

   Reject bootconfig data after an embedded null while accepting
   trailing padding. Validate the full input in the userspace tool, and
   retain internal tree sanity checks there rather than in the kernel.

 - "kbuild: GCOV cleanups following the prefer-atomic fix" (Konstantin
   Khorenko):

   Use the actual GCOV build flags in the prefer-atomic compiler probe.
   Move flag setup into scripts/Makefile.gcov and skip the probe when
   GCOV is disabled.

 - "ocfs2: xattr bucket validation fixes" (Joseph Qi):

   Accept valid OCFS2 xattr buckets spanning 512-byte blocks, avoiding
   false read-only remounts. Reject misaligned buckets and return errors
   instead of panicking on corrupt defrag metadata.

 - "ocfs2: fix metadata reservation for xattr value trees" (Joseph Qi):

   Reserve enough OCFS2 metadata for new and relocated xattr value
   trees. Fix shortfalls which could cause ENOSPC, dropped entries and
   leaked clusters on fragmented filesystems; remove duplicate
   reservations.

 - "Introduce arch_do_panic" (Mete Durlu):

   Add arch_do_panic() and move s390 and sparc handling out of generic
   panic code. The architecture-specific actions now follow the
   end-of-panic marker.

 - "checkpatch: userspace improvements" (Petr Vorel):

   Improve checkpatch's userspace detection and suppress kernel-only
   checks. Recognize standard inttypes macros and add explicit
   --userspace and --no-userspace overrides.

 - "ocfs2: validate dr_fs_generation of dir index root blocks" (Joseph
   Qi):

   Check OCFS2 directory index generations and leaf block numbers.
   Reject stale or misplaced blocks instead of using metadata left by a
   previously formatted filesystem.

 - "selftests/membarrier: Skip an unregistered memory barrier test on
   Musl" (Chris Gellermann):

   Skip the unregistered membarrier test when libc has already
   registered the command. Musl does this during thread creation,
   causing false failures in the multithreaded test.

 - "init: fix array boundary bugs in boot parameter parsing"
   (Wilson Felipe Pereira):

   Fix boot argument boundary cases which leave stale arguments in
   init's command line or panic when replacing the final environment
   variable. Clear the last slot and check duplicates before the limit.

Summary of the 87 singletons in this merge:

  The OCFS2 singletons fix deadlocks between xattr updates and inline
  truncation, and during inode reclaim. Corrupt quota and extent
  metadata could also crash the kernel or corrupt memory; these paths
  now check the layout before using it. Other fixes close use-after-free
  and publication races around cluster reconfiguration, node failure,
  quota remount errors and shared refcount trees. New files now retain
  security labels from all stacked LSMs instead of silently dropping all
  but one. Valid xattr insertions also stop tripping FORTIFY on builds
  with counted arrays.

  Elsewhere, a lost wakeup could leave hardware-monitoring reads stuck
  in unkillable sleep and block further I2C traffic. That is fixed, as
  are kernel memory leaks in POSIX message-queue notifications and tmpfs
  casefold setup which could grow until memory is exhausted. A driver
  removal race which could crash the kernel is fixed too. The
  hibernation command through reboot() also stops taking the same mutex
  twice, avoiding a deadlock before suspension.

  On the boot side, bzip2 decoding now accepts valid full blocks emitted
  by lbzip2, fixing failures to boot those compressed kernels. Malformed
  bzip2 streams can no longer overflow the decode buffer, and LZ4
  initrds are checked before the decoder can read past their end. FAT
  rejects geometry which overflows the data-area calculation on 32-bit
  systems, and rolls back entries when inode setup fails, preventing
  failed creations from reappearing after remount. The x86 XOR and RAID6
  AVX paths also avoid imposing a slowdown on subsequent SSE code.

* tag 'mm-nonmm-stable-2026-10-25-14-57' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (134 commits)
  scripts/gdb: fix stack depot out-of-bounds diagnostic
  scripts/gdb: fix radix tree lookup pointer handling
  ocfs2/cluster: remove zero-address nodes from IP tree on teardown
  ocfs2: snapshot the dentry name while tracing file release
  ocfs2: snapshot dentry names in file and setattr traces
  ocfs2/dlm: drain join handlers before releasing module text
  MAINTAINERS: update Markus's e-mail address
  mailmap: add entries for Andrew Jones
  stackdepot: stop preallocating after the final pool
  ocfs2: drain quorum work before removing the cluster
  watchdog: force console verbose when reporting lockups
  profiling: fix sampling step on 64-bit big-endian systems
  kernel/reboot: avoid potential deadlocks during suspension
  compat: avoid double rounding in times()
  ocfs2: pin owning modules for open debugfs files
  ocfs2/cluster: initialize heartbeat regions before publishing them
  selftests/proc: proc-pid-vm: fix unused variable warning on non-x86
  ocfs2: pin refcount trees before dropping the lookup lock
  ocfs2: validate the xattr tree root of an indexed xattr block
  ocfs2/dlm: hold the lookup reference across convert AST enqueue
  ...
This commit is contained in:
Linus Torvalds 2026-10-27 12:08:22 -10:00
commit 7d1f84f1b9
102 changed files with 2179 additions and 674 deletions

View File

@ -68,6 +68,7 @@ Alex Hung <alexhung@gmail.com> <alex.hung@canonical.com>
Alex Shi <alexs@kernel.org> <alex.shi@intel.com>
Alex Shi <alexs@kernel.org> <alex.shi@linaro.org>
Alex Shi <alexs@kernel.org> <alex.shi@linux.alibaba.com>
Ali Ahmet Memiş <aliamemis@disroot.org> <ali@iusegentoo.com>
Alice Mikityanska <alice.kernel@fastmail.im> <maxtram95@gmail.com>
Alice Mikityanska <alice.kernel@fastmail.im> <maximmi@mellanox.com>
Alice Mikityanska <alice.kernel@fastmail.im> <maximmi@nvidia.com>
@ -88,10 +89,15 @@ Andrej Shadura <andrew@shadura.me> <andrew@beldisplaytech.com>
Andrew Donnellan <andrew+kernel@donnellan.id.au> <andrew@donnellan.id.au>
Andrew Donnellan <andrew+kernel@donnellan.id.au> <ajd@linux.ibm.com>
Andrew Donnellan <andrew+kernel@donnellan.id.au> <andrew.donnellan@au1.ibm.com>
Andrew Jones <andrew.jones@linux.dev> <ajones@ventanamicro.com>
Andrew Jones <andrew.jones@linux.dev> <andrew.jones@oss.qualcomm.com>
Andrew Jones <andrew.jones@linux.dev> <anjones@nvidia.com>
Andrew Jones <andrew.jones@linux.dev> <drjones@redhat.com>
Andrew Morton <akpm@linux-foundation.org>
Andrew Murray <amurray@thegoodpenguin.co.uk> <amurray@embedded-bits.co.uk>
Andrew Murray <amurray@thegoodpenguin.co.uk> <andrew.murray@arm.com>
Andrew Vasquez <andrew.vasquez@qlogic.com>
Andrey Golovko <andrey.golovko@gmail.com> <andrey@golovko.me>
Andrey Konovalov <andreyknvl@gmail.com> <andreyknvl@google.com>
Andrey Ryabinin <ryabinin.a.a@gmail.com> <a.ryabinin@samsung.com>
Andrey Ryabinin <ryabinin.a.a@gmail.com> <aryabinin@virtuozzo.com>
@ -174,6 +180,7 @@ Boris Brezillon <bbrezillon@kernel.org> <b.brezillon.dev@gmail.com>
Boris Brezillon <bbrezillon@kernel.org> <b.brezillon@overkiz.com>
Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@bootlin.com>
Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@free-electrons.com>
Bradley Morgan <brads@mainlining.org> <include@grrlz.net>
Brendan Higgins <brendan.higgins@linux.dev> <brendanhiggins@google.com>
Brendan Jackman <brendan.jackman@linux.dev> <jackmanb@google.com>
Brian Avery <b.avery@hp.com>
@ -597,6 +604,8 @@ Marek Lindner <marek.lindner@mailbox.org> <lindner_marek@yahoo.de>
Marek Lindner <marek.lindner@mailbox.org> <mareklindner@neomailbox.ch>
Mark Brown <broonie@sirena.org.uk>
Mark Starovoytov <mstarovo@pm.me> <mstarovoitov@marvell.com>
Markus Mayer <markus.mayer@broadcom.com> <mmayer@broadcom.com>
Markus Mayer <markus.mayer@broadcom.com> <markus.mayer@linaro.org>
Markus Schneider-Pargmann <msp@baylibre.com> <mpa@pengutronix.de>
Mark Yao <markyao0591@gmail.com> <mark.yao@rock-chips.com>
Martin K. Petersen <mkp@kernel.org> <martin.petersen@oracle.com>

181
CREDITS
View File

@ -1,6 +1,7 @@
This is at least a partial credits-file of people that have
contributed to the Linux project. It is sorted by name and
formatted to allow easy grepping and beautification by
contributed to the Linux project. It is sorted by family name,
assuming the used locale is default, e.g. by setting LC_ALL=C,
and formatted to allow easy grepping and beautification by
scripts. The fields are: name (N), email (E), web-address
(W), PGP key ID and fingerprint (P), description (D), and
snail-mail address (S).
@ -344,6 +345,14 @@ D: Hardware spinlock (hwspinlock) subsystem
D: OMAP hwspinlock driver
D: OMAP remoteproc driver
N: Muli Ben-Yehuda
E: mulix@mulix.org
E: muli@il.ibm.com
W: http://www.mulix.org
D: trident OSS sound driver, x86-64 dma-ops and Calgary IOMMU,
D: KVM and Xen bits and other misc. hackery.
S: Haifa, Israel
N: Krzysztof Benedyczak
E: golbi@mat.uni.torun.pl
W: http://www.mat.uni.torun.pl/~golbi
@ -362,14 +371,6 @@ S: 2322 37th Ave SW
S: Seattle, Washington 98126-2010
S: USA
N: Muli Ben-Yehuda
E: mulix@mulix.org
E: muli@il.ibm.com
W: http://www.mulix.org
D: trident OSS sound driver, x86-64 dma-ops and Calgary IOMMU,
D: KVM and Xen bits and other misc. hackery.
S: Haifa, Israel
N: Johannes Berg
E: johannes@sipsolutions.net
W: https://johannes.sipsolutions.net/
@ -393,14 +394,14 @@ S: 1549 Hiironen Rd.
S: Brimson, MN 55602
S: USA
N: Arnd Bergmann
D: Maintainer of Cell Broadband Engine Architecture
N: Hennus Bergman
P: 1024/77D50909 76 99 FD 31 91 E1 96 1C 90 BB 22 80 62 F6 BD 63
D: Author and maintainer of the QIC-02 tape driver
S: The Netherlands
N: Arnd Bergmann
D: Maintainer of Cell Broadband Engine Architecture
N: Tomas Berndtsson
E: tomas@nocrew.org
W: http://tomas.nocrew.org/
@ -492,10 +493,6 @@ D: Various fixes (mostly networking)
S: Montreal, Quebec
S: Canada
N: Zoltán Böszörményi
E: zboszor@mail.externet.hu
D: MTRR emulation with Cyrix style ARR registers, Athlon MTRR support
N: John Boyd
E: boyd@cis.ohio-state.edu
D: Co-author of wd7000 SCSI driver
@ -589,9 +586,6 @@ N: Zach Brown
E: zab@zabbo.net
D: maestro pci sound
N: Zefan Li
D: Contribution to control group stuff
N: David Brownell
D: Kernel engineer, mentor, and friend. Maintained USB EHCI and
D: gadget layers, SPI subsystem, GPIO subsystem, and more than a few
@ -632,6 +626,10 @@ S: Ravenhorst 58
S: 2317 AK Leiden
S: The Netherlands
N: Zoltán Böszörményi
E: zboszor@mail.externet.hu
D: MTRR emulation with Cyrix style ARR registers, Athlon MTRR support
N: Michael Callahan
E: callahan@maths.ox.ac.uk
D: PPP for Linux
@ -703,6 +701,10 @@ S: Tamsui town, Taipei county,
S: Taiwan 251
S: Republic of China
N: Landen Chao
E: Landen.Chao@mediatek.com
D: MT7531 Ethernet switch support
N: Michael Elizabeth Chastain
E: mec@shout.net
D: Configure, Menuconfig, xconfig
@ -715,10 +717,6 @@ D: Media subsystem (V4L/DVB) drivers and core
D: EDAC drivers and EDAC 3.0 core rework
S: Brazil
N: Landen Chao
E: Landen.Chao@mediatek.com
D: MT7531 Ethernet switch support
N: Raymond Chen
E: raymondc@microsoft.com
D: Author of Configure script
@ -1447,6 +1445,10 @@ D: Made support for modules, ramdisk, generic-serial, etc. optional.
D: Transformed old user space bdflush into 1st kernel thread - kflushd.
D: Many other patches, documentation files, mini kernels, utilities, ...
N: Andy Gospodarek
E: andy@greyhouse.net
D: Maintenance and contributions to the network interface bonding driver.
N: Masanori GOTO
E: gotom@debian.or.jp
D: Workbit NinjaSCSI-32Bi/UDE driver
@ -1459,10 +1461,6 @@ S: 8124 Constitution Apt. 7
S: Sterling Heights, Michigan 48313
S: USA
N: Andy Gospodarek
E: andy@greyhouse.net
D: Maintenance and contributions to the network interface bonding driver.
N: Vivek Goyal
E: vgoyal@redhat.com
D: KDUMP, KEXEC, and VIRTIO FILE SYSTEM
@ -1535,6 +1533,14 @@ S: 44 St. Joseph Street, Suite 506
S: Toronto, Ontario, M4Y 2W4
S: Canada
N: Nitin Gupta
E: ngupta@vflare.org
D: zsmalloc memory allocator and zram block device driver
N: Justin Guyett
E: jguyett@andrew.cmu.edu
D: via-rhine net driver hacking
N: Richard Günther
E: rguenth@tat.physik.uni-tuebingen.de
W: http://www.tat.physik.uni-tuebingen.de/~rguenth
@ -1543,14 +1549,6 @@ D: binfmt_misc
S: 72074 Tübingen
S: Germany
N: Justin Guyett
E: jguyett@andrew.cmu.edu
D: via-rhine net driver hacking
N: Nitin Gupta
E: ngupta@vflare.org
D: zsmalloc memory allocator and zram block device driver
N: Danny ter Haar
E: dth@cistron.nl
D: /proc/cpuinfo, reboot on panic , kernel pre-patch tester ;)
@ -1949,16 +1947,6 @@ E: sjenning@redhat.com
D: Creation and maintenance of zswap
D: Creation and maintenace of the zbud allocator
N: Jeremy Kerr
D: Maintainer of SPU File System
N: Michael Kerrisk
E: mtk.manpages@gmail.com
W: https://man7.org/
P: 4096R/3A35CE5E E522 595B 52ED A4E6 BFCC CB5E 8561 9911 3A35 CE5E
D: Maintainer of the Linux man-pages project
D: Linux man pages online, at <https://man7.org/linux/man-pages/>
N: Niels Kristian Bech Jensen
E: nkbj1970@hotmail.com
D: Miscellaneous kernel updates and fixes.
@ -2103,6 +2091,16 @@ S: Keplerstr. 6
S: 4050 Traun
S: Austria
N: Jeremy Kerr
D: Maintainer of SPU File System
N: Michael Kerrisk
E: mtk.manpages@gmail.com
W: https://man7.org/
P: 4096R/3A35CE5E E522 595B 52ED A4E6 BFCC CB5E 8561 9911 3A35 CE5E
D: Maintainer of the Linux man-pages project
D: Linux man pages online, at <https://man7.org/linux/man-pages/>
N: Karl Keyte
E: karl@koft.com
D: Disk usage statistics and modifications to line printer driver
@ -2487,6 +2485,9 @@ D: and much more. He was the maintainer of MD from 2016 to 2018. Shaohua
D: passed away late 2018, he will be greatly missed.
W: https://www.spinics.net/lists/raid/msg61993.html
N: Zefan Li
D: Contribution to control group stuff
N: Stephan Linz
E: linz@mazet.de
E: Stephan.Linz@gmx.de
@ -2546,11 +2547,6 @@ D: misc. kernel hacking and debugging
S: Cambridge, MA 02139
S: USA
N: Martin von Löwis
E: loewis@informatik.hu-berlin.de
D: script binary format
D: NTFS driver
N: H.J. Lu
E: hjl@gnu.ai.mit.edu
D: GCC + libraries hacker
@ -2579,6 +2575,11 @@ S: Puistokaari 1 E 18
S: 00200 Helsinki
S: Finland
N: Martin von Löwis
E: loewis@informatik.hu-berlin.de
D: script binary format
D: NTFS driver
N: Daniel J. Maas
E: dmaas@dcine.com
W: https://www.maasdigital.com
@ -2629,10 +2630,6 @@ S: PO BOX 220, HFX. CENTRAL
S: Halifax, Nova Scotia
S: Canada B3J 3C8
N: Kai Mäkisara
E: Kai.Makisara@kolumbus.fi
D: SCSI Tape Driver
N: Asit Mallick
E: asit.k.mallick@intel.com
D: Linux/IA-64
@ -2916,13 +2913,6 @@ S: 12725 SW Millikan Way, Suite 400
S: Beaverton, Oregon 97005
S: USA
N: Eberhard Mönkeberg
E: emoenke@gwdg.de
D: CDROM driver "sbpcd" (Matsushita/Panasonic/Soundblaster)
S: Ruhstrathöhe 2 b.
S: D-37085 Göttingen
S: Germany
N: Thomas Molina
E: tmolina@cablespeed.com
D: bug fixes, documentation, minor hackery
@ -3009,6 +2999,17 @@ S: Dragonvagen 1 A 13
S: FIN-00330 Helsingfors
S: Finland
N: Kai Mäkisara
E: Kai.Makisara@kolumbus.fi
D: SCSI Tape Driver
N: Eberhard Mönkeberg
E: emoenke@gwdg.de
D: CDROM driver "sbpcd" (Matsushita/Panasonic/Soundblaster)
S: Ruhstrathöhe 2 b.
S: D-37085 Göttingen
S: Germany
N: Matija Nalis
E: mnalis@jagor.srce.hr
E: mnalis@voyager.hr
@ -3209,13 +3210,6 @@ S: RR #5, 497 Pole Line Road
S: Thunder Bay, Ontario
S: CANADA P7C 5M9
N: Inaky Perez-Gonzalez
E: inaky.perez-gonzalez@intel.com
E: linux-wimax@intel.com
E: inakypg@yahoo.com
D: WiMAX stack
D: Intel Wireless WiMAX Connection 2400 driver
N: Yuri Per
E: yuri@pts.mipt.ru
D: Some smbfs fixes
@ -3223,6 +3217,13 @@ S: Demonstratsii 8-382
S: Tula 300000
S: Russia
N: Inaky Perez-Gonzalez
E: inaky.perez-gonzalez@intel.com
E: linux-wimax@intel.com
E: inakypg@yahoo.com
D: WiMAX stack
D: Intel Wireless WiMAX Connection 2400 driver
N: Thomas Petazzoni
E: thomas.petazzoni@bootlin.com
D: Driver for the Marvell Armada 370/XP network unit.
@ -3337,14 +3338,14 @@ N: Frederic Potter
E: fpotter@cirpack.com
D: Some PCI kernel support
N: Rui Prior
E: rprior@inescn.pt
D: ATM device driver for NICStAR based cards
N: Roopa Prabhu
E: roopa@nvidia.com
D: Bridge co-maintainer, vxlan and networking contributor
N: Rui Prior
E: rprior@inescn.pt
D: ATM device driver for NICStAR based cards
N: Stefan Probst
E: sp@caldera.de
D: The Linux Support Team Erlangen, 1993-97
@ -4032,12 +4033,6 @@ S: C/ Federico Garcia Lorca 1 10-A
S: Sevilla 41005
S: Spain
N: Björn Töpel
E: bjorn@kernel.org
D: AF_XDP
S: Gothenburg
S: Sweden
N: Linus Torvalds
E: torvalds@linux-foundation.org
D: Original kernel hacker
@ -4091,17 +4086,6 @@ D: Linux-Workshop Köln (aka LUG Cologne, Germany), Installfests
S: Tacitusstr. 6
S: D-50968 Köln
N: Tsu-Sheng Tsao
E: tsusheng@scf.usc.edu
D: IGMP (Internet Group Management Protocol) version 2
S: 2F 14 ALY 31 LN 166 SEC 1 SHIH-PEI RD
S: Taipei
S: Taiwan 112
S: Republic of China
S: 24335 Delta Drive
S: Diamond Bar, California 91765
S: USA
N: Theodore Ts'o
E: tytso@mit.edu
D: Random Linux hacker
@ -4118,6 +4102,17 @@ S: 1 Amherst Street
S: Cambridge, Massachusetts 02139
S: USA
N: Tsu-Sheng Tsao
E: tsusheng@scf.usc.edu
D: IGMP (Internet Group Management Protocol) version 2
S: 2F 14 ALY 31 LN 166 SEC 1 SHIH-PEI RD
S: Taipei
S: Taiwan 112
S: Republic of China
S: 24335 Delta Drive
S: Diamond Bar, California 91765
S: USA
N: Luben Tuikov
E: Luben Tuikov <ltuikov89@gmail.com>
D: Maintainer of the DRM GPU Scheduler
@ -4144,6 +4139,12 @@ S: 44 Campbell Park Crescent
S: Edinburgh EH13 0HT
S: United Kingdom
N: Björn Töpel
E: bjorn@kernel.org
D: AF_XDP
S: Gothenburg
S: Sweden
N: Thomas Uhl
E: uhl@sun1.rz.fh-heilbronn.de
D: Application programmer

View File

@ -459,8 +459,9 @@ hung_task_warnings
==================
The maximum number of warnings to report. During a check interval
if a hung task is detected, this value is decreased by 1.
When this value reaches 0, no more warnings will be reported.
if a hung task is detected, the internal warning budget is decreased by 1.
When this budget reaches 0, no more detailed warnings will be reported. The
warning budget is reset to the configured limit when no hung task is found.
This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled.
-1: report an infinite number of warnings.

View File

@ -5413,7 +5413,7 @@ F: Documentation/devicetree/bindings/usb/brcm,bdc.yaml
F: drivers/usb/gadget/udc/bdc/
BROADCOM BMIPS CPUFREQ DRIVER
M: Markus Mayer <mmayer@broadcom.com>
M: Markus Mayer <markus.mayer@broadcom.com>
R: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
L: linux-pm@vger.kernel.org
S: Maintained
@ -5688,7 +5688,7 @@ F: drivers/spi/spi-brcmstb-qspi.c
F: drivers/spi/spi-iproc-qspi.c
BROADCOM STB AVS CPUFREQ DRIVER
M: Markus Mayer <mmayer@broadcom.com>
M: Markus Mayer <markus.mayer@broadcom.com>
R: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
L: linux-pm@vger.kernel.org
S: Maintained
@ -5696,7 +5696,7 @@ F: Documentation/devicetree/bindings/cpufreq/brcm,stb-avs-cpu-freq.txt
F: drivers/cpufreq/brcmstb*
BROADCOM STB AVS TMON DRIVER
M: Markus Mayer <mmayer@broadcom.com>
M: Markus Mayer <markus.mayer@broadcom.com>
R: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
L: linux-pm@vger.kernel.org
S: Maintained
@ -5704,7 +5704,7 @@ F: Documentation/devicetree/bindings/thermal/brcm,avs-tmon.yaml
F: drivers/thermal/broadcom/brcmstb*
BROADCOM STB DPFE DRIVER
M: Markus Mayer <mmayer@broadcom.com>
M: Markus Mayer <markus.mayer@broadcom.com>
R: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
@ -9915,6 +9915,7 @@ M: Jeff Layton <jlayton@kernel.org>
S: Maintained
F: include/linux/errseq.h
F: lib/errseq.c
F: lib/tests/errseq_kunit.c
ES9039Q2M AUDIO CODEC DRIVER
M: Karl Asseily <karl@asseily.com>
@ -11130,6 +11131,7 @@ M: Peter Oberparleiter <oberpar@linux.ibm.com>
S: Maintained
F: Documentation/dev-tools/gcov.rst
F: kernel/gcov/
F: scripts/Makefile.gcov
GDB KERNEL DEBUGGING HELPER SCRIPTS
M: Jan Kiszka <jan.kiszka@siemens.com>

View File

@ -1183,27 +1183,6 @@ endif
# Ensure compilers do not transform certain loops into calls to wcslen()
KBUILD_CFLAGS += -fno-builtin-wcslen
CFLAGS_GCOV := -fprofile-arcs -ftest-coverage
ifdef CONFIG_CC_IS_GCC
CFLAGS_GCOV += -fno-tree-loop-im
# Use atomic counter updates to avoid concurrent-access crashes in GCOV.
# Only enable if -fprofile-update=prefer-atomic does not introduce new
# undefined symbols (e.g. libatomic calls that the kernel cannot link).
CFLAGS_GCOV += $(call try-run,\
echo 'long long x; void f(void){x++;}' | \
$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -w -fprofile-arcs \
-ftest-coverage -x c - -c -o "$$TMP.base" && \
echo 'long long x; void f(void){x++;}' | \
$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -w -fprofile-arcs \
-ftest-coverage -fprofile-update=prefer-atomic \
-x c - -c -o "$$TMP" && \
$(NM) "$$TMP.base" | grep ' U ' > "$$TMP.ubase" || true ; \
$(NM) "$$TMP" | grep ' U ' > "$$TMP.utest" || true ; \
cmp -s "$$TMP.ubase" "$$TMP.utest",\
-fprofile-update=prefer-atomic)
endif
export CFLAGS_GCOV
# change __FILE__ to the relative path to the source directory
ifdef building_out_of_srctree
CFLAGS_PREFIX_MAP := -fmacro-prefix-map=$(srcroot)/=
@ -1224,6 +1203,7 @@ include-$(CONFIG_KCSAN) += scripts/Makefile.kcsan
include-$(CONFIG_KMSAN) += scripts/Makefile.kmsan
include-$(CONFIG_UBSAN) += scripts/Makefile.ubsan
include-$(CONFIG_KCOV) += scripts/Makefile.kcov
include-$(CONFIG_GCOV_KERNEL) += scripts/Makefile.gcov
include-$(CONFIG_RANDSTRUCT) += scripts/Makefile.randstruct
include-$(CONFIG_KSTACK_ERASE) += scripts/Makefile.kstack_erase
include-$(CONFIG_AUTOFDO_CLANG) += scripts/Makefile.autofdo

View File

@ -1230,13 +1230,9 @@ config ARCH_MMAP_RND_BITS_MIN
config ARCH_MMAP_RND_BITS_MAX
int
config ARCH_MMAP_RND_BITS_DEFAULT
int
config ARCH_MMAP_RND_BITS
int "Number of bits to use for ASLR of mmap base address" if EXPERT
range ARCH_MMAP_RND_BITS_MIN ARCH_MMAP_RND_BITS_MAX
default ARCH_MMAP_RND_BITS_DEFAULT if ARCH_MMAP_RND_BITS_DEFAULT
default ARCH_MMAP_RND_BITS_MIN
depends on HAVE_ARCH_MMAP_RND_BITS
help
@ -1264,13 +1260,9 @@ config ARCH_MMAP_RND_COMPAT_BITS_MIN
config ARCH_MMAP_RND_COMPAT_BITS_MAX
int
config ARCH_MMAP_RND_COMPAT_BITS_DEFAULT
int
config ARCH_MMAP_RND_COMPAT_BITS
int "Number of bits to use for ASLR of mmap base address for compatible applications" if EXPERT
range ARCH_MMAP_RND_COMPAT_BITS_MIN ARCH_MMAP_RND_COMPAT_BITS_MAX
default ARCH_MMAP_RND_COMPAT_BITS_DEFAULT if ARCH_MMAP_RND_COMPAT_BITS_DEFAULT
default ARCH_MMAP_RND_COMPAT_BITS_MIN
depends on HAVE_ARCH_MMAP_RND_COMPAT_BITS
help

View File

@ -26,6 +26,7 @@
#include <linux/entry-common.h>
#include <linux/kmsan.h>
#include <linux/bug.h>
#include <linux/panic.h>
#include <asm/pgmcheck-defs.h>
#include <asm/entry-percpu.h>
#include <asm/asm-extable.h>
@ -34,6 +35,7 @@
#include <asm/vtime.h>
#include <asm/fpu.h>
#include <asm/fault.h>
#include <asm/processor.h>
#include "entry.h"
struct pgm_stat {
@ -290,6 +292,11 @@ static void monitor_event_exception(struct pt_regs *regs)
}
}
void arch_do_panic(void)
{
disabled_wait();
}
/*
* Content of the faulting CPU's lowcore, copied by stack_invalid().
*/

View File

@ -2,6 +2,8 @@
#include <asm/setup.h>
#include <linux/sysctl.h>
#include <linux/panic.h>
#include <linux/printk.h>
static const struct ctl_table sparc_sysctl_table[] = {
{
@ -36,6 +38,13 @@ static const struct ctl_table sparc_sysctl_table[] = {
#endif
};
void arch_do_panic(void)
{
/* Make sure the user can actually press Stop-A (L1-A) */
stop_a_enabled = 1;
pr_emerg("Press Stop-A (L1-A) from sun keyboard or send break\n"
"twice on console to return to the boot prom\n");
}
static int __init init_sparc_sysctls(void)
{

View File

@ -216,7 +216,6 @@ int hfi1_fault_init_debugfs(struct hfi1_ibdev *ibd)
ibd->fault->attr.interval = 1;
ibd->fault->attr.require_end = ULONG_MAX;
ibd->fault->attr.stacktrace_depth = 32;
ibd->fault->attr.dname = NULL;
ibd->fault->attr.verbose = 0;
ibd->fault->enable = false;
ibd->fault->opcode = false;

View File

@ -555,7 +555,7 @@ static void dma_req_free(struct kref *ref)
refcount);
struct mport_cdev_priv *priv = req->priv;
dma_unmap_sg(req->dmach->device->dev,
dma_unmap_sg(dmaengine_get_dma_device(req->dmach),
req->sgt.sgl, req->sgt.nents, req->dir);
sg_free_table(&req->sgt);
if (req->page_list) {
@ -916,7 +916,7 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode,
xfer->offset, xfer->length);
}
nents = dma_map_sg(chan->device->dev,
nents = dma_map_sg(dmaengine_get_dma_device(chan),
req->sgt.sgl, req->sgt.nents, dir);
if (nents == 0) {
rmcd_error("Failed to map SG list");
@ -2167,11 +2167,12 @@ static void mport_mm_open(struct vm_area_struct *vma)
static void mport_mm_close(struct vm_area_struct *vma)
{
struct rio_mport_mapping *map = vma->vm_private_data;
struct mport_dev *md = map->md;
rmcd_debug(MMAP, "%pad", &map->phys_addr);
mutex_lock(&map->md->buf_mutex);
mutex_lock(&md->buf_mutex);
kref_put(&map->ref, mport_release_mapping);
mutex_unlock(&map->md->buf_mutex);
mutex_unlock(&md->buf_mutex);
}
static const struct vm_operations_struct vm_ops = {

View File

@ -733,7 +733,7 @@ ep_read_iter(struct kiocb *iocb, struct iov_iter *to)
return -EBADMSG;
}
buf = kmalloc(len, GFP_KERNEL);
buf = kmalloc(len, GFP_KERNEL | __GFP_NOWARN);
if (unlikely(!buf)) {
mutex_unlock(&epdata->lock);
return -ENOMEM;
@ -796,7 +796,7 @@ ep_write_iter(struct kiocb *iocb, struct iov_iter *from)
return -EBADMSG;
}
buf = kmalloc(len, GFP_KERNEL);
buf = kmalloc(len, GFP_KERNEL | __GFP_NOWARN);
if (unlikely(!buf)) {
mutex_unlock(&epdata->lock);
return -ENOMEM;

View File

@ -200,7 +200,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
}
hex_byte_pack(panic_msg, nmistat);
nmi_panic(regs, panic_msg);
nmi_panic(regs, "%s", panic_msg);
return NMI_HANDLED;
}

View File

@ -392,9 +392,10 @@ extern void fat_ent_access_init(struct super_block *sb);
extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent,
int entry);
extern int fat_ent_write(struct inode *inode, struct fat_entry *fatent,
int new, int wait);
int new, int old, int wait);
extern int fat_alloc_clusters(struct inode *inode, int *cluster,
int nr_cluster);
int fat_alloc_chain(struct inode *inode, int *cluster, int nr_cluster);
extern int fat_free_clusters(struct inode *inode, int cluster);
extern int fat_count_free_clusters(struct super_block *sb);
extern int fat_trim_fs(struct inode *inode, struct fstrim_range *range);
@ -440,7 +441,7 @@ static inline unsigned long fat_dir_hash(int logstart)
{
return hash_32(logstart, FAT_HASH_BITS);
}
extern int fat_add_cluster(struct inode *inode);
extern int fat_add_clusters(struct inode *inode, int nr_cluster);
/* fat/misc.c */
extern __printf(3, 4) __cold

View File

@ -413,7 +413,7 @@ static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs,
}
int fat_ent_write(struct inode *inode, struct fat_entry *fatent,
int new, int wait)
int new, int old, int wait)
{
struct super_block *sb = inode->i_sb;
const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
@ -422,10 +422,25 @@ int fat_ent_write(struct inode *inode, struct fat_entry *fatent,
ops->ent_put(fatent, new);
if (wait) {
err = fat_sync_bhs(fatent->bhs, fatent->nr_bhs);
if (err)
if (err) {
/*
* bhs are not uptodate after I/O error. So we
* can't simply re-dirty to revert. And it
* would not have value to write again on I/O
* error.
*/
return err;
}
}
return fat_mirror_bhs(sb, fatent->bhs, fatent->nr_bhs);
err = fat_mirror_bhs(sb, fatent->bhs, fatent->nr_bhs);
if (err) {
/* Try to revert if got the error on mirror FAT */
ops->ent_put(fatent, old);
if (wait)
fat_sync_bhs(fatent->bhs, fatent->nr_bhs);
}
return err;
}
static inline int fat_ent_next(struct msdos_sb_info *sbi,
@ -468,7 +483,28 @@ static void fat_collect_bhs(struct buffer_head **bhs, int *nr_bhs,
}
}
int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
static int fat_flush_bhs(struct super_block *sb, struct buffer_head **bhs,
int *nr_bhs, bool sync)
{
int err, i;
if (sync) {
err = fat_sync_bhs(bhs, *nr_bhs);
if (err)
return err;
}
err = fat_mirror_bhs(sb, bhs, *nr_bhs);
if (err)
return err;
for (i = 0; i < *nr_bhs; i++)
brelse(bhs[i]);
*nr_bhs = 0;
return 0;
}
static int __fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster,
bool return_all)
{
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
@ -477,8 +513,6 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
struct buffer_head *bhs[MAX_BUF_PER_PAGE];
int i, count, err, nr_bhs, idx_clus;
BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2)); /* fixed limit */
lock_fat(sbi);
if (sbi->free_clusters != -1 && sbi->free_clus_valid &&
sbi->free_clusters < nr_cluster) {
@ -509,14 +543,24 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
if (prev_ent.nr_bhs)
ops->ent_put(&prev_ent, entry);
fat_collect_bhs(bhs, &nr_bhs, &fatent);
sbi->prev_free = entry;
if (sbi->free_clusters != -1)
sbi->free_clusters--;
cluster[idx_clus] = entry;
if (return_all)
cluster[idx_clus] = entry;
else if (!idx_clus)
*cluster = entry;
idx_clus++;
if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) {
err = fat_flush_bhs(sb, bhs, &nr_bhs,
inode_needs_sync(inode));
if (err)
goto out;
}
fat_collect_bhs(bhs, &nr_bhs, &fatent);
if (idx_clus == nr_cluster)
goto out;
@ -556,6 +600,16 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
return err;
}
int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
{
return __fat_alloc_clusters(inode, cluster, nr_cluster, true);
}
int fat_alloc_chain(struct inode *inode, int *cluster, int nr_cluster)
{
return __fat_alloc_clusters(inode, cluster, nr_cluster, false);
}
int fat_free_clusters(struct inode *inode, int cluster)
{
struct super_block *sb = inode->i_sb;
@ -606,17 +660,10 @@ int fat_free_clusters(struct inode *inode, int cluster)
}
if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) {
if (sb->s_flags & SB_SYNCHRONOUS) {
err = fat_sync_bhs(bhs, nr_bhs);
if (err)
goto error;
}
err = fat_mirror_bhs(sb, bhs, nr_bhs);
err = fat_flush_bhs(sb, bhs, &nr_bhs,
sb->s_flags & SB_SYNCHRONOUS);
if (err)
goto error;
for (i = 0; i < nr_bhs; i++)
brelse(bhs[i]);
nr_bhs = 0;
}
fat_collect_bhs(bhs, &nr_bhs, &fatent);
} while (cluster != FAT_ENT_EOF);

View File

@ -290,12 +290,10 @@ static long fat_fallocate(struct file *file, int mode,
nr_cluster = (mm_bytes + (sbi->cluster_size - 1)) >>
sbi->cluster_bits;
/* Start the allocation.We are not zeroing out the clusters */
while (nr_cluster-- > 0) {
err = fat_add_cluster(inode);
if (err)
goto error;
}
/* Allocate the clusters. We are not zeroing them out */
err = fat_add_clusters(inode, nr_cluster);
if (err)
goto error;
} else {
if ((offset + len) <= i_size_read(inode))
goto error;
@ -363,7 +361,8 @@ static int fat_free(struct inode *inode, int skip)
__func__, MSDOS_I(inode)->i_pos);
ret = -EIO;
} else if (ret > 0) {
err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait);
err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, ret,
wait);
if (err)
ret = err;
}

View File

@ -20,6 +20,7 @@
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include <linux/unaligned.h>
#include <linux/overflow.h>
#include <linux/random.h>
#include <linux/iversion.h>
#include <linux/fs_struct.h>
@ -101,16 +102,16 @@ static struct fat_floppy_defaults {
},
};
int fat_add_cluster(struct inode *inode)
int fat_add_clusters(struct inode *inode, int nr_cluster)
{
int err, cluster;
err = fat_alloc_clusters(inode, &cluster, 1);
err = fat_alloc_chain(inode, &cluster, nr_cluster);
if (err)
return err;
/* FIXME: this cluster should be added after data of this
* cluster is writed */
err = fat_chain_add(inode, cluster, 1);
err = fat_chain_add(inode, cluster, nr_cluster);
if (err)
fat_free_clusters(inode, cluster);
return err;
@ -152,7 +153,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
*/
if (!offset && !(iblock < last_block)) {
/* TODO: multiple cluster allocation would be desirable. */
err = fat_add_cluster(inode);
err = fat_add_clusters(inode, 1);
if (err)
return err;
}
@ -1577,6 +1578,7 @@ int fat_fill_super(struct super_block *sb, struct fs_context *fc,
struct msdos_sb_info *sbi;
u16 logical_sector_size;
u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors;
u32 dir_start, data_start;
long error;
char buf[50];
struct timespec64 ts;
@ -1752,7 +1754,6 @@ int fat_fill_super(struct super_block *sb, struct fs_context *fc,
sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry);
sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length;
sbi->dir_entries = bpb.fat_dir_entries;
if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
if (!silent)
@ -1763,20 +1764,30 @@ int fat_fill_super(struct super_block *sb, struct fs_context *fc,
rootdir_sectors = sbi->dir_entries
* sizeof(struct msdos_dir_entry) / sb->s_blocksize;
sbi->data_start = sbi->dir_start + rootdir_sectors;
if (check_mul_overflow(sbi->fats, sbi->fat_length, &dir_start) ||
check_add_overflow(sbi->fat_start, dir_start, &dir_start) ||
check_add_overflow(dir_start, rootdir_sectors, &data_start)) {
if (!silent)
fat_msg(sb, KERN_ERR,
"overflow of root dir or data layout");
goto out_invalid;
}
total_sectors = bpb.fat_sectors;
if (total_sectors == 0)
total_sectors = bpb.fat_total_sect;
if (total_sectors < sbi->data_start) {
if (total_sectors < data_start) {
if (!silent)
fat_msg(sb, KERN_ERR,
"data area starts beyond volume (%lu > %u)",
sbi->data_start, total_sectors);
"data area starts beyond volume (%u > %u)",
data_start, total_sectors);
goto out_invalid;
}
total_clusters = (total_sectors - sbi->data_start) / sbi->sec_per_clus;
sbi->dir_start = dir_start;
sbi->data_start = data_start;
total_clusters = (total_sectors - data_start) / sbi->sec_per_clus;
if (!is_fat32(sbi))
sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12;

View File

@ -62,6 +62,7 @@ void _fat_msg(struct super_block *sb, const char *level, const char *fmt, ...)
_printk(FAT_PRINTK_PREFIX "%pV\n", level, sb->s_id, &vaf);
va_end(args);
}
EXPORT_SYMBOL_GPL(_fat_msg);
/* Flushes the number of free clusters on FAT32 */
/* XXX: Need to write one per FSINFO block. Currently only writes 1 */
@ -133,11 +134,9 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
ret = fat_ent_read(inode, &fatent, last);
if (ret >= 0) {
int wait = inode_needs_sync(inode);
int old = ret;
ret = fat_ent_write(inode, &fatent, new_dclus, wait);
if (ret < 0)
fat_ent_write(inode, &fatent, old, wait);
ret = fat_ent_write(inode, &fatent, new_dclus, ret,
wait);
fatent_brelse(&fatent);
}
if (ret < 0)

View File

@ -292,11 +292,17 @@ static int msdos_create(const struct mnt_idmap *idmap, struct inode *dir,
if (err)
goto out;
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh);
if (IS_ERR(inode)) {
int err2;
err = PTR_ERR(inode);
err2 = fat_remove_entries(dir, &sinfo);
if (err2)
fat_msg(sb, KERN_WARNING,
"failed to roll back new entry (%d)", err2);
goto out;
}
brelse(sinfo.bh);
fat_truncate_time(inode, &ts, FAT_UPDATE_ATIME | FAT_UPDATE_CMTIME);
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
@ -381,12 +387,20 @@ static struct dentry *msdos_mkdir(const struct mnt_idmap *idmap, struct inode *d
inc_nlink(dir);
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh);
if (IS_ERR(inode)) {
int err2;
err = PTR_ERR(inode);
/* the directory was completed, just return a error */
goto out;
err2 = fat_remove_entries(dir, &sinfo);
if (err2) {
fat_msg(sb, KERN_WARNING,
"failed to roll back new entry (%d)", err2);
goto out;
}
drop_nlink(dir);
goto out_free;
}
brelse(sinfo.bh);
set_nlink(inode, 2);
fat_truncate_time(inode, &ts, FAT_UPDATE_ATIME | FAT_UPDATE_CMTIME);
/* timestamp is already written, so mark_inode_dirty() is unneeded. */

View File

@ -771,11 +771,17 @@ static int vfat_create(const struct mnt_idmap *idmap, struct inode *dir,
inode_inc_iversion(dir);
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh);
if (IS_ERR(inode)) {
int err2;
err = PTR_ERR(inode);
err2 = fat_remove_entries(dir, &sinfo);
if (err2)
fat_msg(sb, KERN_WARNING,
"failed to roll back new entry (%d)", err2);
goto out;
}
brelse(sinfo.bh);
inode_inc_iversion(inode);
d_instantiate(dentry, inode);
@ -870,12 +876,20 @@ static struct dentry *vfat_mkdir(const struct mnt_idmap *idmap, struct inode *di
inc_nlink(dir);
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh);
if (IS_ERR(inode)) {
int err2;
err = PTR_ERR(inode);
/* the directory was completed, just return a error */
goto out;
err2 = fat_remove_entries(dir, &sinfo);
if (err2) {
fat_msg(sb, KERN_WARNING,
"failed to roll back new entry (%d)", err2);
goto out;
}
drop_nlink(dir);
goto out_free;
}
brelse(sinfo.bh);
inode_inc_iversion(inode);
set_nlink(inode, 2);

View File

@ -925,6 +925,33 @@ static int ocfs2_validate_extent_block(struct super_block *sb,
goto bail;
}
/*
* Extent blocks are allocated from a per-slot suballocator, so the
* slot must be in range. Otherwise freeing the block passes it to
* get_local_system_inode(), which hits BUG_ON() for
* OCFS2_INVALID_SLOT or computes an out-of-bounds index otherwise.
*/
if ((u32)le16_to_cpu(eb->h_suballoc_slot) >= OCFS2_SB(sb)->max_slots) {
rc = ocfs2_error(sb,
"Extent block #%llu has an invalid h_suballoc_slot of %u\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(eb->h_suballoc_slot));
goto bail;
}
/*
* Similarly the suballoc bit must fit in a block group bitmap.
* Otherwise freeing the block will pass the oversized bit to
* _ocfs2_free_suballoc_bits() and trigger ocfs2_error() there.
*/
if (le16_to_cpu(eb->h_suballoc_bit) >= ocfs2_suballoc_bits_per_block(sb)) {
rc = ocfs2_error(sb,
"Extent block #%llu has an invalid h_suballoc_bit of %u\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(eb->h_suballoc_bit));
goto bail;
}
if (le16_to_cpu(eb->h_list.l_count) != ocfs2_extent_recs_per_eb(sb)) {
rc = ocfs2_error(sb,
"Extent block #%llu has invalid l_count %u (expected %u)\n",
@ -1817,6 +1844,7 @@ static int __ocfs2_find_path(struct ocfs2_caching_info *ci,
int i, ret = 0;
u32 range;
u64 blkno;
u32 prev_depth = OCFS2_MAX_PATH_DEPTH;
struct buffer_head *bh = NULL;
struct ocfs2_extent_block *eb;
struct ocfs2_extent_list *el;
@ -1824,14 +1852,16 @@ static int __ocfs2_find_path(struct ocfs2_caching_info *ci,
el = root_el;
while (el->l_tree_depth) {
if (unlikely(le16_to_cpu(el->l_tree_depth) >= OCFS2_MAX_PATH_DEPTH)) {
if (unlikely(le16_to_cpu(el->l_tree_depth) >= prev_depth)) {
ocfs2_error(ocfs2_metadata_cache_get_super(ci),
"Owner %llu has invalid tree depth %u in extent list\n",
"Owner %llu has invalid tree depth %u in extent list (max %u)\n",
(unsigned long long)ocfs2_metadata_cache_owner(ci),
le16_to_cpu(el->l_tree_depth));
le16_to_cpu(el->l_tree_depth), prev_depth - 1);
ret = -EROFS;
goto out;
}
prev_depth = le16_to_cpu(el->l_tree_depth);
if (!el->l_next_free_rec || !el->l_count) {
ocfs2_error(ocfs2_metadata_cache_get_super(ci),
"Owner %llu has empty extent list at depth %u\n"

View File

@ -880,8 +880,11 @@ static void o2hb_shutdown_slot(struct o2hb_disk_slot *slot)
int queued = 0;
node = o2nm_get_node_by_num(slot->ds_node_num);
if (!node)
return;
/*
* The node may have been removed from the node table while this
* region's slot is still linked. The list member must still be
* removed before the region releases its slot array.
*/
spin_lock(&o2hb_live_lock);
if (!list_empty(&slot->ds_live_item)) {
@ -903,7 +906,8 @@ static void o2hb_shutdown_slot(struct o2hb_disk_slot *slot)
if (queued)
o2hb_run_event_list(&event);
o2nm_node_put(node);
if (node)
o2nm_node_put(node);
}
static void o2hb_set_quorum_device(struct o2hb_region *reg)
@ -1038,7 +1042,7 @@ static int o2hb_check_slot(struct o2hb_region *reg,
fire_callbacks:
/* dead nodes only come to life after some number of
* changes at any time during their dead time */
if (list_empty(&slot->ds_live_item) &&
if (node && list_empty(&slot->ds_live_item) &&
slot->ds_changed_samples >= O2HB_LIVE_THRESHOLD) {
mlog(ML_HEARTBEAT, "Node %d (id 0x%llx) joined my region\n",
slot->ds_node_num, (long long)slot->ds_last_generation);
@ -1443,6 +1447,7 @@ static ssize_t o2hb_debug_read(struct file *file, char __user *buf,
#endif /* CONFIG_DEBUG_FS */
static const struct file_operations o2hb_debug_fops = {
.owner = THIS_MODULE,
.open = o2hb_debug_open,
.release = o2hb_debug_release,
.read = o2hb_debug_read,
@ -1966,18 +1971,22 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
atomic_set(&reg->hr_unsteady_iterations, (live_threshold * 3));
o2hb_set_region_stopping(reg, false);
hb_task = kthread_run(o2hb_thread, reg, "o2hb-%s",
reg->hr_item.ci_name);
hb_task = kthread_create(o2hb_thread, reg, "o2hb-%s",
reg->hr_item.ci_name);
if (IS_ERR(hb_task)) {
ret = PTR_ERR(hb_task);
mlog_errno(ret);
goto out;
}
/* The thread may exit on its own, so pin it before it can run. */
get_task_struct(hb_task);
spin_lock(&o2hb_live_lock);
reg->hr_task = hb_task;
spin_unlock(&o2hb_live_lock);
wake_up_process(hb_task);
ret = wait_event_interruptible(o2hb_steady_queue,
atomic_read(&reg->hr_steady_iterations) == 0 ||
reg->hr_node_deleted);
@ -2022,7 +2031,7 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
spin_unlock(&o2hb_live_lock);
if (hb_task)
kthread_stop(hb_task);
kthread_stop_put(hb_task);
o2hb_unmap_slot_data(reg);
@ -2132,6 +2141,18 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g
}
reg->hr_node_num = O2NM_MAX_NODES;
INIT_LIST_HEAD(&reg->hr_all_item);
mutex_init(&reg->hr_arming_mutex);
reg->hr_stopping = true;
INIT_DELAYED_WORK(&reg->hr_write_timeout_work, o2hb_write_timeout);
INIT_DELAYED_WORK(&reg->hr_nego_timeout_work, o2hb_nego_timeout);
INIT_LIST_HEAD(&reg->hr_handler_list);
config_item_init_type_name(&reg->hr_item, name, &o2hb_region_type);
if (!config_item_name(&reg->hr_item)) {
ret = -ENOMEM;
goto put_item;
}
spin_lock(&o2hb_live_lock);
reg->hr_region_num = 0;
if (o2hb_global_heartbeat_active()) {
@ -2140,26 +2161,19 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g
if (reg->hr_region_num >= O2NM_MAX_REGIONS) {
spin_unlock(&o2hb_live_lock);
ret = -EFBIG;
goto free;
goto put_item;
}
set_bit(reg->hr_region_num, o2hb_region_bitmap);
}
list_add_tail(&reg->hr_all_item, &o2hb_all_regions);
spin_unlock(&o2hb_live_lock);
config_item_init_type_name(&reg->hr_item, name, &o2hb_region_type);
/* this is the same way to generate msg key as dlm, for local heartbeat,
* name is also the same, so make initial crc value different to avoid
* message key conflict.
*/
reg->hr_key = crc32_le(reg->hr_region_num + O2NM_MAX_REGIONS,
name, strlen(name));
mutex_init(&reg->hr_arming_mutex);
reg->hr_stopping = true;
INIT_DELAYED_WORK(&reg->hr_write_timeout_work, o2hb_write_timeout);
INIT_DELAYED_WORK(&reg->hr_nego_timeout_work, o2hb_nego_timeout);
INIT_LIST_HEAD(&reg->hr_handler_list);
ret = o2net_register_handler(O2HB_NEGO_TIMEOUT_MSG, reg->hr_key,
sizeof(struct o2hb_nego_msg),
o2hb_nego_timeout_handler,
@ -2182,10 +2196,13 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g
o2net_unregister_and_flush_handler_list(&reg->hr_handler_list);
remove_item:
spin_lock(&o2hb_live_lock);
list_del(&reg->hr_all_item);
list_del_init(&reg->hr_all_item);
if (o2hb_global_heartbeat_active())
clear_bit(reg->hr_region_num, o2hb_region_bitmap);
spin_unlock(&o2hb_live_lock);
put_item:
config_item_put(&reg->hr_item);
return ERR_PTR(ret);
free:
kfree(reg);
return ERR_PTR(ret);
@ -2208,7 +2225,7 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group,
spin_unlock(&o2hb_live_lock);
if (hb_task)
kthread_stop(hb_task);
kthread_stop_put(hb_task);
if (o2hb_global_heartbeat_active()) {
spin_lock(&o2hb_live_lock);

View File

@ -183,6 +183,7 @@ static int nst_fop_release(struct inode *inode, struct file *file)
}
static const struct file_operations nst_seq_fops = {
.owner = THIS_MODULE,
.open = nst_fop_open,
.read = seq_read,
.llseek = seq_lseek,
@ -415,6 +416,7 @@ static int stats_fop_open(struct inode *inode, struct file *file)
}
static const struct file_operations stats_seq_fops = {
.owner = THIS_MODULE,
.open = stats_fop_open,
.read = seq_read,
.llseek = seq_lseek,
@ -427,6 +429,7 @@ static int sc_fop_open(struct inode *inode, struct file *file)
}
static const struct file_operations sc_seq_fops = {
.owner = THIS_MODULE,
.open = sc_fop_open,
.read = seq_read,
.llseek = seq_lseek,
@ -476,6 +479,7 @@ static ssize_t o2net_debug_read(struct file *file, char __user *buf,
}
static const struct file_operations nodes_fops = {
.owner = THIS_MODULE,
.open = nodes_fop_open,
.release = o2net_debug_release,
.read = o2net_debug_read,

View File

@ -12,6 +12,7 @@
#include "tcp.h"
#include "nodemanager.h"
#include "heartbeat.h"
#include "quorum.h"
#include "masklog.h"
#include "sys.h"
@ -626,8 +627,11 @@ static void o2nm_node_group_drop_item(struct config_group *group,
write_lock(&cluster->cl_nodes_lock);
/* XXX sloppy */
if (node->nd_ipv4_address)
/*
* 0.0.0.0 is a valid configured address, so nd_ipv4_address does
* not tell us whether nd_ip_node was published in the IP tree.
*/
if (test_bit(O2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes))
rb_erase(&node->nd_ip_node, &cluster->cl_node_ip_tree);
/* nd_num might be 0 if the node number hasn't been set.. */
@ -740,6 +744,8 @@ static void o2nm_cluster_group_drop_item(struct config_group *group, struct conf
struct o2nm_cluster *cluster = to_o2nm_cluster(item);
BUG_ON(o2nm_single_cluster != cluster);
/* Drain quorum work before it loses access to the cluster. */
o2quo_flush_work();
o2nm_single_cluster = NULL;
configfs_remove_default_groups(&cluster->cl_group);

View File

@ -318,9 +318,14 @@ void o2quo_init(void)
INIT_WORK(&qs->qs_work, o2quo_make_decision);
}
void o2quo_exit(void)
void o2quo_flush_work(void)
{
struct o2quo_state *qs = &o2quo_state;
flush_work(&qs->qs_work);
}
void o2quo_exit(void)
{
o2quo_flush_work();
}

View File

@ -8,6 +8,7 @@
void o2quo_init(void);
void o2quo_exit(void);
void o2quo_flush_work(void);
void o2quo_hb_up(u8 node);
void o2quo_hb_down(u8 node);

View File

@ -301,6 +301,11 @@ static int o2net_prep_nsw(struct o2net_node *nn, struct o2net_status_wait *nsw)
{
int ret;
/* Initialize all completion-visible state before publishing the waiter. */
init_waitqueue_head(&nsw->ns_wq);
nsw->ns_sys_status = O2NET_ERR_NONE;
nsw->ns_status = 0;
spin_lock(&nn->nn_lock);
ret = idr_alloc(&nn->nn_status_idr, nsw, 0, 0, GFP_ATOMIC);
if (ret >= 0) {
@ -311,9 +316,6 @@ static int o2net_prep_nsw(struct o2net_node *nn, struct o2net_status_wait *nsw)
if (ret < 0)
return ret;
init_waitqueue_head(&nsw->ns_wq);
nsw->ns_sys_status = O2NET_ERR_NONE;
nsw->ns_status = 0;
return 0;
}

View File

@ -221,7 +221,8 @@ static void TEA_transform(__u32 buf[4], __u32 const in[])
buf[1] += b1;
}
static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
static void str2hashbuf(const char *msg, int len, __u32 *buf, int num,
bool legacy_signed)
{
__u32 pad, val;
int i;
@ -235,7 +236,10 @@ static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
for (i = 0; i < len; i++) {
if ((i % 4) == 0)
val = pad;
val = msg[i] + (val << 8);
if (legacy_signed)
val = (signed char)msg[i] + (val << 8);
else
val = (unsigned char)msg[i] + (val << 8);
if ((i % 4) == 3) {
*buf++ = val;
val = pad;
@ -248,8 +252,9 @@ static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
*buf++ = pad;
}
static void ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, int len,
struct ocfs2_dx_hinfo *hinfo)
static void __ocfs2_dx_dir_name_hash(struct inode *dir, const char *name,
int len, struct ocfs2_dx_hinfo *hinfo,
bool legacy_signed)
{
struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
const char *p;
@ -279,7 +284,7 @@ static void ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, int len,
p = name;
while (len > 0) {
str2hashbuf(p, len, in, 4);
str2hashbuf(p, len, in, 4, legacy_signed);
TEA_transform(buf, in);
len -= 16;
p += 16;
@ -290,6 +295,19 @@ static void ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, int len,
hinfo->minor_hash = buf[1];
}
static void ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, int len,
struct ocfs2_dx_hinfo *hinfo)
{
__ocfs2_dx_dir_name_hash(dir, name, len, hinfo, false);
}
static void ocfs2_dx_dir_name_hash_signed(struct inode *dir, const char *name,
int len,
struct ocfs2_dx_hinfo *hinfo)
{
__ocfs2_dx_dir_name_hash(dir, name, len, hinfo, true);
}
/*
* bh passed here can be an inode block or a dir data block, depending
* on the inode inline data flag.
@ -605,6 +623,49 @@ static int ocfs2_validate_dx_root(struct super_block *sb,
goto bail;
}
if (le64_to_cpu(dx_root->dr_blkno) != bh->b_blocknr) {
ret = ocfs2_error(sb,
"Dir Index Root # %llu has an invalid dr_blkno of %llu\n",
(unsigned long long)bh->b_blocknr,
(unsigned long long)le64_to_cpu(dx_root->dr_blkno));
goto bail;
}
if (le32_to_cpu(dx_root->dr_fs_generation) != OCFS2_SB(sb)->fs_generation) {
ret = ocfs2_error(sb,
"Dir Index Root # %llu has an invalid dr_fs_generation of #%u\n",
(unsigned long long)bh->b_blocknr,
le32_to_cpu(dx_root->dr_fs_generation));
goto bail;
}
/*
* Dir index root blocks are allocated from a per-slot suballocator,
* so the slot must be in range. Otherwise removing the index passes
* it to get_local_system_inode(), which hits BUG_ON() for
* OCFS2_INVALID_SLOT or computes an out-of-bounds index otherwise.
*/
if ((u32)le16_to_cpu(dx_root->dr_suballoc_slot) >= OCFS2_SB(sb)->max_slots) {
ret = ocfs2_error(sb,
"Dir Index Root # %llu has invalid dr_suballoc_slot %u\n",
(unsigned long long)le64_to_cpu(dx_root->dr_blkno),
le16_to_cpu(dx_root->dr_suballoc_slot));
goto bail;
}
/*
* Similarly the suballoc bit must fit in a block group bitmap.
* Otherwise removing the index will pass the oversized bit to
* _ocfs2_free_suballoc_bits() and trigger ocfs2_error() there.
*/
if (le16_to_cpu(dx_root->dr_suballoc_bit) >= ocfs2_suballoc_bits_per_block(sb)) {
ret = ocfs2_error(sb,
"Dir Index Root # %llu has invalid dr_suballoc_bit %u\n",
(unsigned long long)le64_to_cpu(dx_root->dr_blkno),
le16_to_cpu(dx_root->dr_suballoc_bit));
goto bail;
}
if (!(dx_root->dr_flags & OCFS2_DX_FLAG_INLINE)) {
struct ocfs2_extent_list *el = &dx_root->dr_list;
@ -690,6 +751,18 @@ static int ocfs2_validate_dx_leaf(struct super_block *sb,
return ocfs2_error(sb, "Dir Index Leaf has bad signature %.*s\n",
7, dx_leaf->dl_signature);
if (le64_to_cpu(dx_leaf->dl_blkno) != bh->b_blocknr)
return ocfs2_error(sb,
"Dir Index Leaf # %llu has an invalid dl_blkno of %llu\n",
(unsigned long long)bh->b_blocknr,
(unsigned long long)le64_to_cpu(dx_leaf->dl_blkno));
if (le32_to_cpu(dx_leaf->dl_fs_generation) != OCFS2_SB(sb)->fs_generation)
return ocfs2_error(sb,
"Dir Index Leaf # %llu has an invalid dl_fs_generation of #%u\n",
(unsigned long long)bh->b_blocknr,
le32_to_cpu(dx_leaf->dl_fs_generation));
if (le16_to_cpu(dx_leaf->dl_list.de_count) !=
ocfs2_dx_entries_per_leaf(sb))
return ocfs2_error(sb,
@ -966,10 +1039,10 @@ static int ocfs2_dx_dir_lookup(struct inode *inode,
return ret;
}
static int ocfs2_dx_dir_search(const char *name, int namelen,
struct inode *dir,
struct ocfs2_dx_root_block *dx_root,
struct ocfs2_dir_lookup_result *res)
static int __ocfs2_dx_dir_search(const char *name, int namelen,
struct inode *dir,
struct ocfs2_dx_root_block *dx_root,
struct ocfs2_dir_lookup_result *res)
{
int ret, i, found;
u64 phys;
@ -982,8 +1055,6 @@ static int ocfs2_dx_dir_search(const char *name, int namelen,
struct ocfs2_extent_list *dr_el;
struct ocfs2_dx_entry_list *entry_list;
ocfs2_dx_dir_name_hash(dir, name, namelen, &res->dl_hinfo);
if (ocfs2_dx_root_inline(dx_root)) {
entry_list = &dx_root->dr_entries;
goto search;
@ -1080,6 +1151,44 @@ static int ocfs2_dx_dir_search(const char *name, int namelen,
return ret;
}
static int ocfs2_dx_dir_search(const char *name, int namelen,
struct inode *dir,
struct ocfs2_dx_root_block *dx_root,
struct ocfs2_dir_lookup_result *res)
{
struct ocfs2_dx_hinfo legacy;
int ret;
ocfs2_dx_dir_name_hash(dir, name, namelen, &res->dl_hinfo);
ret = __ocfs2_dx_dir_search(name, namelen, dir, dx_root, res);
if (ret != -ENOENT)
return ret;
/*
* Nothing under the current hash. The entry may have been indexed by
* an older kernel, which sign-extended the name bytes when hashing.
* New entries are always indexed under the unsigned hash, so only fall
* back to the legacy signed one when it can actually differ: an ASCII
* name hashes the same either way, and a genuine miss on one should
* not have to walk the index twice.
*/
ocfs2_dx_dir_name_hash_signed(dir, name, namelen, &legacy);
if (legacy.major_hash == res->dl_hinfo.major_hash &&
legacy.minor_hash == res->dl_hinfo.minor_hash)
return ret;
res->dl_hinfo = legacy;
ret = __ocfs2_dx_dir_search(name, namelen, dir, dx_root, res);
if (ret)
return ret;
pr_warn_once("ocfs2: directory index with signed name hash\n");
return 0;
}
static int ocfs2_find_entry_dx(const char *name, int namelen,
struct inode *dir,
struct ocfs2_dir_lookup_result *lookup)

View File

@ -534,15 +534,19 @@ int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data,
}
leave:
if (lock)
dlm_lock_put(lock);
/* either queue the ast or release it, if reserved */
if (call_ast)
dlm_queue_ast(dlm, lock);
else if (ast_reserved)
dlm_lockres_release_ast(dlm, res);
/*
* Keep the lock alive through AST enqueue: a concurrent
* dlm_free_dead_locks() drops the list and base references.
*/
if (lock)
dlm_lock_put(lock);
if (kick_thread)
dlm_kick_thread(dlm, res);

View File

@ -7,6 +7,7 @@
* Copyright (C) 2004, 2008 Oracle. All rights reserved.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/highmem.h>
@ -339,6 +340,7 @@ static int debug_purgelist_open(struct inode *inode, struct file *file)
}
static const struct file_operations debug_purgelist_fops = {
.owner = THIS_MODULE,
.open = debug_purgelist_open,
.release = debug_release,
.read = debug_read,
@ -394,6 +396,7 @@ static int debug_mle_open(struct inode *inode, struct file *file)
}
static const struct file_operations debug_mle_fops = {
.owner = THIS_MODULE,
.open = debug_mle_open,
.release = debug_release,
.read = debug_read,
@ -601,6 +604,7 @@ static int debug_lockres_release(struct inode *inode, struct file *file)
}
static const struct file_operations debug_lockres_fops = {
.owner = THIS_MODULE,
.open = debug_lockres_open,
.release = debug_lockres_release,
.read = seq_read,
@ -794,6 +798,7 @@ static int debug_state_open(struct inode *inode, struct file *file)
}
static const struct file_operations debug_state_fops = {
.owner = THIS_MODULE,
.open = debug_state_open,
.release = debug_release,
.read = debug_read,

View File

@ -2215,7 +2215,8 @@ static LIST_HEAD(dlm_join_handlers);
static void dlm_unregister_net_handlers(void)
{
o2net_unregister_handler_list(&dlm_join_handlers);
if (!list_empty(&dlm_join_handlers))
o2net_unregister_and_flush_handler_list(&dlm_join_handlers);
}
static int dlm_register_net_handlers(void)

View File

@ -138,6 +138,8 @@ static enum dlm_status dlmlock_master(struct dlm_ctxt *dlm,
res->lockname.len)) {
kick_thread = 1;
call_ast = 1;
/* Keep the lock alive through AST enqueue. */
dlm_lock_get(lock);
} else {
mlog(0, "%s: returning DLM_NORMAL to "
"node %u for reco lock\n", dlm->name,
@ -166,10 +168,12 @@ static enum dlm_status dlmlock_master(struct dlm_ctxt *dlm,
wake_up(&res->wq);
/* either queue the ast or release it */
if (call_ast)
if (call_ast) {
dlm_queue_ast(dlm, lock);
else
dlm_lock_put(lock);
} else {
dlm_lockres_release_ast(dlm, res);
}
dlm_lockres_calc_usage(dlm, res);
if (kick_thread)

View File

@ -7,6 +7,7 @@
* Copyright (C) 2003, 2004 Oracle. All rights reserved.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/highmem.h>
@ -18,6 +19,7 @@
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/quotaops.h>
#include <linux/sched/mm.h>
#include <linux/sched/signal.h>
#include <linux/string_choices.h>
@ -2861,21 +2863,34 @@ void ocfs2_rename_unlock(struct ocfs2_super *osb)
ocfs2_cluster_unlock(osb, lockres, DLM_LOCK_EX);
}
int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex)
int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex, unsigned int *nofs_flag)
{
int status;
unsigned int flags;
struct ocfs2_lock_res *lockres = &osb->osb_nfs_sync_lockres;
if (ocfs2_is_hard_readonly(osb))
return -EROFS;
/*
* ocfs2_delete_inode() takes this lock from ->evict_inode(), which the
* dentry shrinker reaches while holding fs_reclaim. Anything allocated
* under the lock must therefore stay out of filesystem reclaim, or
* reclaim recurses back into the shrinker and tries to take this lock
* again. Cover the whole critical section, including the cluster lock
* and the sysfile inode locks the callers take below it.
*/
flags = memalloc_nofs_save();
if (ex)
down_write(&osb->nfs_sync_rwlock);
else
down_read(&osb->nfs_sync_rwlock);
if (ocfs2_mount_local(osb))
if (ocfs2_mount_local(osb)) {
*nofs_flag = flags;
return 0;
}
status = ocfs2_cluster_lock(osb, lockres, ex ? LKM_EXMODE : LKM_PRMODE,
0, 0);
@ -2886,12 +2901,17 @@ int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex)
up_write(&osb->nfs_sync_rwlock);
else
up_read(&osb->nfs_sync_rwlock);
memalloc_nofs_restore(flags);
return status;
}
return status;
*nofs_flag = flags;
return 0;
}
void ocfs2_nfs_sync_unlock(struct ocfs2_super *osb, int ex)
void ocfs2_nfs_sync_unlock(struct ocfs2_super *osb, int ex,
unsigned int nofs_flag)
{
struct ocfs2_lock_res *lockres = &osb->osb_nfs_sync_lockres;
@ -2902,6 +2922,8 @@ void ocfs2_nfs_sync_unlock(struct ocfs2_super *osb, int ex)
up_write(&osb->nfs_sync_rwlock);
else
up_read(&osb->nfs_sync_rwlock);
memalloc_nofs_restore(nofs_flag);
}
int ocfs2_trim_fs_lock(struct ocfs2_super *osb,
@ -3311,6 +3333,7 @@ static int ocfs2_dlm_debug_open(struct inode *inode, struct file *file)
}
static const struct file_operations ocfs2_dlm_debug_fops = {
.owner = THIS_MODULE,
.open = ocfs2_dlm_debug_open,
.release = ocfs2_dlm_debug_release,
.read = seq_read,
@ -3525,6 +3548,10 @@ void ocfs2_mark_lockres_freeing(struct ocfs2_super *osb,
struct ocfs2_mask_waiter mw;
unsigned long flags, flags2;
/* We didn't get anywhere near actually using this lockres. */
if (!(lockres->l_flags & OCFS2_LOCK_INITIALIZED))
return;
ocfs2_init_mask_waiter(&mw);
spin_lock_irqsave(&lockres->l_lock, flags);

View File

@ -161,8 +161,9 @@ void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno);
int ocfs2_rename_lock(struct ocfs2_super *osb);
void ocfs2_rename_unlock(struct ocfs2_super *osb);
int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex);
void ocfs2_nfs_sync_unlock(struct ocfs2_super *osb, int ex);
int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex, unsigned int *nofs_flag);
void ocfs2_nfs_sync_unlock(struct ocfs2_super *osb, int ex,
unsigned int nofs_flag);
void ocfs2_trim_fs_lock_res_init(struct ocfs2_super *osb);
void ocfs2_trim_fs_lock_res_uninit(struct ocfs2_super *osb);
int ocfs2_trim_fs_lock(struct ocfs2_super *osb,

View File

@ -37,6 +37,7 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb,
struct inode *inode;
struct ocfs2_super *osb = OCFS2_SB(sb);
u64 blkno = handle->ih_blkno;
unsigned int nofs_flag = 0;
int status, set;
struct dentry *result;
@ -59,7 +60,7 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb,
* This will synchronize us against ocfs2_delete_inode() on
* all nodes
*/
status = ocfs2_nfs_sync_lock(osb, 1);
status = ocfs2_nfs_sync_lock(osb, 1, &nofs_flag);
if (status < 0) {
mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
goto check_err;
@ -90,7 +91,7 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb,
inode = ocfs2_iget(osb, blkno, 0, 0);
unlock_nfs_sync:
ocfs2_nfs_sync_unlock(osb, 1);
ocfs2_nfs_sync_unlock(osb, 1, nofs_flag);
check_err:
if (status < 0) {
@ -133,12 +134,13 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
u64 blkno;
struct dentry *parent;
struct inode *dir = d_inode(child);
unsigned int nofs_flag = 0;
int set;
trace_ocfs2_get_parent(child, child->d_name.len, child->d_name.name,
(unsigned long long)OCFS2_I(dir)->ip_blkno);
status = ocfs2_nfs_sync_lock(OCFS2_SB(dir->i_sb), 1);
status = ocfs2_nfs_sync_lock(OCFS2_SB(dir->i_sb), 1, &nofs_flag);
if (status < 0) {
mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
parent = ERR_PTR(status);
@ -183,7 +185,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
ocfs2_inode_unlock(dir, 0);
unlock_nfs_sync:
ocfs2_nfs_sync_unlock(OCFS2_SB(dir->i_sb), 1);
ocfs2_nfs_sync_unlock(OCFS2_SB(dir->i_sb), 1, nofs_flag);
bail:
trace_ocfs2_get_parent_end(parent);

View File

@ -85,10 +85,17 @@ static int ocfs2_file_open(struct inode *inode, struct file *file)
int mode = file->f_flags;
struct ocfs2_inode_info *oi = OCFS2_I(inode);
trace_ocfs2_file_open(inode, file, file->f_path.dentry,
(unsigned long long)oi->ip_blkno,
file->f_path.dentry->d_name.len,
file->f_path.dentry->d_name.name, mode);
if (trace_ocfs2_file_open_enabled()) {
struct dentry *dentry = file->f_path.dentry;
struct name_snapshot name;
take_dentry_name_snapshot(&name, dentry);
trace_ocfs2_file_open(inode, file, dentry,
oi->ip_blkno,
name.name.len, name.name.name,
mode);
release_dentry_name_snapshot(&name);
}
if (file->f_mode & FMODE_WRITE) {
status = dquot_initialize(inode);
@ -134,18 +141,26 @@ static int ocfs2_file_open(struct inode *inode, struct file *file)
static int ocfs2_file_release(struct inode *inode, struct file *file)
{
struct ocfs2_inode_info *oi = OCFS2_I(inode);
struct dentry *dentry = file->f_path.dentry;
struct name_snapshot name;
bool trace_enabled = trace_ocfs2_file_release_enabled();
if (trace_enabled)
take_dentry_name_snapshot(&name, dentry);
spin_lock(&oi->ip_lock);
if (!--oi->ip_open_count)
oi->ip_flags &= ~OCFS2_INODE_OPEN_DIRECT;
trace_ocfs2_file_release(inode, file, file->f_path.dentry,
oi->ip_blkno,
file->f_path.dentry->d_name.len,
file->f_path.dentry->d_name.name,
oi->ip_open_count);
if (trace_enabled)
trace_ocfs2_file_release(inode, file, dentry,
oi->ip_blkno, name.name.len,
name.name.name, oi->ip_open_count);
spin_unlock(&oi->ip_lock);
if (trace_enabled)
release_dentry_name_snapshot(&name);
ocfs2_free_file_private(inode, file);
return 0;
@ -174,11 +189,17 @@ static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end,
tid_t commit_tid;
bool needs_barrier = false;
trace_ocfs2_sync_file(inode, file, file->f_path.dentry,
oi->ip_blkno,
file->f_path.dentry->d_name.len,
file->f_path.dentry->d_name.name,
(unsigned long long)datasync);
if (trace_ocfs2_sync_file_enabled()) {
struct dentry *dentry = file->f_path.dentry;
struct name_snapshot name;
take_dentry_name_snapshot(&name, dentry);
trace_ocfs2_sync_file(inode, file, dentry,
oi->ip_blkno,
name.name.len, name.name.name,
(unsigned long long)datasync);
release_dentry_name_snapshot(&name);
}
if (unlikely(ocfs2_emergency_state(osb)))
return -EROFS;
@ -1132,15 +1153,19 @@ int ocfs2_setattr(const struct mnt_idmap *idmap, struct dentry *dentry,
int had_lock;
struct ocfs2_lock_holder oh;
trace_ocfs2_setattr(inode, dentry,
(unsigned long long)OCFS2_I(inode)->ip_blkno,
dentry->d_name.len, dentry->d_name.name,
attr->ia_valid,
attr->ia_valid & ATTR_MODE ? attr->ia_mode : 0,
attr->ia_valid & ATTR_UID ?
if (trace_ocfs2_setattr_enabled()) {
struct name_snapshot name;
take_dentry_name_snapshot(&name, dentry);
trace_ocfs2_setattr(inode, dentry, OCFS2_I(inode)->ip_blkno,
name.name.len, name.name.name, attr->ia_valid,
attr->ia_valid & ATTR_MODE ? attr->ia_mode : 0,
attr->ia_valid & ATTR_UID ?
from_kuid(&init_user_ns, attr->ia_uid) : 0,
attr->ia_valid & ATTR_GID ?
attr->ia_valid & ATTR_GID ?
from_kgid(&init_user_ns, attr->ia_gid) : 0);
release_dentry_name_snapshot(&name);
}
status = ocfs2_emergency_state(osb);
if (unlikely(status)) {
@ -2392,11 +2417,17 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb,
int direct_io = iocb->ki_flags & IOCB_DIRECT ? 1 : 0;
int nowait = iocb->ki_flags & IOCB_NOWAIT ? 1 : 0;
trace_ocfs2_file_write_iter(inode, file, file->f_path.dentry,
(unsigned long long)OCFS2_I(inode)->ip_blkno,
file->f_path.dentry->d_name.len,
file->f_path.dentry->d_name.name,
(unsigned int)from->nr_segs); /* GRRRRR */
if (trace_ocfs2_file_write_iter_enabled()) {
struct dentry *dentry = file->f_path.dentry;
struct name_snapshot name;
take_dentry_name_snapshot(&name, dentry);
trace_ocfs2_file_write_iter(inode, file, dentry,
OCFS2_I(inode)->ip_blkno,
name.name.len, name.name.name,
(unsigned int)from->nr_segs);
release_dentry_name_snapshot(&name);
}
if (!direct_io && nowait)
return -EOPNOTSUPP;
@ -2542,17 +2573,16 @@ static ssize_t ocfs2_file_read_iter(struct kiocb *iocb,
int direct_io = iocb->ki_flags & IOCB_DIRECT ? 1 : 0;
int nowait = iocb->ki_flags & IOCB_NOWAIT ? 1 : 0;
trace_ocfs2_file_read_iter(inode, filp, filp->f_path.dentry,
(unsigned long long)OCFS2_I(inode)->ip_blkno,
filp->f_path.dentry->d_name.len,
filp->f_path.dentry->d_name.name,
to->nr_segs); /* GRRRRR */
if (trace_ocfs2_file_read_iter_enabled()) {
struct dentry *dentry = filp->f_path.dentry;
struct name_snapshot name;
if (!inode) {
ret = -EINVAL;
mlog_errno(ret);
goto bail;
take_dentry_name_snapshot(&name, dentry);
trace_ocfs2_file_read_iter(inode, filp, dentry,
OCFS2_I(inode)->ip_blkno,
name.name.len, name.name.name,
to->nr_segs);
release_dentry_name_snapshot(&name);
}
if (!direct_io && nowait)
@ -2624,11 +2654,17 @@ static ssize_t ocfs2_file_splice_read(struct file *in, loff_t *ppos,
ssize_t ret = 0;
int lock_level = 0;
trace_ocfs2_file_splice_read(inode, in, in->f_path.dentry,
(unsigned long long)OCFS2_I(inode)->ip_blkno,
in->f_path.dentry->d_name.len,
in->f_path.dentry->d_name.name,
flags);
if (trace_ocfs2_file_splice_read_enabled()) {
struct dentry *dentry = in->f_path.dentry;
struct name_snapshot name;
take_dentry_name_snapshot(&name, dentry);
trace_ocfs2_file_splice_read(inode, in, dentry,
OCFS2_I(inode)->ip_blkno,
name.name.len, name.name.name,
flags);
release_dentry_name_snapshot(&name);
}
/*
* We're fine letting folks race truncates and extending writes with

View File

@ -179,17 +179,20 @@ int ocfs2_filecheck_create_sysfs(struct ocfs2_super *osb)
fcheck->fc_size = 0;
fcheck->fc_done = 0;
/* Publish the initialized owner before activating its sysfs callbacks. */
entry->fs_fcheck = fcheck;
entry->fs_kobj.kset = osb->osb_dev_kset;
init_completion(&entry->fs_kobj_unregister);
ret = kobject_init_and_add(&entry->fs_kobj, &ocfs2_ktype_filecheck,
NULL, "filecheck");
if (ret) {
/* Mount failure still calls ocfs2_filecheck_remove_sysfs(). */
entry->fs_fcheck = NULL;
kobject_put(&entry->fs_kobj);
kfree(fcheck);
return ret;
}
entry->fs_fcheck = fcheck;
return 0;
}

View File

@ -638,14 +638,18 @@ static int ocfs2_read_locked_inode(struct inode *inode,
fe = (struct ocfs2_dinode *) bh->b_data;
/*
* This is a code bug. Right now the caller needs to
* understand whether it is asking for a system file inode or
* not so the proper lock names can be built.
* The caller must know whether it is asking for a system file inode
* or not so the proper lock names can be built. Since i_flags comes
* from disk, a mismatch is filesystem corruption instead of a code
* bug, so handle it with ocfs2_error() rather than BUG_ON().
*/
mlog_bug_on_msg(!!(fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL)) !=
!!(args->fi_flags & OCFS2_FI_FLAG_SYSFILE),
"Inode %llu: system file state is ambiguous\n",
(unsigned long long)args->fi_blkno);
if (!!(fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL)) !=
!!(args->fi_flags & OCFS2_FI_FLAG_SYSFILE)) {
status = ocfs2_error(osb->sb,
"Inode %llu: system file state is ambiguous\n",
(unsigned long long)args->fi_blkno);
goto bail;
}
if (S_ISCHR(le16_to_cpu(fe->i_mode)) ||
S_ISBLK(le16_to_cpu(fe->i_mode)))
@ -1105,6 +1109,7 @@ static void ocfs2_delete_inode(struct inode *inode)
{
int wipe, status;
sigset_t oldset;
unsigned int nofs_flag = 0;
struct buffer_head *di_bh = NULL;
struct ocfs2_dinode *di = NULL;
@ -1139,7 +1144,7 @@ static void ocfs2_delete_inode(struct inode *inode)
* shared mode so that all nodes can still concurrently
* process deletes.
*/
status = ocfs2_nfs_sync_lock(OCFS2_SB(inode->i_sb), 0);
status = ocfs2_nfs_sync_lock(OCFS2_SB(inode->i_sb), 0, &nofs_flag);
if (status < 0) {
mlog(ML_ERROR, "getting nfs sync lock(PR) failed %d\n", status);
ocfs2_cleanup_delete_inode(inode, 0);
@ -1211,7 +1216,7 @@ static void ocfs2_delete_inode(struct inode *inode)
brelse(di_bh);
bail_unlock_nfs_sync:
ocfs2_nfs_sync_unlock(OCFS2_SB(inode->i_sb), 0);
ocfs2_nfs_sync_unlock(OCFS2_SB(inode->i_sb), 0, nofs_flag);
bail_unblock:
ocfs2_unblock_signals(&oldset);
@ -1520,14 +1525,45 @@ int ocfs2_validate_inode_block(struct super_block *sb,
goto bail;
}
if (le16_to_cpu(di->i_suballoc_slot) != (u16)OCFS2_INVALID_SLOT &&
(u32)le16_to_cpu(di->i_suballoc_slot) > OCFS2_SB(sb)->max_slots - 1) {
/*
* Only system inodes created by mkfs.ocfs2 are allocated from the
* global allocator and thus legitimately carry OCFS2_INVALID_SLOT.
* Regular inodes are always allocated from a per-slot suballocator.
* If a regular inode with OCFS2_INVALID_SLOT was accepted here,
* deleting it would pass the slot to get_local_system_inode() via
* ocfs2_remove_inode() and trigger BUG_ON(slot == OCFS2_INVALID_SLOT).
*/
if (le16_to_cpu(di->i_suballoc_slot) == (u16)OCFS2_INVALID_SLOT) {
if (!(le32_to_cpu(di->i_flags) & OCFS2_SYSTEM_FL)) {
rc = ocfs2_error(sb,
"Invalid dinode %llu: suballoc slot %u for non-system inode\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(di->i_suballoc_slot));
goto bail;
}
} else if ((u32)le16_to_cpu(di->i_suballoc_slot) > OCFS2_SB(sb)->max_slots - 1) {
rc = ocfs2_error(sb, "Invalid dinode %llu: suballoc slot %u\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(di->i_suballoc_slot));
goto bail;
}
/*
* A suballocator block group bitmap is contained in a single block
* and starts after the group descriptor header, so a valid suballoc
* bit can never exceed ocfs2_suballoc_bits_per_block(). Otherwise
* deleting the inode will pass the oversized bit to
* _ocfs2_free_suballoc_bits() via ocfs2_free_dinode() and trigger
* BUG_ON((count + start_bit) > ocfs2_bits_per_group(cl)), since any
* group holds at most ocfs2_suballoc_bits_per_block() bits.
*/
if (le16_to_cpu(di->i_suballoc_bit) >= ocfs2_suballoc_bits_per_block(sb)) {
rc = ocfs2_error(sb, "Invalid dinode %llu: suballoc bit %u\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(di->i_suballoc_bit));
goto bail;
}
if ((le32_to_cpu(di->i_flags) & OCFS2_ORPHANED_FL) &&
le16_to_cpu(di->i_orphaned_slot) >= OCFS2_SB(sb)->max_slots) {
rc = ocfs2_error(sb, "Invalid dinode %llu: orphaned slot %u\n",

View File

@ -156,7 +156,7 @@ static void ocfs2_queue_replay_slots(struct ocfs2_super *osb,
replay_map->rm_state = REPLAY_DONE;
}
void ocfs2_free_replay_slots(struct ocfs2_super *osb)
static void ocfs2_free_replay_slots(struct ocfs2_super *osb)
{
struct ocfs2_replay_map *replay_map = osb->replay_map;
@ -243,6 +243,7 @@ void ocfs2_recovery_exit(struct ocfs2_super *osb)
/* XXX: Should we bug if there are dirty entries? */
kfree(rm);
ocfs2_free_replay_slots(osb);
}
static int __ocfs2_recovery_map_test(struct ocfs2_super *osb,

View File

@ -151,7 +151,6 @@ void ocfs2_recovery_exit(struct ocfs2_super *osb);
void ocfs2_recovery_disable_quota(struct ocfs2_super *osb);
int ocfs2_compute_replay_slots(struct ocfs2_super *osb);
void ocfs2_free_replay_slots(struct ocfs2_super *osb);
/*
* Journal Control:
* Initialize, Load, Shutdown, Wipe a journal.

View File

@ -248,7 +248,6 @@ static int ocfs2_mknod(const struct mnt_idmap *idmap,
int want_meta = 0;
int xattr_credits = 0;
struct ocfs2_security_xattr_info si = {
.name = NULL,
.enable = 1,
};
int did_quota_inode = 0;
@ -475,7 +474,7 @@ static int ocfs2_mknod(const struct mnt_idmap *idmap,
brelse(new_fe_bh);
brelse(parent_fe_bh);
kfree(si.value);
ocfs2_free_security_xattrs(&si);
ocfs2_acl_init_release(&acl_state);
@ -1831,7 +1830,6 @@ static int ocfs2_symlink(const struct mnt_idmap *idmap,
int want_clusters = 0;
int xattr_credits = 0;
struct ocfs2_security_xattr_info si = {
.name = NULL,
.enable = 1,
};
int did_quota = 0, did_quota_inode = 0;
@ -2063,7 +2061,7 @@ static int ocfs2_symlink(const struct mnt_idmap *idmap,
brelse(new_fe_bh);
brelse(parent_fe_bh);
kfree(si.value);
ocfs2_free_security_xattrs(&si);
ocfs2_free_dir_lookup_result(&lookup);
if (inode_ac)
ocfs2_free_alloc_context(inode_ac);

View File

@ -502,6 +502,11 @@ struct ocfs2_super
*/
struct workqueue_struct *ocfs2_wq;
/* deferred reclaim of fully freed suballocator block groups */
spinlock_t os_suballoc_reclaim_lock;
struct list_head os_suballoc_reclaim_list;
struct work_struct os_suballoc_reclaim_work;
/* sysfs directory per partition */
struct kset *osb_dev_kset;
@ -588,6 +593,18 @@ static inline int ocfs2_supports_discontig_bg(struct ocfs2_super *osb)
return 0;
}
/*
* A suballocator block group bitmap starts right after the group
* descriptor header, so a suballoc bit can never exceed this number
* of bits. Derive it from ocfs2_group_bitmap_size() which also caps
* it at OCFS2_MAX_BG_BITMAP_SIZE when discontig_bg is enabled.
*/
static inline u32 ocfs2_suballoc_bits_per_block(struct super_block *sb)
{
return ocfs2_group_bitmap_size(sb, 1,
OCFS2_SB(sb)->s_feature_incompat) * 8;
}
static inline unsigned int ocfs2_link_max(struct ocfs2_super *osb)
{
if (ocfs2_supports_indexed_dirs(osb))

View File

@ -249,6 +249,25 @@ static void ocfs2_release_local_quota_bitmaps(struct list_head *head)
}
}
/* Check that the on-disk chunk and block counts match the file layout */
static int ocfs2_check_local_quota_info(struct inode *inode,
unsigned int chunks,
unsigned int blocks)
{
u64 chunk_len = ol_chunk_blocks(inode->i_sb) + 1;
u64 min_blocks = chunks ? 1 + chunk_len * (chunks - 1) + 1 : 1;
u64 max_blocks = 1 + chunk_len * chunks;
if (blocks >= min_blocks && blocks <= max_blocks &&
blocks <= i_size_read(inode) >> inode->i_sb->s_blocksize_bits)
return 0;
return ocfs2_error(inode->i_sb,
"Quota file %llu has bad info: %u chunks, %u blocks\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno,
chunks, blocks);
}
/* Load quota bitmaps into memory */
static int ocfs2_load_local_quota_bitmaps(struct inode *inode,
struct ocfs2_local_disk_dqinfo *ldinfo,
@ -737,6 +756,11 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
oinfo->dqi_blocks = le32_to_cpu(ldinfo->dqi_blocks);
oinfo->dqi_libh = bh;
status = ocfs2_check_local_quota_info(lqinode, oinfo->dqi_chunks,
oinfo->dqi_blocks);
if (status < 0)
goto out_err;
/* We crashed when using local quota file? */
if (!(oinfo->dqi_flags & OLQF_CLEAN)) {
rec = OCFS2_SB(sb)->quota_rec;
@ -820,6 +844,9 @@ static int ocfs2_local_free_info(struct super_block *sb, int type)
int mark_clean = 1, len;
int status = 0;
/* Quota-core error paths can bypass ocfs2_disable_quotas(). */
cancel_delayed_work_sync(&oinfo->dqi_sync_work);
iput(oinfo->dqi_gqinode);
ocfs2_simple_drop_lockres(OCFS2_SB(sb), &oinfo->dqi_gqlock);
ocfs2_lock_res_free(&oinfo->dqi_gqlock);
@ -1075,10 +1102,13 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
goto out;
}
if (list_empty(&oinfo->dqi_chunk))
chunk->qc_num = 0;
else
chunk->qc_num = list_entry(oinfo->dqi_chunk.prev,
struct ocfs2_quota_chunk,
qc_chunk)->qc_num + 1;
list_add_tail(&chunk->qc_chunk, &oinfo->dqi_chunk);
chunk->qc_num = list_entry(chunk->qc_chunk.prev,
struct ocfs2_quota_chunk,
qc_chunk)->qc_num + 1;
chunk->qc_headerbh = bh;
*offset = 0;
return chunk;

View File

@ -117,6 +117,33 @@ static int ocfs2_validate_refcount_block(struct super_block *sb,
goto out;
}
/*
* Refcount blocks are allocated from a per-slot suballocator, so the
* slot must be in range. Otherwise freeing the block passes it to
* get_local_system_inode(), which hits BUG_ON() for
* OCFS2_INVALID_SLOT or computes an out-of-bounds index otherwise.
*/
if ((u32)le16_to_cpu(rb->rf_suballoc_slot) >= OCFS2_SB(sb)->max_slots) {
rc = ocfs2_error(sb,
"Refcount block #%llu has an invalid rf_suballoc_slot of %u\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(rb->rf_suballoc_slot));
goto out;
}
/*
* Similarly the suballoc bit must fit in a block group bitmap.
* Otherwise freeing the block will pass the oversized bit to
* _ocfs2_free_suballoc_bits() and trigger ocfs2_error() there.
*/
if (le16_to_cpu(rb->rf_suballoc_bit) >= ocfs2_suballoc_bits_per_block(sb)) {
rc = ocfs2_error(sb,
"Refcount block #%llu has an invalid rf_suballoc_bit of %u\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(rb->rf_suballoc_bit));
goto out;
}
/*
* rf_records (rl_count/rl_used/rl_recs[]) is only meaningful when
* this block is not an interior tree block (OCFS2_REFCOUNT_TREE_FL);
@ -348,8 +375,10 @@ ocfs2_allocate_refcount_tree(struct ocfs2_super *osb, u64 rf_blkno)
return new;
}
/* Callers without the refcount tree lock must request a reference. */
static int ocfs2_get_refcount_tree(struct ocfs2_super *osb, u64 rf_blkno,
struct ocfs2_refcount_tree **ret_tree)
struct ocfs2_refcount_tree **ret_tree,
bool get_ref)
{
int ret = 0;
struct ocfs2_refcount_tree *tree, *new = NULL;
@ -406,6 +435,8 @@ static int ocfs2_get_refcount_tree(struct ocfs2_super *osb, u64 rf_blkno,
new = NULL;
out:
if (get_ref)
ocfs2_refcount_tree_get(tree);
*ret_tree = tree;
osb->osb_ref_tree_lru = tree;
@ -479,14 +510,12 @@ int ocfs2_lock_refcount_tree(struct ocfs2_super *osb,
struct ocfs2_refcount_block *rb;
again:
ret = ocfs2_get_refcount_tree(osb, ref_blkno, &tree);
ret = ocfs2_get_refcount_tree(osb, ref_blkno, &tree, true);
if (ret) {
mlog_errno(ret);
return ret;
}
ocfs2_refcount_tree_get(tree);
ret = __ocfs2_lock_refcount_tree(osb, tree, rw);
if (ret) {
mlog_errno(ret);
@ -2328,7 +2357,8 @@ int ocfs2_decrease_refcount(struct inode *inode,
goto out;
}
ret = ocfs2_get_refcount_tree(OCFS2_SB(inode->i_sb), ref_blkno, &tree);
ret = ocfs2_get_refcount_tree(OCFS2_SB(inode->i_sb), ref_blkno,
&tree, false);
if (ret) {
mlog_errno(ret);
goto out;
@ -2563,7 +2593,7 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode,
BUG_ON(!ocfs2_is_refcount_inode(inode));
ret = ocfs2_get_refcount_tree(OCFS2_SB(inode->i_sb),
refcount_loc, &tree);
refcount_loc, &tree, false);
if (ret) {
mlog_errno(ret);
goto out;

View File

@ -2687,16 +2687,24 @@ static int ocfs2_block_group_clear_bits(handle_t *handle,
* cleanup rec/alloc_inode job, then switches to the main bitmap
* to reclaim released space.
*
* Callers must hold inode_lock() and ocfs2_inode_lock() on
* main_bm_inode, i.e. the global bitmap inode locks must be taken
* before starting the transaction.
*
* handle: The transaction handle
* alloc_inode: The suballoc inode
* alloc_bh: The buffer_head of suballoc inode
* group_bh: The group descriptor buffer_head of suballocator managed.
* Caller should release the input group_bh.
* This function takes ownership of it and will release it.
* main_bm_inode: The global bitmap inode
* main_bm_bh: The buffer_head of the global bitmap inode
*/
static int _ocfs2_reclaim_suballoc_to_main(handle_t *handle,
struct inode *alloc_inode,
struct buffer_head *alloc_bh,
struct buffer_head *group_bh)
struct buffer_head *group_bh,
struct inode *main_bm_inode,
struct buffer_head *main_bm_bh)
{
int idx, status = 0;
int i, next_free_rec, len = 0;
@ -2706,8 +2714,6 @@ static int _ocfs2_reclaim_suballoc_to_main(handle_t *handle,
u64 bg_blkno, start_blk;
unsigned int count;
struct ocfs2_chain_rec *rec;
struct buffer_head *main_bm_bh = NULL;
struct inode *main_bm_inode = NULL;
struct ocfs2_super *osb = OCFS2_SB(alloc_inode->i_sb);
struct ocfs2_dinode *fe = (struct ocfs2_dinode *) alloc_bh->b_data;
struct ocfs2_chain_list *cl = &fe->id2.i_chain;
@ -2794,24 +2800,12 @@ static int _ocfs2_reclaim_suballoc_to_main(handle_t *handle,
ocfs2_remove_from_cache(INODE_CACHE(alloc_inode), group_bh);
memset(group, 0, sizeof(struct ocfs2_group_desc));
/* prepare job for reclaim clusters */
main_bm_inode = ocfs2_get_system_file_inode(osb,
GLOBAL_BITMAP_SYSTEM_INODE,
OCFS2_INVALID_SLOT);
if (!main_bm_inode)
goto bail; /* ignore the error in reclaim path */
inode_lock(main_bm_inode);
status = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
if (status < 0)
goto free_bm_inode; /* ignore the error in reclaim path */
ocfs2_block_to_cluster_group(main_bm_inode, start_blk, &bg_blkno,
&start_bit);
fe = (struct ocfs2_dinode *) main_bm_bh->b_data;
cl = &fe->id2.i_chain;
/* reuse group_bh, caller will release the input group_bh */
/* release the suballocator group descriptor before reuse */
brelse(group_bh);
group_bh = NULL;
/* reclaim clusters to global_bitmap */
@ -2819,7 +2813,7 @@ static int _ocfs2_reclaim_suballoc_to_main(handle_t *handle,
&group_bh);
if (status < 0) {
mlog_errno(status);
goto free_bm_bh;
goto bail;
}
group = (struct ocfs2_group_desc *) group_bh->b_data;
@ -2827,7 +2821,7 @@ static int _ocfs2_reclaim_suballoc_to_main(handle_t *handle,
ocfs2_error(alloc_inode->i_sb,
"reclaim length (%d) beyands block group length (%d)",
count + start_bit, le16_to_cpu(group->bg_bits));
goto free_group_bh;
goto bail;
}
old_bg_contig_free_bits = group->bg_contig_free_bits;
@ -2837,7 +2831,7 @@ static int _ocfs2_reclaim_suballoc_to_main(handle_t *handle,
_ocfs2_clear_bit);
if (status < 0) {
mlog_errno(status);
goto free_group_bh;
goto bail;
}
status = ocfs2_journal_access_di(handle, INODE_CACHE(main_bm_inode),
@ -2847,7 +2841,7 @@ static int _ocfs2_reclaim_suballoc_to_main(handle_t *handle,
ocfs2_block_group_set_bits(handle, main_bm_inode, group, group_bh,
start_bit, count,
le16_to_cpu(old_bg_contig_free_bits), 1);
goto free_group_bh;
goto bail;
}
idx = le16_to_cpu(group->bg_chain);
@ -2858,19 +2852,168 @@ static int _ocfs2_reclaim_suballoc_to_main(handle_t *handle,
fe->id1.bitmap1.i_used = cpu_to_le32(tmp_used - count);
ocfs2_journal_dirty(handle, main_bm_bh);
free_group_bh:
bail:
brelse(group_bh);
return status;
}
free_bm_bh:
/*
* When a suballocator block group becomes fully freed, its space is
* reclaimed back to the global bitmap. Taking the global bitmap inode
* lock inside the freeing transaction would create a lock dependency
* of "j_trans_barrier -> global bitmap inode i_rwsem", which forms a
* circular dependency with paths like ocfs2_shutdown_local_alloc() that
* take the inode lock before starting a transaction, and can lead to a
* real deadlock with the ocfs2cmt journal commit thread. So queue the
* reclaim to the workqueue and let it run outside the freeing
* transaction.
*/
struct ocfs2_suballoc_reclaim_work {
struct list_head list;
struct inode *alloc_inode;
u64 bg_blkno;
};
static void ocfs2_queue_suballoc_reclaim(struct ocfs2_super *osb,
struct inode *alloc_inode,
u64 bg_blkno)
{
struct ocfs2_suballoc_reclaim_work *reclaim_work;
reclaim_work = kmalloc_obj(*reclaim_work, GFP_NOFS);
if (!reclaim_work) {
/*
* Reclaim is only a space return optimization. If we can't
* queue it, the freed block group just stays owned by the
* suballocator.
*/
return;
}
igrab(alloc_inode);
reclaim_work->alloc_inode = alloc_inode;
reclaim_work->bg_blkno = bg_blkno;
spin_lock(&osb->os_suballoc_reclaim_lock);
list_add_tail(&reclaim_work->list, &osb->os_suballoc_reclaim_list);
spin_unlock(&osb->os_suballoc_reclaim_lock);
queue_work(osb->ocfs2_wq, &osb->os_suballoc_reclaim_work);
}
static void ocfs2_do_suballoc_reclaim(struct ocfs2_super *osb,
struct ocfs2_suballoc_reclaim_work *reclaim_work)
{
int status, i;
handle_t *handle;
struct inode *alloc_inode = reclaim_work->alloc_inode;
struct inode *main_bm_inode;
struct buffer_head *alloc_bh = NULL, *group_bh = NULL;
struct buffer_head *main_bm_bh = NULL;
struct ocfs2_dinode *fe;
struct ocfs2_chain_list *cl;
struct ocfs2_chain_rec *rec;
/* journal already gone, e.g. during dismount cleanup */
if (!osb->journal)
return;
inode_lock(alloc_inode);
status = ocfs2_inode_lock(alloc_inode, &alloc_bh, 1);
if (status < 0)
goto out_alloc;
fe = (struct ocfs2_dinode *) alloc_bh->b_data;
cl = &fe->id2.i_chain;
/*
* The block group may have been allocated from again since the
* reclaim work was queued, re-check that it is still fully freed.
* A stale work item can also reference a group that is no longer
* chained, whose descriptor would fail validation and trigger a
* spurious ocfs2_error(), so verify chain membership first.
*/
for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i++) {
rec = &cl->cl_recs[i];
if (le64_to_cpu(rec->c_blkno) == reclaim_work->bg_blkno)
break;
}
if (i == le16_to_cpu(cl->cl_next_free_rec) ||
ocfs2_is_cluster_bitmap(alloc_inode) ||
(le32_to_cpu(rec->c_free) != (le32_to_cpu(rec->c_total) - 1)) ||
(le16_to_cpu(cl->cl_next_free_rec) == 1))
goto out_alloc_unlock;
status = ocfs2_read_group_descriptor(alloc_inode, fe,
reclaim_work->bg_blkno, &group_bh);
if (status < 0)
goto out_alloc_unlock;
main_bm_inode = ocfs2_get_system_file_inode(osb,
GLOBAL_BITMAP_SYSTEM_INODE,
OCFS2_INVALID_SLOT);
if (!main_bm_inode)
goto out_group;
inode_lock(main_bm_inode);
status = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1);
if (status < 0)
goto out_main;
handle = ocfs2_start_trans(osb, OCFS2_SUBALLOC_FREE);
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
mlog_errno(status);
goto out_main_unlock;
}
status = _ocfs2_reclaim_suballoc_to_main(handle, alloc_inode,
alloc_bh, group_bh,
main_bm_inode, main_bm_bh);
/* group_bh ownership passed to _ocfs2_reclaim_suballoc_to_main() */
group_bh = NULL;
if (status < 0)
mlog_errno(status);
ocfs2_commit_trans(osb, handle);
out_main_unlock:
ocfs2_inode_unlock(main_bm_inode, 1);
brelse(main_bm_bh);
free_bm_inode:
out_main:
inode_unlock(main_bm_inode);
iput(main_bm_inode);
out_group:
brelse(group_bh);
out_alloc_unlock:
ocfs2_inode_unlock(alloc_inode, 1);
brelse(alloc_bh);
out_alloc:
inode_unlock(alloc_inode);
}
bail:
return status;
void ocfs2_suballoc_reclaim_worker(struct work_struct *work)
{
struct ocfs2_super *osb = container_of(work, struct ocfs2_super,
os_suballoc_reclaim_work);
struct ocfs2_suballoc_reclaim_work *reclaim_work;
while (1) {
spin_lock(&osb->os_suballoc_reclaim_lock);
if (list_empty(&osb->os_suballoc_reclaim_list)) {
spin_unlock(&osb->os_suballoc_reclaim_lock);
break;
}
reclaim_work = list_first_entry(&osb->os_suballoc_reclaim_list,
struct ocfs2_suballoc_reclaim_work,
list);
list_del(&reclaim_work->list);
spin_unlock(&osb->os_suballoc_reclaim_lock);
ocfs2_do_suballoc_reclaim(osb, reclaim_work);
iput(reclaim_work->alloc_inode);
kfree(reclaim_work);
}
}
/*
@ -2897,10 +3040,22 @@ static int _ocfs2_free_suballoc_bits(handle_t *handle,
/* The alloc_bh comes from ocfs2_free_dinode() or
* ocfs2_free_clusters(). The callers have all locked the
* allocator and gotten alloc_bh from the lock call. This
* validates the dinode buffer. Any corruption that has happened
* is a code bug. */
* validates the dinode buffer. */
BUG_ON(!OCFS2_IS_VALID_DINODE(fe));
BUG_ON((count + start_bit) > ocfs2_bits_per_group(cl));
/*
* ocfs2_bits_per_group() is derived from cl_cpg and cl_bpc of the
* allocator dinode, which are not validated against the volume
* geometry. A corrupted image can carry a suballoc bit beyond it,
* so error out instead of crashing.
*/
if ((count + start_bit) > ocfs2_bits_per_group(cl)) {
return ocfs2_error(alloc_inode->i_sb,
"Allocator #%llu: freeing bits %u+%u exceeds bits per group %u\n",
(unsigned long long)le64_to_cpu(fe->i_blkno),
count, start_bit,
ocfs2_bits_per_group(cl));
}
trace_ocfs2_free_suballoc_bits(
(unsigned long long)OCFS2_I(alloc_inode)->ip_blkno,
@ -2915,7 +3070,20 @@ static int _ocfs2_free_suballoc_bits(handle_t *handle,
}
group = (struct ocfs2_group_desc *) group_bh->b_data;
BUG_ON((count + start_bit) > le16_to_cpu(group->bg_bits));
/*
* Group descriptor validation only guarantees bg_bits within the
* physical bitmap size, so double check the freeing range here.
* Otherwise ocfs2_block_group_clear_bits() would clear bits beyond
* bg_bitmap.
*/
if ((count + start_bit) > le16_to_cpu(group->bg_bits)) {
status = ocfs2_error(alloc_inode->i_sb,
"Group descriptor #%llu has %u bits, cannot free bits %u+%u\n",
(unsigned long long)le64_to_cpu(group->bg_blkno),
le16_to_cpu(group->bg_bits),
count, start_bit);
goto bail;
}
if (ocfs2_is_cluster_bitmap(alloc_inode))
old_bg_contig_free_bits = group->bg_contig_free_bits;
@ -2955,7 +3123,8 @@ static int _ocfs2_free_suballoc_bits(handle_t *handle,
goto bail;
}
_ocfs2_reclaim_suballoc_to_main(handle, alloc_inode, alloc_bh, group_bh);
ocfs2_queue_suballoc_reclaim(OCFS2_SB(alloc_inode->i_sb), alloc_inode,
bg_blkno);
bail:
brelse(group_bh);

View File

@ -206,7 +206,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_extent_tree *et,
int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res);
void ocfs2_suballoc_reclaim_worker(struct work_struct *work);
/*
* The following two interfaces are for ocfs2_create_inode_in_orphan().

View File

@ -387,6 +387,7 @@ static ssize_t ocfs2_debug_read(struct file *file, char __user *buf,
#endif /* CONFIG_DEBUG_FS */
static const struct file_operations ocfs2_osb_debug_fops = {
.owner = THIS_MODULE,
.open = ocfs2_osb_debug_open,
.release = ocfs2_debug_release,
.read = ocfs2_debug_read,
@ -1162,15 +1163,23 @@ static int ocfs2_fill_super(struct super_block *sb, struct fs_context *fc)
out_dismount:
atomic_set(&osb->vol_state, VOLUME_DISABLED);
wake_up(&osb->osb_mount_event);
ocfs2_free_replay_slots(osb);
ocfs2_dismount_volume(sb, 1);
goto out;
out_debugfs:
debugfs_remove_recursive(osb->osb_debug_root);
out_super:
/*
* A recovery thread launched by a node failure event may still be
* waiting for the volume to be mounted. Set VOLUME_DISABLED and
* wake it up, then wait for it to exit before osb is freed,
* otherwise the kthread would leak and stay blocked on the wait
* queue embedded in the freed osb.
*/
atomic_set(&osb->vol_state, VOLUME_DISABLED);
wake_up(&osb->osb_mount_event);
ocfs2_release_system_inodes(osb);
kfree(osb->recovery_map);
ocfs2_recovery_exit(osb);
ocfs2_delete_osb(osb);
kfree(osb);
out:
@ -1767,17 +1776,18 @@ static int ocfs2_mount_volume(struct super_block *sb)
status = ocfs2_truncate_log_init(osb);
if (status < 0) {
mlog_errno(status);
goto out_check_volume;
goto out_system_inodes;
}
ocfs2_super_unlock(osb, 1);
return 0;
out_check_volume:
ocfs2_free_replay_slots(osb);
out_system_inodes:
if (osb->local_alloc_state == OCFS2_LA_ENABLED)
ocfs2_shutdown_local_alloc(osb);
/* Drain pending suballoc reclaim work before the journal goes away */
if (osb->ocfs2_wq)
flush_workqueue(osb->ocfs2_wq);
ocfs2_release_system_inodes(osb);
/* before journal shutdown, we should release slot_info */
ocfs2_free_slot_info(osb);
@ -1848,6 +1858,14 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
if (osb->cconn)
ocfs2_super_unlock(osb, 1);
/*
* Drain pending suballoc reclaim work while the system inodes and
* the journal are still alive, since the worker needs to look up
* the global bitmap inode and start a transaction.
*/
if (osb->ocfs2_wq)
flush_workqueue(osb->ocfs2_wq);
ocfs2_release_system_inodes(osb);
ocfs2_journal_shutdown(osb);
@ -2134,6 +2152,11 @@ static int ocfs2_initialize_super(struct super_block *sb,
INIT_WORK(&osb->dquot_drop_work, ocfs2_drop_dquot_refs);
init_llist_head(&osb->dquot_drop_list);
spin_lock_init(&osb->os_suballoc_reclaim_lock);
INIT_LIST_HEAD(&osb->os_suballoc_reclaim_list);
INIT_WORK(&osb->os_suballoc_reclaim_work,
ocfs2_suballoc_reclaim_worker);
/* get some pseudo constants for clustersize bits */
osb->s_clustersize_bits =
le32_to_cpu(di->id2.i_super.s_clustersize_bits);

View File

@ -237,6 +237,21 @@ static int namevalue_size_xe(struct ocfs2_xattr_entry *xe)
return namevalue_size(xe->xe_name_len, value_len);
}
static int ocfs2_validate_xattr_entry(struct super_block *sb, u64 blkno,
struct ocfs2_xattr_entry *xe)
{
u64 value_len = le64_to_cpu(xe->xe_value_size);
if (value_len > OCFS2_XATTR_INLINE_SIZE &&
ocfs2_xattr_is_local(xe))
return ocfs2_error(sb,
"Invalid local xattr in block %llu: value size %llu\n",
(unsigned long long)blkno,
(unsigned long long)value_len);
return 0;
}
static int ocfs2_xattr_bucket_get_name_value(struct super_block *sb,
struct ocfs2_xattr_header *xh,
@ -476,6 +491,7 @@ static int ocfs2_validate_xattr_block(struct super_block *sb,
struct buffer_head *bh)
{
int rc;
struct ocfs2_extent_list *el;
struct ocfs2_xattr_block *xb =
(struct ocfs2_xattr_block *)bh->b_data;
@ -517,6 +533,31 @@ static int ocfs2_validate_xattr_block(struct super_block *sb,
le32_to_cpu(xb->xb_fs_generation));
}
/*
* Xattr blocks are allocated from a per-slot suballocator, so the
* slot must be in range. Otherwise freeing the block passes it to
* get_local_system_inode(), which hits BUG_ON() for
* OCFS2_INVALID_SLOT or computes an out-of-bounds index otherwise.
*/
if ((u32)le16_to_cpu(xb->xb_suballoc_slot) >= OCFS2_SB(sb)->max_slots) {
return ocfs2_error(sb,
"Extended attribute block #%llu has an invalid xb_suballoc_slot of %u\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(xb->xb_suballoc_slot));
}
/*
* Similarly the suballoc bit must fit in a block group bitmap.
* Otherwise freeing the block will pass the oversized bit to
* _ocfs2_free_suballoc_bits() and trigger ocfs2_error() there.
*/
if (le16_to_cpu(xb->xb_suballoc_bit) >= ocfs2_suballoc_bits_per_block(sb)) {
return ocfs2_error(sb,
"Extended attribute block #%llu has an invalid xb_suballoc_bit of %u\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(xb->xb_suballoc_bit));
}
if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
size_t region_offset =
offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header);
@ -533,6 +574,30 @@ static int ocfs2_validate_xattr_block(struct super_block *sb,
region_offset);
}
/*
* An indexed xattr block carries the root of the xattr tree. Its
* record count is fixed by the block size and l_next_free_rec never
* exceeds it. A zero l_next_free_rec is valid: emptying the tree on
* the inode deletion path leaves the root with no extents.
*/
el = &xb->xb_attrs.xb_root.xt_list;
if (le16_to_cpu(el->l_count) != ocfs2_xattr_recs_per_xb(sb)) {
return ocfs2_error(sb,
"Xattr tree root #%llu has invalid l_count %u (expected %u)\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(el->l_count),
ocfs2_xattr_recs_per_xb(sb));
}
if (le16_to_cpu(el->l_next_free_rec) > le16_to_cpu(el->l_count)) {
return ocfs2_error(sb,
"Xattr tree root #%llu has l_next_free_rec %u past the end of its list (l_count %u)\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(el->l_next_free_rec),
le16_to_cpu(el->l_count));
}
return 0;
}
@ -561,9 +626,10 @@ static inline const char *ocfs2_xattr_prefix(int name_index)
return handler ? xattr_prefix(handler) : NULL;
}
static u32 ocfs2_xattr_name_hash(struct inode *inode,
const char *name,
int name_len)
static u32 __ocfs2_xattr_name_hash(struct inode *inode,
const char *name,
int name_len,
bool legacy_signed)
{
/* Get hash value of uuid from super block */
u32 hash = OCFS2_SB(inode->i_sb)->uuid_hash;
@ -572,13 +638,30 @@ static u32 ocfs2_xattr_name_hash(struct inode *inode,
/* hash extended attribute name */
for (i = 0; i < name_len; i++) {
hash = (hash << OCFS2_HASH_SHIFT) ^
(hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^
*name++;
(hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT));
if (legacy_signed)
hash ^= (signed char)name[i];
else
hash ^= (unsigned char)name[i];
}
return hash;
}
static u32 ocfs2_xattr_name_hash(struct inode *inode,
const char *name,
int name_len)
{
return __ocfs2_xattr_name_hash(inode, name, name_len, false);
}
static u32 ocfs2_xattr_name_hash_signed(struct inode *inode,
const char *name,
int name_len)
{
return __ocfs2_xattr_name_hash(inode, name, name_len, true);
}
static int ocfs2_xattr_entry_real_size(int name_len, size_t value_len)
{
return namevalue_size(name_len, value_len) +
@ -603,10 +686,15 @@ int ocfs2_calc_security_init(struct inode *dir,
int *xattr_credits,
struct ocfs2_alloc_context **xattr_ac)
{
int i;
int ret = 0;
struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
int s_size = ocfs2_xattr_entry_real_size(strlen(si->name),
si->value_len);
int s_size = 0;
for (i = 0; i < si->count; i++)
s_size += ocfs2_xattr_entry_real_size(
strlen(si->xattrs[i].name),
si->xattrs[i].value_len);
/*
* The max space of security xattr taken inline is
@ -623,14 +711,27 @@ int ocfs2_calc_security_init(struct inode *dir,
*xattr_credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS;
}
/* reserve clusters for xattr value which will be set in B tree*/
if (si->value_len > OCFS2_XATTR_INLINE_SIZE) {
int new_clusters = ocfs2_clusters_for_bytes(dir->i_sb,
si->value_len);
/*
* when blocksize = 512, the security xattrs may not fit in the
* single block reserved above and a bucket has to be allocated
* for them, so reserve the cluster it needs as well.
*/
if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE &&
s_size > OCFS2_XATTR_FREE_IN_BLOCK(dir)) {
*want_clusters += 1;
*xattr_credits += ocfs2_blocks_per_xattr_bucket(dir->i_sb);
}
*xattr_credits += ocfs2_clusters_to_blocks(dir->i_sb,
new_clusters);
*want_clusters += new_clusters;
/* reserve clusters for xattr value which will be set in B tree*/
for (i = 0; i < si->count; i++) {
if (si->xattrs[i].value_len > OCFS2_XATTR_INLINE_SIZE) {
int new_clusters = ocfs2_clusters_for_bytes(dir->i_sb,
si->xattrs[i].value_len);
*xattr_credits += ocfs2_clusters_to_blocks(dir->i_sb,
new_clusters);
*want_clusters += new_clusters;
}
}
return ret;
}
@ -640,12 +741,16 @@ void ocfs2_calc_xattr_init(struct inode *dir, umode_t mode,
int *want_clusters, int *xattr_credits,
int *want_meta, struct ocfs2_acl_state *acl_state)
{
int i;
struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
int s_size = 0, a_size = 0, acl_len = 0, new_clusters;
if (si->enable)
s_size = ocfs2_xattr_entry_real_size(strlen(si->name),
si->value_len);
if (si->enable) {
for (i = 0; i < si->count; i++)
s_size += ocfs2_xattr_entry_real_size(
strlen(si->xattrs[i].name),
si->xattrs[i].value_len);
}
if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
if (acl_state->default_acl && S_ISDIR(mode)) {
@ -692,12 +797,14 @@ void ocfs2_calc_xattr_init(struct inode *dir, umode_t mode,
* reserve credits and clusters for xattrs which has large value
* and have to be set outside
*/
if (si->enable && si->value_len > OCFS2_XATTR_INLINE_SIZE) {
new_clusters = ocfs2_clusters_for_bytes(dir->i_sb,
si->value_len);
*xattr_credits += ocfs2_clusters_to_blocks(dir->i_sb,
new_clusters);
*want_clusters += new_clusters;
for (i = 0; si->enable && i < si->count; i++) {
if (si->xattrs[i].value_len > OCFS2_XATTR_INLINE_SIZE) {
new_clusters = ocfs2_clusters_for_bytes(dir->i_sb,
si->xattrs[i].value_len);
*xattr_credits += ocfs2_clusters_to_blocks(dir->i_sb,
new_clusters);
*want_clusters += new_clusters;
}
}
if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
if (acl_state->default_acl && S_ISDIR(mode)) {
@ -989,7 +1096,7 @@ static int ocfs2_validate_xattr_entries_flat(struct super_block *sb, u64 blkno,
size_t entries_limit = region_size;
size_t nv_limit = region_size;
size_t max_entries;
int i;
int i, ret;
if (region_size < sizeof(*xh))
return ocfs2_error(sb,
@ -1009,6 +1116,11 @@ static int ocfs2_validate_xattr_entries_flat(struct super_block *sb, u64 blkno,
struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
size_t name_offset = le16_to_cpu(xe->xe_name_offset);
size_t value_offset;
u64 value_len = le64_to_cpu(xe->xe_value_size);
ret = ocfs2_validate_xattr_entry(sb, blkno, xe);
if (ret)
return ret;
if (name_offset > nv_limit ||
xe->xe_name_len > nv_limit - name_offset)
@ -1023,8 +1135,7 @@ static int ocfs2_validate_xattr_entries_flat(struct super_block *sb, u64 blkno,
(unsigned long long)blkno, i);
if (ocfs2_xattr_is_local(xe)) {
if (le64_to_cpu(xe->xe_value_size) >
nv_limit - value_offset)
if (value_len > nv_limit - value_offset)
return ocfs2_error(sb,
"Invalid xattr in block %llu: entry %d value is out of bounds\n",
(unsigned long long)blkno,
@ -1106,10 +1217,29 @@ static int ocfs2_validate_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
struct ocfs2_xattr_header *xh = bucket_xh(bucket);
u16 xattr_count = le16_to_cpu(xh->xh_count);
size_t region_size = (size_t)sb->s_blocksize * bucket->bu_blocks;
size_t entries_limit = sb->s_blocksize;
/*
* The entry array grows up from the header across the whole
* bucket region, so it may extend beyond the first bucket block
* when the blocksize is smaller than OCFS2_XATTR_BUCKET_SIZE.
* Name/value pairs, however, always live within a single block.
*/
size_t entries_limit = region_size;
size_t nv_limit = sb->s_blocksize;
size_t max_entries;
int i;
int i, ret;
/*
* The entry array is one contiguous region that may span the
* bucket's buffer_heads. Buckets are allocated within clusters,
* so their first block is always aligned to
* OCFS2_XATTR_BUCKET_SIZE and the whole bucket fits in one page.
* A corrupted xattr tree can point a bucket at blocks straddling
* a page, so reject it before touching the entry array.
*/
if (blkno & (bucket->bu_blocks - 1))
return ocfs2_error(sb,
"Invalid xattr bucket %llu: unaligned block number\n",
(unsigned long long)blkno);
if (region_size < sizeof(*xh))
return ocfs2_error(sb,
@ -1137,6 +1267,11 @@ static int ocfs2_validate_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
size_t block_off = name_offset >> sb->s_blocksize_bits;
size_t block_offset = name_offset % nv_limit;
size_t value_offset;
u64 value_len = le64_to_cpu(xe->xe_value_size);
ret = ocfs2_validate_xattr_entry(sb, blkno, xe);
if (ret)
return ret;
if (name_offset >= region_size || block_off >= bucket->bu_blocks)
return ocfs2_error(sb,
@ -1155,8 +1290,7 @@ static int ocfs2_validate_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
(unsigned long long)blkno, i);
if (ocfs2_xattr_is_local(xe)) {
if (le64_to_cpu(xe->xe_value_size) >
nv_limit - value_offset)
if (value_len > nv_limit - value_offset)
return ocfs2_error(sb,
"Invalid xattr bucket %llu: entry %d value is out of bounds\n",
(unsigned long long)blkno,
@ -1304,7 +1438,7 @@ static int ocfs2_xattr_find_entry(struct inode *inode, int name_index,
{
struct ocfs2_xattr_entry *entry;
size_t name_len;
int i, name_offset, cmp = 1;
int i, name_offset, cmp = 1, ret;
if (name == NULL)
return -EINVAL;
@ -1327,6 +1461,12 @@ static int ocfs2_xattr_find_entry(struct inode *inode, int name_index,
return -EFSCORRUPTED;
}
cmp = memcmp(name, (xs->base + name_offset), name_len);
if (!cmp) {
ret = ocfs2_validate_xattr_entry(inode->i_sb,
OCFS2_I(inode)->ip_blkno, entry);
if (ret)
return ret;
}
}
if (cmp == 0)
break;
@ -2073,12 +2213,17 @@ static void ocfs2_xa_bucket_add_entry(struct ocfs2_xa_loc *loc, u32 name_hash)
}
}
/*
* Increment xh_count before memmove() so __counted_by_le(xh_count)
* includes the new entry in the destination bounds.
*/
le16_add_cpu(&xh->xh_count, 1);
if (low != count)
memmove(&xh->xh_entries[low + 1],
&xh->xh_entries[low],
((count - low) * sizeof(struct ocfs2_xattr_entry)));
le16_add_cpu(&xh->xh_count, 1);
loc->xl_entry = &xh->xh_entries[low];
memset(loc->xl_entry, 0, sizeof(struct ocfs2_xattr_entry));
}
@ -2909,6 +3054,9 @@ static int ocfs2_xattr_has_space_inline(struct inode *inode,
*
* Find extended attribute in inode block and
* fill search info into struct ocfs2_xattr_search.
*
* The inline free-space check races with truncate and allocation, so
* callers must hold ip_alloc_sem for writing.
*/
static int ocfs2_xattr_ibody_find(struct inode *inode,
int name_index,
@ -2920,13 +3068,13 @@ static int ocfs2_xattr_ibody_find(struct inode *inode,
int ret;
int has_space = 0;
lockdep_assert_held_write(&oi->ip_alloc_sem);
if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
return 0;
if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
down_read(&oi->ip_alloc_sem);
has_space = ocfs2_xattr_has_space_inline(inode, di);
up_read(&oi->ip_alloc_sem);
if (!has_space)
return 0;
}
@ -3007,6 +3155,7 @@ static int ocfs2_xattr_ibody_init(struct inode *inode,
*
* Set, replace or remove an extended attribute into inode block.
*
* Callers must hold ip_alloc_sem for writing.
*/
static int ocfs2_xattr_ibody_set(struct inode *inode,
struct ocfs2_xattr_info *xi,
@ -3017,16 +3166,17 @@ static int ocfs2_xattr_ibody_set(struct inode *inode,
struct ocfs2_inode_info *oi = OCFS2_I(inode);
struct ocfs2_xa_loc loc;
lockdep_assert_held_write(&oi->ip_alloc_sem);
if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
return -ENOSPC;
down_write(&oi->ip_alloc_sem);
if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
ret = ocfs2_xattr_ibody_init(inode, xs->inode_bh, ctxt);
if (ret) {
if (ret != -ENOSPC)
mlog_errno(ret);
goto out;
return ret;
}
}
@ -3036,13 +3186,10 @@ static int ocfs2_xattr_ibody_set(struct inode *inode,
if (ret) {
if (ret != -ENOSPC)
mlog_errno(ret);
goto out;
return ret;
}
xs->here = loc.xl_entry;
out:
up_write(&oi->ip_alloc_sem);
return ret;
}
@ -3376,6 +3523,14 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode,
credits += ocfs2_calc_extend_credits(
inode->i_sb,
&def_xv.xv.xr_list);
/*
* A value too big to stay inline is only charged as
* OCFS2_XATTR_ROOT_SIZE above, so it can still need a
* value tree of its own. No xattr block is allocated
* on this path, so the tree is all we reserve for.
*/
if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE)
meta_add += ocfs2_extend_meta_needed(&def_xv.xv.xr_list);
goto out;
}
}
@ -3397,12 +3552,21 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode,
credits += ocfs2_remove_extent_credits(inode->i_sb);
goto out;
} else {
meta_add += ocfs2_extend_meta_needed(&xv->xr_list);
clusters_add += new_clusters - old_clusters;
credits += ocfs2_calc_extend_credits(inode->i_sb,
&xv->xr_list);
if (value_size >= OCFS2_XATTR_ROOT_SIZE)
/*
* The old value occupies at least as much room as a
* value root, whether it sat outside or inline, so the
* new root fits where it was and no new xattr block or
* bucket is needed -- only the metadata to extend the
* tree hanging off it. A smaller one is replaced
* outright, which meta_guess below reserves for.
*/
if (value_size >= OCFS2_XATTR_ROOT_SIZE) {
meta_add += ocfs2_extend_meta_needed(&xv->xr_list);
goto out;
}
}
} else {
/*
@ -3454,6 +3618,10 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode,
* Reserve metadata for the new xattr's value extent tree.
* The not_found path above adds credits for this tree but
* omits meta_add, leaving meta_ac NULL for large values.
*
* This is all of meta_ac on this side beyond the xattr tree
* above: no xattr block is allocated here, and a new bucket or
* index block is paid for out of data_ac.
*/
if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE)
meta_add += ocfs2_extend_meta_needed(&def_xv.xv.xr_list);
@ -3476,7 +3644,13 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode,
credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS;
if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) {
struct ocfs2_extent_list *el = &def_xv.xv.xr_list;
meta_add += ocfs2_extend_meta_needed(el);
/*
* One block for the xattr block we may have to
* allocate, the rest for growing the value tree it
* would hold. If ocfs2_xattr_ibody_set() succeeds
* instead, that first block goes unused.
*/
meta_add += 1 + ocfs2_extend_meta_needed(el);
credits += ocfs2_calc_extend_credits(inode->i_sb,
el);
} else {
@ -3686,6 +3860,18 @@ static int __ocfs2_xattr_set_handle(struct inode *inode,
return ret;
}
/*
* ip_alloc_sem subclass for inodes being initialized before publication.
* ocfs2_xattr_set_handle() runs inside the create transaction, so taking
* ip_alloc_sem there adds a transaction -> ip_alloc_sem order that would
* form a lockdep cycle with the ip_alloc_sem -> transaction order used
* elsewhere, if not for this separate subclass. The inode is unpublished
* so the acquisition can never contend.
*/
enum {
OCFS2_IP_ALLOC_SEM_UNPUBLISHED = 1,
};
/*
* This helper is only for setting initial ACL or security xattrs on an inode
* that is still unpublished, unhashed, and unattached to a dentry.
@ -3747,6 +3933,13 @@ int ocfs2_xattr_set_handle(handle_t *handle,
xis.inode_bh = xbs.inode_bh = di_bh;
di = (struct ocfs2_dinode *)di_bh->b_data;
/*
* The inode is unpublished and cannot contend, but take the
* semaphore anyway so the helpers' lockdep assertions hold.
*/
down_write_nested(&OCFS2_I(inode)->ip_alloc_sem,
OCFS2_IP_ALLOC_SEM_UNPUBLISHED);
ret = ocfs2_xattr_ibody_find(inode, name_index, name, &xis);
if (ret)
goto cleanup;
@ -3759,6 +3952,7 @@ int ocfs2_xattr_set_handle(handle_t *handle,
ret = __ocfs2_xattr_set_handle(inode, di, &xi, &xis, &xbs, &ctxt);
cleanup:
up_write(&OCFS2_I(inode)->ip_alloc_sem);
brelse(xbs.xattr_bh);
ocfs2_xattr_bucket_free(xbs.bucket);
@ -3827,30 +4021,38 @@ int ocfs2_xattr_set(struct inode *inode,
di = (struct ocfs2_dinode *)di_bh->b_data;
down_write(&OCFS2_I(inode)->ip_xattr_sem);
/*
* The allocation and truncate paths take ip_alloc_sem before
* starting a transaction, so take it here before xattr
* preparation, allocation reservations and ocfs2_start_trans()
* to keep that order. The xattr helpers below no longer take
* it themselves.
*/
down_write(&OCFS2_I(inode)->ip_alloc_sem);
/*
* Scan inode and external block to find the same name
* extended attribute and collect search information.
*/
ret = ocfs2_xattr_ibody_find(inode, name_index, name, &xis);
if (ret)
goto cleanup;
goto out_free_ac;
if (xis.not_found) {
ret = ocfs2_xattr_block_find(inode, name_index, name, &xbs);
if (ret)
goto cleanup;
goto out_free_ac;
}
if (xis.not_found && xbs.not_found) {
ret = -ENODATA;
if (flags & XATTR_REPLACE)
goto cleanup;
goto out_free_ac;
ret = 0;
if (!value)
goto cleanup;
goto out_free_ac;
} else {
ret = -EEXIST;
if (flags & XATTR_CREATE)
goto cleanup;
goto out_free_ac;
}
/* Check whether the value is refcounted and do some preparation. */
@ -3861,7 +4063,7 @@ int ocfs2_xattr_set(struct inode *inode,
&ref_meta, &ref_credits);
if (ret) {
mlog_errno(ret);
goto cleanup;
goto out_free_ac;
}
}
@ -3872,7 +4074,7 @@ int ocfs2_xattr_set(struct inode *inode,
if (ret < 0) {
inode_unlock(tl_inode);
mlog_errno(ret);
goto cleanup;
goto out_free_ac;
}
}
inode_unlock(tl_inode);
@ -3881,7 +4083,7 @@ int ocfs2_xattr_set(struct inode *inode,
&xbs, &ctxt, ref_meta, &credits);
if (ret) {
mlog_errno(ret);
goto cleanup;
goto out_free_ac;
}
/* we need to update inode's ctime field, so add credit for it. */
@ -3899,6 +4101,7 @@ int ocfs2_xattr_set(struct inode *inode,
ocfs2_commit_trans(osb, ctxt.handle);
out_free_ac:
up_write(&OCFS2_I(inode)->ip_alloc_sem);
if (ctxt.data_ac)
ocfs2_free_alloc_context(ctxt.data_ac);
if (ctxt.meta_ac)
@ -3907,7 +4110,6 @@ int ocfs2_xattr_set(struct inode *inode,
ocfs2_schedule_truncate_log_flush(osb, 1);
ocfs2_run_deallocs(osb, &ctxt.dealloc);
cleanup:
if (ref_tree)
ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
up_write(&OCFS2_I(inode)->ip_xattr_sem);
@ -4038,6 +4240,10 @@ static int ocfs2_find_xe_in_bucket(struct inode *inode,
xe_name = bucket_block(bucket, block_off) + new_offset;
if (!memcmp(name, xe_name, name_len)) {
ret = ocfs2_validate_xattr_entry(inode->i_sb,
OCFS2_I(inode)->ip_blkno, xe);
if (ret)
break;
*xe_index = i;
*found = 1;
ret = 0;
@ -4168,11 +4374,12 @@ static int ocfs2_xattr_bucket_find(struct inode *inode,
return ret;
}
static int ocfs2_xattr_index_block_find(struct inode *inode,
struct buffer_head *root_bh,
int name_index,
const char *name,
struct ocfs2_xattr_search *xs)
static int __ocfs2_xattr_index_block_find(struct inode *inode,
struct buffer_head *root_bh,
int name_index,
const char *name,
u32 name_hash,
struct ocfs2_xattr_search *xs)
{
int ret;
struct ocfs2_xattr_block *xb =
@ -4181,7 +4388,6 @@ static int ocfs2_xattr_index_block_find(struct inode *inode,
struct ocfs2_extent_list *el = &xb_root->xt_list;
u64 p_blkno = 0;
u32 first_hash, num_clusters = 0;
u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name));
if (le16_to_cpu(el->l_next_free_rec) == 0)
return -ENODATA;
@ -4212,6 +4418,59 @@ static int ocfs2_xattr_index_block_find(struct inode *inode,
return ret;
}
static int ocfs2_xattr_index_block_find(struct inode *inode,
struct buffer_head *root_bh,
int name_index,
const char *name,
struct ocfs2_xattr_search *xs)
{
u32 name_hash, legacy_hash;
int name_len = strlen(name);
int ret;
name_hash = ocfs2_xattr_name_hash(inode, name, name_len);
ret = __ocfs2_xattr_index_block_find(inode, root_bh, name_index, name,
name_hash, xs);
if (ret != -ENODATA)
return ret;
/*
* Nothing under the current hash. The entry may have been stored by
* an older kernel, which sign-extended the name bytes when hashing.
* Skip the retry when the two hashes are equal, so that a name made
* only of ASCII does not have to walk the tree twice.
*/
legacy_hash = ocfs2_xattr_name_hash_signed(inode, name, name_len);
if (legacy_hash == name_hash)
return ret;
/*
* A miss still leaves xs->bucket holding the bucket a new entry would
* be inserted into, so drop it before searching again.
*/
ocfs2_xattr_bucket_relse(xs->bucket);
ret = __ocfs2_xattr_index_block_find(inode, root_bh, name_index, name,
legacy_hash, xs);
if (!ret) {
pr_warn_once("ocfs2: xattr tree with signed name hash\n");
return ret;
}
if (ret != -ENODATA)
return ret;
/*
* Not under either hash. Restore the unsigned placement, since that
* is where a new entry is stored: leaving the bucket where the legacy
* hash put it would break the ordering the search relies on.
*/
ocfs2_xattr_bucket_relse(xs->bucket);
return __ocfs2_xattr_index_block_find(inode, root_bh, name_index, name,
name_hash, xs);
}
static int ocfs2_iterate_xattr_buckets(struct inode *inode,
u64 blkno,
u32 clusters,
@ -4390,7 +4649,8 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
ret = ocfs2_iterate_xattr_index_block(inode, blk_bh,
ocfs2_list_xattr_tree_rec, &xl);
if (ret) {
mlog_errno(ret);
if (ret != -ERANGE)
mlog_errno(ret);
goto out;
}
@ -4508,6 +4768,10 @@ static void ocfs2_xattr_update_xattr_search(struct inode *inode,
xs->here = &xs->header->xh_entries[i];
}
/*
* Caller must hold ip_alloc_sem for writing, since a new xattr block
* is allocated and the xattr block header is rewritten.
*/
static int ocfs2_xattr_create_index_block(struct inode *inode,
struct ocfs2_xattr_search *xs,
struct ocfs2_xattr_set_ctxt *ctxt)
@ -4523,19 +4787,14 @@ static int ocfs2_xattr_create_index_block(struct inode *inode,
struct ocfs2_xattr_tree_root *xr;
u16 xb_flags = le16_to_cpu(xb->xb_flags);
lockdep_assert_held_write(&oi->ip_alloc_sem);
trace_ocfs2_xattr_create_index_block_begin(
(unsigned long long)xb_bh->b_blocknr);
BUG_ON(xb_flags & OCFS2_XATTR_INDEXED);
BUG_ON(!xs->bucket);
/*
* XXX:
* We can use this lock for now, and maybe move to a dedicated mutex
* if performance becomes a problem later.
*/
down_write(&oi->ip_alloc_sem);
ret = ocfs2_journal_access_xb(handle, INODE_CACHE(inode), xb_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (ret) {
@ -4597,8 +4856,6 @@ static int ocfs2_xattr_create_index_block(struct inode *inode,
ocfs2_journal_dirty(handle, xb_bh);
out:
up_write(&oi->ip_alloc_sem);
return ret;
}
@ -4678,6 +4935,9 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode,
xe = xh->xh_entries;
end = OCFS2_XATTR_BUCKET_SIZE;
for (i = 0; i < le16_to_cpu(xh->xh_count); i++, xe++) {
ret = ocfs2_validate_xattr_entry(inode->i_sb, blkno, xe);
if (ret)
goto out;
offset = le16_to_cpu(xe->xe_name_offset);
len = namevalue_size_xe(xe);
@ -4694,16 +4954,22 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode,
memmove(bucket_buf + end - len,
bucket_buf + offset, len);
xe->xe_name_offset = cpu_to_le16(end - len);
} else if (end < offset + len) {
ret = ocfs2_error(inode->i_sb,
"Defrag check failed for bucket %llu\n",
(unsigned long long)blkno);
goto out;
}
mlog_bug_on_msg(end < offset + len, "Defrag check failed for "
"bucket %llu\n", (unsigned long long)blkno);
end -= len;
}
mlog_bug_on_msg(xh_free_start > end, "Defrag check failed for "
"bucket %llu\n", (unsigned long long)blkno);
if (xh_free_start > end) {
ret = ocfs2_error(inode->i_sb,
"Defrag check failed for bucket %llu\n",
(unsigned long long)blkno);
goto out;
}
if (xh_free_start == end)
goto out;
@ -4960,6 +5226,9 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode,
name_value_len = 0;
for (i = 0; i < start; i++) {
xe = &xh->xh_entries[i];
ret = ocfs2_validate_xattr_entry(inode->i_sb, blk, xe);
if (ret)
goto out;
name_value_len += namevalue_size_xe(xe);
if (le16_to_cpu(xe->xe_name_offset) < name_offset)
name_offset = le16_to_cpu(xe->xe_name_offset);
@ -5750,16 +6019,14 @@ static int ocfs2_rm_xattr_cluster(struct inode *inode,
/*
* check whether the xattr bucket is filled up with the same hash value.
* If we want to insert the xattr with the same hash, return -ENOSPC.
* If we want to insert a xattr with different hash value, go ahead
* and ocfs2_divide_xattr_bucket will handle this.
* If the entry being set carries that same hash, return -ENOSPC, since
* ocfs2_divide_xattr_bucket() has no divide position to work with.
* Otherwise go ahead and ocfs2_divide_xattr_bucket() will handle this.
*/
static int ocfs2_check_xattr_bucket_collision(struct inode *inode,
struct ocfs2_xattr_bucket *bucket,
const char *name)
static int ocfs2_check_xattr_bucket_collision(struct ocfs2_xattr_bucket *bucket,
u32 name_hash)
{
struct ocfs2_xattr_header *xh = bucket_xh(bucket);
u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name));
if (name_hash != le32_to_cpu(xh->xh_entries[0].xe_name_hash))
return 0;
@ -5828,6 +6095,7 @@ static int ocfs2_xattr_set_entry_index_block(struct inode *inode,
struct ocfs2_xattr_search *xs,
struct ocfs2_xattr_set_ctxt *ctxt)
{
u32 name_hash;
int ret;
trace_ocfs2_xattr_set_entry_index_block(xi->xi_name);
@ -5847,10 +6115,18 @@ static int ocfs2_xattr_set_entry_index_block(struct inode *inode,
* the maximum number of collisions we will allow for then is
* one bucket's worth, so check it here whether we need to
* add a new bucket for the insert.
*
* An existing entry keeps the hash it was stored under, and that is
* the hash a split has to work with. A new entry is stored under the
* unsigned one, which is what ocfs2_xa_add_entry() will write.
*/
ret = ocfs2_check_xattr_bucket_collision(inode,
xs->bucket,
xi->xi_name);
if (xs->not_found)
name_hash = ocfs2_xattr_name_hash(inode, xi->xi_name,
xi->xi_name_len);
else
name_hash = le32_to_cpu(xs->here->xe_name_hash);
ret = ocfs2_check_xattr_bucket_collision(xs->bucket, name_hash);
if (ret) {
mlog_errno(ret);
goto out;
@ -7514,17 +7790,46 @@ static int ocfs2_initxattrs(struct inode *inode, const struct xattr *xattr_array
{
struct ocfs2_security_xattr_info *si = fs_info;
const struct xattr *xattr;
struct ocfs2_security_xattr *xattrs;
int count = 0, i;
int err = 0;
if (si) {
si->value = kmemdup(xattr_array->value, xattr_array->value_len,
GFP_KERNEL);
if (!si->value)
for (xattr = xattr_array; xattr->name != NULL; xattr++)
count++;
xattrs = kcalloc(count, sizeof(*xattrs), GFP_NOFS);
if (!xattrs)
return -ENOMEM;
si->name = xattr_array->name;
si->value_len = xattr_array->value_len;
for (i = 0; i < count; i++) {
xattrs[i].name = kstrdup(xattr_array[i].name, GFP_NOFS);
if (!xattrs[i].name) {
err = -ENOMEM;
goto out_err;
}
xattrs[i].value = kmemdup(xattr_array[i].value,
xattr_array[i].value_len,
GFP_NOFS);
if (!xattrs[i].value) {
err = -ENOMEM;
goto out_err;
}
xattrs[i].value_len = xattr_array[i].value_len;
}
si->xattrs = xattrs;
si->count = count;
return 0;
out_err:
for (; i >= 0; i--) {
kfree(xattrs[i].name);
kfree(xattrs[i].value);
}
kfree(xattrs);
return err;
}
for (xattr = xattr_array; xattr->name != NULL; xattr++) {
@ -7537,6 +7842,19 @@ static int ocfs2_initxattrs(struct inode *inode, const struct xattr *xattr_array
return err;
}
void ocfs2_free_security_xattrs(struct ocfs2_security_xattr_info *si)
{
int i;
for (i = 0; i < si->count; i++) {
kfree(si->xattrs[i].name);
kfree(si->xattrs[i].value);
}
kfree(si->xattrs);
si->xattrs = NULL;
si->count = 0;
}
int ocfs2_init_security_get(struct inode *inode,
struct inode *dir,
const struct qstr *qstr,
@ -7554,7 +7872,7 @@ int ocfs2_init_security_get(struct inode *inode,
* security_inode_init_security() does not return -EOPNOTSUPP,
* we have to check the xattr ourselves.
*/
if (!ret && !si->name)
if (!ret && !si->count)
si->enable = 0;
return ret;
@ -7571,10 +7889,21 @@ int ocfs2_init_security_set(handle_t *handle,
struct ocfs2_alloc_context *xattr_ac,
struct ocfs2_alloc_context *data_ac)
{
return ocfs2_xattr_set_handle(handle, inode, di_bh,
OCFS2_XATTR_INDEX_SECURITY,
si->name, si->value, si->value_len, 0,
xattr_ac, data_ac);
int i;
int ret = 0;
for (i = 0; i < si->count; i++) {
ret = ocfs2_xattr_set_handle(handle, inode, di_bh,
OCFS2_XATTR_INDEX_SECURITY,
si->xattrs[i].name,
si->xattrs[i].value,
si->xattrs[i].value_len, 0,
xattr_ac, data_ac);
if (ret)
break;
}
return ret;
}
const struct xattr_handler ocfs2_xattr_security_handler = {

View File

@ -20,13 +20,18 @@ enum ocfs2_xattr_type {
OCFS2_XATTR_MAX
};
struct ocfs2_security_xattr_info {
int enable;
const char *name;
struct ocfs2_security_xattr {
char *name;
void *value;
size_t value_len;
};
struct ocfs2_security_xattr_info {
int enable;
struct ocfs2_security_xattr *xattrs;
int count;
};
extern const struct xattr_handler ocfs2_xattr_user_handler;
extern const struct xattr_handler ocfs2_xattr_trusted_handler;
extern const struct xattr_handler ocfs2_xattr_security_handler;
@ -49,6 +54,7 @@ int ocfs2_xattr_remove(struct inode *, struct buffer_head *);
int ocfs2_init_security_get(struct inode *, struct inode *,
const struct qstr *,
struct ocfs2_security_xattr_info *);
void ocfs2_free_security_xattrs(struct ocfs2_security_xattr_info *);
int ocfs2_init_security_set(handle_t *, struct inode *,
struct buffer_head *,
struct ocfs2_security_xattr_info *,

View File

@ -2520,17 +2520,23 @@ static int show_timer(struct seq_file *m, void *v)
struct k_itimer *timer = hlist_entry((struct hlist_node *)v, struct k_itimer, list);
struct timers_private *tp = m->private;
int notify = timer->it_sigev_notify;
pid_t nr = 0;
guard(spinlock_irq)(&timer->it_lock);
if (!posixtimer_valid(timer))
return 0;
if (timer->it_pid && pid_has_task(timer->it_pid, timer->it_pid_type))
nr = pid_nr_ns(timer->it_pid, tp->ns);
else
notify = SIGEV_NONE;
seq_printf(m, "ID: %d\n", timer->it_id);
seq_printf(m, "signal: %d/%px\n", timer->sigq.info.si_signo,
timer->sigq.info.si_value.sival_ptr);
seq_printf(m, "notify: %s/%s.%d\n", nstr[notify & ~SIGEV_THREAD_ID],
(notify & SIGEV_THREAD_ID) ? "tid" : "pid",
pid_nr_ns(timer->it_pid, tp->ns));
nr);
seq_printf(m, "ClockID: %d\n", timer->it_clock);
return 0;

View File

@ -18,6 +18,13 @@ enum fault_flags {
#include <linux/configfs.h>
#include <linux/ratelimit.h>
/*
* Length of the debugfs directory name embedded in struct fault_attr.
* Chosen to accommodate every in-tree caller of fault_create_debugfs_attr()
* (the longest is "fail_dma_array_full", 19 chars) with generous headroom.
*/
#define FAULT_ATTR_DNAME_LEN 64
/*
* For explanation of the elements of this struct, see
* Documentation/fault-injection/fault-injection.rst
@ -37,7 +44,7 @@ struct fault_attr {
unsigned long count;
struct ratelimit_state ratelimit_state;
struct dentry *dname;
char dname[FAULT_ATTR_DNAME_LEN];
};
#define FAULT_ATTR_INITIALIZER { \
@ -47,7 +54,6 @@ struct fault_attr {
.stacktrace_depth = 32, \
.ratelimit_state = RATELIMIT_STATE_INIT_DISABLED, \
.verbose = 2, \
.dname = NULL, \
}
#define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER

View File

@ -9,7 +9,7 @@
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
#define MKDEV(ma, mi) (((dev_t)(ma) << MINORBITS) | (mi))
#define print_dev_t(buffer, dev) \
sprintf((buffer), "%u:%u\n", MAJOR(dev), MINOR(dev))

View File

@ -38,9 +38,9 @@
* Note that 'x' is the original expression, and 'ux' is the unique variable
* that contains the value.
*
* We use 'ux' for pure type checking, and 'x' for when we need to look at the
* value (but without evaluating it for side effects!
* Careful to only ever evaluate it with sizeof() or __builtin_constant_p() etc).
* We use 'ux' for both the type and the value checks, so 'x' itself is only
* expanded twice: once to initialise 'ux', and once quoted in the error
* message.
*
* Pointers end up being checked by the normal C type rules at the actual
* comparison, and these expressions only need to be careful to not cause

View File

@ -13,7 +13,8 @@ __printf(1, 2)
void panic(const char *fmt, ...) __noreturn __cold;
__printf(1, 0)
void vpanic(const char *fmt, va_list args) __noreturn __cold;
void nmi_panic(struct pt_regs *regs, const char *msg);
__printf(2, 3)
void nmi_panic(struct pt_regs *regs, const char *fmt, ...);
void check_panic_on_warn(const char *origin);
extern void oops_enter(void);
extern void oops_exit(void);
@ -111,4 +112,6 @@ extern void add_taint(unsigned flag, enum lockdep_ok);
extern int test_taint(unsigned flag);
extern unsigned long get_taint(void);
void arch_do_panic(void);
#endif /* _LINUX_PANIC_H */

View File

@ -6,10 +6,10 @@
ccflags-y := -fno-function-sections -fno-data-sections
obj-y := main.o version.o mounts.o
ifneq ($(CONFIG_BLK_DEV_INITRD),y)
obj-y += noinitramfs.o
ifeq ($(CONFIG_BLK_DEV_INITRD),y)
obj-y += initramfs.o
else
obj-$(CONFIG_BLK_DEV_INITRD) += initramfs.o
obj-y += noinitramfs.o
endif
obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o
obj-$(CONFIG_INITRAMFS_TEST) += initramfs_test.o

View File

@ -215,10 +215,6 @@ static bool __init obsolete_checksetup(char *line)
* params and __setups of same names 8( */
if (line[n] == '\0' || line[n] == '=')
had_early_param = true;
} else if (!p->setup_func) {
pr_warn("Parameter %s is obsolete, ignored\n",
p->str);
return true;
} else if (p->setup_func(line + n))
return true;
}
@ -609,12 +605,12 @@ static int __init unknown_bootoption(char *param, char *val,
/* Environment option */
unsigned int i;
for (i = 0; envp_init[i]; i++) {
if (!strncmp(param, envp_init[i], len+1))
break;
if (i == MAX_INIT_ENVS) {
panic_later = "env";
panic_param = param;
}
if (!strncmp(param, envp_init[i], len+1))
break;
}
envp_init[i] = param;
} else {
@ -642,7 +638,7 @@ static int __init init_setup(char *str)
* the shell think it should execute a script with such name.
* So we ignore all arguments entered _before_ init=... [MJ]
*/
for (i = 1; i < MAX_INIT_ARGS; i++)
for (i = 1; i <= MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;
}
@ -655,7 +651,7 @@ static int __init rdinit_setup(char *str)
ramdisk_execute_command = str;
ramdisk_execute_command_set = true;
/* See "auto" comment in init_setup */
for (i = 1; i < MAX_INIT_ARGS; i++)
for (i = 1; i <= MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;
}

View File

@ -21,13 +21,14 @@ static int __init early_hostname(char *arg)
{
size_t bufsize = sizeof(init_uts_ns.name.nodename);
size_t maxlen = bufsize - 1;
ssize_t arglen;
arglen = strscpy(init_uts_ns.name.nodename, arg, bufsize);
if (arglen < 0) {
pr_warn("hostname parameter exceeds %zd characters and will be truncated",
if (!arg)
return -EINVAL;
if (strscpy(init_uts_ns.name.nodename, arg, bufsize) < 0)
pr_warn("hostname parameter exceeds %zu characters and will be truncated\n",
maxlen);
}
return 0;
}
early_param("hostname", early_hostname);

View File

@ -858,7 +858,8 @@ void __init fork_init(void)
#ifndef ARCH_MIN_TASKALIGN
#define ARCH_MIN_TASKALIGN 0
#endif
int align = max_t(int, L1_CACHE_BYTES, ARCH_MIN_TASKALIGN);
int align = max3(L1_CACHE_BYTES, ARCH_MIN_TASKALIGN,
__alignof__(struct task_struct));
unsigned long useroffset, usersize;
/* create a slab on which task_structs can be allocated */

View File

@ -529,7 +529,7 @@ static void init_node(struct gcov_node *node, struct gcov_info *info,
}
node->parent = parent;
if (name)
strcpy(node->name, name);
strscpy(node->name, name, strlen(name) + 1);
}
/*

View File

@ -57,8 +57,20 @@ unsigned long __read_mostly sysctl_hung_task_timeout_secs = CONFIG_DEFAULT_HUNG_
*/
static unsigned long __read_mostly sysctl_hung_task_check_interval_secs;
/*
* Limit the number of printed hung tasks to prevent printing
* the same or similar backtraces repeatedly.
*/
static int __read_mostly sysctl_hung_task_warnings = 10;
/*
* The number of hung tasks which still can be reported.
* The budget gets restored to the original limit when
* the previous stall is resolved.
*/
static int hung_task_warnings_budget = 10;
static atomic_t reset_hung_task_warnings = ATOMIC_INIT(0);
static int __read_mostly did_panic;
static bool hung_task_call_panic;
@ -245,11 +257,11 @@ static void hung_task_info(struct task_struct *t, unsigned long timeout,
/*
* The given task did not get scheduled for more than
* CONFIG_DEFAULT_HUNG_TASK_TIMEOUT. Therefore, complain
* accordingly
* accordingly with full details if the budget is not exhausted.
*/
if (sysctl_hung_task_warnings || hung_task_call_panic) {
if (sysctl_hung_task_warnings > 0)
sysctl_hung_task_warnings--;
if (hung_task_warnings_budget || hung_task_call_panic) {
if (hung_task_warnings_budget > 0)
hung_task_warnings_budget--;
pr_err("INFO: task %s:%d blocked%s for more than %ld seconds.\n",
t->comm, t->pid, t->in_iowait ? " in I/O wait" : "",
(jiffies - t->last_switch_time) / HZ);
@ -264,8 +276,8 @@ static void hung_task_info(struct task_struct *t, unsigned long timeout,
sched_show_task(t);
debug_show_blocker(t, timeout);
if (!sysctl_hung_task_warnings)
pr_info("Future hung task reports are suppressed, see sysctl kernel.hung_task_warnings\n");
if (!hung_task_warnings_budget && !hung_task_call_panic)
pr_info("hung_task: further per-task details suppressed until warning budget is reset (see sysctl kernel.hung_task_warnings)\n");
}
touch_nmi_watchdog();
@ -304,7 +316,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
unsigned long last_break = jiffies;
struct task_struct *g, *t;
unsigned long this_round_count;
int need_warning = sysctl_hung_task_warnings;
int need_warning;
unsigned long si_mask = hung_task_si_mask;
/*
@ -314,6 +326,11 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
if (test_taint(TAINT_DIE) || did_panic)
return;
if (atomic_xchg_acquire(&reset_hung_task_warnings, 0))
hung_task_warnings_budget =
READ_ONCE(sysctl_hung_task_warnings);
need_warning = hung_task_warnings_budget;
this_round_count = 0;
rcu_read_lock();
for_each_process_thread(g, t) {
@ -340,8 +357,15 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
unlock:
rcu_read_unlock();
if (!this_round_count)
if (!this_round_count) {
hung_task_warnings_budget =
READ_ONCE(sysctl_hung_task_warnings);
return;
}
if (!hung_task_warnings_budget && !hung_task_call_panic)
pr_info("hung_task: %lu hung tasks detected, warning budget exhausted\n",
this_round_count);
if (need_warning || hung_task_call_panic) {
si_mask |= SYS_INFO_LOCKS;
@ -425,6 +449,19 @@ static int proc_dohung_task_timeout_secs(const struct ctl_table *table, int writ
return ret;
}
static int proc_dohung_task_warnings(const struct ctl_table *table, int write,
void *buffer,
size_t *lenp, loff_t *ppos)
{
int ret;
ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
if (!ret && write)
atomic_set_release(&reset_hung_task_warnings, 1);
return ret;
}
/*
* This is needed for proc_doulongvec_minmax of sysctl_hung_task_timeout_secs
* and hung_task_check_interval_secs
@ -480,7 +517,7 @@ static const struct ctl_table hung_task_sysctls[] = {
.data = &sysctl_hung_task_warnings,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.proc_handler = proc_dohung_task_warnings,
.extra1 = SYSCTL_NEG_ONE,
},
{

View File

@ -198,6 +198,16 @@ static notrace unsigned long canonicalize_ip(unsigned long ip)
return ip;
}
#ifdef CONFIG_KCOV_SELFTEST
static unsigned long __init decanonicalize_ip(unsigned long ip)
{
#ifdef CONFIG_RANDOMIZE_BASE
ip += kaslr_offset();
#endif
return ip;
}
#endif
/*
* Entry point from instrumented code.
* This is called once per basic-block/edge.
@ -253,6 +263,14 @@ static void notrace write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip)
count = READ_ONCE(area[0]);
/*
* area[0] is writable by the collecting process, so count cannot be
* trusted. Bound it to the records that fit, as kcov_move_area()
* does, so the end_pos multiply below cannot wrap past its check.
*/
if (count >= max_pos / (sizeof(u64) * KCOV_WORDS_PER_CMP))
return;
/* Every record is KCOV_WORDS_PER_CMP 64-bit words. */
start_index = 1 + count * KCOV_WORDS_PER_CMP;
end_pos = (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64);
@ -1099,9 +1117,11 @@ struct kcov_common_handle_id kcov_common_handle(void)
EXPORT_SYMBOL(kcov_common_handle);
#ifdef CONFIG_KCOV_SELFTEST
static unsigned long selftest_area[16] __initdata;
static void __init selftest(void)
{
unsigned long start;
unsigned long start, i, ip, count;
pr_err("running self test\n");
/*
@ -1111,15 +1131,26 @@ static void __init selftest(void)
* leaks out of that section and leads to spurious coverage.
* It's hard to call the actual interrupt handler directly,
* so we just loop here for a bit waiting for a timer interrupt.
* We set kcov_mode to enable tracing, but don't setup the area,
* so any attempt to trace will crash. Note: we must not call any
* A small coverage area records the PCs of any leaks. The first word
* holds the count, leaving room for 15 PCs. Note: we must not call any
* potentially traced functions in this region.
*/
kcov_start(current, NULL, ARRAY_SIZE(selftest_area),
selftest_area, KCOV_MODE_TRACE_PC, 0);
start = jiffies;
WRITE_ONCE(current->kcov_mode, KCOV_MODE_TRACE_PC);
while ((jiffies - start) * MSEC_PER_SEC / HZ < 300)
;
WRITE_ONCE(current->kcov_mode, 0);
cpu_relax();
kcov_stop(current);
count = READ_ONCE(selftest_area[0]);
if (count) {
pr_err("spurious coverage detected during interrupt selftest:\n");
for (i = 1; i <= count; i++) {
ip = decanonicalize_ip(selftest_area[i]);
pr_err(" %pB\n", (void *)ip);
}
panic("kcov: interrupt selftest detected spurious coverage");
}
pr_err("done running self test\n");
}
#endif

View File

@ -307,7 +307,7 @@ atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);
atomic_t panic_redirect_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);
#if defined(CONFIG_SMP) && defined(CONFIG_CRASH_DUMP)
static char *panic_force_buf;
static char panic_force_buf[PANIC_MSG_BUFSZ];
static int __init panic_force_cpu_setup(char *str)
{
@ -326,17 +326,6 @@ static int __init panic_force_cpu_setup(char *str)
}
early_param("panic_force_cpu", panic_force_cpu_setup);
static int __init panic_force_cpu_late_init(void)
{
if (panic_force_cpu < 0)
return 0;
panic_force_buf = kmalloc(PANIC_MSG_BUFSZ, GFP_KERNEL);
return 0;
}
late_initcall(panic_force_cpu_late_init);
static void do_panic_on_target_cpu(void *info)
{
panic("%s", (char *)info);
@ -371,15 +360,16 @@ int __weak panic_smp_redirect_cpu(int target_cpu, void *msg)
* for the crash kernel to function correctly. This function redirects
* panic handling to the CPU specified via the panic_force_cpu= boot parameter.
*
* Returns false if panic should proceed on current CPU.
* Returns true if panic was redirected.
* Returns true when this CPU must stop: the panic was redirected or is
* already running on another CPU.
* Returns false when panic() should proceed on this CPU.
*/
__printf(1, 0)
static bool panic_try_force_cpu(const char *fmt, va_list args)
{
int this_cpu = raw_smp_processor_id();
int old_cpu = PANIC_CPU_INVALID;
const char *msg;
va_list ap;
/* Feature not enabled via boot parameter */
if (panic_force_cpu < 0)
@ -396,27 +386,27 @@ static bool panic_try_force_cpu(const char *fmt, va_list args)
return false;
}
/* Another panic already in progress */
/*
* Don't redirect when a panic is already in progress. Stop this
* CPU when it's another one, proceed when it's this one.
*/
if (panic_in_progress())
return false;
return panic_on_other_cpu();
/*
* Only one CPU can do the redirect. Use atomic cmpxchg to ensure
* we don't race with another CPU also trying to redirect.
* Only one CPU can do the redirection. Others should go offline.
* Continue with panic() when we already tried the redirection
* from this CPU before, for example via nmi_panic().
*/
if (!atomic_try_cmpxchg(&panic_redirect_cpu, &old_cpu, this_cpu))
return false;
return old_cpu != this_cpu;
/*
* Use dynamically allocated buffer if available, otherwise
* fall back to static message for early boot panics or allocation failure.
* Do not consume args, the caller reuses them if we fail.
*/
if (panic_force_buf) {
vsnprintf(panic_force_buf, PANIC_MSG_BUFSZ, fmt, args);
msg = panic_force_buf;
} else {
msg = "Redirected panic (buffer unavailable)";
}
va_copy(ap, args);
vsnprintf(panic_force_buf, PANIC_MSG_BUFSZ, fmt, ap);
va_end(ap);
console_verbose();
bust_spinlocks(1);
@ -431,7 +421,7 @@ static bool panic_try_force_cpu(const char *fmt, va_list args)
dump_stack();
}
if (panic_smp_redirect_cpu(panic_force_cpu, (void *)msg) != 0) {
if (panic_smp_redirect_cpu(panic_force_cpu, panic_force_buf) != 0) {
atomic_set(&panic_redirect_cpu, PANIC_CPU_INVALID);
pr_warn("panic: failed to redirect to CPU %d, continuing on CPU %d\n",
panic_force_cpu, this_cpu);
@ -503,17 +493,35 @@ bool panic_on_other_cpu(void)
EXPORT_SYMBOL(panic_on_other_cpu);
/*
* A variant of panic() called from NMI context. We return if we've already
* panicked on this CPU. If another CPU already panicked, loop in
* nmi_panic_self_stop() which can provide architecture dependent code such
* as saving register state for crash dump.
* A variant of panic() called from NMI context. The panic is first
* redirected to the CPU requested via panic_force_cpu=, when configured.
* We return if we've already panicked on this CPU. If another CPU already
* panicked, loop in nmi_panic_self_stop() which can provide architecture
* dependent code for saving register state for crash dump.
*/
void nmi_panic(struct pt_regs *regs, const char *msg)
void nmi_panic(struct pt_regs *regs, const char *fmt, ...)
{
if (panic_try_start())
panic("%s", msg);
else if (panic_on_other_cpu())
va_list args;
va_start(args, fmt);
/* Try to redirect to the requested CPU before claiming panic_cpu. */
if (panic_try_force_cpu(fmt, args)) {
/*
* Mark ourselves offline so panic_other_cpus_shutdown() won't
* wait for us on architectures that check num_online_cpus().
*/
set_cpu_online(raw_smp_processor_id(), false);
nmi_panic_self_stop(regs);
}
if (panic_try_start())
vpanic(fmt, args);
if (panic_on_other_cpu())
nmi_panic_self_stop(regs);
va_end(args);
}
EXPORT_SYMBOL(nmi_panic);
@ -567,6 +575,8 @@ static void panic_other_cpus_shutdown(bool crash_kexec)
crash_smp_send_stop();
}
void __weak arch_do_panic(void) {}
/**
* vpanic - halt the system
* @fmt: The text string to print
@ -742,20 +752,9 @@ void vpanic(const char *fmt, va_list args)
reboot_mode = panic_reboot_mode;
emergency_restart();
}
#ifdef __sparc__
{
extern int stop_a_enabled;
/* Make sure the user can actually press Stop-A (L1-A) */
stop_a_enabled = 1;
pr_emerg("Press Stop-A (L1-A) from sun keyboard or send break\n"
"twice on console to return to the boot prom\n");
}
#endif
#if defined(CONFIG_S390)
disabled_wait();
#endif
pr_emerg("---[ end Kernel panic - not syncing: %s ]---\n", buf);
arch_do_panic();
/* Do not scroll important messages printed above */
suppress_printk = 1;
@ -1227,14 +1226,9 @@ static int panic_print_set(const char *val, const struct kernel_param *kp)
return param_set_ulong(val, kp);
}
static int panic_print_get(char *val, const struct kernel_param *kp)
{
return param_get_ulong(val, kp);
}
static const struct kernel_param_ops panic_print_ops = {
.set = panic_print_set,
.get = panic_print_get,
.get = param_get_ulong,
};
__core_param_cb(panic_print, &panic_print_ops, &panic_print, 0644);

View File

@ -156,7 +156,7 @@ read_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos)
unsigned long p = *ppos;
ssize_t read;
char *pnt;
unsigned long sample_step = 1UL << prof_shift;
unsigned int sample_step = (unsigned int)(1UL << prof_shift);
if (p >= (prof_len+1)*sizeof(unsigned int))
return 0;

View File

@ -813,8 +813,8 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
#ifdef CONFIG_HIBERNATION
case LINUX_REBOOT_CMD_SW_SUSPEND:
ret = hibernate();
break;
mutex_unlock(&system_transition_mutex);
return hibernate();
#endif
default:

View File

@ -1350,8 +1350,8 @@ static int __request_region_locked(struct resource *res, struct resource *parent
}
if (conflict->flags & flags & IORESOURCE_MUXED) {
add_wait_queue(&muxed_resource_wait, &wait);
write_unlock(&resource_lock);
set_current_state(TASK_UNINTERRUPTIBLE);
write_unlock(&resource_lock);
schedule();
remove_wait_queue(&muxed_resource_wait, &wait);
write_lock(&resource_lock);
@ -1833,7 +1833,7 @@ __setup("reserve=", reserve_setup);
*/
int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
{
resource_size_t end = addr + size - 1;
struct resource mem = DEFINE_RES_MEM(addr, size);
struct resource *p;
int err = 0;
@ -1843,12 +1843,10 @@ int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
* We can probably skip the resources without
* IORESOURCE_IO attribute?
*/
if (p->start > end)
if (!resource_overlaps(p, &mem))
continue;
if (p->end < addr)
continue;
if (PFN_DOWN(p->start) <= PFN_DOWN(addr) &&
PFN_DOWN(p->end) >= PFN_DOWN(end))
if (PFN_DOWN(p->start) <= PFN_DOWN(mem.start) &&
PFN_DOWN(p->end) >= PFN_DOWN(mem.end))
continue;
/*
* if a resource is "BUSY", it's not a hardware resource
@ -1859,8 +1857,8 @@ int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
if (p->flags & IORESOURCE_BUSY)
continue;
pr_debug("resource sanity check: requesting [mem %pa-%pa], which spans more than %s %pR\n",
&addr, &end, p->name, p);
pr_debug("resource sanity check: requesting %pR, which spans more than %s %pR\n",
&mem, p->name, p);
err = -1;
break;
}

View File

@ -225,6 +225,9 @@ static void resource_test_region_intersects(struct kunit *test)
struct resource *parent;
resource_size_t start;
if (!IS_ENABLED(CONFIG_GET_FREE_REGION))
kunit_skip(test, "CONFIG_GET_FREE_REGION is disabled");
/* Find an iomem_resource hole to hold test resources */
parent = alloc_free_mem_region(&iomem_resource, RES_TEST_TOTAL_SIZE, SZ_1M,
"test resources");

View File

@ -1077,6 +1077,9 @@ SYSCALL_DEFINE1(times, struct tms __user *, tbuf)
#ifdef CONFIG_COMPAT
static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
{
if (USER_HZ == COMPAT_USER_HZ)
return x;
return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));
}

View File

@ -59,8 +59,7 @@ static DEFINE_PER_CPU(struct listener_list, listener_array);
enum actions {
REGISTER,
DEREGISTER,
CPU_DONT_CARE
DEREGISTER
};
static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
@ -473,7 +472,8 @@ static size_t taskstats_packet_size(void)
return size;
}
static int cmd_attr_pid(struct genl_info *info)
static int cmd_attr_pid_tgid(struct genl_info *info, int attr,
int (*fill)(pid_t, struct taskstats *))
{
struct taskstats *stats;
struct sk_buff *rep_skb;
@ -488,41 +488,15 @@ static int cmd_attr_pid(struct genl_info *info)
return rc;
rc = -EINVAL;
pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid);
pid = nla_get_u32(info->attrs[attr]);
stats = mk_reply(rep_skb,
attr == TASKSTATS_CMD_ATTR_PID
? TASKSTATS_TYPE_PID : TASKSTATS_TYPE_TGID,
pid);
if (!stats)
goto err;
rc = fill_stats_for_pid(pid, stats);
if (rc < 0)
goto err;
return send_reply(rep_skb, info);
err:
nlmsg_free(rep_skb);
return rc;
}
static int cmd_attr_tgid(struct genl_info *info)
{
struct taskstats *stats;
struct sk_buff *rep_skb;
size_t size;
u32 tgid;
int rc;
size = taskstats_packet_size();
rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
if (rc < 0)
return rc;
rc = -EINVAL;
tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);
stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid);
if (!stats)
goto err;
rc = fill_stats_for_tgid(tgid, stats);
rc = fill(pid, stats);
if (rc < 0)
goto err;
return send_reply(rep_skb, info);
@ -542,9 +516,11 @@ static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
DEREGISTER);
else if (info->attrs[TASKSTATS_CMD_ATTR_PID])
return cmd_attr_pid(info);
return cmd_attr_pid_tgid(info, TASKSTATS_CMD_ATTR_PID,
fill_stats_for_pid);
else if (info->attrs[TASKSTATS_CMD_ATTR_TGID])
return cmd_attr_tgid(info);
return cmd_attr_pid_tgid(info, TASKSTATS_CMD_ATTR_TGID,
fill_stats_for_tgid);
else
return -EINVAL;
}

View File

@ -255,6 +255,9 @@ void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs)
return;
}
if (hardlockup_panic)
console_verbose();
/*
* NOTE: we call printk_cpu_sync_get_irqsave() after printing
* the lockup message. While it would be nice to serialize
@ -880,6 +883,10 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
/* Start period for the next softlockup warning. */
update_report_ts();
thresh_count = duration / get_softlockup_thresh();
if (softlockup_panic && thresh_count >= softlockup_panic)
console_verbose();
printk_cpu_sync_get_irqsave(flags);
pr_emerg("BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n",
smp_processor_id(), duration,
@ -901,7 +908,6 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
add_taint(TAINT_SOFTLOCKUP, LOCKDEP_STILL_OK);
sys_info(softlockup_si_mask & ~SYS_INFO_ALL_BT);
thresh_count = duration / get_softlockup_thresh();
if (softlockup_panic && thresh_count >= softlockup_panic)
panic("softlockup: hung tasks");

View File

@ -301,10 +301,10 @@ void __init hardlockup_config_perf_event(const char *str)
} else {
unsigned int len = comma - str;
if (len > sizeof(buf))
if (len >= sizeof(buf))
return;
strscpy(buf, str, len);
strscpy(buf, str, len + 1);
if (kstrtoull(buf, 16, &config))
return;
}

View File

@ -219,29 +219,29 @@ source "lib/xz/Kconfig"
#
config DECOMPRESS_GZIP
select ZLIB_INFLATE
tristate
bool
config DECOMPRESS_BZIP2
tristate
bool
config DECOMPRESS_LZMA
tristate
bool
config DECOMPRESS_XZ
select XZ_DEC
tristate
bool
config DECOMPRESS_LZO
select LZO_DECOMPRESS
tristate
bool
config DECOMPRESS_LZ4
select LZ4_DECOMPRESS
tristate
bool
config DECOMPRESS_ZSTD
select ZSTD_DECOMPRESS
tristate
bool
#
# Generic allocator support is selected if needed

View File

@ -2810,7 +2810,6 @@ config RESOURCE_KUNIT_TEST
tristate "KUnit test for resource API" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS
select GET_FREE_REGION
help
This builds the resource API unit test.
Tests the logic of API provided by resource.c and ioport.h.
@ -2831,6 +2830,21 @@ config SYSCTL_KUNIT_TEST
If unsure, say N.
config ERRSEQ_KUNIT_TEST
tristate "KUnit test for errseq" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS
help
This builds the errseq KUnit test suite.
It tests the documented semantics of the errseq_t error-tracking
infrastructure (lib/errseq.c), which underpins writeback error
reporting.
For more information on KUnit and unit tests in general please refer
to the KUnit documentation in Documentation/dev-tools/kunit/.
If unsure, say N.
config KFIFO_KUNIT_TEST
tristate "KUnit Test for the generic kernel FIFO implementation" if !KUNIT_ALL_TESTS
depends on KUNIT

View File

@ -11,6 +11,7 @@
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/overflow.h>
#include <linux/string.h>
#include <linux/ctype.h>
@ -26,7 +27,9 @@ static int get_range(char **str, int *pint, int n)
(*str)++;
upper_range = simple_strtol((*str), NULL, 0);
inc_counter = upper_range - *pint;
/* Keep the sign of the result when the difference doesn't fit */
if (check_sub_overflow(upper_range, *pint, &inc_counter))
inc_counter = upper_range < *pint ? -1 : INT_MAX;
for (x = *pint; n && x < upper_range; x++, n--)
*pint++ = x;
return inc_counter;
@ -122,6 +125,14 @@ char *get_options(const char *str, int nints, int *ints)
range_nums = get_range((char **)&str, pint, n);
if (range_nums < 0)
break;
/* The range didn't fit, so the array is full */
if (!validate && range_nums > n) {
i = nints;
break;
}
/* Leave room for the upper number of the range */
if (range_nums >= INT_MAX - i)
break;
/*
* Decrement the result by one to leave out the
* last number in the range. The next iteration

View File

@ -428,6 +428,10 @@ static int INIT get_next_block(struct bunzip_data *bd)
t += (runPos << nextSym);
/* +runPos if RUNA; +2*runPos if RUNB */
/* Bound the run so t and runPos cannot overflow. */
if (t >= dbufSize)
return RETVAL_DATA_ERROR;
runPos <<= 1;
continue;
}
@ -439,7 +443,7 @@ static int INIT get_next_block(struct bunzip_data *bd)
array.) */
if (runPos) {
runPos = 0;
if (dbufCount+t >= dbufSize)
if (dbufCount+t > dbufSize)
return RETVAL_DATA_ERROR;
uc = symToByte[mtfSymbol[0]];

View File

@ -139,6 +139,10 @@ STATIC inline int INIT unlz4(u8 *input, long in_len,
if (!fill) {
inp += 4;
size -= 4;
if (chunksize > size) {
error("data corrupted");
goto exit_2;
}
} else {
if (chunksize > LZ4_compressBound(uncomp_chunksize)) {
error("chunk length is longer than allocated");

View File

@ -342,14 +342,14 @@ STATIC int INIT unxz(unsigned char *in, long in_size,
b.out_pos = 0;
}
} while (ret == XZ_OK);
if (must_free_in)
free(in);
if (flush != NULL)
free(b.out);
}
if (must_free_in)
free(in);
if (flush != NULL)
free(b.out);
if (in_used != NULL)
*in_used += b.in_pos;

View File

@ -5,6 +5,7 @@
#include <linux/debugfs.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/export.h>
@ -64,7 +65,7 @@ static void fail_dump(struct fault_attr *attr)
{
if (attr->verbose > 0 && __ratelimit(&attr->ratelimit_state)) {
printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure.\n"
"name %pd, interval %lu, probability %lu, "
"name %s, interval %lu, probability %lu, "
"space %d, times %d\n", attr->dname,
attr->interval, attr->probability,
atomic_read(&attr->space),
@ -261,7 +262,9 @@ struct dentry *fault_create_debugfs_attr(const char *name,
debugfs_create_xul("reject-end", mode, dir, &attr->reject_end);
#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
attr->dname = dget(dir);
if (strscpy(attr->dname, name, sizeof(attr->dname)) == -E2BIG)
pr_warn("FAULT_INJECTION: name '%s' truncated to '%s'\n",
name, attr->dname);
return dir;
}
EXPORT_SYMBOL_GPL(fault_create_debugfs_attr);

View File

@ -36,6 +36,7 @@
#include <linux/klist.h>
#include <linux/export.h>
#include <linux/sched.h>
#include <linux/sched/task.h>
/*
* Use the lowest bit of n_klist to mark deleted nodes and exclude
@ -187,18 +188,24 @@ static void klist_release(struct kref *kref)
WARN_ON(!knode_dead(n));
list_del(&n->n_node);
knode_set_klist(n, NULL);
spin_lock(&klist_remove_lock);
list_for_each_entry_safe(waiter, tmp, &klist_remove_waiters, list) {
struct task_struct *p;
if (waiter->node != n)
continue;
p = waiter->process;
get_task_struct(p);
list_del(&waiter->list);
waiter->woken = 1;
/* Publish only after the final waiter and n accesses */
smp_store_release(&waiter->woken, 1);
mb();
wake_up_process(waiter->process);
wake_up_process(p);
put_task_struct(p);
}
spin_unlock(&klist_remove_lock);
knode_set_klist(n, NULL);
}
static int klist_dec_and_del(struct klist_node *n)
@ -250,7 +257,8 @@ void klist_remove(struct klist_node *n)
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (waiter.woken)
/* Pairs with the release store in klist_release() */
if (smp_load_acquire(&waiter.woken))
break;
schedule();
}

View File

@ -69,7 +69,7 @@ unsigned int _parse_integer_limit(const char *s, unsigned int base, unsigned lon
unsigned int lc = _tolower(c);
unsigned int val;
if ('0' <= c && c <= '9')
if (isdigit(c))
val = c - '0';
else if ('a' <= lc && lc <= 'f')
val = lc - 'a' + 10;

View File

@ -328,6 +328,7 @@ bool __percpu_counter_limited_add(struct percpu_counter *fbc,
s64 limit, s64 amount, s32 batch)
{
s64 count;
s64 gcount;
s64 unknown;
unsigned long flags;
bool good = false;
@ -338,11 +339,16 @@ bool __percpu_counter_limited_add(struct percpu_counter *fbc,
local_irq_save(flags);
unknown = batch * num_online_cpus();
count = __this_cpu_read(*fbc->counters);
/*
* Lockless on purpose: gcount may be stale, so this is only an
* approximation, bounded by the per-cpu slack ("unknown").
*/
gcount = data_race(READ_ONCE(fbc->count));
/* Skip taking the lock when safe */
if (abs(count + amount) <= batch &&
((amount > 0 && fbc->count + unknown <= limit) ||
(amount < 0 && fbc->count - unknown >= limit))) {
((amount > 0 && gcount + unknown <= limit) ||
(amount < 0 && gcount - unknown >= limit))) {
this_cpu_add(*fbc->counters, amount);
local_irq_restore(flags);
return true;

View File

@ -174,8 +174,15 @@ void plist_requeue(struct plist_node *node, struct plist_head *head)
/*
* After plist_del(), iter is the replacement of the node. If the node
* was on prio_list, take shortcut to find node_next instead of looping.
*
* prio_list is a headless ring, so from the LAST bucket ->next wraps
* round to the first one; in that case node_next is the list head.
*/
if (!list_empty(&iter->prio_list)) {
struct plist_node *first = plist_first(head);
if (iter->prio_list.next == &first->prio_list)
goto queue;
iter = list_entry(iter->prio_list.next, struct plist_node,
prio_list);
node_next = &iter->node_list;

View File

@ -32,6 +32,7 @@ config XOR_KUNIT_TEST
config XOR_BENCHMARK
bool "Benchmark for xor_gen"
depends on XOR_KUNIT_TEST
default y if KUNIT_ALL_TESTS=m
help
Include benchmarks in the KUnit test suite for xor_gen.
@ -63,6 +64,7 @@ config RAID6_PQ_KUNIT_TEST
config RAID6_PQ_KUNIT_BENCHMARK
bool "Benchmark for RAID6 PQ"
depends on RAID6_PQ_KUNIT_TEST
default y if KUNIT_ALL_TESTS=m
help
Include benchmarks in the KUnit test suite for raid P/Q generation.

View File

@ -67,6 +67,7 @@ static void raid6_avx21_gen_syndrome(int disks, size_t bytes, void **ptrs)
}
asm volatile("sfence" : : : "memory");
asm volatile("vzeroupper");
kernel_fpu_end();
}
@ -115,6 +116,7 @@ static void raid6_avx21_xor_syndrome(int disks, int start, int stop,
}
asm volatile("sfence" : : : "memory");
asm volatile("vzeroupper");
kernel_fpu_end();
}
@ -175,6 +177,7 @@ static void raid6_avx22_gen_syndrome(int disks, size_t bytes, void **ptrs)
}
asm volatile("sfence" : : : "memory");
asm volatile("vzeroupper");
kernel_fpu_end();
}
@ -243,6 +246,7 @@ static void raid6_avx22_xor_syndrome(int disks, int start, int stop,
}
asm volatile("sfence" : : : "memory");
asm volatile("vzeroupper");
kernel_fpu_end();
}
@ -334,6 +338,7 @@ static void raid6_avx24_gen_syndrome(int disks, size_t bytes, void **ptrs)
}
asm volatile("sfence" : : : "memory");
asm volatile("vzeroupper");
kernel_fpu_end();
}
@ -444,6 +449,7 @@ static void raid6_avx24_xor_syndrome(int disks, int start, int stop,
asm volatile("vmovntdq %%ymm14,%0" : "=m" (q[d+96]));
}
asm volatile("sfence" : : : "memory");
asm volatile("vzeroupper");
kernel_fpu_end();
}

View File

@ -78,6 +78,7 @@ static void raid6_avx5121_gen_syndrome(int disks, size_t bytes, void **ptrs)
}
asm volatile("sfence" : : : "memory");
asm volatile("vzeroupper");
kernel_fpu_end();
}
@ -137,6 +138,7 @@ static void raid6_avx5121_xor_syndrome(int disks, int start, int stop,
}
asm volatile("sfence" : : : "memory");
asm volatile("vzeroupper");
kernel_fpu_end();
}
@ -208,6 +210,7 @@ static void raid6_avx5122_gen_syndrome(int disks, size_t bytes, void **ptrs)
}
asm volatile("sfence" : : : "memory");
asm volatile("vzeroupper");
kernel_fpu_end();
}
@ -292,6 +295,7 @@ static void raid6_avx5122_xor_syndrome(int disks, int start, int stop,
}
asm volatile("sfence" : : : "memory");
asm volatile("vzeroupper");
kernel_fpu_end();
}
@ -396,6 +400,7 @@ static void raid6_avx5124_gen_syndrome(int disks, size_t bytes, void **ptrs)
}
asm volatile("sfence" : : : "memory");
asm volatile("vzeroupper");
kernel_fpu_end();
}
@ -529,6 +534,7 @@ static void raid6_avx5124_xor_syndrome(int disks, int start, int stop,
"m" (q[d+128]), "m" (q[d+192]));
}
asm volatile("sfence" : : : "memory");
asm volatile("vzeroupper");
kernel_fpu_end();
}
const struct raid6_calls raid6_avx512x4 = {

View File

@ -176,6 +176,7 @@ static void raid6_2data_recov_avx2(int disks, size_t bytes, int faila,
#endif
}
asm volatile("vzeroupper");
kernel_fpu_end();
}
@ -293,6 +294,7 @@ static void raid6_datap_recov_avx2(int disks, size_t bytes, int faila,
#endif
}
asm volatile("vzeroupper");
kernel_fpu_end();
}

View File

@ -211,6 +211,7 @@ static void raid6_2data_recov_avx512(int disks, size_t bytes, int faila,
#endif
}
asm volatile("vzeroupper");
kernel_fpu_end();
}
@ -353,6 +354,7 @@ static void raid6_datap_recov_avx512(int disks, size_t bytes, int faila,
#endif
}
asm volatile("vzeroupper");
kernel_fpu_end();
}

View File

@ -147,6 +147,7 @@ static void xor_gen_avx(void *dest, void **srcs, unsigned int src_cnt,
{
kernel_fpu_begin();
xor_gen_avx_inner(dest, srcs, src_cnt, bytes);
asm volatile("vzeroupper");
kernel_fpu_end();
}

View File

@ -323,7 +323,7 @@ static bool depot_init_pool(void **prealloc)
* NULL; do not reset to NULL if we have reached the maximum number of
* pools.
*/
if (pools_num < stack_max_pools)
if (pools_num + 1 < stack_max_pools)
WRITE_ONCE(new_pool, NULL);
else
WRITE_ONCE(new_pool, STACK_DEPOT_POISON);

View File

@ -14,6 +14,7 @@ obj-$(CONFIG_BLACKHOLE_DEV_KUNIT_TEST) += blackhole_dev_kunit.o
obj-$(CONFIG_CHECKSUM_KUNIT) += checksum_kunit.o
obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o
obj-$(CONFIG_CPUMASK_KUNIT_TEST) += cpumask_kunit.o
obj-$(CONFIG_ERRSEQ_KUNIT_TEST) += errseq_kunit.o
obj-$(CONFIG_FFS_KUNIT_TEST) += ffs_kunit.o
CFLAGS_fortify_kunit.o += $(call cc-disable-warning, unsequenced)
CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-overread)

View File

@ -140,6 +140,44 @@ static void cmdline_test_range(struct kunit *test)
} while (++i < ARRAY_SIZE(cmdline_test_range_strings));
}
static const struct {
const char *in;
int parsed[4];
int validated;
} cmdline_test_range_overflow_cases[] = {
{ "1-100", { 3, 1, 2, 3, }, 100, },
{ "1,5-100,7", { 3, 1, 5, 6, }, 98, },
{ "1-2147483646", { 3, 1, 2, 3, }, 2147483646, },
{ "0-2147483647", { 3, 0, 1, 2, }, 0, },
{ "-5-2147483647", { 3, -5, -4, -3, }, 0, },
{ "2147483647--5", { 0, 2147483647, }, 0, },
{ "1,0-2147483647", { 3, 1, 0, 1, }, 1, },
};
static void cmdline_test_range_overflow(struct kunit *test)
{
unsigned int i, j;
for (i = 0; i < ARRAY_SIZE(cmdline_test_range_overflow_cases); i++) {
const char *in = cmdline_test_range_overflow_cases[i].in;
const int *e = cmdline_test_range_overflow_cases[i].parsed;
/* Two guard elements past the array handed to get_options() */
int r[ARRAY_SIZE(cmdline_test_range_overflow_cases[0].parsed) + 2];
int n;
memset(r, 0, sizeof(r));
get_options(in, ARRAY_SIZE(r) - 2, r);
for (j = 0; j < ARRAY_SIZE(r) - 2; j++)
KUNIT_EXPECT_EQ_MSG(test, r[j], e[j], "Pattern: %s at %u", in, j);
for (; j < ARRAY_SIZE(r); j++)
KUNIT_EXPECT_EQ_MSG(test, r[j], 0, "Pattern: %s out of bound at %u", in, j);
get_options(in, 0, &n);
KUNIT_EXPECT_EQ_MSG(test, n, cmdline_test_range_overflow_cases[i].validated,
"Pattern: %s (validated)", in);
}
}
static void cmdline_test_next_arg_quoted_value(struct kunit *test)
{
char in[] = "foo=\"bar baz\" qux=1";
@ -258,6 +296,7 @@ static struct kunit_case cmdline_test_cases[] = {
KUNIT_CASE(cmdline_test_lead_int),
KUNIT_CASE(cmdline_test_tail_int),
KUNIT_CASE(cmdline_test_range),
KUNIT_CASE(cmdline_test_range_overflow),
KUNIT_CASE(cmdline_test_next_arg_quoted_value),
KUNIT_CASE(cmdline_test_next_arg_bare_quote_regression),
KUNIT_CASE(cmdline_test_next_arg_mixed_tokens),

237
lib/tests/errseq_kunit.c Normal file
View File

@ -0,0 +1,237 @@
// SPDX-License-Identifier: GPL-2.0
/*
* KUnit tests for the errseq_t error-tracking infrastructure.
*
* These exercise the documented single-threaded semantics of the errseq
* API (see Documentation/core-api/errseq.rst and lib/errseq.c): error
* recording and overwriting, the "seen" handoff between errseq_sample()
* and errseq_check_and_advance(), and the re-reporting of an error that
* is recorded again after it has been seen.
*
* The lockless properties of errseq_t under concurrent updates are
* outside the scope of these deterministic tests, as is the WARN path
* for invalid error values.
*/
#include <kunit/test.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/errseq.h>
/*
* A zeroed errseq_t is the "no error has ever occurred" epoch: it
* samples as zero and no check against it reports anything.
*/
static void errseq_test_zero_epoch_reports_no_error(struct kunit *test)
{
errseq_t eseq = 0;
errseq_t since = 0;
KUNIT_EXPECT_EQ(test, errseq_sample(&eseq), 0);
KUNIT_EXPECT_EQ(test, errseq_check(&eseq, 0), 0);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), 0);
KUNIT_EXPECT_EQ(test, since, 0);
}
static void errseq_test_set_records_error(struct kunit *test)
{
errseq_t eseq = 0;
/* errseq_set() returns the previous value; the epoch is zero. */
KUNIT_EXPECT_EQ(test, errseq_set(&eseq, -EIO), 0);
KUNIT_EXPECT_EQ(test, errseq_check(&eseq, 0), -EIO);
}
/* Any error set always overwrites an existing error. */
static void errseq_test_set_overwrites_error(struct kunit *test)
{
errseq_t eseq = 0;
errseq_set(&eseq, -EIO);
errseq_set(&eseq, -ENOSPC);
KUNIT_EXPECT_EQ(test, errseq_check(&eseq, 0), -ENOSPC);
}
/* Both ends of the valid error range are recorded exactly. */
static void errseq_test_errno_range_extremes(struct kunit *test)
{
errseq_t lo = 0;
errseq_t hi = 0;
errseq_set(&lo, -1);
KUNIT_EXPECT_EQ(test, errseq_check(&lo, 0), -1);
errseq_set(&hi, -MAX_ERRNO);
KUNIT_EXPECT_EQ(test, errseq_check(&hi, 0), -MAX_ERRNO);
}
/*
* An error nobody has seen yet samples as zero, so that a check against
* the sample still reports it (see commit b4678df184b3 ("errseq: Always
* report a writeback error once")).
*/
static void errseq_test_sample_of_unseen_error_is_zero(struct kunit *test)
{
errseq_t eseq = 0;
errseq_set(&eseq, -EIO);
KUNIT_EXPECT_EQ(test, errseq_sample(&eseq), 0);
}
static void errseq_test_new_sampler_sees_unseen_error(struct kunit *test)
{
errseq_t eseq = 0;
errseq_t since;
errseq_set(&eseq, -EIO);
since = errseq_sample(&eseq);
KUNIT_EXPECT_EQ(test, errseq_check(&eseq, since), -EIO);
}
/* A given error is reported exactly once per advancing cursor. */
static void errseq_test_check_and_advance_reports_once(struct kunit *test)
{
errseq_t eseq = 0;
errseq_t since = errseq_sample(&eseq);
errseq_set(&eseq, -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), 0);
}
/*
* Once an error has been seen, a fresh sample is non-zero and checking
* against it reports nothing: handled errors do not reach new samplers.
*/
static void errseq_test_sample_after_seen_is_current(struct kunit *test)
{
errseq_t eseq = 0;
errseq_t since = 0;
errseq_t sample;
errseq_set(&eseq, -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -EIO);
sample = errseq_sample(&eseq);
KUNIT_EXPECT_NE(test, sample, 0);
KUNIT_EXPECT_EQ(test, errseq_check(&eseq, sample), 0);
}
static void errseq_test_new_error_after_advance(struct kunit *test)
{
errseq_t eseq = 0;
errseq_t since = 0;
errseq_set(&eseq, -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -EIO);
errseq_set(&eseq, -ENOSPC);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -ENOSPC);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), 0);
}
/*
* Recording the same error again after it has been seen must bump the
* sequence, so cursors that consumed the first occurrence see the
* second one too.
*/
static void errseq_test_same_error_reported_again_after_seen(struct kunit *test)
{
errseq_t eseq = 0;
errseq_t since = 0;
errseq_t seen_cursor;
errseq_set(&eseq, -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -EIO);
seen_cursor = since;
errseq_set(&eseq, -EIO);
KUNIT_EXPECT_EQ(test, errseq_check(&eseq, since), -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -EIO);
/* The repeat must advance the sequence, not just re-toggle "seen". */
KUNIT_EXPECT_NE(test, since, seen_cursor);
}
/*
* A cursor that consumed an error must still observe a repeat of that
* error even when another cursor has already marked the repeat seen:
* recording over a seen value must advance the sequence.
*/
static void errseq_test_repeat_error_visible_to_all_cursors(struct kunit *test)
{
errseq_t eseq = 0;
errseq_t cursor_a = 0;
errseq_t cursor_b = 0;
errseq_set(&eseq, -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_a), -EIO);
errseq_set(&eseq, -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_b), -EIO);
KUNIT_EXPECT_EQ(test, errseq_check(&eseq, cursor_a), -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_a), -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_a), 0);
}
/* An advance with no new error reports nothing and leaves the cursor put. */
static void errseq_test_advance_stable_when_unchanged(struct kunit *test)
{
errseq_t eseq = 0;
errseq_t since = 0;
errseq_t cursor;
errseq_set(&eseq, -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), -EIO);
cursor = since;
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &since), 0);
KUNIT_EXPECT_EQ(test, since, cursor);
}
/*
* Cursors are independent: one subscriber consuming an error does not
* consume it for another, and each subscriber sees each error once.
*/
static void errseq_test_two_subscribers_independent(struct kunit *test)
{
errseq_t eseq = 0;
errseq_t cursor_a = errseq_sample(&eseq);
errseq_t cursor_b = errseq_sample(&eseq);
errseq_set(&eseq, -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_a), -EIO);
KUNIT_EXPECT_EQ(test, errseq_check(&eseq, cursor_b), -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_b), -EIO);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_a), 0);
KUNIT_EXPECT_EQ(test, errseq_check_and_advance(&eseq, &cursor_b), 0);
}
static struct kunit_case errseq_test_cases[] = {
KUNIT_CASE(errseq_test_zero_epoch_reports_no_error),
KUNIT_CASE(errseq_test_set_records_error),
KUNIT_CASE(errseq_test_set_overwrites_error),
KUNIT_CASE(errseq_test_errno_range_extremes),
KUNIT_CASE(errseq_test_sample_of_unseen_error_is_zero),
KUNIT_CASE(errseq_test_new_sampler_sees_unseen_error),
KUNIT_CASE(errseq_test_check_and_advance_reports_once),
KUNIT_CASE(errseq_test_sample_after_seen_is_current),
KUNIT_CASE(errseq_test_new_error_after_advance),
KUNIT_CASE(errseq_test_same_error_reported_again_after_seen),
KUNIT_CASE(errseq_test_repeat_error_visible_to_all_cursors),
KUNIT_CASE(errseq_test_advance_stable_when_unchanged),
KUNIT_CASE(errseq_test_two_subscribers_independent),
{}
};
static struct kunit_suite errseq_test_suite = {
.name = "errseq",
.test_cases = errseq_test_cases,
};
kunit_test_suite(errseq_test_suite);
MODULE_DESCRIPTION("KUnit tests for the errseq infrastructure");
MODULE_LICENSE("GPL");

View File

@ -4710,6 +4710,9 @@ static int shmem_parse_opt_casefold(struct fs_context *fc, struct fs_parameter *
struct unicode_map *encoding;
char *version_str = param->string + 5;
if (ctx->encoding)
return invalfc(fc, "casefold parameter cannot be specified twice\n");
if (!latest_version) {
if (strncmp(param->string, "utf8-", 5))
return invalfc(fc, "Only UTF-8 encodings are supported "
@ -5205,6 +5208,7 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
if (ctx->encoding) {
sb->s_encoding = ctx->encoding;
ctx->encoding = NULL;
set_default_d_op(sb, &shmem_ci_dentry_ops);
if (ctx->strict_encoding)
sb->s_encoding_flags = SB_ENC_STRICT_MODE_FL;
@ -5306,6 +5310,9 @@ static void shmem_free_fc(struct fs_context *fc)
struct shmem_options *ctx = fc->fs_private;
if (ctx) {
#if IS_ENABLED(CONFIG_UNICODE)
utf8_unload(ctx->encoding);
#endif
mpol_put(ctx->mpol);
kfree(ctx);
}

21
scripts/Makefile.gcov Normal file
View File

@ -0,0 +1,21 @@
# SPDX-License-Identifier: GPL-2.0-only
CFLAGS_GCOV := -fprofile-arcs -ftest-coverage
ifdef CONFIG_CC_IS_GCC
CFLAGS_GCOV += -fno-tree-loop-im
# Use atomic counter updates to avoid concurrent-access crashes in GCOV.
# Only enable if -fprofile-update=prefer-atomic does not introduce new
# undefined symbols (e.g. libatomic calls that the kernel cannot link).
CFLAGS_GCOV += $(call try-run,\
echo 'long long x; void f(void){x++;}' | \
$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -w $(CFLAGS_GCOV) \
-x c - -c -o "$$TMP.base" && \
echo 'long long x; void f(void){x++;}' | \
$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -w $(CFLAGS_GCOV) \
-fprofile-update=prefer-atomic \
-x c - -c -o "$$TMP" && \
$(NM) "$$TMP.base" | grep ' U ' > "$$TMP.ubase" || true ; \
$(NM) "$$TMP" | grep ' U ' > "$$TMP.utest" || true ; \
cmp -s "$$TMP.ubase" "$$TMP.utest",\
-fprofile-update=prefer-atomic)
endif
export CFLAGS_GCOV

View File

@ -63,6 +63,7 @@ my $env_config_dir = 'CHECKPATCH_CONFIG_DIR';
my $max_line_length = 100;
my $ignore_perl_version = 0;
my $spdx_cxx_comments = 0;
my $userspace;
my $minimum_perl_version = 5.10.0;
my $min_conf_desc_length = 4;
my $spelling_file = "$D/spelling.txt";
@ -143,6 +144,7 @@ Options:
(required by old toolchains), allow also C++
comments (//).
NOTE: it should *not* be used for Linux mainline.
--userspace Force rules specific for userspace.
--codespell Use the codespell dictionary for spelling/typos
(default:$codespellfile)
--codespellfile Use this codespell dictionary
@ -358,6 +360,7 @@ GetOptions(
'codespell!' => \$codespell,
'codespellfile=s' => \$user_codespellfile,
'typedefsfile=s' => \$typedefsfile,
'userspace!' => \$userspace,
'color=s' => \$color,
'no-color' => \$color, #keep old behaviors of -nocolor
'nocolor' => \$color, #keep old behaviors of -nocolor
@ -1205,6 +1208,8 @@ sub seed_camelcase_includes {
my $git_last_include_commit = `${git_command} log --no-merges --pretty=format:"%h%n" -1 -- include`;
chomp $git_last_include_commit;
$camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit";
} elsif (not defined $root) {
return;
} else {
my $last_mod_date = 0;
$files = `find $root/include -name "*.h"`;
@ -2664,7 +2669,12 @@ sub exclude_global_initialisers {
sub is_userspace {
my ($realfile) = @_;
return ($realfile =~ m@^tools/@ || $realfile =~ m@^scripts/@);
return $userspace if (defined $userspace);
return ($realfile =~ m@^tools/@ ||
$realfile =~ m@^scripts/@ ||
$realfile =~ m@^arch/.*/tools/@);
}
sub process {
@ -5766,7 +5776,21 @@ sub process {
my ($s, $c) = ($stat, $cond);
my $fixed_assign_in_if = 0;
# ACQUIRE_ERR() and its wrappers, e.g. PM_RUNTIME_ACQUIRE_ERR()
# and IIO_DEV_ACQUIRE_FAILED(), are meant to be evaluated in an
# if condition, with the error assigned in the condition:
# if ((rc = ACQUIRE_ERR(name, &lock)))
# Allow that only when every assignment in the condition assigns
# the result of such a call, so that a mixed condition keeps
# getting flagged:
# if ((rc = regular_function()) || (ret = ACQUIRE_ERR(name, &lock)))
my $assign_in_if = 0;
if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) {
my $has_assignment = $c =~ /\b$Lval\s*=\s*[^,)&|=]+/;
my $has_other_assignment = $c =~ /\b$Lval\s*=\s*(?!\s*\w*ACQUIRE_(?:ERR|FAILED)\s*\()[^,)&|=]+/;
$assign_in_if = !$has_assignment || $has_other_assignment;
}
if ($assign_in_if) {
if (ERROR("ASSIGN_IN_IF",
"do not use assignment in if condition\n" . $herecurr) &&
$fix && $perl_version_ok) {
@ -5935,6 +5959,8 @@ sub process {
#Ignore SI style variants like nS, mV and dB
#(ie: max_uV, regulator_min_uA_show, RANGE_mA_VALUE)
$var !~ /^(?:[a-z0-9_]*|[A-Z0-9_]*)?_?[a-z][A-Z](?:_[a-z0-9_]+|_[A-Z0-9_]+)?$/ &&
#Ignore <inttypes.h> format macros (e.g. PRIu64, SCNu64)
(is_userspace($realfile) ? $var !~ /^(?:PRI|SCN)[dioux][A-Z0-9]+$/ : 1) &&
#Ignore some three character SI units explicitly, like MiB and KHz
$var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[a-z_]+)?$/) {
while ($var =~ m{\b($Ident)}g) {
@ -6673,7 +6699,8 @@ sub process {
}
# prefer usleep_range over udelay
if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) {
if (!is_userspace($realfile) &&
$line =~ /\budelay\s*\(\s*(\d+)\s*\)/) {
my $delay = $1;
# ignore udelay's < 10, however
if (! ($delay < 10) ) {
@ -6687,7 +6714,8 @@ sub process {
}
# warn about unexpectedly long msleep's
if ($line =~ /\bmsleep\s*\((\d+)\);/) {
if (!is_userspace($realfile) &&
$line =~ /\bmsleep\s*\((\d+)\);/) {
if ($1 < 20) {
WARN("MSLEEP",
"msleep < 20ms can sleep for up to 20ms; see function description of msleep().\n" . $herecurr);
@ -6909,7 +6937,7 @@ sub process {
# check for c99 types like uint8_t used outside of uapi/ and tools/
if ($realfile !~ m@\binclude/uapi/@ &&
$realfile !~ m@\btools/@ &&
!is_userspace($realfile) &&
$line =~ /\b($Declare)\s*$Ident\s*[=;,\[]/) {
my $type = $1;
if ($type =~ /\b($typeC99Typedefs)\b/) {
@ -7159,6 +7187,7 @@ sub process {
# check usleep_range arguments
if ($perl_version_ok &&
defined $stat &&
!is_userspace($realfile) &&
$stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) {
my $min = $1;
my $max = $7;
@ -7402,6 +7431,7 @@ sub process {
# check for #defines like: 1 << <digit> that could be BIT(digit), it is not exported to uapi
if ($realfile !~ m@^include/uapi/@ &&
!is_userspace($realfile) &&
$line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) {
my $ull = "";
$ull = "_ULL" if (defined($1) && $1 =~ /ll/i);

View File

@ -66,8 +66,10 @@ my (@stack, $re, $dre, $sub, $x, $xs, $funcre, $min_stack);
#c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp
# or
# 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp
$re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%(e|r)sp$/o;
$dre = qr/^.*[as][du][db] (%.*),\%(e|r)sp$/o;
# or
# 0: 48 81 ec e8 05 00 00 subq $0x5e8, %rsp
$re = qr/^.*[as][du][db][ql]?\s+\$(0x$x{1,8}),\s*\%(e|r)sp/o;
$dre = qr/^.*[as][du][db][ql]?\s+(%.*),\s*\%(e|r)sp/o;
} elsif ($arch eq 'm68k') {
# 2b6c: 4e56 fb70 linkw %fp,#-1168
# 1df770: defc ffe4 addaw #-28,%sp

View File

@ -27,6 +27,24 @@ def entry_to_node(node):
indirect_ptr = node.cast(long_type) & ~constants.LX_RADIX_TREE_INTERNAL_NODE
return indirect_ptr.cast(radix_tree_node_type.get_type().pointer())
def is_node(entry):
# Like xa_is_node(): internal entries below 4096 are sibling, retry
# or zero entries rather than pointers to a struct xa_node.
ulong_type = utils.get_ulong_type()
return is_internal_node(entry) and entry.cast(ulong_type) > 4096
def is_sibling(entry):
# Like xa_is_sibling(): a multi-index entry occupies several slots,
# and all but the first hold a sibling entry that encodes the offset
# of the first one.
ulong_type = utils.get_ulong_type()
return is_internal_node(entry) and entry.cast(ulong_type) < \
xa_mk_internal(constants.LX_RADIX_TREE_MAP_SIZE - 1)
def sibling_offset(entry):
ulong_type = utils.get_ulong_type()
return int(entry.cast(ulong_type)) >> 2
def node_maxindex(node):
return (constants.LX_RADIX_TREE_MAP_SIZE << node['shift']) - 1
@ -40,39 +58,35 @@ def resolve_root(root):
def lookup(root, index):
root = resolve_root(root)
node = root['xa_head']
if node == 0:
entry = root['xa_head']
if is_node(entry):
node = entry_to_node(entry)
if index > node_maxindex(node):
return None
# Walk down the tree like xas_load() does.
while True:
offset = (index >> node['shift']) & constants.LX_RADIX_TREE_MAP_MASK
entry = node['slots'][offset]
while is_sibling(entry):
entry = node['slots'][sibling_offset(entry)]
if node['shift'] and is_node(entry):
# xas_descend() turns this into a retry entry.
return None
if not is_node(entry) or node['shift'] == 0:
break
node = entry_to_node(entry)
elif index > 0:
return None
if not (is_internal_node(node)):
if (index > 0):
return None
return node
node = entry_to_node(node)
maxindex = node_maxindex(node)
if (index > maxindex):
# Empty slots and retry or zero entries hold no data.
if entry == 0 or is_internal_node(entry):
return None
shift = node['shift'] + constants.LX_RADIX_TREE_MAP_SHIFT
while True:
offset = (index >> node['shift']) & constants.LX_RADIX_TREE_MAP_MASK
slot = node['slots'][offset]
if slot == 0:
return None
node = slot.cast(node.type.pointer()).dereference()
if node == 0:
return None
shift -= constants.LX_RADIX_TREE_MAP_SHIFT
if (shift <= 0):
break
return node
return entry
def descend(parent, index):
offset = (index >> int(parent["shift"])) & constants.LX_RADIX_TREE_MAP_MASK

View File

@ -39,7 +39,7 @@ def stack_depot_fetch(handle):
pool_index = parts['pool_index_plus_1'] - 1
if pool_index >= pools_num:
gdb.write("pool index %d out of bounds (%d) for stack id 0x%08x\n" % (parts['pool_index'], pools_num, handle))
gdb.write("pool index %d out of bounds (%d) for stack id 0x%08x\n" % (pool_index, pools_num, handle))
return gdb.Value(0), 0
stack_pools = gdb.parse_and_eval('stack_pools')

View File

@ -872,8 +872,8 @@ infromation||information
ingore||ignore
inheritence||inheritance
inital||initial
initalised||initialized
initalise||initialize
initalised||initialised
initalise||initialise
initalized||initialized
initalize||initialize
initation||initiation

View File

@ -40,6 +40,14 @@ TEST(unshare_EMFILE)
ASSERT_EQ(sscanf(buf, "%d", &nr_open), 1);
/*
* Cap nr_open for the duration of the test to avoid ENOMEM from a
* huge fd table allocation; buf/n keep the real original value so
* fs.nr_open can be restored to it once the test is done.
*/
if (nr_open > 1024 * 1024)
nr_open = 1024 * 1024;
ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
/* bump fs.nr_open */
@ -73,10 +81,13 @@ TEST(unshare_EMFILE)
if (pid == 0) {
int err;
char buf3[32];
ssize_t n3;
/* restore fs.nr_open */
/* restore fs.nr_open to the (possibly capped) test baseline */
n3 = sprintf(buf3, "%d\n", nr_open);
lseek(fd, 0, SEEK_SET);
write(fd, buf, n);
write(fd, buf3, n3);
/* ... and now unshare(CLONE_FILES) must fail with EMFILE */
err = unshare(CLONE_FILES);
EXPECT_EQ(err, -1)
@ -89,6 +100,10 @@ TEST(unshare_EMFILE)
EXPECT_EQ(waitpid(pid, &status, 0), pid);
EXPECT_EQ(true, WIFEXITED(status));
EXPECT_EQ(0, WEXITSTATUS(status));
/* restore the real fs.nr_open value */
lseek(fd, 0, SEEK_SET);
write(fd, buf, n);
}
TEST_HARNESS_MAIN

View File

@ -40,7 +40,7 @@ int main(void)
int fd2 = open("/tmp/aa", O_RDONLY);
ksft_print_header();
ksft_set_plan(4);
ksft_set_plan(5);
unlink("/tmp/aa");
assert(fd != -1);

View File

@ -74,6 +74,24 @@ static void *waiter_entry1ap(void *data)
return NULL;
}
static void *waiter_entry1ap_loop(void *data)
{
struct pollfd pfd;
struct epoll_event e;
struct epoll_mtcontext *ctx = data;
pfd.fd = ctx->efd[0];
pfd.events = POLLIN;
while (poll(&pfd, 1, 2000) > 0) {
if (epoll_wait(ctx->efd[0], &e, 1, 0) > 0) {
__sync_fetch_and_add(&ctx->count, 1);
break;
}
}
return NULL;
}
static void *waiter_entry1o(void *data)
{
struct epoll_event e;
@ -809,7 +827,7 @@ TEST(epoll16)
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.sfd[2], events), 0);
ctx.main = pthread_self();
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap_loop, &ctx), 0);
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
if (epoll_wait(ctx.efd[0], events, 1, -1) > 0)
@ -2925,7 +2943,7 @@ TEST(epoll56)
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
ctx.main = pthread_self();
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap_loop, &ctx), 0);
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
if (epoll_wait(ctx.efd[0], &e, 1, -1) > 0)
@ -3030,7 +3048,6 @@ TEST(epoll57)
TEST(epoll58)
{
pthread_t emitter;
struct pollfd pfd;
struct epoll_event e;
struct epoll_mtcontext ctx = { 0 };
@ -3061,15 +3078,10 @@ TEST(epoll58)
ASSERT_EQ(epoll_ctl(ctx.efd[0], EPOLL_CTL_ADD, ctx.efd[2], &e), 0);
ctx.main = pthread_self();
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap, &ctx), 0);
ASSERT_EQ(pthread_create(&ctx.waiter, NULL, waiter_entry1ap_loop, &ctx), 0);
ASSERT_EQ(pthread_create(&emitter, NULL, emitter_entry2, &ctx), 0);
pfd.fd = ctx.efd[0];
pfd.events = POLLIN;
if (poll(&pfd, 1, -1) > 0) {
if (epoll_wait(ctx.efd[0], &e, 1, 0) > 0)
__sync_fetch_and_add(&ctx.count, 1);
}
waiter_entry1ap_loop(&ctx);
ASSERT_EQ(pthread_join(ctx.waiter, NULL), 0);
EXPECT_EQ(ctx.count, 2);

Some files were not shown because too many files have changed in this diff Show More