Merge branch 'akpm' (incoming from Andrew)
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 3 Apr 2014 23:22:16 +0000 (16:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 3 Apr 2014 23:22:16 +0000 (16:22 -0700)
Merge first patch-bomb from Andrew Morton:
 - Various misc bits
 - kmemleak fixes
 - small befs, codafs, cifs, efs, freexxfs, hfsplus, minixfs, reiserfs things
 - fanotify
 - I appear to have become SuperH maintainer
 - ocfs2 updates
 - direct-io tweaks
 - a bit of the MM queue
 - printk updates
 - MAINTAINERS maintenance
 - some backlight things
 - lib/ updates
 - checkpatch updates
 - the rtc queue
 - nilfs2 updates
 - Small Documentation/ updates

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (237 commits)
  Documentation/SubmittingPatches: remove references to patch-scripts
  Documentation/SubmittingPatches: update some dead URLs
  Documentation/filesystems/ntfs.txt: remove changelog reference
  Documentation/kmemleak.txt: updates
  fs/reiserfs/super.c: add __init to init_inodecache
  fs/reiserfs: move prototype declaration to header file
  fs/hfsplus/attributes.c: add __init to hfsplus_create_attr_tree_cache()
  fs/hfsplus/extents.c: fix concurrent acess of alloc_blocks
  fs/hfsplus/extents.c: remove unused variable in hfsplus_get_block
  nilfs2: update project's web site in nilfs2.txt
  nilfs2: update MAINTAINERS file entries fix
  nilfs2: verify metadata sizes read from disk
  nilfs2: add FITRIM ioctl support for nilfs2
  nilfs2: add nilfs_sufile_trim_fs to trim clean segs
  nilfs2: implementation of NILFS_IOCTL_SET_SUINFO ioctl
  nilfs2: add nilfs_sufile_set_suinfo to update segment usage
  nilfs2: add struct nilfs_suinfo_update and flags
  nilfs2: update MAINTAINERS file entries
  fs/coda/inode.c: add __init to init_inodecache()
  BEFS: logging cleanup
  ...

276 files changed:
CREDITS
Documentation/SubmittingPatches
Documentation/devicetree/bindings/rtc/sunxi-rtc.txt
Documentation/filesystems/nilfs2.txt
Documentation/filesystems/ntfs.txt
Documentation/filesystems/porting
Documentation/ja_JP/SubmittingPatches
Documentation/kmemleak.txt
Documentation/sysctl/vm.txt
Documentation/zh_CN/SubmittingPatches
MAINTAINERS
arch/arm/boot/dts/sun4i-a10.dtsi
arch/score/Kconfig
arch/sh/boards/board-sh7757lcr.c
arch/sh/drivers/pci/pcie-sh7786.h
arch/sh/include/asm/syscalls_32.h
arch/sh/include/asm/traps_32.h
arch/sh/kernel/cpu/sh4a/clock-sh7757.c
arch/sh/kernel/dumpstack.c
arch/sh/kernel/entry-common.S
arch/sh/kernel/signal_32.c
arch/sh/kernel/sys_sh32.c
arch/sh/kernel/traps_32.c
arch/sh/math-emu/math.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/interface.c
drivers/rtc/rtc-as3722.c
drivers/rtc/rtc-at32ap700x.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-coh901331.c
drivers/rtc/rtc-da9052.c
drivers/rtc/rtc-da9055.c
drivers/rtc/rtc-davinci.c
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1347.c [new file with mode: 0644]
drivers/rtc/rtc-ds1390.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-ds1553.c
drivers/rtc/rtc-ds1672.c
drivers/rtc/rtc-ds1742.c
drivers/rtc/rtc-ds3232.c
drivers/rtc/rtc-imxdi.c
drivers/rtc/rtc-isl12057.c
drivers/rtc/rtc-jz4740.c
drivers/rtc/rtc-lpc32xx.c
drivers/rtc/rtc-mc13xxx.c
drivers/rtc/rtc-moxart.c
drivers/rtc/rtc-nuc900.c
drivers/rtc/rtc-palmas.c
drivers/rtc/rtc-pm8xxx.c
drivers/rtc/rtc-rv3029c2.c
drivers/rtc/rtc-rx8025.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-sirfsoc.c
drivers/rtc/rtc-spear.c
drivers/rtc/rtc-stk17ta8.c
drivers/rtc/rtc-sunxi.c
drivers/rtc/rtc-test.c
drivers/rtc/rtc-tx4939.c
drivers/rtc/rtc-vt8500.c
drivers/rtc/rtc-x1205.c
drivers/staging/lustre/lustre/llite/llite_lib.c
drivers/video/backlight/aat2870_bl.c
drivers/video/backlight/adp8860_bl.c
drivers/video/backlight/adp8870_bl.c
drivers/video/backlight/backlight.c
drivers/video/backlight/corgi_lcd.c
drivers/video/backlight/hx8357.c
drivers/video/backlight/ili922x.c
drivers/video/backlight/ili9320.c
drivers/video/backlight/l4f00242t03.c
drivers/video/backlight/lm3533_bl.c
drivers/video/backlight/lms283gf05.c
drivers/video/backlight/platform_lcd.c
drivers/video/backlight/tps65217_bl.c
fs/9p/vfs_inode.c
fs/affs/inode.c
fs/afs/inode.c
fs/befs/Makefile
fs/befs/befs.h
fs/befs/btree.c
fs/befs/datastream.c
fs/befs/debug.c
fs/befs/inode.c
fs/befs/io.c
fs/befs/linuxvfs.c
fs/bfs/inode.c
fs/binfmt_elf.c
fs/binfmt_misc.c
fs/block_dev.c
fs/btrfs/compression.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/cachefiles/rdwr.c
fs/cifs/cifsfs.c
fs/coda/coda_int.h
fs/coda/inode.c
fs/cramfs/inode.c
fs/direct-io.c
fs/drop_caches.c
fs/ecryptfs/super.c
fs/efs/super.c
fs/exec.c
fs/exofs/inode.c
fs/ext2/inode.c
fs/ext3/inode.c
fs/ext4/file.c
fs/ext4/inode.c
fs/f2fs/inode.c
fs/fat/inode.c
fs/filesystems.c
fs/freevxfs/vxfs_inode.c
fs/freevxfs/vxfs_lookup.c
fs/fs-writeback.c
fs/fuse/inode.c
fs/gfs2/super.c
fs/hfs/inode.c
fs/hfsplus/attributes.c
fs/hfsplus/extents.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/super.c
fs/hostfs/hostfs_kern.c
fs/hpfs/inode.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/jffs2/fs.c
fs/jfs/inode.c
fs/kernfs/inode.c
fs/logfs/readwrite.c
fs/minix/inode.c
fs/ncpfs/inode.c
fs/nfs/blocklayout/blocklayout.c
fs/nfs/inode.c
fs/nfs/nfs4super.c
fs/nfsd/auth.c
fs/nilfs2/cpfile.c
fs/nilfs2/dat.c
fs/nilfs2/inode.c
fs/nilfs2/ioctl.c
fs/nilfs2/sufile.c
fs/nilfs2/sufile.h
fs/nilfs2/the_nilfs.c
fs/notify/fanotify/fanotify.c
fs/notify/fanotify/fanotify.h
fs/notify/fanotify/fanotify_user.c
fs/ntfs/inode.c
fs/ocfs2/acl.c
fs/ocfs2/alloc.c
fs/ocfs2/aops.c
fs/ocfs2/aops.h
fs/ocfs2/buffer_head_io.c
fs/ocfs2/cluster/tcp.c
fs/ocfs2/dcache.c
fs/ocfs2/dcache.h
fs/ocfs2/dir.c
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/dlmglue.c
fs/ocfs2/dlmglue.h
fs/ocfs2/file.c
fs/ocfs2/inode.c
fs/ocfs2/inode.h
fs/ocfs2/ioctl.c
fs/ocfs2/journal.c
fs/ocfs2/journal.h
fs/ocfs2/locks.c
fs/ocfs2/move_extents.c
fs/ocfs2/namei.c
fs/ocfs2/ocfs2.h
fs/ocfs2/quota.h
fs/ocfs2/quota_global.c
fs/ocfs2/stackglue.c
fs/ocfs2/suballoc.c
fs/ocfs2/suballoc.h
fs/ocfs2/super.c
fs/ocfs2/sysfile.c
fs/ocfs2/xattr.c
fs/omfs/inode.c
fs/proc/inode.c
fs/quota/dquot.c
fs/reiserfs/inode.c
fs/reiserfs/reiserfs.h
fs/reiserfs/super.c
fs/sysv/inode.c
fs/ubifs/super.c
fs/udf/inode.c
fs/ufs/inode.c
fs/xfs/xfs_super.c
include/linux/backing-dev.h
include/linux/backlight.h
include/linux/cpuset.h
include/linux/cred.h
include/linux/decompress/inflate.h
include/linux/err.h
include/linux/fs.h
include/linux/fsnotify_backend.h
include/linux/hugetlb.h
include/linux/kmemleak.h
include/linux/kobject.h
include/linux/list_lru.h
include/linux/mfd/pm8xxx/rtc.h [deleted file]
include/linux/mm.h
include/linux/mmzone.h
include/linux/nilfs2_fs.h
include/linux/pagemap.h
include/linux/pagevec.h
include/linux/printk.h
include/linux/quotaops.h
include/linux/radix-tree.h
include/linux/shmem_fs.h
include/linux/swap.h
include/linux/syscalls.h
include/linux/vm_event_item.h
include/linux/vmstat.h
include/uapi/linux/libc-compat.h
include/uapi/linux/xattr.h
init/Kconfig
init/do_mounts.c
kernel/cpuset.c
kernel/groups.c
kernel/hung_task.c
kernel/kexec.c
kernel/kthread.c
kernel/printk/printk.c
kernel/profile.c
kernel/resource.c
kernel/sched/stats.c
kernel/sys_ni.c
kernel/sysctl.c
kernel/user.c
kernel/user_namespace.c
kernel/watchdog.c
lib/clz_ctz.c
lib/decompress_inflate.c
lib/devres.c
lib/kobject_uevent.c
lib/radix-tree.c
lib/random32.c
lib/syscall.c
lib/vsprintf.c
mm/Makefile
mm/backing-dev.c
mm/compaction.c
mm/filemap.c
mm/huge_memory.c
mm/hugetlb.c
mm/kmemleak.c
mm/list_lru.c
mm/memory.c
mm/mempolicy.c
mm/mincore.c
mm/mmap.c
mm/nobootmem.c
mm/page_alloc.c
mm/page_cgroup.c
mm/process_vm_access.c
mm/readahead.c
mm/shmem.c
mm/slab.c
mm/slub.c
mm/swap.c
mm/truncate.c
mm/vmscan.c
mm/vmstat.c
mm/workingset.c [new file with mode: 0644]
samples/seccomp/Makefile
scripts/checkpatch.pl
scripts/genksyms/keywords.gperf
scripts/genksyms/keywords.hash.c_shipped
scripts/genksyms/lex.l
scripts/genksyms/lex.lex.c_shipped
scripts/genksyms/parse.tab.c_shipped
scripts/genksyms/parse.tab.h_shipped
scripts/genksyms/parse.y

diff --git a/CREDITS b/CREDITS
index 4f2f45d..61eabf7 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2564,6 +2564,10 @@ N: Wolfgang Muees
 E: wolfgang@iksw-muees.de
 D: Auerswald USB driver
 
+N: Paul Mundt
+E: paul.mundt@gmail.com
+D: SuperH maintainer
+
 N: Ian A. Murdock
 E: imurdock@gnu.ai.mit.edu
 D: Creator of Debian distribution
@@ -2707,6 +2711,9 @@ N: Greg Page
 E: gpage@sovereign.org
 D: IPX development and support
 
+N: Venkatesh Pallipadi (Venki)
+D: x86/HPET
+
 N: David Parsons
 E: orc@pell.chi.il.us
 D: improved memory detection code.
index 26b1e31..2a8e89e 100644 (file)
@@ -14,7 +14,10 @@ Read Documentation/SubmitChecklist for a list of items to check
 before submitting code.  If you are submitting a driver, also read
 Documentation/SubmittingDrivers.
 
-
+Many of these steps describe the default behavior of the git version
+control system; if you use git to prepare your patches, you'll find much
+of the mechanical work done for you, though you'll still need to prepare
+and document a sensible set of patches.
 
 --------------------------------------------
 SECTION 1 - CREATING AND SENDING YOUR CHANGE
@@ -25,7 +28,9 @@ SECTION 1 - CREATING AND SENDING YOUR CHANGE
 1) "diff -up"
 ------------
 
-Use "diff -up" or "diff -uprN" to create patches.
+Use "diff -up" or "diff -uprN" to create patches.  git generates patches
+in this form by default; if you're using git, you can skip this section
+entirely.
 
 All changes to the Linux kernel occur in the form of patches, as
 generated by diff(1).  When creating your patch, make sure to create it
@@ -66,19 +71,14 @@ Make sure your patch does not include any extra files which do not
 belong in a patch submission.  Make sure to review your patch -after-
 generated it with diff(1), to ensure accuracy.
 
-If your changes produce a lot of deltas, you may want to look into
-splitting them into individual patches which modify things in
-logical stages.  This will facilitate easier reviewing by other
-kernel developers, very important if you want your patch accepted.
-There are a number of scripts which can aid in this:
-
-Quilt:
-http://savannah.nongnu.org/projects/quilt
+If your changes produce a lot of deltas, you need to split them into
+individual patches which modify things in logical stages; see section
+#3.  This will facilitate easier reviewing by other kernel developers,
+very important if you want your patch accepted.
 
-Andrew Morton's patch scripts:
-http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz
-Instead of these scripts, quilt is the recommended patch management
-tool (see above).
+If you're using git, "git rebase -i" can help you with this process.  If
+you're not using git, quilt <http://savannah.nongnu.org/projects/quilt>
+is another popular alternative.
 
 
 
@@ -106,8 +106,21 @@ I.e., the patch (series) and its description should be self-contained.
 This benefits both the patch merger(s) and reviewers.  Some reviewers
 probably didn't even receive earlier versions of the patch.
 
+Describe your changes in imperative mood, e.g. "make xyzzy do frotz"
+instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy
+to do frotz", as if you are giving orders to the codebase to change
+its behaviour.
+
 If the patch fixes a logged bug entry, refer to that bug entry by
-number and URL.
+number and URL.  If the patch follows from a mailing list discussion,
+give a URL to the mailing list archive; use the https://lkml.kernel.org/
+redirector with a Message-Id, to ensure that the links cannot become
+stale.
+
+However, try to make your explanation understandable without external
+resources.  In addition to giving a URL to a mailing list archive or
+bug, summarize the relevant points of the discussion that led to the
+patch as submitted.
 
 If you want to refer to a specific commit, don't just refer to the
 SHA-1 ID of the commit. Please also include the oneline summary of
@@ -594,7 +607,8 @@ patch.
 If you are going to include a diffstat after the "---" marker, please
 use diffstat options "-p 1 -w 70" so that filenames are listed from
 the top of the kernel source tree and don't use too much horizontal
-space (easily fit in 80 columns, maybe with some indentation).
+space (easily fit in 80 columns, maybe with some indentation).  (git
+generates appropriate diffstats by default.)
 
 See more details on the proper patch format in the following
 references.
@@ -725,7 +739,7 @@ SECTION 3 - REFERENCES
 ----------------------
 
 Andrew Morton, "The perfect patch" (tpp).
-  <http://userweb.kernel.org/~akpm/stuff/tpp.txt>
+  <http://www.ozlabs.org/~akpm/stuff/tpp.txt>
 
 Jeff Garzik, "Linux kernel patch submission format".
   <http://linux.yyz.us/patch-format.html>
@@ -738,7 +752,7 @@ Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
   <http://www.kroah.com/log/linux/maintainer-05.html>
 
 NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
-  <http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
+  <https://lkml.org/lkml/2005/7/11/336>
 
 Kernel Documentation/CodingStyle:
   <http://users.sosdg.org/~qiyong/lxr/source/Documentation/CodingStyle>
index 7cb9dbf..6983aad 100644 (file)
@@ -3,7 +3,7 @@
 RTC controller for the Allwinner A10/A20
 
 Required properties:
-- compatible : Should be "allwinner,sun4i-rtc" or "allwinner,sun7i-a20-rtc"
+- compatible : Should be "allwinner,sun4i-a10-rtc" or "allwinner,sun7i-a20-rtc"
 - reg: physical base address of the controller and length of memory mapped
   region.
 - interrupts: IRQ line for the RTC.
@@ -11,7 +11,7 @@ Required properties:
 Example:
 
 rtc: rtc@01c20d00 {
-       compatible = "allwinner,sun4i-rtc";
+       compatible = "allwinner,sun4i-a10-rtc";
        reg = <0x01c20d00 0x20>;
        interrupts = <24>;
 };
index 06887d4..41c3d33 100644 (file)
@@ -25,9 +25,8 @@ available from the following download page.  At least "mkfs.nilfs2",
 cleaner or garbage collector) are required.  Details on the tools are
 described in the man pages included in the package.
 
-Project web page:    http://www.nilfs.org/en/
-Download page:       http://www.nilfs.org/en/download.html
-Git tree web page:   http://www.nilfs.org/git/
+Project web page:    http://nilfs.sourceforge.net/
+Download page:       http://nilfs.sourceforge.net/en/download.html
 List info:           http://vger.kernel.org/vger-lists.html#linux-nilfs
 
 Caveats
@@ -111,6 +110,13 @@ Table of NILFS2 specific ioctls
                                nilfs_resize utilities and by nilfs_cleanerd
                                daemon.
 
+ NILFS_IOCTL_SET_SUINFO         Modify segment usage info of requested
+                               segments. This ioctl is used by
+                               nilfs_cleanerd daemon to skip unnecessary
+                               cleaning operation of segments and reduce
+                               performance penalty or wear of flash device
+                               due to redundant move of in-use blocks.
+
  NILFS_IOCTL_GET_SUSTAT         Return segment usage statistics. This ioctl
                                is used in lssu, nilfs_resize utilities and
                                by nilfs_cleanerd daemon.
index 791af8d..61947fa 100644 (file)
@@ -455,8 +455,6 @@ not have this problem with odd numbers of sectors.
 ChangeLog
 =========
 
-Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
-
 2.1.30:
        - Fix writev() (it kept writing the first segment over and over again
          instead of moving onto subsequent segments).
index fe2b7ae..0f3a139 100644 (file)
@@ -295,9 +295,9 @@ in the beginning of ->setattr unconditionally.
        ->clear_inode() and ->delete_inode() are gone; ->evict_inode() should
 be used instead.  It gets called whenever the inode is evicted, whether it has
 remaining links or not.  Caller does *not* evict the pagecache or inode-associated
-metadata buffers; getting rid of those is responsibility of method, as it had
-been for ->delete_inode(). Caller makes sure async writeback cannot be running
-for the inode while (or after) ->evict_inode() is called.
+metadata buffers; the method has to use truncate_inode_pages_final() to get rid
+of those. Caller makes sure async writeback cannot be running for the inode while
+(or after) ->evict_inode() is called.
 
        ->drop_inode() returns int now; it's called on final iput() with
 inode->i_lock held and it returns true if filesystems wants the inode to be
index 97f78dd..5d6ae63 100644 (file)
@@ -98,11 +98,6 @@ dontdiff ファイルには Linux カーネルのビルドプロセスの過程
 Quilt:
 http://savannah.nongnu.org/projects/quilt
 
-Andrew Morton's patch scripts:
-http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz
-このリンクの先のスクリプトの代わりとして、quilt がパッチマネジメント
-ツールとして推奨されています(上のリンクを見てください)。
-
 2) パッチに対する説明
 
 パッチの中の変更点に対する技術的な詳細について説明してください。
@@ -695,7 +690,7 @@ gcc においては、マクロと同じくらい軽いです。
 ----------------------
 
 Andrew Morton, "The perfect patch" (tpp).
-  <http://userweb.kernel.org/~akpm/stuff/tpp.txt>
+  <http://www.ozlabs.org/~akpm/stuff/tpp.txt>
 
 Jeff Garzik, "Linux kernel patch submission format".
   <http://linux.yyz.us/patch-format.html>
@@ -707,7 +702,7 @@ Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
   <http://www.kroah.com/log/2006/01/11/>
 
 NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
-  <http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
+  <https://lkml.org/lkml/2005/7/11/336>
 
 Kernel Documentation/CodingStyle:
   <http://users.sosdg.org/~qiyong/lxr/source/Documentation/CodingStyle>
index b6e3973..a7563ec 100644 (file)
@@ -11,9 +11,7 @@ with the difference that the orphan objects are not freed but only
 reported via /sys/kernel/debug/kmemleak. A similar method is used by the
 Valgrind tool (memcheck --leak-check) to detect the memory leaks in
 user-space applications.
-
-Please check DEBUG_KMEMLEAK dependencies in lib/Kconfig.debug for supported
-architectures.
+Kmemleak is supported on x86, arm, powerpc, sparc, sh, microblaze, ppc, mips, s390, metag and tile.
 
 Usage
 -----
@@ -53,7 +51,8 @@ Memory scanning parameters can be modified at run-time by writing to the
                  (default 600, 0 to stop the automatic scanning)
   scan         - trigger a memory scan
   clear                - clear list of current memory leak suspects, done by
-                 marking all current reported unreferenced objects grey
+                 marking all current reported unreferenced objects grey,
+                 or free all kmemleak objects if kmemleak has been disabled.
   dump=<addr>  - dump information about the object found at <addr>
 
 Kmemleak can also be disabled at boot-time by passing "kmemleak=off" on
@@ -68,7 +67,7 @@ Basic Algorithm
 
 The memory allocations via kmalloc, vmalloc, kmem_cache_alloc and
 friends are traced and the pointers, together with additional
-information like size and stack trace, are stored in a prio search tree.
+information like size and stack trace, are stored in a rbtree.
 The corresponding freeing function calls are tracked and the pointers
 removed from the kmemleak data structures.
 
@@ -84,7 +83,7 @@ The scanning algorithm steps:
   1. mark all objects as white (remaining white objects will later be
      considered orphan)
   2. scan the memory starting with the data section and stacks, checking
-     the values against the addresses stored in the prio search tree. If
+     the values against the addresses stored in the rbtree. If
      a pointer to a white object is found, the object is added to the
      gray list
   3. scan the gray objects for matching addresses (some white objects
@@ -120,6 +119,18 @@ Then as usual to get your report with:
 
   # cat /sys/kernel/debug/kmemleak
 
+Freeing kmemleak internal objects
+---------------------------------
+
+To allow access to previosuly found memory leaks after kmemleak has been
+disabled by the user or due to an fatal error, internal kmemleak objects
+won't be freed when kmemleak is disabled, and those objects may occupy
+a large part of physical memory.
+
+In this situation, you may reclaim memory with:
+
+  # echo clear > /sys/kernel/debug/kmemleak
+
 Kmemleak API
 ------------
 
index d614a9b..dd9d0e3 100644 (file)
@@ -175,18 +175,39 @@ Setting this to zero disables periodic writeback altogether.
 
 drop_caches
 
-Writing to this will cause the kernel to drop clean caches, dentries and
-inodes from memory, causing that memory to become free.
+Writing to this will cause the kernel to drop clean caches, as well as
+reclaimable slab objects like dentries and inodes.  Once dropped, their
+memory becomes free.
 
 To free pagecache:
        echo 1 > /proc/sys/vm/drop_caches
-To free dentries and inodes:
+To free reclaimable slab objects (includes dentries and inodes):
        echo 2 > /proc/sys/vm/drop_caches
-To free pagecache, dentries and inodes:
+To free slab objects and pagecache:
        echo 3 > /proc/sys/vm/drop_caches
 
-As this is a non-destructive operation and dirty objects are not freeable, the
-user should run `sync' first.
+This is a non-destructive operation and will not free any dirty objects.
+To increase the number of objects freed by this operation, the user may run
+`sync' prior to writing to /proc/sys/vm/drop_caches.  This will minimize the
+number of dirty objects on the system and create more candidates to be
+dropped.
+
+This file is not a means to control the growth of the various kernel caches
+(inodes, dentries, pagecache, etc...)  These objects are automatically
+reclaimed by the kernel when memory is needed elsewhere on the system.
+
+Use of this file can cause performance problems.  Since it discards cached
+objects, it may cost a significant amount of I/O and CPU to recreate the
+dropped objects, especially if they were under heavy use.  Because of this,
+use outside of a testing or debugging environment is not recommended.
+
+You may see informational messages in your kernel log when this file is
+used:
+
+       cat (1234): drop_caches: 3
+
+These are informational only.  They do not mean that anything is wrong
+with your system.  To disable them, echo 4 (bit 3) into drop_caches.
 
 ==============================================================
 
index be0bd47..1d3a10f 100644 (file)
@@ -82,10 +82,6 @@ Documentation/SubmittingDrivers 。
 Quilt:
 http://savannah.nongnu.org/projects/quilt
 
-Andrew Morton 的补丁脚本:
-http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz
-作为这些脚本的替代,quilt 是值得推荐的补丁管理工具(看上面的链接)。
-
 2)描述你的改动。
 描述你的改动包含的技术细节。
 
@@ -394,7 +390,7 @@ Static inline 函数相比宏来说,是好得多的选择。Static inline 函
 ----------------
 
 Andrew Morton, "The perfect patch" (tpp).
-  <http://userweb.kernel.org/~akpm/stuff/tpp.txt>
+  <http://www.ozlabs.org/~akpm/stuff/tpp.txt>
 
 Jeff Garzik, "Linux kernel patch submission format".
   <http://linux.yyz.us/patch-format.html>
@@ -406,7 +402,7 @@ Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
   <http://www.kroah.com/log/2006/01/11/>
 
 NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
-  <http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
+  <https://lkml.org/lkml/2005/7/11/336>
 
 Kernel Documentation/CodingStyle:
   <http://sosdg.org/~coywolf/lxr/source/Documentation/CodingStyle>
index 3467445..e1af732 100644 (file)
@@ -1704,6 +1704,8 @@ F:        drivers/net/wireless/b43legacy/
 
 BACKLIGHT CLASS/SUBSYSTEM
 M:     Jingoo Han <jg1.han@samsung.com>
+M:     Bryan Wu <cooloney@gmail.com>
+M:     Lee Jones <lee.jones@linaro.org>
 S:     Maintained
 F:     drivers/video/backlight/
 F:     include/linux/backlight.h
@@ -2728,6 +2730,31 @@ F:       include/linux/device-mapper.h
 F:     include/linux/dm-*.h
 F:     include/uapi/linux/dm-*.h
 
+DIALOG SEMICONDUCTOR DRIVERS
+M:     Support Opensource <support.opensource@diasemi.com>
+W:     http://www.dialog-semiconductor.com/products
+S:     Supported
+F:     Documentation/hwmon/da90??
+F:     drivers/gpio/gpio-da90??.c
+F:     drivers/hwmon/da90??-hwmon.c
+F:     drivers/input/misc/da90??_onkey.c
+F:     drivers/input/touchscreen/da9052_tsi.c
+F:     drivers/leds/leds-da90??.c
+F:     drivers/mfd/da903x.c
+F:     drivers/mfd/da90??-*.c
+F:     drivers/power/da9052-battery.c
+F:     drivers/regulator/da903x.c
+F:     drivers/regulator/da9???-regulator.[ch]
+F:     drivers/rtc/rtc-da90??.c
+F:     drivers/video/backlight/da90??_bl.c
+F:     drivers/watchdog/da90??_wdt.c
+F:     include/linux/mfd/da903x.h
+F:     include/linux/mfd/da9052/
+F:     include/linux/mfd/da9055/
+F:     include/linux/mfd/da9063/
+F:     include/sound/da[79]*.h
+F:     sound/soc/codecs/da[79]*.[ch]
+
 DIGI NEO AND CLASSIC PCI PRODUCTS
 M:     Lidza Louina <lidza.louina@gmail.com>
 L:     driverdev-devel@linuxdriverproject.org
@@ -4128,8 +4155,7 @@ F:        include/linux/hpet.h
 F:     include/uapi/linux/hpet.h
 
 HPET:  x86
-M:     "Venkatesh Pallipadi (Venki)" <venki@google.com>
-S:     Maintained
+S:     Orphan
 F:     arch/x86/kernel/hpet.c
 F:     arch/x86/include/asm/hpet.h
 
@@ -4620,7 +4646,7 @@ F:        arch/x86/kernel/tboot.c
 INTEL WIRELESS WIMAX CONNECTION 2400
 M:     Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
 M:     linux-wimax@intel.com
-L:     wimax@linuxwimax.org
+L:     wimax@linuxwimax.org (subscribers-only)
 S:     Supported
 W:     http://linuxwimax.org
 F:     Documentation/wimax/README.i2400m
@@ -5734,7 +5760,6 @@ F:        fs/imgdafs/
 
 MICROBLAZE ARCHITECTURE
 M:     Michal Simek <monstr@monstr.eu>
-L:     microblaze-uclinux@itee.uq.edu.au (moderated for non-subscribers)
 W:     http://www.monstr.eu/fdt/
 T:     git git://git.monstr.eu/linux-2.6-microblaze.git
 S:     Supported
@@ -6156,10 +6181,10 @@ F:      include/uapi/linux/nfs*
 F:     include/uapi/linux/sunrpc/
 
 NILFS2 FILESYSTEM
-M:     KONISHI Ryusuke <konishi.ryusuke@lab.ntt.co.jp>
+M:     Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
 L:     linux-nilfs@vger.kernel.org
-W:     http://www.nilfs.org/en/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2.git
+W:     http://nilfs.sourceforge.net/
+T:     git git://github.com/konis/nilfs2.git
 S:     Supported
 F:     Documentation/filesystems/nilfs2.txt
 F:     fs/nilfs2/
@@ -8476,12 +8501,10 @@ S:      Maintained
 F:     drivers/net/ethernet/dlink/sundance.c
 
 SUPERH
-M:     Paul Mundt <lethal@linux-sh.org>
 L:     linux-sh@vger.kernel.org
 W:     http://www.linux-sh.org
 Q:     http://patchwork.kernel.org/project/linux-sh/list/
-T:     git git://github.com/pmundt/linux-sh.git sh-latest
-S:     Supported
+S:     Orphan
 F:     Documentation/sh/
 F:     arch/sh/
 F:     drivers/sh/
@@ -8765,6 +8788,7 @@ M:        Max Filippov <jcmvbkbc@gmail.com>
 L:     linux-xtensa@linux-xtensa.org
 S:     Maintained
 F:     arch/xtensa/
+F:     drivers/irqchip/irq-xtensa-*
 
 THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
@@ -9656,7 +9680,7 @@ F:        drivers/media/rc/winbond-cir.c
 WIMAX STACK
 M:     Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
 M:     linux-wimax@intel.com
-L:     wimax@linuxwimax.org
+L:     wimax@linuxwimax.org (subscribers-only)
 S:     Supported
 W:     http://linuxwimax.org
 F:     Documentation/wimax/README.wimax
index 7753be0..9321681 100644 (file)
                };
 
                rtc: rtc@01c20d00 {
-                       compatible = "allwinner,sun4i-rtc";
+                       compatible = "allwinner,sun4i-a10-rtc";
                        reg = <0x01c20d00 0x20>;
                        interrupts = <24>;
                };
index c75d06a..4ac8cae 100644 (file)
@@ -22,27 +22,21 @@ choice
 config ARCH_SCORE7
        bool "SCORE7 processor"
        select SYS_SUPPORTS_32BIT_KERNEL
-       select CPU_SCORE7
        select GENERIC_HAS_IOMAP
 
 config MACH_SPCT6600
        bool "SPCT6600 series based machines"
        select SYS_SUPPORTS_32BIT_KERNEL
-       select CPU_SCORE7
        select GENERIC_HAS_IOMAP
 
 config SCORE_SIM
        bool "Score simulator"
        select SYS_SUPPORTS_32BIT_KERNEL
-       select CPU_SCORE7
        select GENERIC_HAS_IOMAP
 endchoice
 
 endmenu
 
-config CPU_SCORE7
-       bool
-
 config NO_DMA
        bool
        default y
index 25c5a93..669df51 100644 (file)
@@ -252,7 +252,7 @@ static struct sh_mobile_sdhi_info sdhi_info = {
 static struct resource sdhi_resources[] = {
        [0] = {
                .start  = 0xffe50000,
-               .end    = 0xffe501ff,
+               .end    = 0xffe500ff,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
index 1ee054e..4a6ff55 100644 (file)
 /*     PCIERMSGIER     */
 #define        SH4A_PCIERMSGIER        (0x004040)      /* R/W - 0x0000 0000 32 */
 
-/*     PCIEPHYCTLR     */
-#define SH4A_PCIEPHYCTLR       (0x010000)      /* R/W - 0x0000 0000 32 */
-
 /*     PCIEPHYADRR     */
 #define        SH4A_PCIEPHYADRR        (0x010004)      /* R/W - 0x0000 0000 32 */
 #define                BITS_ACK        (24)                    // Rev1.171
index 4f97df8..4f643aa 100644 (file)
@@ -9,15 +9,9 @@
 
 struct pt_regs;
 
-asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5,
-                            unsigned long r6, unsigned long r7,
-                            struct pt_regs __regs);
-asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,
-                               unsigned long r6, unsigned long r7,
-                               struct pt_regs __regs);
-asmlinkage int sys_sh_pipe(unsigned long r4, unsigned long r5,
-                          unsigned long r6, unsigned long r7,
-                          struct pt_regs __regs);
+asmlinkage int sys_sigreturn(void);
+asmlinkage int sys_rt_sigreturn(void);
+asmlinkage int sys_sh_pipe(void);
 asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char __user *buf,
                                     size_t count, long dummy, loff_t pos);
 asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char __user *buf,
index cfd55ff..17e129f 100644 (file)
@@ -42,18 +42,10 @@ static inline void trigger_address_error(void)
 asmlinkage void do_address_error(struct pt_regs *regs,
                                 unsigned long writeaccess,
                                 unsigned long address);
-asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
-                               unsigned long r6, unsigned long r7,
-                               struct pt_regs __regs);
-asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
-                               unsigned long r6, unsigned long r7,
-                               struct pt_regs __regs);
-asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
-                               unsigned long r6, unsigned long r7,
-                               struct pt_regs __regs);
-asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
-                                  unsigned long r6, unsigned long r7,
-                                  struct pt_regs __regs);
+asmlinkage void do_divide_error(unsigned long r4);
+asmlinkage void do_reserved_inst(void);
+asmlinkage void do_illegal_slot_inst(void);
+asmlinkage void do_exception_error(void);
 
 #define BUILD_TRAP_HANDLER(name)                                       \
 asmlinkage void name##_trap_handler(unsigned long r4, unsigned long r5,        \
index e84a432..5c0e3c3 100644 (file)
@@ -132,7 +132,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP103]),
        CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP102]),
        CLKDEV_CON_ID("mmc0", &mstp_clks[MSTP220]),
-       CLKDEV_CON_ID("rspi2", &mstp_clks[MSTP127]),
+       CLKDEV_DEV_ID("rspi.2", &mstp_clks[MSTP127]),
 };
 
 int __init arch_clk_init(void)
index b959f55..8dfe645 100644 (file)
@@ -115,7 +115,7 @@ static int print_trace_stack(void *data, char *name)
  */
 static void print_trace_address(void *data, unsigned long addr, int reliable)
 {
-       printk(data);
+       printk("%s", (char *)data);
        printk_address(addr, reliable);
 }
 
index ca46834..13047a4 100644 (file)
@@ -193,10 +193,10 @@ syscall_trace_entry:
        !                       Reload R0-R4 from kernel stack, where the
        !                       parent may have modified them using
        !                       ptrace(POKEUSR).  (Note that R0-R2 are
-       !                       used by the system call handler directly
-       !                       from the kernel stack anyway, so don't need
-       !                       to be reloaded here.)  This allows the parent
-       !                       to rewrite system calls and args on the fly.
+       !                       reloaded from the kernel stack by syscall_call
+       !                       below, so don't need to be reloaded here.)
+       !                       This allows the parent to rewrite system calls
+       !                       and args on the fly.
        mov.l   @(OFF_R4,r15), r4   ! arg0
        mov.l   @(OFF_R5,r15), r5
        mov.l   @(OFF_R6,r15), r6
@@ -357,8 +357,15 @@ syscall_call:
        mov.l   3f, r8          ! Load the address of sys_call_table
        add     r8, r3
        mov.l   @r3, r8
+       mov.l   @(OFF_R2,r15), r2
+       mov.l   @(OFF_R1,r15), r1
+       mov.l   @(OFF_R0,r15), r0
+       mov.l   r2, @-r15
+       mov.l   r1, @-r15
+       mov.l   r0, @-r15
        jsr     @r8             ! jump to specific syscall handler
         nop
+       add     #12, r15
        mov.l   @(OFF_R0,r15), r12              ! save r0
        mov.l   r0, @(OFF_R0,r15)               ! save the return value
        !
index 6af6e7c..594cd37 100644 (file)
@@ -148,11 +148,9 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p
        return err;
 }
 
-asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5,
-                            unsigned long r6, unsigned long r7,
-                            struct pt_regs __regs)
+asmlinkage int sys_sigreturn(void)
 {
-       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+       struct pt_regs *regs = current_pt_regs();
        struct sigframe __user *frame = (struct sigframe __user *)regs->regs[15];
        sigset_t set;
        int r0;
@@ -180,11 +178,9 @@ badframe:
        return 0;
 }
 
-asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,
-                               unsigned long r6, unsigned long r7,
-                               struct pt_regs __regs)
+asmlinkage int sys_rt_sigreturn(void)
 {
-       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+       struct pt_regs *regs = current_pt_regs();
        struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->regs[15];
        sigset_t set;
        int r0;
index 497bab3..b66d1c6 100644 (file)
  * sys_pipe() is the normal C calling standard for creating
  * a pipe. It's not the way Unix traditionally does this, though.
  */
-asmlinkage int sys_sh_pipe(unsigned long r4, unsigned long r5,
-       unsigned long r6, unsigned long r7,
-       struct pt_regs __regs)
+asmlinkage int sys_sh_pipe(void)
 {
-       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
        int fd[2];
        int error;
 
        error = do_pipe_flags(fd, 0);
        if (!error) {
-               regs->regs[1] = fd[1];
+               current_pt_regs()->regs[1] = fd[1];
                return fd[0];
        }
        return error;
index 68e99f0..ff63934 100644 (file)
@@ -594,9 +594,7 @@ int is_dsp_inst(struct pt_regs *regs)
 #endif /* CONFIG_SH_DSP */
 
 #ifdef CONFIG_CPU_SH2A
-asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
-                               unsigned long r6, unsigned long r7,
-                               struct pt_regs __regs)
+asmlinkage void do_divide_error(unsigned long r4)
 {
        siginfo_t info;
 
@@ -613,11 +611,9 @@ asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
 }
 #endif
 
-asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
-                               unsigned long r6, unsigned long r7,
-                               struct pt_regs __regs)
+asmlinkage void do_reserved_inst(void)
 {
-       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+       struct pt_regs *regs = current_pt_regs();
        unsigned long error_code;
        struct task_struct *tsk = current;
 
@@ -701,11 +697,9 @@ static int emulate_branch(unsigned short inst, struct pt_regs *regs)
 }
 #endif
 
-asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
-                               unsigned long r6, unsigned long r7,
-                               struct pt_regs __regs)
+asmlinkage void do_illegal_slot_inst(void)
 {
-       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+       struct pt_regs *regs = current_pt_regs();
        unsigned long inst;
        struct task_struct *tsk = current;
 
@@ -730,15 +724,12 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
        die_if_no_fixup("illegal slot instruction", regs, inst);
 }
 
-asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
-                                  unsigned long r6, unsigned long r7,
-                                  struct pt_regs __regs)
+asmlinkage void do_exception_error(void)
 {
-       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
        long ex;
 
        ex = lookup_exception_vector();
-       die_if_kernel("exception", regs, ex);
+       die_if_kernel("exception", current_pt_regs(), ex);
 }
 
 void per_cpu_trap_init(void)
index b876780..04aa55f 100644 (file)
@@ -574,24 +574,6 @@ static int ieee_fpe_handler(struct pt_regs *regs)
        return 0;
 }
 
-asmlinkage void do_fpu_error(unsigned long r4, unsigned long r5,
-                            unsigned long r6, unsigned long r7,
-                            struct pt_regs regs)
-{
-       struct task_struct *tsk = current;
-       siginfo_t info;
-
-       if (ieee_fpe_handler (&regs))
-               return;
-
-       regs.pc += 2;
-       info.si_signo = SIGFPE;
-       info.si_errno = 0;
-       info.si_code = FPE_FLTINV;
-       info.si_addr = (void __user *)regs.pc;
-       force_sig_info(SIGFPE, &info, tsk);
-}
-
 /**
  * fpu_init - Initialize FPU registers
  * @fpu: Pointer to software emulated FPU registers.
index db933de..2e565f8 100644 (file)
@@ -573,6 +573,18 @@ config RTC_DRV_DS1305
          This driver can also be built as a module. If so, the module
          will be called rtc-ds1305.
 
+config RTC_DRV_DS1347
+       tristate "Dallas/Maxim DS1347"
+       help
+         If you say yes here you get support for the
+         Dallas/Maxim DS1347 chips.
+
+         This driver only supports the RTC feature, and not other chip
+         features such as alarms.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-ds1347.
+
 config RTC_DRV_DS1390
        tristate "Dallas/Maxim DS1390/93/94"
        help
index b427bf7..40a0991 100644 (file)
@@ -40,6 +40,7 @@ obj-$(CONFIG_RTC_DRV_DS1286)  += rtc-ds1286.o
 obj-$(CONFIG_RTC_DRV_DS1302)   += rtc-ds1302.o
 obj-$(CONFIG_RTC_DRV_DS1305)   += rtc-ds1305.o
 obj-$(CONFIG_RTC_DRV_DS1307)   += rtc-ds1307.o
+obj-$(CONFIG_RTC_DRV_DS1347)   += rtc-ds1347.o
 obj-$(CONFIG_RTC_DRV_DS1374)   += rtc-ds1374.o
 obj-$(CONFIG_RTC_DRV_DS1390)   += rtc-ds1390.o
 obj-$(CONFIG_RTC_DRV_DS1511)   += rtc-ds1511.o
index 544be72..c2eff60 100644 (file)
@@ -584,6 +584,9 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
 void rtc_update_irq(struct rtc_device *rtc,
                unsigned long num, unsigned long events)
 {
+       if (unlikely(IS_ERR_OR_NULL(rtc)))
+               return;
+
        pm_stay_awake(rtc->dev.parent);
        schedule_work(&rtc->irqwork);
 }
index 4af0169..9f38eda 100644 (file)
@@ -242,9 +242,8 @@ static int as3722_rtc_resume(struct device *dev)
 }
 #endif
 
-static const struct dev_pm_ops as3722_rtc_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(as3722_rtc_suspend, as3722_rtc_resume)
-};
+static SIMPLE_DEV_PM_OPS(as3722_rtc_pm_ops, as3722_rtc_suspend,
+                        as3722_rtc_resume);
 
 static struct platform_driver as3722_rtc_driver = {
        .probe = as3722_rtc_probe,
index 3161ab5..aee3387 100644 (file)
@@ -204,10 +204,8 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(struct rtc_at32ap700x),
                           GFP_KERNEL);
-       if (!rtc) {
-               dev_dbg(&pdev->dev, "out of memory\n");
+       if (!rtc)
                return -ENOMEM;
-       }
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs) {
index cae212f..0963c93 100644 (file)
@@ -837,7 +837,7 @@ static void __exit cmos_do_remove(struct device *dev)
        cmos->dev = NULL;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 static int cmos_suspend(struct device *dev)
 {
@@ -935,8 +935,6 @@ static int cmos_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume);
-
 #else
 
 static inline int cmos_poweroff(struct device *dev)
@@ -946,6 +944,8 @@ static inline int cmos_poweroff(struct device *dev)
 
 #endif
 
+static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume);
+
 /*----------------------------------------------------------------*/
 
 /* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus.
@@ -1088,11 +1088,9 @@ static struct pnp_driver cmos_pnp_driver = {
 
        /* flag ensures resume() gets called, and stops syslog spam */
        .flags          = PNP_DRIVER_RES_DO_NOT_CHANGE,
-#ifdef CONFIG_PM_SLEEP
        .driver         = {
                        .pm = &cmos_pm_ops,
        },
-#endif
 };
 
 #endif /* CONFIG_PNP */
index 73f1575..869cae2 100644 (file)
@@ -43,8 +43,6 @@
 struct coh901331_port {
        struct rtc_device *rtc;
        struct clk *clk;
-       u32 phybase;
-       u32 physize;
        void __iomem *virtbase;
        int irq;
 #ifdef CONFIG_PM_SLEEP
@@ -173,19 +171,9 @@ static int __init coh901331_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENOENT;
-
-       rtap->phybase = res->start;
-       rtap->physize = resource_size(res);
-
-       if (devm_request_mem_region(&pdev->dev, rtap->phybase, rtap->physize,
-                                   "rtc-coh901331") == NULL)
-               return -EBUSY;
-
-       rtap->virtbase = devm_ioremap(&pdev->dev, rtap->phybase, rtap->physize);
-       if (!rtap->virtbase)
-               return -ENOMEM;
+       rtap->virtbase  = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(rtap->virtbase))
+               return PTR_ERR(rtap->virtbase);
 
        rtap->irq = platform_get_irq(pdev, 0);
        if (devm_request_irq(&pdev->dev, rtap->irq, coh901331_interrupt, 0,
index 4385ca4..a1cbf64 100644 (file)
@@ -26,7 +26,6 @@
 struct da9052_rtc {
        struct rtc_device *rtc;
        struct da9052 *da9052;
-       int irq;
 };
 
 static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable)
@@ -240,8 +239,7 @@ static int da9052_rtc_probe(struct platform_device *pdev)
 
        rtc->da9052 = dev_get_drvdata(pdev->dev.parent);
        platform_set_drvdata(pdev, rtc);
-       rtc->irq =  DA9052_IRQ_ALARM;
-       ret = da9052_request_irq(rtc->da9052, rtc->irq, "ALM",
+       ret = da9052_request_irq(rtc->da9052, DA9052_IRQ_ALARM, "ALM",
                                da9052_rtc_irq, rtc);
        if (ret != 0) {
                rtc_err(rtc->da9052, "irq registration failed: %d\n", ret);
index 48cb2ac..a825491 100644 (file)
@@ -302,7 +302,9 @@ static int da9055_rtc_probe(struct platform_device *pdev)
        }
 
        alm_irq = platform_get_irq_byname(pdev, "ALM");
-       alm_irq = regmap_irq_get_virq(rtc->da9055->irq_data, alm_irq);
+       if (alm_irq < 0)
+               return alm_irq;
+
        ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL,
                                        da9055_rtc_alm_irq,
                                        IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
index 24677ef..c0a3b59 100644 (file)
@@ -119,8 +119,6 @@ static DEFINE_SPINLOCK(davinci_rtc_lock);
 struct davinci_rtc {
        struct rtc_device               *rtc;
        void __iomem                    *base;
-       resource_size_t                 pbase;
-       size_t                          base_size;
        int                             irq;
 };
 
@@ -482,14 +480,12 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct davinci_rtc *davinci_rtc;
-       struct resource *res, *mem;
+       struct resource *res;
        int ret = 0;
 
        davinci_rtc = devm_kzalloc(&pdev->dev, sizeof(struct davinci_rtc), GFP_KERNEL);
-       if (!davinci_rtc) {
-               dev_dbg(dev, "could not allocate memory for private data\n");
+       if (!davinci_rtc)
                return -ENOMEM;
-       }
 
        davinci_rtc->irq = platform_get_irq(pdev, 0);
        if (davinci_rtc->irq < 0) {
@@ -498,28 +494,9 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(dev, "no mem resource\n");
-               return -EINVAL;
-       }
-
-       davinci_rtc->pbase = res->start;
-       davinci_rtc->base_size = resource_size(res);
-
-       mem = devm_request_mem_region(dev, davinci_rtc->pbase,
-                               davinci_rtc->base_size, pdev->name);
-       if (!mem) {
-               dev_err(dev, "RTC registers at %08x are not free\n",
-                       davinci_rtc->pbase);
-               return -EBUSY;
-       }
-
-       davinci_rtc->base = devm_ioremap(dev, davinci_rtc->pbase,
-                                       davinci_rtc->base_size);
-       if (!davinci_rtc->base) {
-               dev_err(dev, "unable to ioremap MEM resource\n");
-               return -ENOMEM;
-       }
+       davinci_rtc->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(davinci_rtc->base))
+               return PTR_ERR(davinci_rtc->base);
 
        platform_set_drvdata(pdev, davinci_rtc);
 
index 2dd586a..129add7 100644 (file)
@@ -756,19 +756,17 @@ static int ds1305_probe(struct spi_device *spi)
                status = devm_request_irq(&spi->dev, spi->irq, ds1305_irq,
                                0, dev_name(&ds1305->rtc->dev), ds1305);
                if (status < 0) {
-                       dev_dbg(&spi->dev, "request_irq %d --> %d\n",
+                       dev_err(&spi->dev, "request_irq %d --> %d\n",
                                        spi->irq, status);
-                       return status;
+               } else {
+                       device_set_wakeup_capable(&spi->dev, 1);
                }
-
-               device_set_wakeup_capable(&spi->dev, 1);
        }
 
        /* export NVRAM */
        status = sysfs_create_bin_file(&spi->dev.kobj, &nvram);
        if (status < 0) {
-               dev_dbg(&spi->dev, "register nvram --> %d\n", status);
-               return status;
+               dev_err(&spi->dev, "register nvram --> %d\n", status);
        }
 
        return 0;
index 4e75345..f03d5ba 100644 (file)
@@ -154,6 +154,7 @@ static const struct chip_desc chips[last_ds_type] = {
                .alarm          = 1,
        },
        [mcp7941x] = {
+               .alarm          = 1,
                /* this is battery backed SRAM */
                .nvram_offset   = 0x20,
                .nvram_size     = 0x40,
@@ -606,6 +607,178 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
 
 /*----------------------------------------------------------------------*/
 
+/*
+ * Alarm support for mcp7941x devices.
+ */
+
+#define MCP7941X_REG_CONTROL           0x07
+#      define MCP7941X_BIT_ALM0_EN     0x10
+#      define MCP7941X_BIT_ALM1_EN     0x20
+#define MCP7941X_REG_ALARM0_BASE       0x0a
+#define MCP7941X_REG_ALARM0_CTRL       0x0d
+#define MCP7941X_REG_ALARM1_BASE       0x11
+#define MCP7941X_REG_ALARM1_CTRL       0x14
+#      define MCP7941X_BIT_ALMX_IF     (1 << 3)
+#      define MCP7941X_BIT_ALMX_C0     (1 << 4)
+#      define MCP7941X_BIT_ALMX_C1     (1 << 5)
+#      define MCP7941X_BIT_ALMX_C2     (1 << 6)
+#      define MCP7941X_BIT_ALMX_POL    (1 << 7)
+#      define MCP7941X_MSK_ALMX_MATCH  (MCP7941X_BIT_ALMX_C0 | \
+                                        MCP7941X_BIT_ALMX_C1 | \
+                                        MCP7941X_BIT_ALMX_C2)
+
+static void mcp7941x_work(struct work_struct *work)
+{
+       struct ds1307 *ds1307 = container_of(work, struct ds1307, work);
+       struct i2c_client *client = ds1307->client;
+       int reg, ret;
+
+       mutex_lock(&ds1307->rtc->ops_lock);
+
+       /* Check and clear alarm 0 interrupt flag. */
+       reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_ALARM0_CTRL);
+       if (reg < 0)
+               goto out;
+       if (!(reg & MCP7941X_BIT_ALMX_IF))
+               goto out;
+       reg &= ~MCP7941X_BIT_ALMX_IF;
+       ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_ALARM0_CTRL, reg);
+       if (ret < 0)
+               goto out;
+
+       /* Disable alarm 0. */
+       reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL);
+       if (reg < 0)
+               goto out;
+       reg &= ~MCP7941X_BIT_ALM0_EN;
+       ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg);
+       if (ret < 0)
+               goto out;
+
+       rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
+
+out:
+       if (test_bit(HAS_ALARM, &ds1307->flags))
+               enable_irq(client->irq);
+       mutex_unlock(&ds1307->rtc->ops_lock);
+}
+
+static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ds1307 *ds1307 = i2c_get_clientdata(client);
+       u8 *regs = ds1307->regs;
+       int ret;
+
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -EINVAL;
+
+       /* Read control and alarm 0 registers. */
+       ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+       if (ret < 0)
+               return ret;
+
+       t->enabled = !!(regs[0] & MCP7941X_BIT_ALM0_EN);
+
+       /* Report alarm 0 time assuming 24-hour and day-of-month modes. */
+       t->time.tm_sec = bcd2bin(ds1307->regs[3] & 0x7f);
+       t->time.tm_min = bcd2bin(ds1307->regs[4] & 0x7f);
+       t->time.tm_hour = bcd2bin(ds1307->regs[5] & 0x3f);
+       t->time.tm_wday = bcd2bin(ds1307->regs[6] & 0x7) - 1;
+       t->time.tm_mday = bcd2bin(ds1307->regs[7] & 0x3f);
+       t->time.tm_mon = bcd2bin(ds1307->regs[8] & 0x1f) - 1;
+       t->time.tm_year = -1;
+       t->time.tm_yday = -1;
+       t->time.tm_isdst = -1;
+
+       dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
+               "enabled=%d polarity=%d irq=%d match=%d\n", __func__,
+               t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
+               t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled,
+               !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_POL),
+               !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_IF),
+               (ds1307->regs[6] & MCP7941X_MSK_ALMX_MATCH) >> 4);
+
+       return 0;
+}
+
+static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ds1307 *ds1307 = i2c_get_clientdata(client);
+       unsigned char *regs = ds1307->regs;
+       int ret;
+
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -EINVAL;
+
+       dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
+               "enabled=%d pending=%d\n", __func__,
+               t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
+               t->time.tm_wday, t->time.tm_mday, t->time.tm_mon,
+               t->enabled, t->pending);
+
+       /* Read control and alarm 0 registers. */
+       ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+       if (ret < 0)
+               return ret;
+
+       /* Set alarm 0, using 24-hour and day-of-month modes. */
+       regs[3] = bin2bcd(t->time.tm_sec);
+       regs[4] = bin2bcd(t->time.tm_min);
+       regs[5] = bin2bcd(t->time.tm_hour);
+       regs[6] = bin2bcd(t->time.tm_wday) + 1;
+       regs[7] = bin2bcd(t->time.tm_mday);
+       regs[8] = bin2bcd(t->time.tm_mon) + 1;
+
+       /* Clear the alarm 0 interrupt flag. */
+       regs[6] &= ~MCP7941X_BIT_ALMX_IF;
+       /* Set alarm match: second, minute, hour, day, date, month. */
+       regs[6] |= MCP7941X_MSK_ALMX_MATCH;
+
+       if (t->enabled)
+               regs[0] |= MCP7941X_BIT_ALM0_EN;
+       else
+               regs[0] &= ~MCP7941X_BIT_ALM0_EN;
+
+       ret = ds1307->write_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ds1307 *ds1307 = i2c_get_clientdata(client);
+       int reg;
+
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -EINVAL;
+
+       reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL);
+       if (reg < 0)
+               return reg;
+
+       if (enabled)
+               reg |= MCP7941X_BIT_ALM0_EN;
+       else
+               reg &= ~MCP7941X_BIT_ALM0_EN;
+
+       return i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg);
+}
+
+static const struct rtc_class_ops mcp7941x_rtc_ops = {
+       .read_time      = ds1307_get_time,
+       .set_time       = ds1307_set_time,
+       .read_alarm     = mcp7941x_read_alarm,
+       .set_alarm      = mcp7941x_set_alarm,
+       .alarm_irq_enable = mcp7941x_alarm_irq_enable,
+};
+
+/*----------------------------------------------------------------------*/
+
 static ssize_t
 ds1307_nvram_read(struct file *filp, struct kobject *kobj,
                struct bin_attribute *attr,
@@ -678,6 +851,7 @@ static int ds1307_probe(struct i2c_client *client,
                [ds_1339] = DS1339_BIT_BBSQI,
                [ds_3231] = DS3231_BIT_BBSQW,
        };
+       const struct rtc_class_ops *rtc_ops = &ds13xx_rtc_ops;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)
            && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
@@ -816,6 +990,13 @@ static int ds1307_probe(struct i2c_client *client,
        case ds_1388:
                ds1307->offset = 1; /* Seconds starts at 1 */
                break;
+       case mcp7941x:
+               rtc_ops = &mcp7941x_rtc_ops;
+               if (ds1307->client->irq > 0 && chip->alarm) {
+                       INIT_WORK(&ds1307->work, mcp7941x_work);
+                       want_irq = true;
+               }
+               break;
        default:
                break;
        }
@@ -927,55 +1108,61 @@ read_rtc:
                                bin2bcd(tmp));
        }
 
+       device_set_wakeup_capable(&client->dev, want_irq);
        ds1307->rtc = devm_rtc_device_register(&client->dev, client->name,
-                               &ds13xx_rtc_ops, THIS_MODULE);
+                               rtc_ops, THIS_MODULE);
        if (IS_ERR(ds1307->rtc)) {
-               err = PTR_ERR(ds1307->rtc);
-               dev_err(&client->dev,
-                       "unable to register the class device\n");
-               goto exit;
+               return PTR_ERR(ds1307->rtc);
        }
 
        if (want_irq) {
                err = request_irq(client->irq, ds1307_irq, IRQF_SHARED,
                          ds1307->rtc->name, client);
                if (err) {
-                       dev_err(&client->dev,
-                               "unable to request IRQ!\n");
-                       goto exit;
-               }
+                       client->irq = 0;
+                       dev_err(&client->dev, "unable to request IRQ!\n");
+               } else {
 
-               device_set_wakeup_capable(&client->dev, 1);
-               set_bit(HAS_ALARM, &ds1307->flags);
-               dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
+                       set_bit(HAS_ALARM, &ds1307->flags);
+                       dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
+               }
        }
 
        if (chip->nvram_size) {
+
                ds1307->nvram = devm_kzalloc(&client->dev,
                                        sizeof(struct bin_attribute),
                                        GFP_KERNEL);
                if (!ds1307->nvram) {
-                       err = -ENOMEM;
-                       goto err_irq;
+                       dev_err(&client->dev, "cannot allocate memory for nvram sysfs\n");
+               } else {
+
+                       ds1307->nvram->attr.name = "nvram";
+                       ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
+
+                       sysfs_bin_attr_init(ds1307->nvram);
+
+                       ds1307->nvram->read = ds1307_nvram_read;
+                       ds1307->nvram->write = ds1307_nvram_write;
+                       ds1307->nvram->size = chip->nvram_size;
+                       ds1307->nvram_offset = chip->nvram_offset;
+
+                       err = sysfs_create_bin_file(&client->dev.kobj,
+                                                   ds1307->nvram);
+                       if (err) {
+                               dev_err(&client->dev,
+                                       "unable to create sysfs file: %s\n",
+                                       ds1307->nvram->attr.name);
+                       } else {
+                               set_bit(HAS_NVRAM, &ds1307->flags);
+                               dev_info(&client->dev, "%zu bytes nvram\n",
+                                        ds1307->nvram->size);
+                       }
                }
-               ds1307->nvram->attr.name = "nvram";
-               ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
-               sysfs_bin_attr_init(ds1307->nvram);
-               ds1307->nvram->read = ds1307_nvram_read;
-               ds1307->nvram->write = ds1307_nvram_write;
-               ds1307->nvram->size = chip->nvram_size;
-               ds1307->nvram_offset = chip->nvram_offset;
-               err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
-               if (err)
-                       goto err_irq;
-               set_bit(HAS_NVRAM, &ds1307->flags);
-               dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size);
        }
 
        return 0;
 
-err_irq:
-       free_irq(client->irq, client);
 exit:
        return err;
 }
diff --git a/drivers/rtc/rtc-ds1347.c b/drivers/rtc/rtc-ds1347.c
new file mode 100644 (file)
index 0000000..c82b4c0
--- /dev/null
@@ -0,0 +1,166 @@
+/* rtc-ds1347.c
+ *
+ * Driver for Dallas Semiconductor DS1347 Low Current, SPI Compatible
+ * Real Time Clock
+ *
+ * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+
+/* Registers in ds1347 rtc */
+
+#define DS1347_SECONDS_REG     0x01
+#define DS1347_MINUTES_REG     0x03
+#define DS1347_HOURS_REG       0x05
+#define DS1347_DATE_REG                0x07
+#define DS1347_MONTH_REG       0x09
+#define DS1347_DAY_REG         0x0B
+#define DS1347_YEAR_REG                0x0D
+#define DS1347_CONTROL_REG     0x0F
+#define DS1347_STATUS_REG      0x17
+#define DS1347_CLOCK_BURST     0x3F
+
+static int ds1347_read_reg(struct device *dev, unsigned char address,
+                               unsigned char *data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+
+       *data = address | 0x80;
+
+       return spi_write_then_read(spi, data, 1, data, 1);
+}
+
+static int ds1347_write_reg(struct device *dev, unsigned char address,
+                               unsigned char data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       unsigned char buf[2];
+
+       buf[0] = address & 0x7F;
+       buf[1] = data;
+
+       return spi_write_then_read(spi, buf, 2, NULL, 0);
+}
+
+static int ds1347_read_time(struct device *dev, struct rtc_time *dt)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       int err;
+       unsigned char buf[8];
+
+       buf[0] = DS1347_CLOCK_BURST | 0x80;
+
+       err = spi_write_then_read(spi, buf, 1, buf, 8);
+       if (err)
+               return err;
+
+       dt->tm_sec = bcd2bin(buf[0]);
+       dt->tm_min = bcd2bin(buf[1]);
+       dt->tm_hour = bcd2bin(buf[2] & 0x3F);
+       dt->tm_mday = bcd2bin(buf[3]);
+       dt->tm_mon = bcd2bin(buf[4]) - 1;
+       dt->tm_wday = bcd2bin(buf[5]) - 1;
+       dt->tm_year = bcd2bin(buf[6]) + 100;
+
+       return rtc_valid_tm(dt);
+}
+
+static int ds1347_set_time(struct device *dev, struct rtc_time *dt)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       unsigned char buf[9];
+
+       buf[0] = DS1347_CLOCK_BURST & 0x7F;
+       buf[1] = bin2bcd(dt->tm_sec);
+       buf[2] = bin2bcd(dt->tm_min);
+       buf[3] = (bin2bcd(dt->tm_hour) & 0x3F);
+       buf[4] = bin2bcd(dt->tm_mday);
+       buf[5] = bin2bcd(dt->tm_mon + 1);
+       buf[6] = bin2bcd(dt->tm_wday + 1);
+
+       /* year in linux is from 1900 i.e in range of 100
+       in rtc it is from 00 to 99 */
+       dt->tm_year = dt->tm_year % 100;
+
+       buf[7] = bin2bcd(dt->tm_year);
+       buf[8] = bin2bcd(0x00);
+
+       /* write the rtc settings */
+       return spi_write_then_read(spi, buf, 9, NULL, 0);
+}
+
+static const struct rtc_class_ops ds1347_rtc_ops = {
+       .read_time = ds1347_read_time,
+       .set_time = ds1347_set_time,
+};
+
+static int ds1347_probe(struct spi_device *spi)
+{
+       struct rtc_device *rtc;
+       unsigned char data;
+       int res;
+
+       /* spi setup with ds1347 in mode 3 and bits per word as 8 */
+       spi->mode = SPI_MODE_3;
+       spi->bits_per_word = 8;
+       spi_setup(spi);
+
+       /* RTC Settings */
+       res = ds1347_read_reg(&spi->dev, DS1347_SECONDS_REG, &data);
+       if (res)
+               return res;
+
+       /* Disable the write protect of rtc */
+       ds1347_read_reg(&spi->dev, DS1347_CONTROL_REG, &data);
+       data = data & ~(1<<7);
+       ds1347_write_reg(&spi->dev, DS1347_CONTROL_REG, data);
+
+       /* Enable the oscillator , disable the oscillator stop flag,
+        and glitch filter to reduce current consumption */
+       ds1347_read_reg(&spi->dev, DS1347_STATUS_REG, &data);
+       data = data & 0x1B;
+       ds1347_write_reg(&spi->dev, DS1347_STATUS_REG, data);
+
+       /* display the settings */
+       ds1347_read_reg(&spi->dev, DS1347_CONTROL_REG, &data);
+       dev_info(&spi->dev, "DS1347 RTC CTRL Reg = 0x%02x\n", data);
+
+       ds1347_read_reg(&spi->dev, DS1347_STATUS_REG, &data);
+       dev_info(&spi->dev, "DS1347 RTC Status Reg = 0x%02x\n", data);
+
+       rtc = devm_rtc_device_register(&spi->dev, "ds1347",
+                               &ds1347_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       spi_set_drvdata(spi, rtc);
+
+       return 0;
+}
+
+static struct spi_driver ds1347_driver = {
+       .driver = {
+               .name = "ds1347",
+               .owner = THIS_MODULE,
+       },
+       .probe = ds1347_probe,
+};
+
+module_spi_driver(ds1347_driver);
+
+MODULE_DESCRIPTION("DS1347 SPI RTC DRIVER");
+MODULE_AUTHOR("Raghavendra C Ganiga <ravi23ganiga@gmail.com>");
+MODULE_LICENSE("GPL v2");
index be9d8c0..e67bfcb 100644 (file)
@@ -132,10 +132,9 @@ static int ds1390_probe(struct spi_device *spi)
        spi_setup(spi);
 
        chip = devm_kzalloc(&spi->dev, sizeof(*chip), GFP_KERNEL);
-       if (!chip) {
-               dev_err(&spi->dev, "unable to allocate device memory\n");
+       if (!chip)
                return -ENOMEM;
-       }
+
        spi_set_drvdata(spi, chip);
 
        res = ds1390_get_reg(&spi->dev, DS1390_REG_SECONDS, &tmp);
index bc7b4fc..b13d139 100644 (file)
@@ -371,8 +371,7 @@ ds1511_interrupt(int irq, void *dev_id)
                        events |= RTC_UF;
                else
                        events |= RTC_AF;
-               if (likely(pdata->rtc))
-                       rtc_update_irq(pdata->rtc, 1, events);
+               rtc_update_irq(pdata->rtc, 1, events);
        }
        spin_unlock(&pdata->lock);
        return events ? IRQ_HANDLED : IRQ_NONE;
@@ -473,7 +472,6 @@ static struct bin_attribute ds1511_nvram_attr = {
 
 static int ds1511_rtc_probe(struct platform_device *pdev)
 {
-       struct rtc_device *rtc;
        struct resource *res;
        struct rtc_plat_data *pdata;
        int ret = 0;
@@ -512,6 +510,12 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
 
        spin_lock_init(&pdata->lock);
        platform_set_drvdata(pdev, pdata);
+
+       pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+                                             &ds1511_rtc_ops, THIS_MODULE);
+       if (IS_ERR(pdata->rtc))
+               return PTR_ERR(pdata->rtc);
+
        /*
         * if the platform has an interrupt in mind for this device,
         * then by all means, set it
@@ -526,15 +530,12 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
                }
        }
 
-       rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &ds1511_rtc_ops,
-                                       THIS_MODULE);
-       if (IS_ERR(rtc))
-               return PTR_ERR(rtc);
-       pdata->rtc = rtc;
-
        ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
+       if (ret)
+               dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n",
+                       ds1511_nvram_attr.attr.name);
 
-       return ret;
+       return 0;
 }
 
 static int ds1511_rtc_remove(struct platform_device *pdev)
index fd31571..ab56893 100644 (file)
@@ -206,8 +206,7 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)
                        events |= RTC_UF;
                else
                        events |= RTC_AF;
-               if (likely(pdata->rtc))
-                       rtc_update_irq(pdata->rtc, 1, events);
+               rtc_update_irq(pdata->rtc, 1, events);
        }
        spin_unlock(&pdata->lock);
        return events ? IRQ_HANDLED : IRQ_NONE;
@@ -278,7 +277,6 @@ static struct bin_attribute ds1553_nvram_attr = {
 
 static int ds1553_rtc_probe(struct platform_device *pdev)
 {
-       struct rtc_device *rtc;
        struct resource *res;
        unsigned int cen, sec;
        struct rtc_plat_data *pdata;
@@ -311,6 +309,12 @@ static int ds1553_rtc_probe(struct platform_device *pdev)
        spin_lock_init(&pdata->lock);
        pdata->last_jiffies = jiffies;
        platform_set_drvdata(pdev, pdata);
+
+       pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+                                 &ds1553_rtc_ops, THIS_MODULE);
+       if (IS_ERR(pdata->rtc))
+               return PTR_ERR(pdata->rtc);
+
        if (pdata->irq > 0) {
                writeb(0, ioaddr + RTC_INTERRUPTS);
                if (devm_request_irq(&pdev->dev, pdata->irq,
@@ -321,15 +325,12 @@ static int ds1553_rtc_probe(struct platform_device *pdev)
                }
        }
 
-       rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
-                                 &ds1553_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc))
-               return PTR_ERR(rtc);
-       pdata->rtc = rtc;
-
        ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
+       if (ret)
+               dev_err(&pdev->dev, "unable to create sysfs file: %s\n",
+                       ds1553_nvram_attr.attr.name);
 
-       return ret;
+       return 0;
 }
 
 static int ds1553_rtc_remove(struct platform_device *pdev)
index 18e2d84..a4888db 100644 (file)
@@ -177,8 +177,9 @@ static int ds1672_probe(struct i2c_client *client,
 
        /* read control register */
        err = ds1672_get_control(client, &control);
-       if (err)
-               goto exit_devreg;
+       if (err) {
+               dev_warn(&client->dev, "Unable to read the control register\n");
+       }
 
        if (control & DS1672_REG_CONTROL_EOSC)
                dev_warn(&client->dev, "Oscillator not enabled. "
@@ -187,12 +188,10 @@ static int ds1672_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        err = device_create_file(&client->dev, &dev_attr_control);
        if (err)
-               goto exit_devreg;
+               dev_err(&client->dev, "Unable to create sysfs entry: %s\n",
+                       dev_attr_control.attr.name);
 
        return 0;
-
- exit_devreg:
-       return err;
 }
 
 static struct i2c_device_id ds1672_id[] = {
index 5a1f3b2..942103d 100644 (file)
@@ -204,8 +204,11 @@ static int ds1742_rtc_probe(struct platform_device *pdev)
                return PTR_ERR(rtc);
 
        ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr);
+       if (ret)
+               dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n",
+                       pdata->nvram_attr.attr.name);
 
-       return ret;
+       return 0;
 }
 
 static int ds1742_rtc_remove(struct platform_device *pdev)
index b83bb5a..adaf06c 100644 (file)
@@ -57,6 +57,7 @@ struct ds3232 {
         * in the remove function.
         */
        struct mutex mutex;
+       bool suspended;
        int exiting;
 };
 
@@ -345,7 +346,15 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id)
        struct ds3232 *ds3232 = i2c_get_clientdata(client);
 
        disable_irq_nosync(irq);
-       schedule_work(&ds3232->work);
+
+       /*
+        * If rtc as a wakeup source, can't schedule the work
+        * at system resume flow, because at this time the i2c bus
+        * has not been resumed.
+        */
+       if (!ds3232->suspended)
+               schedule_work(&ds3232->work);
+
        return IRQ_HANDLED;
 }
 
@@ -363,22 +372,26 @@ static void ds3232_work(struct work_struct *work)
 
        if (stat & DS3232_REG_SR_A1F) {
                control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
-               if (control < 0)
-                       goto out;
-               /* disable alarm1 interrupt */
-               control &= ~(DS3232_REG_CR_A1IE);
-               i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
-
-               /* clear the alarm pend flag */
-               stat &= ~DS3232_REG_SR_A1F;
-               i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
-
-               rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
+               if (control < 0) {
+                       pr_warn("Read DS3232 Control Register error."
+                               "Disable IRQ%d.\n", client->irq);
+               } else {
+                       /* disable alarm1 interrupt */
+                       control &= ~(DS3232_REG_CR_A1IE);
+                       i2c_smbus_write_byte_data(client, DS3232_REG_CR,
+                                               control);
+
+                       /* clear the alarm pend flag */
+                       stat &= ~DS3232_REG_SR_A1F;
+                       i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
+
+                       rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
+
+                       if (!ds3232->exiting)
+                               enable_irq(client->irq);
+               }
        }
 
-out:
-       if (!ds3232->exiting)
-               enable_irq(client->irq);
 unlock:
        mutex_unlock(&ds3232->mutex);
 }
@@ -411,23 +424,17 @@ static int ds3232_probe(struct i2c_client *client,
        if (ret)
                return ret;
 
-       ds3232->rtc = devm_rtc_device_register(&client->dev, client->name,
-                                         &ds3232_rtc_ops, THIS_MODULE);
-       if (IS_ERR(ds3232->rtc)) {
-               dev_err(&client->dev, "unable to register the class device\n");
-               return PTR_ERR(ds3232->rtc);
-       }
-
-       if (client->irq >= 0) {
-               ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, 0,
-                                "ds3232", client);
+       if (client->irq > 0) {
+               ret = devm_request_irq(&client->dev, client->irq, ds3232_irq,
+                                      IRQF_SHARED, "ds3232", client);
                if (ret) {
                        dev_err(&client->dev, "unable to request IRQ\n");
-                       return ret;
                }
+               device_init_wakeup(&client->dev, 1);
        }
-
-       return 0;
+       ds3232->rtc = devm_rtc_device_register(&client->dev, client->name,
+                                         &ds3232_rtc_ops, THIS_MODULE);
+       return PTR_ERR_OR_ZERO(ds3232->rtc);
 }
 
 static int ds3232_remove(struct i2c_client *client)
@@ -446,6 +453,42 @@ static int ds3232_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int ds3232_suspend(struct device *dev)
+{
+       struct ds3232 *ds3232 = dev_get_drvdata(dev);
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (device_can_wakeup(dev)) {
+               ds3232->suspended = true;
+               irq_set_irq_wake(client->irq, 1);
+       }
+
+       return 0;
+}
+
+static int ds3232_resume(struct device *dev)
+{
+       struct ds3232 *ds3232 = dev_get_drvdata(dev);
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (ds3232->suspended) {
+               ds3232->suspended = false;
+
+               /* Clear the hardware alarm pend flag */
+               schedule_work(&ds3232->work);
+
+               irq_set_irq_wake(client->irq, 0);
+       }
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops ds3232_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume)
+};
+
 static const struct i2c_device_id ds3232_id[] = {
        { "ds3232", 0 },
        { }
@@ -456,6 +499,7 @@ static struct i2c_driver ds3232_driver = {
        .driver = {
                .name = "rtc-ds3232",
                .owner = THIS_MODULE,
+               .pm     = &ds3232_pm_ops,
        },
        .probe = ds3232_probe,
        .remove = ds3232_remove,
index abd7f90..cd741c7 100644 (file)
@@ -401,7 +401,9 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
        imxdi->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(imxdi->clk))
                return PTR_ERR(imxdi->clk);
-       clk_prepare_enable(imxdi->clk);
+       rc = clk_prepare_enable(imxdi->clk);
+       if (rc)
+               return rc;
 
        /*
         * Initialize dryice hardware
index 7854a65..7e5ead9 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/rtc.h>
 #include <linux/i2c.h>
 #include <linux/bcd.h>
-#include <linux/rtc.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/regmap.h>
index 1b126d2..08f5160 100644 (file)
@@ -38,7 +38,6 @@
 #define JZ_RTC_CTRL_ENABLE     BIT(0)
 
 struct jz4740_rtc {
-       struct resource *mem;
        void __iomem *base;
 
        struct rtc_device *rtc;
@@ -216,6 +215,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
        int ret;
        struct jz4740_rtc *rtc;
        uint32_t scratchpad;
+       struct resource *mem;
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
        if (!rtc)
@@ -227,25 +227,10 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
                return -ENOENT;
        }
 
-       rtc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!rtc->mem) {
-               dev_err(&pdev->dev, "Failed to get platform mmio memory\n");
-               return -ENOENT;
-       }
-
-       rtc->mem = devm_request_mem_region(&pdev->dev, rtc->mem->start,
-                                       resource_size(rtc->mem), pdev->name);
-       if (!rtc->mem) {
-               dev_err(&pdev->dev, "Failed to request mmio memory region\n");
-               return -EBUSY;
-       }
-
-       rtc->base = devm_ioremap_nocache(&pdev->dev, rtc->mem->start,
-                                       resource_size(rtc->mem));
-       if (!rtc->base) {
-               dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
-               return -EBUSY;
-       }
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       rtc->base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(rtc->base))
+               return PTR_ERR(rtc->base);
 
        spin_lock_init(&rtc->lock);
 
index bfdbcb8..f130c08 100644 (file)
@@ -211,10 +211,9 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev)
        }
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
-       if (unlikely(!rtc)) {
-               dev_err(&pdev->dev, "Can't allocate memory\n");
+       if (unlikely(!rtc))
                return -ENOMEM;
-       }
+
        rtc->irq = rtcirq;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index 77ea989..0765606 100644 (file)
@@ -23,6 +23,8 @@
 #define MC13XXX_RTCDAY 22
 #define MC13XXX_RTCDAYA        23
 
+#define SEC_PER_DAY    (24 * 60 * 60)
+
 struct mc13xxx_rtc {
        struct rtc_device *rtc;
        struct mc13xxx *mc13xxx;
@@ -42,15 +44,15 @@ static int mc13xxx_rtc_irq_enable_unlocked(struct device *dev,
        return func(priv->mc13xxx, irq);
 }
 
-static int mc13xxx_rtc_irq_enable(struct device *dev,
-               unsigned int enabled, int irq)
+static int mc13xxx_rtc_alarm_irq_enable(struct device *dev,
+                                       unsigned int enabled)
 {
        struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
        int ret;
 
        mc13xxx_lock(priv->mc13xxx);
 
-       ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, irq);
+       ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, MC13XXX_IRQ_TODA);
 
        mc13xxx_unlock(priv->mc13xxx);
 
@@ -61,44 +63,27 @@ static int mc13xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
        unsigned int seconds, days1, days2;
-       unsigned long s1970;
-       int ret;
-
-       mc13xxx_lock(priv->mc13xxx);
-
-       if (!priv->valid) {
-               ret = -ENODATA;
-               goto out;
-       }
 
-       ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1);
-       if (unlikely(ret))
-               goto out;
-
-       ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds);
-       if (unlikely(ret))
-               goto out;
-
-       ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2);
-out:
-       mc13xxx_unlock(priv->mc13xxx);
+       if (!priv->valid)
+               return -ENODATA;
 
-       if (ret)
-               return ret;
+       do {
+               int ret;
 
-       if (days2 == days1 + 1) {
-               if (seconds >= 86400 / 2)
-                       days2 = days1;
-               else
-                       days1 = days2;
-       }
+               ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1);
+               if (ret)
+                       return ret;
 
-       if (days1 != days2)
-               return -EIO;
+               ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds);
+               if (ret)
+                       return ret;
 
-       s1970 = days1 * 86400 + seconds;
+               ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2);
+               if (ret)
+                       return ret;
+       } while (days1 != days2);
 
-       rtc_time_to_tm(s1970, tm);
+       rtc_time_to_tm(days1 * SEC_PER_DAY + seconds, tm);
 
        return rtc_valid_tm(tm);
 }
@@ -110,8 +95,8 @@ static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs)
        unsigned int alarmseconds;
        int ret;
 
-       seconds = secs % 86400;
-       days = secs / 86400;
+       seconds = secs % SEC_PER_DAY;
+       days = secs / SEC_PER_DAY;
 
        mc13xxx_lock(priv->mc13xxx);
 
@@ -123,7 +108,7 @@ static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs)
        if (unlikely(ret))
                goto out;
 
-       if (alarmseconds < 86400) {
+       if (alarmseconds < SEC_PER_DAY) {
                ret = mc13xxx_reg_write(priv->mc13xxx,
                                MC13XXX_RTCTODA, 0x1ffff);
                if (unlikely(ret))
@@ -147,18 +132,21 @@ static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs)
                goto out;
 
        /* restore alarm */
-       if (alarmseconds < 86400) {
+       if (alarmseconds < SEC_PER_DAY) {
                ret = mc13xxx_reg_write(priv->mc13xxx,
                                MC13XXX_RTCTODA, alarmseconds);
                if (unlikely(ret))
                        goto out;
        }
 
-       ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
-       if (unlikely(ret))
-               goto out;
+       if (!priv->valid) {
+               ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
+               if (unlikely(ret))
+                       goto out;
+
+               ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
+       }
 
-       ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
 out:
        priv->valid = !ret;
 
@@ -180,7 +168,7 @@ static int mc13xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &seconds);
        if (unlikely(ret))
                goto out;
-       if (seconds >= 86400) {
+       if (seconds >= SEC_PER_DAY) {
                ret = -ENODATA;
                goto out;
        }
@@ -201,7 +189,7 @@ out:
        alarm->enabled = enabled;
        alarm->pending = pending;
 
-       s1970 = days * 86400 + seconds;
+       s1970 = days * SEC_PER_DAY + seconds;
 
        rtc_time_to_tm(s1970, &alarm->time);
        dev_dbg(dev, "%s: %lu\n", __func__, s1970);
@@ -239,8 +227,8 @@ static int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        if (unlikely(ret))
                goto out;
 
-       seconds = s1970 % 86400;
-       days = s1970 / 86400;
+       seconds = s1970 % SEC_PER_DAY;
+       days = s1970 / SEC_PER_DAY;
 
        ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAYA, days);
        if (unlikely(ret))
@@ -259,8 +247,6 @@ static irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev)
        struct mc13xxx_rtc *priv = dev;
        struct mc13xxx *mc13xxx = priv->mc13xxx;
 
-       dev_dbg(&priv->rtc->dev, "Alarm\n");
-
        rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF);
 
        mc13xxx_irq_ack(mc13xxx, irq);
@@ -273,8 +259,6 @@ static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev)
        struct mc13xxx_rtc *priv = dev;
        struct mc13xxx *mc13xxx = priv->mc13xxx;
 
-       dev_dbg(&priv->rtc->dev, "1HZ\n");
-
        rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF);
 
        mc13xxx_irq_ack(mc13xxx, irq);
@@ -282,12 +266,6 @@ static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
-static int mc13xxx_rtc_alarm_irq_enable(struct device *dev,
-               unsigned int enabled)
-{
-       return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_TODA);
-}
-
 static const struct rtc_class_ops mc13xxx_rtc_ops = {
        .read_time = mc13xxx_rtc_read_time,
        .set_mmss = mc13xxx_rtc_set_mmss,
@@ -301,7 +279,6 @@ static irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev)
        struct mc13xxx_rtc *priv = dev;
        struct mc13xxx *mc13xxx = priv->mc13xxx;
 
-       dev_dbg(&priv->rtc->dev, "RTCRST\n");
        priv->valid = 0;
 
        mc13xxx_irq_mask(mc13xxx, irq);
@@ -314,7 +291,6 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
        int ret;
        struct mc13xxx_rtc *priv;
        struct mc13xxx *mc13xxx;
-       int rtcrst_pending;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -322,60 +298,47 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
 
        mc13xxx = dev_get_drvdata(pdev->dev.parent);
        priv->mc13xxx = mc13xxx;
+       priv->valid = 1;
 
        platform_set_drvdata(pdev, priv);
 
        mc13xxx_lock(mc13xxx);
 
+       mc13xxx_irq_ack(mc13xxx, MC13XXX_IRQ_RTCRST);
+
        ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_RTCRST,
                        mc13xxx_rtc_reset_handler, DRIVER_NAME, priv);
        if (ret)
-               goto err_reset_irq_request;
-
-       ret = mc13xxx_irq_status(mc13xxx, MC13XXX_IRQ_RTCRST,
-                       NULL, &rtcrst_pending);
-       if (ret)
-               goto err_reset_irq_status;
-
-       priv->valid = !rtcrst_pending;
+               goto err_irq_request;
 
-       ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_1HZ,
+       ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_1HZ,
                        mc13xxx_rtc_update_handler, DRIVER_NAME, priv);
        if (ret)
-               goto err_update_irq_request;
+               goto err_irq_request;
 
        ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_TODA,
                        mc13xxx_rtc_alarm_handler, DRIVER_NAME, priv);
        if (ret)
-               goto err_alarm_irq_request;
+               goto err_irq_request;
 
        mc13xxx_unlock(mc13xxx);
 
        priv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
-                                       &mc13xxx_rtc_ops, THIS_MODULE);
-       if (IS_ERR(priv->rtc)) {
-               ret = PTR_ERR(priv->rtc);
+                                            &mc13xxx_rtc_ops, THIS_MODULE);
 
-               mc13xxx_lock(mc13xxx);
-
-               mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv);
-err_alarm_irq_request:
-
-               mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv);
-err_update_irq_request:
-
-err_reset_irq_status:
+       return 0;
 
-               mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv);
-err_reset_irq_request:
+err_irq_request:
+       mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv);
+       mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv);
+       mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv);
 
-               mc13xxx_unlock(mc13xxx);
-       }
+       mc13xxx_unlock(mc13xxx);
 
        return ret;
 }
 
-static int __exit mc13xxx_rtc_remove(struct platform_device *pdev)
+static int mc13xxx_rtc_remove(struct platform_device *pdev)
 {
        struct mc13xxx_rtc *priv = platform_get_drvdata(pdev);
 
@@ -404,7 +367,7 @@ MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable);
 
 static struct platform_driver mc13xxx_rtc_driver = {
        .id_table = mc13xxx_rtc_idtable,
-       .remove = __exit_p(mc13xxx_rtc_remove),
+       .remove = mc13xxx_rtc_remove,
        .driver = {
                .name = DRIVER_NAME,
                .owner = THIS_MODULE,
index c29dee0..c318462 100644 (file)
@@ -247,10 +247,8 @@ static int moxart_rtc_probe(struct platform_device *pdev)
        int ret = 0;
 
        moxart_rtc = devm_kzalloc(&pdev->dev, sizeof(*moxart_rtc), GFP_KERNEL);
-       if (!moxart_rtc) {
-               dev_err(&pdev->dev, "devm_kzalloc failed\n");
+       if (!moxart_rtc)
                return -ENOMEM;
-       }
 
        moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node,
                                                  "gpio-rtc-data", 0);
index 248653c..a53da09 100644 (file)
@@ -229,10 +229,9 @@ static int __init nuc900_rtc_probe(struct platform_device *pdev)
 
        nuc900_rtc = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_rtc),
                                GFP_KERNEL);
-       if (!nuc900_rtc) {
-               dev_err(&pdev->dev, "kzalloc nuc900_rtc failed\n");
+       if (!nuc900_rtc)
                return -ENOMEM;
-       }
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        nuc900_rtc->rtc_reg = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(nuc900_rtc->rtc_reg))
index fffb7d3..c360d62 100644 (file)
@@ -348,9 +348,8 @@ static int palmas_rtc_resume(struct device *dev)
 }
 #endif
 
-static const struct dev_pm_ops palmas_rtc_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(palmas_rtc_suspend, palmas_rtc_resume)
-};
+static SIMPLE_DEV_PM_OPS(palmas_rtc_pm_ops, palmas_rtc_suspend,
+                        palmas_rtc_resume);
 
 #ifdef CONFIG_OF
 static struct of_device_id of_palmas_rtc_match[] = {
index 03f8f75..197699f 100644 (file)
@@ -9,18 +9,16 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-
+#include <linux/of.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/rtc.h>
+#include <linux/platform_device.h>
 #include <linux/pm.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
-#include <linux/mfd/pm8xxx/core.h>
-#include <linux/mfd/pm8xxx/rtc.h>
-
-
 /* RTC Register offsets from RTC CTRL REG */
 #define PM8XXX_ALARM_CTRL_OFFSET       0x01
 #define PM8XXX_RTC_WRITE_OFFSET                0x02
@@ -37,6 +35,8 @@
 /**
  * struct pm8xxx_rtc -  rtc driver internal structure
  * @rtc:               rtc device for this driver.
+ * @regmap:            regmap used to access RTC registers
+ * @allow_set_time:    indicates whether writing to the RTC is allowed
  * @rtc_alarm_irq:     rtc alarm irq number.
  * @rtc_base:          address of rtc control register.
  * @rtc_read_base:     base address of read registers.
  */
 struct pm8xxx_rtc {
        struct rtc_device *rtc;
+       struct regmap *regmap;
+       bool allow_set_time;
        int rtc_alarm_irq;
        int rtc_base;
        int rtc_read_base;
        int rtc_write_base;
        int alarm_rw_base;
-       u8  ctrl_reg;
+       u8 ctrl_reg;
        struct device *rtc_dev;
        spinlock_t ctrl_reg_lock;
 };
 
-/*
- * The RTC registers need to be read/written one byte at a time. This is a
- * hardware limitation.
- */
-static int pm8xxx_read_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val,
-               int base, int count)
-{
-       int i, rc;
-       struct device *parent = rtc_dd->rtc_dev->parent;
-
-       for (i = 0; i < count; i++) {
-               rc = pm8xxx_readb(parent, base + i, &rtc_val[i]);
-               if (rc < 0) {
-                       dev_err(rtc_dd->rtc_dev, "PMIC read failed\n");
-                       return rc;
-               }
-       }
-
-       return 0;
-}
-
-static int pm8xxx_write_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val,
-               int base, int count)
-{
-       int i, rc;
-       struct device *parent = rtc_dd->rtc_dev->parent;
-
-       for (i = 0; i < count; i++) {
-               rc = pm8xxx_writeb(parent, base + i, rtc_val[i]);
-               if (rc < 0) {
-                       dev_err(rtc_dd->rtc_dev, "PMIC write failed\n");
-                       return rc;
-               }
-       }
-
-       return 0;
-}
-
 /*
  * Steps to write the RTC registers.
  * 1. Disable alarm if enabled.
@@ -107,9 +71,12 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        int rc, i;
        unsigned long secs, irq_flags;
-       u8 value[NUM_8_BIT_RTC_REGS], reg = 0, alarm_enabled = 0, ctrl_reg;
+       u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, ctrl_reg;
        struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
 
+       if (!rtc_dd->allow_set_time)
+               return -EACCES;
+
        rtc_tm_to_time(tm, &secs);
 
        for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
@@ -125,47 +92,43 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
        if (ctrl_reg & PM8xxx_RTC_ALARM_ENABLE) {
                alarm_enabled = 1;
                ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
-               rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
-                               1);
-               if (rc < 0) {
-                       dev_err(dev, "Write to RTC control register "
-                                                               "failed\n");
+               rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+               if (rc) {
+                       dev_err(dev, "Write to RTC control register failed\n");
                        goto rtc_rw_fail;
                }
                rtc_dd->ctrl_reg = ctrl_reg;
-       } else
+       } else {
                spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
+       }
 
        /* Write 0 to Byte[0] */
-       reg = 0;
-       rc = pm8xxx_write_wrapper(rtc_dd, &reg, rtc_dd->rtc_write_base, 1);
-       if (rc < 0) {
+       rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_write_base, 0);
+       if (rc) {
                dev_err(dev, "Write to RTC write data register failed\n");
                goto rtc_rw_fail;
        }
 
        /* Write Byte[1], Byte[2], Byte[3] */
-       rc = pm8xxx_write_wrapper(rtc_dd, value + 1,
-                                       rtc_dd->rtc_write_base + 1, 3);
-       if (rc < 0) {
+       rc = regmap_bulk_write(rtc_dd->regmap, rtc_dd->rtc_write_base + 1,
+                              &value[1], sizeof(value) - 1);
+       if (rc) {
                dev_err(dev, "Write to RTC write data register failed\n");
                goto rtc_rw_fail;
        }
 
        /* Write Byte[0] */
-       rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->rtc_write_base, 1);
-       if (rc < 0) {
+       rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_write_base, value[0]);
+       if (rc) {
                dev_err(dev, "Write to RTC write data register failed\n");
                goto rtc_rw_fail;
        }
 
        if (alarm_enabled) {
                ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE;
-               rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
-                                                                       1);
-               if (rc < 0) {
-                       dev_err(dev, "Write to RTC control register "
-                                                               "failed\n");
+               rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+               if (rc) {
+                       dev_err(dev, "Write to RTC control register failed\n");
                        goto rtc_rw_fail;
                }
                rtc_dd->ctrl_reg = ctrl_reg;
@@ -181,13 +144,14 @@ rtc_rw_fail:
 static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        int rc;
-       u8 value[NUM_8_BIT_RTC_REGS], reg;
+       u8 value[NUM_8_BIT_RTC_REGS];
        unsigned long secs;
+       unsigned int reg;
        struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
 
-       rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->rtc_read_base,
-                                                       NUM_8_BIT_RTC_REGS);
-       if (rc < 0) {
+       rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->rtc_read_base,
+                             value, sizeof(value));
+       if (rc) {
                dev_err(dev, "RTC read data register failed\n");
                return rc;
        }
@@ -196,16 +160,16 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
         * Read the LSB again and check if there has been a carry over.
         * If there is, redo the read operation.
         */
-       rc = pm8xxx_read_wrapper(rtc_dd, &reg, rtc_dd->rtc_read_base, 1);
+       rc = regmap_read(rtc_dd->regmap, rtc_dd->rtc_read_base, &reg);
        if (rc < 0) {
                dev_err(dev, "RTC read data register failed\n");
                return rc;
        }
 
        if (unlikely(reg < value[0])) {
-               rc = pm8xxx_read_wrapper(rtc_dd, value,
-                               rtc_dd->rtc_read_base, NUM_8_BIT_RTC_REGS);
-               if (rc < 0) {
+               rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->rtc_read_base,
+                                     value, sizeof(value));
+               if (rc) {
                        dev_err(dev, "RTC read data register failed\n");
                        return rc;
                }
@@ -222,8 +186,8 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
        }
 
        dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n",
-                               secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
-                               tm->tm_mday, tm->tm_mon, tm->tm_year);
+               secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
+               tm->tm_mday, tm->tm_mon, tm->tm_year);
 
        return 0;
 }
@@ -244,19 +208,22 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 
        spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
 
-       rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base,
-                                                       NUM_8_BIT_RTC_REGS);
-       if (rc < 0) {
+       rc = regmap_bulk_write(rtc_dd->regmap, rtc_dd->alarm_rw_base, value,
+                              sizeof(value));
+       if (rc) {
                dev_err(dev, "Write to RTC ALARM register failed\n");
                goto rtc_rw_fail;
        }
 
        ctrl_reg = rtc_dd->ctrl_reg;
-       ctrl_reg = alarm->enabled ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
-                                       (ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE);
 
-       rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
-       if (rc < 0) {
+       if (alarm->enabled)
+               ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE;
+       else
+               ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
+
+       rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+       if (rc) {
                dev_err(dev, "Write to RTC control register failed\n");
                goto rtc_rw_fail;
        }
@@ -264,9 +231,9 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        rtc_dd->ctrl_reg = ctrl_reg;
 
        dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
-                               alarm->time.tm_hour, alarm->time.tm_min,
-                               alarm->time.tm_sec, alarm->time.tm_mday,
-                               alarm->time.tm_mon, alarm->time.tm_year);
+               alarm->time.tm_hour, alarm->time.tm_min,
+               alarm->time.tm_sec, alarm->time.tm_mday,
+               alarm->time.tm_mon, alarm->time.tm_year);
 rtc_rw_fail:
        spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
        return rc;
@@ -279,9 +246,9 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        unsigned long secs;
        struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
 
-       rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base,
-                       NUM_8_BIT_RTC_REGS);
-       if (rc < 0) {
+       rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->alarm_rw_base, value,
+                             sizeof(value));
+       if (rc) {
                dev_err(dev, "RTC alarm time read failed\n");
                return rc;
        }
@@ -297,9 +264,9 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        }
 
        dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
-                               alarm->time.tm_hour, alarm->time.tm_min,
-                               alarm->time.tm_sec, alarm->time.tm_mday,
-                               alarm->time.tm_mon, alarm->time.tm_year);
+               alarm->time.tm_hour, alarm->time.tm_min,
+               alarm->time.tm_sec, alarm->time.tm_mday,
+               alarm->time.tm_mon, alarm->time.tm_year);
 
        return 0;
 }
@@ -312,12 +279,16 @@ static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
        u8 ctrl_reg;
 
        spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
+
        ctrl_reg = rtc_dd->ctrl_reg;
-       ctrl_reg = (enable) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
-                               (ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE);
 
-       rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
-       if (rc < 0) {
+       if (enable)
+               ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE;
+       else
+               ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
+
+       rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+       if (rc) {
                dev_err(dev, "Write to RTC control register failed\n");
                goto rtc_rw_fail;
        }
@@ -329,8 +300,9 @@ rtc_rw_fail:
        return rc;
 }
 
-static struct rtc_class_ops pm8xxx_rtc_ops = {
+static const struct rtc_class_ops pm8xxx_rtc_ops = {
        .read_time      = pm8xxx_rtc_read_time,
+       .set_time       = pm8xxx_rtc_set_time,
        .set_alarm      = pm8xxx_rtc_set_alarm,
        .read_alarm     = pm8xxx_rtc_read_alarm,
        .alarm_irq_enable = pm8xxx_rtc_alarm_irq_enable,
@@ -339,7 +311,7 @@ static struct rtc_class_ops pm8xxx_rtc_ops = {
 static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)
 {
        struct pm8xxx_rtc *rtc_dd = dev_id;
-       u8 ctrl_reg;
+       unsigned int ctrl_reg;
        int rc;
        unsigned long irq_flags;
 
@@ -351,11 +323,11 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)
        ctrl_reg = rtc_dd->ctrl_reg;
        ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
 
-       rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
-       if (rc < 0) {
+       rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+       if (rc) {
                spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
-               dev_err(rtc_dd->rtc_dev, "Write to RTC control register "
-                                                               "failed\n");
+               dev_err(rtc_dd->rtc_dev,
+                       "Write to RTC control register failed\n");
                goto rtc_alarm_handled;
        }
 
@@ -363,61 +335,71 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)
        spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
 
        /* Clear RTC alarm register */
-       rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base +
-                                               PM8XXX_ALARM_CTRL_OFFSET, 1);
-       if (rc < 0) {
-               dev_err(rtc_dd->rtc_dev, "RTC Alarm control register read "
-                                                               "failed\n");
+       rc = regmap_read(rtc_dd->regmap,
+                        rtc_dd->rtc_base + PM8XXX_ALARM_CTRL_OFFSET,
+                        &ctrl_reg);
+       if (rc) {
+               dev_err(rtc_dd->rtc_dev,
+                       "RTC Alarm control register read failed\n");
                goto rtc_alarm_handled;
        }
 
        ctrl_reg &= ~PM8xxx_RTC_ALARM_CLEAR;
-       rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base +
-                                               PM8XXX_ALARM_CTRL_OFFSET, 1);
-       if (rc < 0)
-               dev_err(rtc_dd->rtc_dev, "Write to RTC Alarm control register"
-                                                               " failed\n");
+       rc = regmap_write(rtc_dd->regmap,
+                         rtc_dd->rtc_base + PM8XXX_ALARM_CTRL_OFFSET,
+                         ctrl_reg);
+       if (rc)
+               dev_err(rtc_dd->rtc_dev,
+                       "Write to RTC Alarm control register failed\n");
 
 rtc_alarm_handled:
        return IRQ_HANDLED;
 }
 
+/*
+ * Hardcoded RTC bases until IORESOURCE_REG mapping is figured out
+ */
+static const struct of_device_id pm8xxx_id_table[] = {
+       { .compatible = "qcom,pm8921-rtc", .data = (void *) 0x11D },
+       { .compatible = "qcom,pm8058-rtc", .data = (void *) 0x1E8 },
+       { },
+};
+MODULE_DEVICE_TABLE(of, pm8xxx_id_table);
+
 static int pm8xxx_rtc_probe(struct platform_device *pdev)
 {
        int rc;
-       u8 ctrl_reg;
-       bool rtc_write_enable = false;
+       unsigned int ctrl_reg;
        struct pm8xxx_rtc *rtc_dd;
-       struct resource *rtc_resource;
-       const struct pm8xxx_rtc_platform_data *pdata =
-                                               dev_get_platdata(&pdev->dev);
+       const struct of_device_id *match;
 
-       if (pdata != NULL)
-               rtc_write_enable = pdata->rtc_write_enable;
+       match = of_match_node(pm8xxx_id_table, pdev->dev.of_node);
+       if (!match)
+               return -ENXIO;
 
        rtc_dd = devm_kzalloc(&pdev->dev, sizeof(*rtc_dd), GFP_KERNEL);
-       if (rtc_dd == NULL) {
-               dev_err(&pdev->dev, "Unable to allocate memory!\n");
+       if (rtc_dd == NULL)
                return -ENOMEM;
-       }
 
        /* Initialise spinlock to protect RTC control register */
        spin_lock_init(&rtc_dd->ctrl_reg_lock);
 
+       rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!rtc_dd->regmap) {
+               dev_err(&pdev->dev, "Parent regmap unavailable.\n");
+               return -ENXIO;
+       }
+
        rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0);
        if (rtc_dd->rtc_alarm_irq < 0) {
                dev_err(&pdev->dev, "Alarm IRQ resource absent!\n");
                return -ENXIO;
        }
 
-       rtc_resource = platform_get_resource_byname(pdev, IORESOURCE_IO,
-                                                       "pmic_rtc_base");
-       if (!(rtc_resource && rtc_resource->start)) {
-               dev_err(&pdev->dev, "RTC IO resource absent!\n");
-               return -ENXIO;
-       }
+       rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
+                                                     "allow-set-time");
 
-       rtc_dd->rtc_base = rtc_resource->start;
+       rtc_dd->rtc_base = (long) match->data;
 
        /* Setup RTC register addresses */
        rtc_dd->rtc_write_base = rtc_dd->rtc_base + PM8XXX_RTC_WRITE_OFFSET;
@@ -427,64 +409,52 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
        rtc_dd->rtc_dev = &pdev->dev;
 
        /* Check if the RTC is on, else turn it on */
-       rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
-       if (rc < 0) {
+       rc = regmap_read(rtc_dd->regmap, rtc_dd->rtc_base, &ctrl_reg);
+       if (rc) {
                dev_err(&pdev->dev, "RTC control register read failed!\n");
                return rc;
        }
 
        if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) {
                ctrl_reg |= PM8xxx_RTC_ENABLE;
-               rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
-                                                                       1);
-               if (rc < 0) {
-                       dev_err(&pdev->dev, "Write to RTC control register "
-                                                               "failed\n");
+               rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg);
+               if (rc) {
+                       dev_err(&pdev->dev,
+                               "Write to RTC control register failed\n");
                        return rc;
                }
        }
 
        rtc_dd->ctrl_reg = ctrl_reg;
-       if (rtc_write_enable == true)
-               pm8xxx_rtc_ops.set_time = pm8xxx_rtc_set_time;
 
        platform_set_drvdata(pdev, rtc_dd);
 
+       device_init_wakeup(&pdev->dev, 1);
+
        /* Register the RTC device */
        rtc_dd->rtc = devm_rtc_device_register(&pdev->dev, "pm8xxx_rtc",
-                               &pm8xxx_rtc_ops, THIS_MODULE);
+                                              &pm8xxx_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc_dd->rtc)) {
                dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n",
-                                       __func__, PTR_ERR(rtc_dd->rtc));
+                       __func__, PTR_ERR(rtc_dd->rtc));
                return PTR_ERR(rtc_dd->rtc);
        }
 
        /* Request the alarm IRQ */
-       rc = request_any_context_irq(rtc_dd->rtc_alarm_irq,
-                                pm8xxx_alarm_trigger, IRQF_TRIGGER_RISING,
-                                "pm8xxx_rtc_alarm", rtc_dd);
+       rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->rtc_alarm_irq,
+                                         pm8xxx_alarm_trigger,
+                                         IRQF_TRIGGER_RISING,
+                                         "pm8xxx_rtc_alarm", rtc_dd);
        if (rc < 0) {
                dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc);
                return rc;
        }
 
-       device_init_wakeup(&pdev->dev, 1);
-
        dev_dbg(&pdev->dev, "Probe success !!\n");
 
        return 0;
 }
 
-static int pm8xxx_rtc_remove(struct platform_device *pdev)
-{
-       struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
-
-       device_init_wakeup(&pdev->dev, 0);
-       free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int pm8xxx_rtc_resume(struct device *dev)
 {
@@ -507,15 +477,17 @@ static int pm8xxx_rtc_suspend(struct device *dev)
 }
 #endif
 
-static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume);
+static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops,
+                        pm8xxx_rtc_suspend,
+                        pm8xxx_rtc_resume);
 
 static struct platform_driver pm8xxx_rtc_driver = {
        .probe          = pm8xxx_rtc_probe,
-       .remove         = pm8xxx_rtc_remove,
        .driver = {
-               .name   = PM8XXX_RTC_DEV_NAME,
-               .owner  = THIS_MODULE,
-               .pm     = &pm8xxx_rtc_pm_ops,
+               .name           = "rtc-pm8xxx",
+               .owner          = THIS_MODULE,
+               .pm             = &pm8xxx_rtc_pm_ops,
+               .of_match_table = pm8xxx_id_table,
        },
 };
 
index 1a779a6..e9ac5a4 100644 (file)
@@ -395,6 +395,12 @@ static int rv3029c2_probe(struct i2c_client *client,
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL))
                return -ENODEV;
 
+       rc = rv3029c2_i2c_get_sr(client, buf);
+       if (rc < 0) {
+               dev_err(&client->dev, "reading status failed\n");
+               return rc;
+       }
+
        rtc = devm_rtc_device_register(&client->dev, client->name,
                                        &rv3029c2_rtc_ops, THIS_MODULE);
 
@@ -403,12 +409,6 @@ static int rv3029c2_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, rtc);
 
-       rc = rv3029c2_i2c_get_sr(client, buf);
-       if (rc < 0) {
-               dev_err(&client->dev, "reading status failed\n");
-               return rc;
-       }
-
        return 0;
 }
 
index 8fa23ea..e6298e0 100644 (file)
@@ -551,7 +551,6 @@ static int rx8025_probe(struct i2c_client *client,
 
        rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL);
        if (!rx8025) {
-               dev_err(&adapter->dev, "failed to alloc memory\n");
                err = -ENOMEM;
                goto errout;
        }
index c4cde9c..4958a36 100644 (file)
@@ -48,8 +48,8 @@ struct s3c_rtc_drv_data {
 
 static struct clk *rtc_clk;
 static void __iomem *s3c_rtc_base;
-static int s3c_rtc_alarmno = NO_IRQ;
-static int s3c_rtc_tickno  = NO_IRQ;
+static int s3c_rtc_alarmno;
+static int s3c_rtc_tickno;
 static enum s3c_cpu_type s3c_rtc_cpu_type;
 
 static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
index 3eb3642..76e3800 100644 (file)
@@ -264,12 +264,8 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)
 
        rtcdrv = devm_kzalloc(&pdev->dev,
                sizeof(struct sirfsoc_rtc_drv), GFP_KERNEL);
-       if (rtcdrv == NULL) {
-               dev_err(&pdev->dev,
-                       "%s: can't alloc mem for drv struct\n",
-                       pdev->name);
+       if (rtcdrv == NULL)
                return -ENOMEM;
-       }
 
        err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base);
        if (err) {
@@ -335,39 +331,29 @@ static int sirfsoc_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
 static int sirfsoc_rtc_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
+       struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);
        rtcdrv->overflow_rtc =
                sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE);
 
        rtcdrv->saved_counter =
                sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
        rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc;
-       if (device_may_wakeup(&pdev->dev) && !enable_irq_wake(rtcdrv->irq))
+       if (device_may_wakeup(dev) && !enable_irq_wake(rtcdrv->irq))
                rtcdrv->irq_wake = 1;
 
        return 0;
 }
 
-static int sirfsoc_rtc_freeze(struct device *dev)
-{
-       sirfsoc_rtc_suspend(dev);
-
-       return 0;
-}
-
-static int sirfsoc_rtc_thaw(struct device *dev)
+static int sirfsoc_rtc_resume(struct device *dev)
 {
        u32 tmp;
-       struct sirfsoc_rtc_drv *rtcdrv;
-       rtcdrv = dev_get_drvdata(dev);
+       struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);
 
        /*
-        * if resume from snapshot and the rtc power is losed,
+        * if resume from snapshot and the rtc power is lost,
         * restroe the rtc settings
         */
        if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl(
@@ -407,57 +393,23 @@ static int sirfsoc_rtc_thaw(struct device *dev)
        sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc,
                        rtcdrv->rtc_base + RTC_SW_VALUE);
 
-       return 0;
-}
-
-static int sirfsoc_rtc_resume(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
-       sirfsoc_rtc_thaw(dev);
-       if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) {
+       if (device_may_wakeup(dev) && rtcdrv->irq_wake) {
                disable_irq_wake(rtcdrv->irq);
                rtcdrv->irq_wake = 0;
        }
 
        return 0;
 }
-
-static int sirfsoc_rtc_restore(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
-
-       if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) {
-               disable_irq_wake(rtcdrv->irq);
-               rtcdrv->irq_wake = 0;
-       }
-       return 0;
-}
-
-#else
-#define sirfsoc_rtc_suspend    NULL
-#define sirfsoc_rtc_resume     NULL
-#define sirfsoc_rtc_freeze     NULL
-#define sirfsoc_rtc_thaw       NULL
-#define sirfsoc_rtc_restore    NULL
 #endif
 
-static const struct dev_pm_ops sirfsoc_rtc_pm_ops = {
-       .suspend = sirfsoc_rtc_suspend,
-       .resume = sirfsoc_rtc_resume,
-       .freeze = sirfsoc_rtc_freeze,
-       .thaw = sirfsoc_rtc_thaw,
-       .restore = sirfsoc_rtc_restore,
-};
+static SIMPLE_DEV_PM_OPS(sirfsoc_rtc_pm_ops,
+               sirfsoc_rtc_suspend, sirfsoc_rtc_resume);
 
 static struct platform_driver sirfsoc_rtc_driver = {
        .driver = {
                .name = "sirfsoc-rtc",
                .owner = THIS_MODULE,
-#ifdef CONFIG_PM
                .pm = &sirfsoc_rtc_pm_ops,
-#endif
                .of_match_table = sirfsoc_rtc_of_match,
        },
        .probe = sirfsoc_rtc_probe,
index c492cf0..d2cdb98 100644 (file)
@@ -365,10 +365,8 @@ static int spear_rtc_probe(struct platform_device *pdev)
        }
 
        config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
-       if (!config) {
-               dev_err(&pdev->dev, "out of memory\n");
+       if (!config)
                return -ENOMEM;
-       }
 
        /* alarm irqs */
        irq = platform_get_irq(pdev, 0);
index a176ba6..35ed49e 100644 (file)
@@ -214,8 +214,7 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
                        events |= RTC_UF;
                else
                        events |= RTC_AF;
-               if (likely(pdata->rtc))
-                       rtc_update_irq(pdata->rtc, 1, events);
+               rtc_update_irq(pdata->rtc, 1, events);
        }
        spin_unlock(&pdata->lock);
        return events ? IRQ_HANDLED : IRQ_NONE;
index 68a3528..b6f21f7 100644 (file)
@@ -428,7 +428,7 @@ static const struct rtc_class_ops sunxi_rtc_ops = {
 };
 
 static const struct of_device_id sunxi_rtc_dt_ids[] = {
-       { .compatible = "allwinner,sun4i-rtc", .data = &data_year_param[0] },
+       { .compatible = "allwinner,sun4i-a10-rtc", .data = &data_year_param[0] },
        { .compatible = "allwinner,sun7i-a20-rtc", .data = &data_year_param[1] },
        { /* sentinel */ },
 };
index 7746e65..6599c20 100644 (file)
@@ -104,20 +104,17 @@ static int test_probe(struct platform_device *plat_dev)
        rtc = devm_rtc_device_register(&plat_dev->dev, "test",
                                &test_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc)) {
-               err = PTR_ERR(rtc);
-               return err;
+               return PTR_ERR(rtc);
        }
 
        err = device_create_file(&plat_dev->dev, &dev_attr_irq);
        if (err)
-               goto err;
+               dev_err(&plat_dev->dev, "Unable to create sysfs entry: %s\n",
+                       dev_attr_irq.attr.name);
 
        platform_set_drvdata(plat_dev, rtc);
 
        return 0;
-
-err:
-       return err;
 }
 
 static int test_remove(struct platform_device *plat_dev)
index 4f87234..2e678c6 100644 (file)
@@ -176,8 +176,8 @@ static irqreturn_t tx4939_rtc_interrupt(int irq, void *dev_id)
                tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP);
        }
        spin_unlock(&pdata->lock);
-       if (likely(pdata->rtc))
-               rtc_update_irq(pdata->rtc, 1, events);
+       rtc_update_irq(pdata->rtc, 1, events);
+
        return IRQ_HANDLED;
 }
 
index df2ef3e..051da96 100644 (file)
@@ -79,7 +79,6 @@
 
 struct vt8500_rtc {
        void __iomem            *regbase;
-       struct resource         *res;
        int                     irq_alarm;
        struct rtc_device       *rtc;
        spinlock_t              lock;           /* Protects this structure */
@@ -209,6 +208,7 @@ static const struct rtc_class_ops vt8500_rtc_ops = {
 static int vt8500_rtc_probe(struct platform_device *pdev)
 {
        struct vt8500_rtc *vt8500_rtc;
+       struct resource *res;
        int ret;
 
        vt8500_rtc = devm_kzalloc(&pdev->dev,
@@ -219,34 +219,16 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
        spin_lock_init(&vt8500_rtc->lock);
        platform_set_drvdata(pdev, vt8500_rtc);
 
-       vt8500_rtc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!vt8500_rtc->res) {
-               dev_err(&pdev->dev, "No I/O memory resource defined\n");
-               return -ENXIO;
-       }
-
        vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0);
        if (vt8500_rtc->irq_alarm < 0) {
                dev_err(&pdev->dev, "No alarm IRQ resource defined\n");
                return vt8500_rtc->irq_alarm;
        }
 
-       vt8500_rtc->res = devm_request_mem_region(&pdev->dev,
-                                       vt8500_rtc->res->start,
-                                       resource_size(vt8500_rtc->res),
-                                       "vt8500-rtc");
-       if (vt8500_rtc->res == NULL) {
-               dev_err(&pdev->dev, "failed to request I/O memory\n");
-               return -EBUSY;
-       }
-
-       vt8500_rtc->regbase = devm_ioremap(&pdev->dev, vt8500_rtc->res->start,
-                                     resource_size(vt8500_rtc->res));
-       if (!vt8500_rtc->regbase) {
-               dev_err(&pdev->dev, "Unable to map RTC I/O memory\n");
-               ret = -EBUSY;
-               goto err_return;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       vt8500_rtc->regbase = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(vt8500_rtc->regbase))
+               return PTR_ERR(vt8500_rtc->regbase);
 
        /* Enable RTC and set it to 24-hour mode */
        writel(VT8500_RTC_CR_ENABLE,
index 365dc65..b1de58e 100644 (file)
@@ -660,7 +660,7 @@ static int x1205_probe(struct i2c_client *client,
 
        err = x1205_sysfs_register(&client->dev);
        if (err)
-               return err;
+               dev_err(&client->dev, "Unable to create sysfs entries\n");
 
        return 0;
 }
index 26003d3..7c4fd97 100644 (file)
@@ -1877,7 +1877,7 @@ void ll_delete_inode(struct inode *inode)
                cl_sync_file_range(inode, 0, OBD_OBJECT_EOF,
                                   CL_FSYNC_DISCARD, 1);
 
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
 
        /* Workaround for LU-118 */
        if (inode->i_data.nrpages) {
index ee0c0a9..ec5350f 100644 (file)
@@ -149,8 +149,6 @@ static int aat2870_bl_probe(struct platform_device *pdev)
                                  sizeof(struct aat2870_bl_driver_data),
                                  GFP_KERNEL);
        if (!aat2870_bl) {
-               dev_err(&pdev->dev,
-                       "Failed to allocate memory for aat2870 backlight\n");
                ret = -ENOMEM;
                goto out;
        }
index 9d65671..be8d83d 100644 (file)
@@ -224,10 +224,8 @@ static int adp8860_led_probe(struct i2c_client *client)
 
        led = devm_kzalloc(&client->dev, sizeof(*led) * pdata->num_leds,
                                GFP_KERNEL);
-       if (led == NULL) {
-               dev_err(&client->dev, "failed to alloc memory\n");
+       if (led == NULL)
                return -ENOMEM;
-       }
 
        ret = adp8860_write(client, ADP8860_ISCFR, pdata->led_fade_law);
        ret = adp8860_write(client, ADP8860_ISCT1,
index 6370720..251af4d 100644 (file)
@@ -246,10 +246,8 @@ static int adp8870_led_probe(struct i2c_client *client)
 
        led = devm_kzalloc(&client->dev, pdata->num_leds * sizeof(*led),
                                GFP_KERNEL);
-       if (led == NULL) {
-               dev_err(&client->dev, "failed to alloc memory\n");
+       if (led == NULL)
                return -ENOMEM;
-       }
 
        ret = adp8870_write(client, ADP8870_ISCLAW, pdata->led_fade_law);
        if (ret)
index 5d05555..27d3cf2 100644 (file)
@@ -34,13 +34,15 @@ static const char *const backlight_types[] = {
                           defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
 /* This callback gets called when something important happens inside a
  * framebuffer driver. We're looking if that important event is blanking,
- * and if it is, we're switching backlight power as well ...
+ * and if it is and necessary, we're switching backlight power as well ...
  */
 static int fb_notifier_callback(struct notifier_block *self,
                                unsigned long event, void *data)
 {
        struct backlight_device *bd;
        struct fb_event *evdata = data;
+       int node = evdata->info->node;
+       int fb_blank = 0;
 
        /* If we aren't interested in this event, skip it immediately ... */
        if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK)
@@ -51,12 +53,24 @@ static int fb_notifier_callback(struct notifier_block *self,
        if (bd->ops)
                if (!bd->ops->check_fb ||
                    bd->ops->check_fb(bd, evdata->info)) {
-                       bd->props.fb_blank = *(int *)evdata->data;
-                       if (bd->props.fb_blank == FB_BLANK_UNBLANK)
-                               bd->props.state &= ~BL_CORE_FBBLANK;
-                       else
-                               bd->props.state |= BL_CORE_FBBLANK;
-                       backlight_update_status(bd);
+                       fb_blank = *(int *)evdata->data;
+                       if (fb_blank == FB_BLANK_UNBLANK &&
+                           !bd->fb_bl_on[node]) {
+                               bd->fb_bl_on[node] = true;
+                               if (!bd->use_count++) {
+                                       bd->props.state &= ~BL_CORE_FBBLANK;
+                                       bd->props.fb_blank = FB_BLANK_UNBLANK;
+                                       backlight_update_status(bd);
+                               }
+                       } else if (fb_blank != FB_BLANK_UNBLANK &&
+                                  bd->fb_bl_on[node]) {
+                               bd->fb_bl_on[node] = false;
+                               if (!(--bd->use_count)) {
+                                       bd->props.state |= BL_CORE_FBBLANK;
+                                       bd->props.fb_blank = fb_blank;
+                                       backlight_update_status(bd);
+                               }
+                       }
                }
        mutex_unlock(&bd->ops_lock);
        return 0;
index db8db5f..51d18d6 100644 (file)
@@ -543,10 +543,8 @@ static int corgi_lcd_probe(struct spi_device *spi)
        }
 
        lcd = devm_kzalloc(&spi->dev, sizeof(struct corgi_lcd), GFP_KERNEL);
-       if (!lcd) {
-               dev_err(&spi->dev, "failed to allocate memory\n");
+       if (!lcd)
                return -ENOMEM;
-       }
 
        lcd->spi_dev = spi;
 
index 985e854..23f50b9 100644 (file)
@@ -587,10 +587,8 @@ static int hx8357_probe(struct spi_device *spi)
        int i, ret;
 
        lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL);
-       if (!lcd) {
-               dev_err(&spi->dev, "Couldn't allocate lcd internal structure!\n");
+       if (!lcd)
                return -ENOMEM;
-       }
 
        ret = spi_setup(spi);
        if (ret < 0) {
index 73464e4..ea67fe1 100644 (file)
@@ -482,10 +482,8 @@ static int ili922x_probe(struct spi_device *spi)
        u16 reg = 0;
 
        ili = devm_kzalloc(&spi->dev, sizeof(*ili), GFP_KERNEL);
-       if (!ili) {
-               dev_err(&spi->dev, "cannot alloc priv data\n");
+       if (!ili)
                return -ENOMEM;
-       }
 
        ili->spi = spi;
        spi_set_drvdata(spi, ili);
index e2b8b40..2cf39e6 100644 (file)
@@ -219,10 +219,8 @@ int ili9320_probe_spi(struct spi_device *spi,
        /* allocate and initialse our state */
 
        ili = devm_kzalloc(&spi->dev, sizeof(struct ili9320), GFP_KERNEL);
-       if (ili == NULL) {
-               dev_err(dev, "no memory for device\n");
+       if (ili == NULL)
                return -ENOMEM;
-       }
 
        ili->access.spi.id = ILI9320_SPI_IDCODE | ILI9320_SPI_ID(1);
 
index 63e7638..5fa2649 100644 (file)
@@ -181,11 +181,8 @@ static int l4f00242t03_probe(struct spi_device *spi)
 
        priv = devm_kzalloc(&spi->dev, sizeof(struct l4f00242t03_priv),
                                GFP_KERNEL);
-
-       if (priv == NULL) {
-               dev_err(&spi->dev, "No memory for this device.\n");
+       if (priv == NULL)
                return -ENOMEM;
-       }
 
        spi_set_drvdata(spi, priv);
        spi->bits_per_word = 9;
index 187d1c2..cff1fbe 100644 (file)
@@ -296,11 +296,8 @@ static int lm3533_bl_probe(struct platform_device *pdev)
        }
 
        bl = devm_kzalloc(&pdev->dev, sizeof(*bl), GFP_KERNEL);
-       if (!bl) {
-               dev_err(&pdev->dev,
-                               "failed to allocate memory for backlight\n");
+       if (!bl)
                return -ENOMEM;
-       }
 
        bl->lm3533 = lm3533;
        bl->id = pdev->id;
index de88325..14590c5 100644 (file)
@@ -168,10 +168,8 @@ static int lms283gf05_probe(struct spi_device *spi)
 
        st = devm_kzalloc(&spi->dev, sizeof(struct lms283gf05_state),
                                GFP_KERNEL);
-       if (st == NULL) {
-               dev_err(&spi->dev, "No memory for device state\n");
+       if (st == NULL)
                return -ENOMEM;
-       }
 
        ld = devm_lcd_device_register(&spi->dev, "lms283gf05", &spi->dev, st,
                                        &lms_ops);
index d01884d..c3d2e20 100644 (file)
@@ -94,10 +94,8 @@ static int platform_lcd_probe(struct platform_device *pdev)
 
        plcd = devm_kzalloc(&pdev->dev, sizeof(struct platform_lcd),
                            GFP_KERNEL);
-       if (!plcd) {
-               dev_err(dev, "no memory for state\n");
+       if (!plcd)
                return -ENOMEM;
-       }
 
        plcd->us = dev;
        plcd->pdata = pdata;
index cbba37e..595dcf5 100644 (file)
@@ -200,7 +200,6 @@ tps65217_bl_parse_dt(struct platform_device *pdev)
 
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata) {
-               dev_err(&pdev->dev, "failed to allocate platform data\n");
                err = ERR_PTR(-ENOMEM);
                goto err;
        }
@@ -296,10 +295,8 @@ static int tps65217_bl_probe(struct platform_device *pdev)
 
        tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl),
                                GFP_KERNEL);
-       if (tps65217_bl == NULL) {
-               dev_err(&pdev->dev, "allocation of struct tps65217_bl failed\n");
+       if (tps65217_bl == NULL)
                return -ENOMEM;
-       }
 
        tps65217_bl->tps = tps;
        tps65217_bl->dev = &pdev->dev;
index bb7991c..53161ec 100644 (file)
@@ -451,7 +451,7 @@ void v9fs_evict_inode(struct inode *inode)
 {
        struct v9fs_inode *v9inode = V9FS_I(inode);
 
-       truncate_inode_pages(inode->i_mapping, 0);
+       truncate_inode_pages_final(inode->i_mapping);
        clear_inode(inode);
        filemap_fdatawrite(inode->i_mapping);
 
index 0e092d0..96df91e 100644 (file)
@@ -259,7 +259,7 @@ affs_evict_inode(struct inode *inode)
 {
        unsigned long cache_page;
        pr_debug("AFFS: evict_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
 
        if (!inode->i_nlink) {
                inode->i_size = 0;
index ce25d75..2946712 100644 (file)
@@ -422,7 +422,7 @@ void afs_evict_inode(struct inode *inode)
 
        ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode);
 
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
 
        afs_give_up_callback(vnode);
index 2f370bd..8b9f666 100644 (file)
@@ -3,5 +3,5 @@
 #
  
 obj-$(CONFIG_BEFS_FS) += befs.o
-
+ccflags-$(CONFIG_BEFS_DEBUG)    += -DDEBUG
 befs-objs := datastream.o btree.o super.o inode.o debug.o io.o linuxvfs.o
index b266428..3a7813a 100644 (file)
@@ -88,8 +88,11 @@ enum befs_err {
 
 /****************************/
 /* debug.c */
+__printf(2, 3)
 void befs_error(const struct super_block *sb, const char *fmt, ...);
+__printf(2, 3)
 void befs_warning(const struct super_block *sb, const char *fmt, ...);
+__printf(2, 3)
 void befs_debug(const struct super_block *sb, const char *fmt, ...);
 
 void befs_dump_super_block(const struct super_block *sb, befs_super_block *);
index 74e397d..a2cd305 100644 (file)
@@ -137,7 +137,7 @@ befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
        struct buffer_head *bh = NULL;
        befs_disk_btree_super *od_sup = NULL;
 
-       befs_debug(sb, "---> befs_btree_read_super()");
+       befs_debug(sb, "---> %s", __func__);
 
        bh = befs_read_datastream(sb, ds, 0, NULL);
 
@@ -162,11 +162,11 @@ befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
                goto error;
        }
 
-       befs_debug(sb, "<--- befs_btree_read_super()");
+       befs_debug(sb, "<--- %s", __func__);
        return BEFS_OK;
 
       error:
-       befs_debug(sb, "<--- befs_btree_read_super() ERROR");
+       befs_debug(sb, "<--- %s ERROR", __func__);
        return BEFS_ERR;
 }
 
@@ -195,16 +195,16 @@ befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
 {
        uint off = 0;
 
-       befs_debug(sb, "---> befs_bt_read_node()");
+       befs_debug(sb, "---> %s", __func__);
 
        if (node->bh)
                brelse(node->bh);
 
        node->bh = befs_read_datastream(sb, ds, node_off, &off);
        if (!node->bh) {
-               befs_error(sb, "befs_bt_read_node() failed to read "
-                          "node at %Lu", node_off);
-               befs_debug(sb, "<--- befs_bt_read_node() ERROR");
+               befs_error(sb, "%s failed to read "
+                          "node at %llu", __func__, node_off);
+               befs_debug(sb, "<--- %s ERROR", __func__);
 
                return BEFS_ERR;
        }
@@ -221,7 +221,7 @@ befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
        node->head.all_key_length =
            fs16_to_cpu(sb, node->od_node->all_key_length);
 
-       befs_debug(sb, "<--- befs_btree_read_node()");
+       befs_debug(sb, "<--- %s", __func__);
        return BEFS_OK;
 }
 
@@ -252,7 +252,7 @@ befs_btree_find(struct super_block *sb, befs_data_stream * ds,
        befs_off_t node_off;
        int res;
 
-       befs_debug(sb, "---> befs_btree_find() Key: %s", key);
+       befs_debug(sb, "---> %s Key: %s", __func__, key);
 
        if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) {
                befs_error(sb,
@@ -263,7 +263,7 @@ befs_btree_find(struct super_block *sb, befs_data_stream * ds,
        this_node = kmalloc(sizeof (befs_btree_node),
                                                GFP_NOFS);
        if (!this_node) {
-               befs_error(sb, "befs_btree_find() failed to allocate %u "
+               befs_error(sb, "befs_btree_find() failed to allocate %zu "
                           "bytes of memory", sizeof (befs_btree_node));
                goto error;
        }
@@ -274,7 +274,7 @@ befs_btree_find(struct super_block *sb, befs_data_stream * ds,
        node_off = bt_super.root_node_ptr;
        if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) {
                befs_error(sb, "befs_btree_find() failed to read "
-                          "node at %Lu", node_off);
+                          "node at %llu", node_off);
                goto error_alloc;
        }
 
@@ -285,7 +285,7 @@ befs_btree_find(struct super_block *sb, befs_data_stream * ds,
                /* if no match, go to overflow node */
                if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) {
                        befs_error(sb, "befs_btree_find() failed to read "
-                                  "node at %Lu", node_off);
+                                  "node at %llu", node_off);
                        goto error_alloc;
                }
        }
@@ -298,11 +298,11 @@ befs_btree_find(struct super_block *sb, befs_data_stream * ds,
        kfree(this_node);
 
        if (res != BEFS_BT_MATCH) {
-               befs_debug(sb, "<--- befs_btree_find() Key %s not found", key);
+               befs_debug(sb, "<--- %s Key %s not found", __func__, key);
                *value = 0;
                return BEFS_BT_NOT_FOUND;
        }
-       befs_debug(sb, "<--- befs_btree_find() Found key %s, value %Lu",
+       befs_debug(sb, "<--- %s Found key %s, value %llu", __func__,
                   key, *value);
        return BEFS_OK;
 
@@ -310,7 +310,7 @@ befs_btree_find(struct super_block *sb, befs_data_stream * ds,
        kfree(this_node);
       error:
        *value = 0;
-       befs_debug(sb, "<--- befs_btree_find() ERROR");
+       befs_debug(sb, "<--- %s ERROR", __func__);
        return BEFS_ERR;
 }
 
@@ -343,7 +343,7 @@ befs_find_key(struct super_block *sb, befs_btree_node * node,
        char *thiskey;
        fs64 *valarray;
 
-       befs_debug(sb, "---> befs_find_key() %s", findkey);
+       befs_debug(sb, "---> %s %s", __func__, findkey);
 
        *value = 0;
 
@@ -355,7 +355,7 @@ befs_find_key(struct super_block *sb, befs_btree_node * node,
 
        eq = befs_compare_strings(thiskey, keylen, findkey, findkey_len);
        if (eq < 0) {
-               befs_debug(sb, "<--- befs_find_key() %s not found", findkey);
+               befs_debug(sb, "<--- %s %s not found", __func__, findkey);
                return BEFS_BT_NOT_FOUND;
        }
 
@@ -373,8 +373,8 @@ befs_find_key(struct super_block *sb, befs_btree_node * node,
                                          findkey_len);
 
                if (eq == 0) {
-                       befs_debug(sb, "<--- befs_find_key() found %s at %d",
-                                  thiskey, mid);
+                       befs_debug(sb, "<--- %s found %s at %d",
+                                  __func__, thiskey, mid);
 
                        *value = fs64_to_cpu(sb, valarray[mid]);
                        return BEFS_BT_MATCH;
@@ -388,7 +388,7 @@ befs_find_key(struct super_block *sb, befs_btree_node * node,
                *value = fs64_to_cpu(sb, valarray[mid + 1]);
        else
                *value = fs64_to_cpu(sb, valarray[mid]);
-       befs_debug(sb, "<--- befs_find_key() found %s at %d", thiskey, mid);
+       befs_debug(sb, "<--- %s found %s at %d", __func__, thiskey, mid);
        return BEFS_BT_PARMATCH;
 }
 
@@ -428,7 +428,7 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
 
        uint key_sum = 0;
 
-       befs_debug(sb, "---> befs_btree_read()");
+       befs_debug(sb, "---> %s", __func__);
 
        if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) {
                befs_error(sb,
@@ -437,7 +437,7 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
        }
 
        if ((this_node = kmalloc(sizeof (befs_btree_node), GFP_NOFS)) == NULL) {
-               befs_error(sb, "befs_btree_read() failed to allocate %u "
+               befs_error(sb, "befs_btree_read() failed to allocate %zu "
                           "bytes of memory", sizeof (befs_btree_node));
                goto error;
        }
@@ -452,7 +452,7 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
                kfree(this_node);
                *value = 0;
                *keysize = 0;
-               befs_debug(sb, "<--- befs_btree_read() Tree is EMPTY");
+               befs_debug(sb, "<--- %s Tree is EMPTY", __func__);
                return BEFS_BT_EMPTY;
        } else if (res == BEFS_ERR) {
                goto error_alloc;
@@ -467,7 +467,8 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
                        *keysize = 0;
                        *value = 0;
                        befs_debug(sb,
-                                  "<--- befs_btree_read() END of keys at %Lu",
+                                  "<--- %s END of keys at %llu", __func__,
+                                  (unsigned long long)
                                   key_sum + this_node->head.all_key_count);
                        brelse(this_node->bh);
                        kfree(this_node);
@@ -478,8 +479,8 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
                node_off = this_node->head.right;
 
                if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) {
-                       befs_error(sb, "befs_btree_read() failed to read "
-                                  "node at %Lu", node_off);
+                       befs_error(sb, "%s failed to read node at %llu",
+                                 __func__, (unsigned long long)node_off);
                        goto error_alloc;
                }
        }
@@ -492,11 +493,13 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
 
        keystart = befs_bt_get_key(sb, this_node, cur_key, &keylen);
 
-       befs_debug(sb, "Read [%Lu,%d]: keysize %d", node_off, cur_key, keylen);
+       befs_debug(sb, "Read [%llu,%d]: keysize %d",
+                  (long long unsigned int)node_off, (int)cur_key,
+                  (int)keylen);
 
        if (bufsize < keylen + 1) {
-               befs_error(sb, "befs_btree_read() keybuf too small (%u) "
-                          "for key of size %d", bufsize, keylen);
+               befs_error(sb, "%s keybuf too small (%zu) "
+                          "for key of size %d", __func__, bufsize, keylen);
                brelse(this_node->bh);
                goto error_alloc;
        };
@@ -506,13 +509,13 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
        *keysize = keylen;
        keybuf[keylen] = '\0';
 
-       befs_debug(sb, "Read [%Lu,%d]: Key \"%.*s\", Value %Lu", node_off,
+       befs_debug(sb, "Read [%llu,%d]: Key \"%.*s\", Value %llu", node_off,
                   cur_key, keylen, keybuf, *value);
 
        brelse(this_node->bh);
        kfree(this_node);
 
-       befs_debug(sb, "<--- befs_btree_read()");
+       befs_debug(sb, "<--- %s", __func__);
 
        return BEFS_OK;
 
@@ -522,7 +525,7 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
       error:
        *keysize = 0;
        *value = 0;
-       befs_debug(sb, "<--- befs_btree_read() ERROR");
+       befs_debug(sb, "<--- %s ERROR", __func__);
        return BEFS_ERR;
 }
 
@@ -547,26 +550,26 @@ befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
                    befs_off_t * node_off)
 {
 
-       befs_debug(sb, "---> befs_btree_seekleaf()");
+       befs_debug(sb, "---> %s", __func__);
 
        if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) {
-               befs_error(sb, "befs_btree_seekleaf() failed to read "
-                          "node at %Lu", *node_off);
+               befs_error(sb, "%s failed to read "
+                          "node at %llu", __func__, *node_off);
                goto error;
        }
-       befs_debug(sb, "Seekleaf to root node %Lu", *node_off);
+       befs_debug(sb, "Seekleaf to root node %llu", *node_off);
 
        if (this_node->head.all_key_count == 0 && befs_leafnode(this_node)) {
-               befs_debug(sb, "<--- befs_btree_seekleaf() Tree is EMPTY");
+               befs_debug(sb, "<--- %s Tree is EMPTY", __func__);
                return BEFS_BT_EMPTY;
        }
 
        while (!befs_leafnode(this_node)) {
 
                if (this_node->head.all_key_count == 0) {
-                       befs_debug(sb, "befs_btree_seekleaf() encountered "
-                                  "an empty interior node: %Lu. Using Overflow "
-                                  "node: %Lu", *node_off,
+                       befs_debug(sb, "%s encountered "
+                                  "an empty interior node: %llu. Using Overflow "
+                                  "node: %llu", __func__, *node_off,
                                   this_node->head.overflow);
                        *node_off = this_node->head.overflow;
                } else {
@@ -574,19 +577,19 @@ befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
                        *node_off = fs64_to_cpu(sb, valarray[0]);
                }
                if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) {
-                       befs_error(sb, "befs_btree_seekleaf() failed to read "
-                                  "node at %Lu", *node_off);
+                       befs_error(sb, "%s failed to read "
+                                  "node at %llu", __func__, *node_off);
                        goto error;
                }
 
-               befs_debug(sb, "Seekleaf to child node %Lu", *node_off);
+               befs_debug(sb, "Seekleaf to child node %llu", *node_off);
        }
-       befs_debug(sb, "Node %Lu is a leaf node", *node_off);
+       befs_debug(sb, "Node %llu is a leaf node", *node_off);
 
        return BEFS_OK;
 
       error:
-       befs_debug(sb, "<--- befs_btree_seekleaf() ERROR");
+       befs_debug(sb, "<--- %s ERROR", __func__);
        return BEFS_ERR;
 }
 
index 59096b5..c467beb 100644 (file)
@@ -52,26 +52,25 @@ befs_read_datastream(struct super_block *sb, befs_data_stream * ds,
        befs_block_run run;
        befs_blocknr_t block;   /* block coresponding to pos */
 
-       befs_debug(sb, "---> befs_read_datastream() %Lu", pos);
+       befs_debug(sb, "---> %s %llu", __func__, pos);
        block = pos >> BEFS_SB(sb)->block_shift;
        if (off)
                *off = pos - (block << BEFS_SB(sb)->block_shift);
 
        if (befs_fblock2brun(sb, ds, block, &run) != BEFS_OK) {
                befs_error(sb, "BeFS: Error finding disk addr of block %lu",
-                          block);
-               befs_debug(sb, "<--- befs_read_datastream() ERROR");
+                          (unsigned long)block);
+               befs_debug(sb, "<--- %s ERROR", __func__);
                return NULL;
        }
        bh = befs_bread_iaddr(sb, run);
        if (!bh) {
                befs_error(sb, "BeFS: Error reading block %lu from datastream",
-                          block);
+                          (unsigned long)block);
                return NULL;
        }
 
-       befs_debug(sb, "<--- befs_read_datastream() read data, starting at %Lu",
-                  pos);
+       befs_debug(sb, "<--- %s read data, starting at %llu", __func__, pos);
 
        return bh;
 }
@@ -106,7 +105,8 @@ befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
        } else {
                befs_error(sb,
                           "befs_fblock2brun() was asked to find block %lu, "
-                          "which is not mapped by the datastream\n", fblock);
+                          "which is not mapped by the datastream\n",
+                          (unsigned long)fblock);
                err = BEFS_ERR;
        }
        return err;
@@ -128,14 +128,14 @@ befs_read_lsymlink(struct super_block * sb, befs_data_stream * ds, void *buff,
        befs_off_t bytes_read = 0;      /* bytes readed */
        u16 plen;
        struct buffer_head *bh = NULL;
-       befs_debug(sb, "---> befs_read_lsymlink() length: %Lu", len);
+       befs_debug(sb, "---> %s length: %llu", __func__, len);
 
        while (bytes_read < len) {
                bh = befs_read_datastream(sb, ds, bytes_read, NULL);
                if (!bh) {
                        befs_error(sb, "BeFS: Error reading datastream block "
-                                  "starting from %Lu", bytes_read);
-                       befs_debug(sb, "<--- befs_read_lsymlink() ERROR");
+                                  "starting from %llu", bytes_read);
+                       befs_debug(sb, "<--- %s ERROR", __func__);
                        return bytes_read;
 
                }
@@ -146,7 +146,8 @@ befs_read_lsymlink(struct super_block * sb, befs_data_stream * ds, void *buff,
                bytes_read += plen;
        }
 
-       befs_debug(sb, "<--- befs_read_lsymlink() read %u bytes", bytes_read);
+       befs_debug(sb, "<--- %s read %u bytes", __func__, (unsigned int)
+                  bytes_read);
        return bytes_read;
 }
 
@@ -169,7 +170,7 @@ befs_count_blocks(struct super_block * sb, befs_data_stream * ds)
        befs_blocknr_t metablocks;      /* FS metadata blocks */
        befs_sb_info *befs_sb = BEFS_SB(sb);
 
-       befs_debug(sb, "---> befs_count_blocks()");
+       befs_debug(sb, "---> %s", __func__);
 
        datablocks = ds->size >> befs_sb->block_shift;
        if (ds->size & (befs_sb->block_size - 1))
@@ -206,7 +207,7 @@ befs_count_blocks(struct super_block * sb, befs_data_stream * ds)
        }
 
        blocks = datablocks + metablocks;
-       befs_debug(sb, "<--- befs_count_blocks() %u blocks", blocks);
+       befs_debug(sb, "<--- %s %u blocks", __func__, (unsigned int)blocks);
 
        return blocks;
 }
@@ -251,11 +252,11 @@ befs_find_brun_direct(struct super_block *sb, befs_data_stream * data,
        befs_blocknr_t max_block =
            data->max_direct_range >> BEFS_SB(sb)->block_shift;
 
-       befs_debug(sb, "---> befs_find_brun_direct(), find %lu", blockno);
+       befs_debug(sb, "---> %s, find %lu", __func__, (unsigned long)blockno);
 
        if (blockno > max_block) {
-               befs_error(sb, "befs_find_brun_direct() passed block outside of"
-                          "direct region");
+               befs_error(sb, "%s passed block outside of direct region",
+                          __func__);
                return BEFS_ERR;
        }
 
@@ -267,13 +268,14 @@ befs_find_brun_direct(struct super_block *sb, befs_data_stream * data,
                        run->start = array[i].start + offset;
                        run->len = array[i].len - offset;
 
-                       befs_debug(sb, "---> befs_find_brun_direct(), "
-                                  "found %lu at direct[%d]", blockno, i);
+                       befs_debug(sb, "---> %s, "
+                                  "found %lu at direct[%d]", __func__,
+                                  (unsigned long)blockno, i);
                        return BEFS_OK;
                }
        }
 
-       befs_debug(sb, "---> befs_find_brun_direct() ERROR");
+       befs_debug(sb, "---> %s ERROR", __func__);
        return BEFS_ERR;
 }
 
@@ -316,7 +318,7 @@ befs_find_brun_indirect(struct super_block *sb,
        befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect);
        int arraylen = befs_iaddrs_per_block(sb);
 
-       befs_debug(sb, "---> befs_find_brun_indirect(), find %lu", blockno);
+       befs_debug(sb, "---> %s, find %lu", __func__, (unsigned long)blockno);
 
        indir_start_blk = data->max_direct_range >> BEFS_SB(sb)->block_shift;
        search_blk = blockno - indir_start_blk;
@@ -325,10 +327,9 @@ befs_find_brun_indirect(struct super_block *sb,
        for (i = 0; i < indirect.len; i++) {
                indirblock = befs_bread(sb, indirblockno + i);
                if (indirblock == NULL) {
-                       befs_debug(sb,
-                                  "---> befs_find_brun_indirect() failed to "
-                                  "read disk block %lu from the indirect brun",
-                                  indirblockno + i);
+                       befs_debug(sb, "---> %s failed to read "
+                                  "disk block %lu from the indirect brun",
+                                  __func__, (unsigned long)indirblockno + i);
                        return BEFS_ERR;
                }
 
@@ -348,9 +349,10 @@ befs_find_brun_indirect(struct super_block *sb,
 
                                brelse(indirblock);
                                befs_debug(sb,
-                                          "<--- befs_find_brun_indirect() found "
-                                          "file block %lu at indirect[%d]",
-                                          blockno, j + (i * arraylen));
+                                          "<--- %s found file block "
+                                          "%lu at indirect[%d]", __func__,
+                                          (unsigned long)blockno,
+                                          j + (i * arraylen));
                                return BEFS_OK;
                        }
                        sum += len;
@@ -360,10 +362,10 @@ befs_find_brun_indirect(struct super_block *sb,
        }
 
        /* Only fallthrough is an error */
-       befs_error(sb, "BeFS: befs_find_brun_indirect() failed to find "
-                  "file block %lu", blockno);
+       befs_error(sb, "BeFS: %s failed to find "
+                  "file block %lu", __func__, (unsigned long)blockno);
 
-       befs_debug(sb, "<--- befs_find_brun_indirect() ERROR");
+       befs_debug(sb, "<--- %s ERROR", __func__);
        return BEFS_ERR;
 }
 
@@ -444,7 +446,7 @@ befs_find_brun_dblindirect(struct super_block *sb,
        size_t diblklen = iblklen * befs_iaddrs_per_block(sb)
            * BEFS_DBLINDIR_BRUN_LEN;
 
-       befs_debug(sb, "---> befs_find_brun_dblindirect() find %lu", blockno);
+       befs_debug(sb, "---> %s find %lu", __func__, (unsigned long)blockno);
 
        /* First, discover which of the double_indir->indir blocks
         * contains pos. Then figure out how much of pos that
@@ -460,8 +462,9 @@ befs_find_brun_dblindirect(struct super_block *sb,
        dbl_which_block = dblindir_indx / befs_iaddrs_per_block(sb);
        if (dbl_which_block > data->double_indirect.len) {
                befs_error(sb, "The double-indirect index calculated by "
-                          "befs_read_brun_dblindirect(), %d, is outside the range "
-                          "of the double-indirect block", dblindir_indx);
+                          "%s, %d, is outside the range "
+                          "of the double-indirect block", __func__,
+                          dblindir_indx);
                return BEFS_ERR;
        }
 
@@ -469,10 +472,10 @@ befs_find_brun_dblindirect(struct super_block *sb,
            befs_bread(sb, iaddr2blockno(sb, &data->double_indirect) +
                                        dbl_which_block);
        if (dbl_indir_block == NULL) {
-               befs_error(sb, "befs_read_brun_dblindirect() couldn't read the "
-                          "double-indirect block at blockno %lu",
-                          iaddr2blockno(sb,
-                                        &data->double_indirect) +
+               befs_error(sb, "%s couldn't read the "
+                          "double-indirect block at blockno %lu", __func__,
+                          (unsigned long)
+                          iaddr2blockno(sb, &data->double_indirect) +
                           dbl_which_block);
                brelse(dbl_indir_block);
                return BEFS_ERR;
@@ -489,16 +492,16 @@ befs_find_brun_dblindirect(struct super_block *sb,
        which_block = indir_indx / befs_iaddrs_per_block(sb);
        if (which_block > indir_run.len) {
                befs_error(sb, "The indirect index calculated by "
-                          "befs_read_brun_dblindirect(), %d, is outside the range "
-                          "of the indirect block", indir_indx);
+                          "%s, %d, is outside the range "
+                          "of the indirect block", __func__, indir_indx);
                return BEFS_ERR;
        }
 
        indir_block =
            befs_bread(sb, iaddr2blockno(sb, &indir_run) + which_block);
        if (indir_block == NULL) {
-               befs_error(sb, "befs_read_brun_dblindirect() couldn't read the "
-                          "indirect block at blockno %lu",
+               befs_error(sb, "%s couldn't read the indirect block "
+                          "at blockno %lu", __func__, (unsigned long)
                           iaddr2blockno(sb, &indir_run) + which_block);
                brelse(indir_block);
                return BEFS_ERR;
@@ -519,7 +522,7 @@ befs_find_brun_dblindirect(struct super_block *sb,
        run->len -= offset;
 
        befs_debug(sb, "Found file block %lu in double_indirect[%d][%d],"
-                  " double_indirect_leftover = %lu",
+                  " double_indirect_leftover = %lu", (unsigned long)
                   blockno, dblindir_indx, indir_indx, dblindir_leftover);
 
        return BEFS_OK;
index 622e737..4de7cff 100644 (file)
@@ -10,6 +10,7 @@
  * debug functions
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #ifdef __KERNEL__
 
 #include <stdarg.h>
 
 #include "befs.h"
 
-#define ERRBUFSIZE 1024
-
 void
 befs_error(const struct super_block *sb, const char *fmt, ...)
 {
+       struct va_format vaf;
        va_list args;
-       char *err_buf = kmalloc(ERRBUFSIZE, GFP_KERNEL);
-       if (err_buf == NULL) {
-               printk(KERN_ERR "could not allocate %d bytes\n", ERRBUFSIZE);
-               return;
-       }
 
        va_start(args, fmt);
-       vsnprintf(err_buf, ERRBUFSIZE, fmt, args);
+       vaf.fmt = fmt;
+       vaf.va = &args;
+       pr_err("(%s): %pV\n", sb->s_id, &vaf);
        va_end(args);
-
-       printk(KERN_ERR "BeFS(%s): %s\n", sb->s_id, err_buf);
-       kfree(err_buf);
 }
 
 void
 befs_warning(const struct super_block *sb, const char *fmt, ...)
 {
+       struct va_format vaf;
        va_list args;
-       char *err_buf = kmalloc(ERRBUFSIZE, GFP_KERNEL);
-       if (err_buf == NULL) {
-               printk(KERN_ERR "could not allocate %d bytes\n", ERRBUFSIZE);
-               return;
-       }
 
        va_start(args, fmt);
-       vsnprintf(err_buf, ERRBUFSIZE, fmt, args);
+       vaf.fmt = fmt;
+       vaf.va = &args;
+       pr_warn("(%s): %pV\n", sb->s_id, &vaf);
        va_end(args);
-
-       printk(KERN_WARNING "BeFS(%s): %s\n", sb->s_id, err_buf);
-
-       kfree(err_buf);
 }
 
 void
@@ -67,25 +55,13 @@ befs_debug(const struct super_block *sb, const char *fmt, ...)
 {
 #ifdef CONFIG_BEFS_DEBUG
 
+       struct va_format vaf;
        va_list args;
-       char *err_buf = NULL;
-
-       if (BEFS_SB(sb)->mount_opts.debug) {
-               err_buf = kmalloc(ERRBUFSIZE, GFP_KERNEL);
-               if (err_buf == NULL) {
-                       printk(KERN_ERR "could not allocate %d bytes\n",
-                               ERRBUFSIZE);
-                       return;
-               }
-
-               va_start(args, fmt);
-               vsnprintf(err_buf, ERRBUFSIZE, fmt, args);
-               va_end(args);
-
-               printk(KERN_DEBUG "BeFS(%s): %s\n", sb->s_id, err_buf);
-
-               kfree(err_buf);
-       }
+       va_start(args, fmt);
+       vaf.fmt = fmt;
+       vaf.va = &args;
+       pr_debug("(%s): %pV\n", sb->s_id, &vaf);
+       va_end(args);
 
 #endif                         //CONFIG_BEFS_DEBUG
 }
@@ -109,9 +85,9 @@ befs_dump_inode(const struct super_block *sb, befs_inode * inode)
        befs_debug(sb, "  gid %u", fs32_to_cpu(sb, inode->gid));
        befs_debug(sb, "  mode %08x", fs32_to_cpu(sb, inode->mode));
        befs_debug(sb, "  flags %08x", fs32_to_cpu(sb, inode->flags));
-       befs_debug(sb, "  create_time %Lu",
+       befs_debug(sb, "  create_time %llu",
                   fs64_to_cpu(sb, inode->create_time));
-       befs_debug(sb, "  last_modified_time %Lu",
+       befs_debug(sb, "  last_modified_time %llu",
                   fs64_to_cpu(sb, inode->last_modified_time));
 
        tmp_run = fsrun_to_cpu(sb, inode->parent);
@@ -137,7 +113,7 @@ befs_dump_inode(const struct super_block *sb, befs_inode * inode)
                                   tmp_run.allocation_group, tmp_run.start,
                                   tmp_run.len);
                }
-               befs_debug(sb, "  max_direct_range %Lu",
+               befs_debug(sb, "  max_direct_range %llu",
                           fs64_to_cpu(sb,
                                       inode->data.datastream.
                                       max_direct_range));
@@ -147,7 +123,7 @@ befs_dump_inode(const struct super_block *sb, befs_inode * inode)
                           tmp_run.allocation_group,
                           tmp_run.start, tmp_run.len);
 
-               befs_debug(sb, "  max_indirect_range %Lu",
+               befs_debug(sb, "  max_indirect_range %llu",
                           fs64_to_cpu(sb,
                                       inode->data.datastream.
                                       max_indirect_range));
@@ -158,12 +134,12 @@ befs_dump_inode(const struct super_block *sb, befs_inode * inode)
                           tmp_run.allocation_group, tmp_run.start,
                           tmp_run.len);
 
-               befs_debug(sb, "  max_double_indirect_range %Lu",
+               befs_debug(sb, "  max_double_indirect_range %llu",
                           fs64_to_cpu(sb,
                                       inode->data.datastream.
                                       max_double_indirect_range));
 
-               befs_debug(sb, "  size %Lu",
+               befs_debug(sb, "  size %llu",
                           fs64_to_cpu(sb, inode->data.datastream.size));
        }
 
@@ -191,8 +167,8 @@ befs_dump_super_block(const struct super_block *sb, befs_super_block * sup)
        befs_debug(sb, "  block_size %u", fs32_to_cpu(sb, sup->block_size));
        befs_debug(sb, "  block_shift %u", fs32_to_cpu(sb, sup->block_shift));
 
-       befs_debug(sb, "  num_blocks %Lu", fs64_to_cpu(sb, sup->num_blocks));
-       befs_debug(sb, "  used_blocks %Lu", fs64_to_cpu(sb, sup->used_blocks));
+       befs_debug(sb, "  num_blocks %llu", fs64_to_cpu(sb, sup->num_blocks));
+       befs_debug(sb, "  used_blocks %llu", fs64_to_cpu(sb, sup->used_blocks));
 
        befs_debug(sb, "  magic2 %08x", fs32_to_cpu(sb, sup->magic2));
        befs_debug(sb, "  blocks_per_ag %u",
@@ -206,8 +182,8 @@ befs_dump_super_block(const struct super_block *sb, befs_super_block * sup)
        befs_debug(sb, "  log_blocks %u, %hu, %hu",
                   tmp_run.allocation_group, tmp_run.start, tmp_run.len);
 
-       befs_debug(sb, "  log_start %Ld", fs64_to_cpu(sb, sup->log_start));
-       befs_debug(sb, "  log_end %Ld", fs64_to_cpu(sb, sup->log_end));
+       befs_debug(sb, "  log_start %lld", fs64_to_cpu(sb, sup->log_start));
+       befs_debug(sb, "  log_end %lld", fs64_to_cpu(sb, sup->log_end));
 
        befs_debug(sb, "  magic3 %08x", fs32_to_cpu(sb, sup->magic3));
 
index 94c17f9..fa4b718 100644 (file)
@@ -25,7 +25,8 @@ befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
        /* check magic header. */
        if (magic1 != BEFS_INODE_MAGIC1) {
                befs_error(sb,
-                          "Inode has a bad magic header - inode = %lu", inode);
+                          "Inode has a bad magic header - inode = %lu",
+                          (unsigned long)inode);
                return BEFS_BAD_INODE;
        }
 
@@ -34,8 +35,8 @@ befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
         */
        if (inode != iaddr2blockno(sb, &ino_num)) {
                befs_error(sb, "inode blocknr field disagrees with vfs "
-                          "VFS: %lu, Inode %lu",
-                          inode, iaddr2blockno(sb, &ino_num));
+                          "VFS: %lu, Inode %lu", (unsigned long)
+                          inode, (unsigned long)iaddr2blockno(sb, &ino_num));
                return BEFS_BAD_INODE;
        }
 
@@ -44,7 +45,8 @@ befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
         */
 
        if (!(flags & BEFS_INODE_IN_USE)) {
-               befs_error(sb, "inode is not used - inode = %lu", inode);
+               befs_error(sb, "inode is not used - inode = %lu",
+                          (unsigned long)inode);
                return BEFS_BAD_INODE;
        }
 
index ddef98a..0408a3d 100644 (file)
@@ -30,9 +30,9 @@ befs_bread_iaddr(struct super_block *sb, befs_inode_addr iaddr)
        befs_blocknr_t block = 0;
        befs_sb_info *befs_sb = BEFS_SB(sb);
 
-       befs_debug(sb, "---> Enter befs_read_iaddr() "
-                  "[%u, %hu, %hu]",
-                  iaddr.allocation_group, iaddr.start, iaddr.len);
+       befs_debug(sb, "---> Enter %s "
+                  "[%u, %hu, %hu]", __func__, iaddr.allocation_group,
+                  iaddr.start, iaddr.len);
 
        if (iaddr.allocation_group > befs_sb->num_ags) {
                befs_error(sb, "BEFS: Invalid allocation group %u, max is %u",
@@ -42,20 +42,21 @@ befs_bread_iaddr(struct super_block *sb, befs_inode_addr iaddr)
 
        block = iaddr2blockno(sb, &iaddr);
 
-       befs_debug(sb, "befs_read_iaddr: offset = %lu", block);
+       befs_debug(sb, "%s: offset = %lu", __func__, (unsigned long)block);
 
        bh = sb_bread(sb, block);
 
        if (bh == NULL) {
-               befs_error(sb, "Failed to read block %lu", block);
+               befs_error(sb, "Failed to read block %lu",
+                          (unsigned long)block);
                goto error;
        }
 
-       befs_debug(sb, "<--- befs_read_iaddr()");
+       befs_debug(sb, "<--- %s", __func__);
        return bh;
 
       error:
-       befs_debug(sb, "<--- befs_read_iaddr() ERROR");
+       befs_debug(sb, "<--- %s ERROR", __func__);
        return NULL;
 }
 
@@ -64,20 +65,21 @@ befs_bread(struct super_block *sb, befs_blocknr_t block)
 {
        struct buffer_head *bh = NULL;
 
-       befs_debug(sb, "---> Enter befs_read() %Lu", block);
+       befs_debug(sb, "---> Enter %s %lu", __func__, (unsigned long)block);
 
        bh = sb_bread(sb, block);
 
        if (bh == NULL) {
-               befs_error(sb, "Failed to read block %lu", block);
+               befs_error(sb, "Failed to read block %lu",
+                          (unsigned long)block);
                goto error;
        }
 
-       befs_debug(sb, "<--- befs_read()");
+       befs_debug(sb, "<--- %s", __func__);
 
        return bh;
 
       error:
-       befs_debug(sb, "<--- befs_read() ERROR");
+       befs_debug(sb, "<--- %s ERROR", __func__);
        return NULL;
 }
index 845d2d6..5188f12 100644 (file)
@@ -5,6 +5,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
@@ -39,7 +41,6 @@ static struct dentry *befs_lookup(struct inode *, struct dentry *, unsigned int)
 static struct inode *befs_iget(struct super_block *, unsigned long);
 static struct inode *befs_alloc_inode(struct super_block *sb);
 static void befs_destroy_inode(struct inode *inode);
-static int befs_init_inodecache(void);
 static void befs_destroy_inodecache(void);
 static void *befs_follow_link(struct dentry *, struct nameidata *);
 static void *befs_fast_follow_link(struct dentry *, struct nameidata *);
@@ -131,26 +132,28 @@ befs_get_block(struct inode *inode, sector_t block,
        ulong disk_off;
 
        befs_debug(sb, "---> befs_get_block() for inode %lu, block %ld",
-                  inode->i_ino, block);
+                  (unsigned long)inode->i_ino, (long)block);
 
        if (block < 0) {
                befs_error(sb, "befs_get_block() was asked for a block "
                           "number less than zero: block %ld in inode %lu",
-                          block, inode->i_ino);
+                          (long)block, (unsigned long)inode->i_ino);
                return -EIO;
        }
 
        if (create) {
                befs_error(sb, "befs_get_block() was asked to write to "
-                          "block %ld in inode %lu", block, inode->i_ino);
+                          "block %ld in inode %lu", (long)block,
+                          (unsigned long)inode->i_ino);
                return -EPERM;
        }
 
        res = befs_fblock2brun(sb, ds, block, &run);
        if (res != BEFS_OK) {
                befs_error(sb,
-                          "<--- befs_get_block() for inode %lu, block "
-                          "%ld ERROR", inode->i_ino, block);
+                          "<--- %s for inode %lu, block %ld ERROR",
+                          __func__, (unsigned long)inode->i_ino,
+                          (long)block);
                return -EFBIG;
        }
 
@@ -158,8 +161,9 @@ befs_get_block(struct inode *inode, sector_t block,
 
        map_bh(bh_result, inode->i_sb, disk_off);
 
-       befs_debug(sb, "<--- befs_get_block() for inode %lu, block %ld, "
-                  "disk address %lu", inode->i_ino, block, disk_off);
+       befs_debug(sb, "<--- %s for inode %lu, block %ld, disk address %lu",
+                 __func__, (unsigned long)inode->i_ino, (long)block,
+                 (unsigned long)disk_off);
 
        return 0;
 }
@@ -176,15 +180,15 @@ befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
        char *utfname;
        const char *name = dentry->d_name.name;
 
-       befs_debug(sb, "---> befs_lookup() "
-                  "name %s inode %ld", dentry->d_name.name, dir->i_ino);
+       befs_debug(sb, "---> %s name %s inode %ld", __func__,
+                  dentry->d_name.name, dir->i_ino);
 
        /* Convert to UTF-8 */
        if (BEFS_SB(sb)->nls) {
                ret =
                    befs_nls2utf(sb, name, strlen(name), &utfname, &utfnamelen);
                if (ret < 0) {
-                       befs_debug(sb, "<--- befs_lookup() ERROR");
+                       befs_debug(sb, "<--- %s ERROR", __func__);
                        return ERR_PTR(ret);
                }
                ret = befs_btree_find(sb, ds, utfname, &offset);
@@ -195,12 +199,12 @@ befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
        }
 
        if (ret == BEFS_BT_NOT_FOUND) {
-               befs_debug(sb, "<--- befs_lookup() %s not found",
+               befs_debug(sb, "<--- %s %s not found", __func__,
                           dentry->d_name.name);
                return ERR_PTR(-ENOENT);
 
        } else if (ret != BEFS_OK || offset == 0) {
-               befs_warning(sb, "<--- befs_lookup() Error");
+               befs_warning(sb, "<--- %s Error", __func__);
                return ERR_PTR(-ENODATA);
        }
 
@@ -210,7 +214,7 @@ befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 
        d_add(dentry, inode);
 
-       befs_debug(sb, "<--- befs_lookup()");
+       befs_debug(sb, "<--- %s", __func__);
 
        return NULL;
 }
@@ -228,26 +232,25 @@ befs_readdir(struct file *file, struct dir_context *ctx)
        char keybuf[BEFS_NAME_LEN + 1];
        const char *dirname = file->f_path.dentry->d_name.name;
 
-       befs_debug(sb, "---> befs_readdir() "
-                  "name %s, inode %ld, ctx->pos %Ld",
-                  dirname, inode->i_ino, ctx->pos);
+       befs_debug(sb, "---> %s name %s, inode %ld, ctx->pos %lld",
+                 __func__, dirname, inode->i_ino, ctx->pos);
 
 more:
        result = befs_btree_read(sb, ds, ctx->pos, BEFS_NAME_LEN + 1,
                                 keybuf, &keysize, &value);
 
        if (result == BEFS_ERR) {
-               befs_debug(sb, "<--- befs_readdir() ERROR");
+               befs_debug(sb, "<--- %s ERROR", __func__);
                befs_error(sb, "IO error reading %s (inode %lu)",
                           dirname, inode->i_ino);
                return -EIO;
 
        } else if (result == BEFS_BT_END) {
-               befs_debug(sb, "<--- befs_readdir() END");
+               befs_debug(sb, "<--- %s END", __func__);
                return 0;
 
        } else if (result == BEFS_BT_EMPTY) {
-               befs_debug(sb, "<--- befs_readdir() Empty directory");
+               befs_debug(sb, "<--- %s Empty directory", __func__);
                return 0;
        }
 
@@ -260,7 +263,7 @@ more:
                result =
                    befs_utf2nls(sb, keybuf, keysize, &nlsname, &nlsnamelen);
                if (result < 0) {
-                       befs_debug(sb, "<--- befs_readdir() ERROR");
+                       befs_debug(sb, "<--- %s ERROR", __func__);
                        return result;
                }
                if (!dir_emit(ctx, nlsname, nlsnamelen,
@@ -277,7 +280,7 @@ more:
        ctx->pos++;
        goto more;
 
-       befs_debug(sb, "<--- befs_readdir() pos %Ld", ctx->pos);
+       befs_debug(sb, "<--- %s pos %lld", __func__, ctx->pos);
 
        return 0;
 }
@@ -321,7 +324,7 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
        struct inode *inode;
        long ret = -EIO;
 
-       befs_debug(sb, "---> befs_read_inode() " "inode = %lu", ino);
+       befs_debug(sb, "---> %s inode = %lu", __func__, ino);
 
        inode = iget_locked(sb, ino);
        if (!inode)
@@ -428,7 +431,7 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
        }
 
        brelse(bh);
-       befs_debug(sb, "<--- befs_read_inode()");
+       befs_debug(sb, "<--- %s", __func__);
        unlock_new_inode(inode);
        return inode;
 
@@ -437,7 +440,7 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
 
       unacquire_none:
        iget_failed(inode);
-       befs_debug(sb, "<--- befs_read_inode() - Bad inode");
+       befs_debug(sb, "<--- %s - Bad inode", __func__);
        return ERR_PTR(ret);
 }
 
@@ -445,7 +448,7 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
  *
  * Taken from NFS implementation by Al Viro.
  */
-static int
+static int __init
 befs_init_inodecache(void)
 {
        befs_inode_cachep = kmem_cache_create("befs_inode_cache",
@@ -454,11 +457,9 @@ befs_init_inodecache(void)
                                                SLAB_MEM_SPREAD),
                                              init_once);
        if (befs_inode_cachep == NULL) {
-               printk(KERN_ERR "befs_init_inodecache: "
-                      "Couldn't initialize inode slabcache\n");
+               pr_err("%s: Couldn't initialize inode slabcache\n", __func__);
                return -ENOMEM;
        }
-
        return 0;
 }
 
@@ -544,16 +545,16 @@ befs_utf2nls(struct super_block *sb, const char *in,
         */
        int maxlen = in_len + 1;
 
-       befs_debug(sb, "---> utf2nls()");
+       befs_debug(sb, "---> %s", __func__);
 
        if (!nls) {
-               befs_error(sb, "befs_utf2nls called with no NLS table loaded");
+               befs_error(sb, "%s called with no NLS table loaded", __func__);
                return -EINVAL;
        }
 
        *out = result = kmalloc(maxlen, GFP_NOFS);
        if (!*out) {
-               befs_error(sb, "befs_utf2nls() cannot allocate memory");
+               befs_error(sb, "%s cannot allocate memory", __func__);
                *out_len = 0;
                return -ENOMEM;
        }
@@ -575,14 +576,14 @@ befs_utf2nls(struct super_block *sb, const char *in,
        result[o] = '\0';
        *out_len = o;
 
-       befs_debug(sb, "<--- utf2nls()");
+       befs_debug(sb, "<--- %s", __func__);
 
        return o;
 
       conv_err:
        befs_error(sb, "Name using character set %s contains a character that "
                   "cannot be converted to unicode.", nls->charset);
-       befs_debug(sb, "<--- utf2nls()");
+       befs_debug(sb, "<--- %s", __func__);
        kfree(result);
        return -EILSEQ;
 }
@@ -623,16 +624,17 @@ befs_nls2utf(struct super_block *sb, const char *in,
         * in special cases */
        int maxlen = (3 * in_len) + 1;
 
-       befs_debug(sb, "---> nls2utf()\n");
+       befs_debug(sb, "---> %s\n", __func__);
 
        if (!nls) {
-               befs_error(sb, "befs_nls2utf called with no NLS table loaded.");
+               befs_error(sb, "%s called with no NLS table loaded.",
+                          __func__);
                return -EINVAL;
        }
 
        *out = result = kmalloc(maxlen, GFP_NOFS);
        if (!*out) {
-               befs_error(sb, "befs_nls2utf() cannot allocate memory");
+               befs_error(sb, "%s cannot allocate memory", __func__);
                *out_len = 0;
                return -ENOMEM;
        }
@@ -653,14 +655,14 @@ befs_nls2utf(struct super_block *sb, const char *in,
        result[o] = '\0';
        *out_len = o;
 
-       befs_debug(sb, "<--- nls2utf()");
+       befs_debug(sb, "<--- %s", __func__);
 
        return i;
 
       conv_err:
        befs_error(sb, "Name using charecter set %s contains a charecter that "
                   "cannot be converted to unicode.", nls->charset);
-       befs_debug(sb, "<--- nls2utf()");
+       befs_debug(sb, "<--- %s", __func__);
        kfree(result);
        return -EILSEQ;
 }
@@ -715,8 +717,8 @@ parse_options(char *options, befs_mount_options * opts)
                        if (option >= 0)
                                uid = make_kuid(current_user_ns(), option);
                        if (!uid_valid(uid)) {
-                               printk(KERN_ERR "BeFS: Invalid uid %d, "
-                                               "using default\n", option);
+                               pr_err("Invalid uid %d, "
+                                      "using default\n", option);
                                break;
                        }
                        opts->uid = uid;
@@ -729,8 +731,8 @@ parse_options(char *options, befs_mount_options * opts)
                        if (option >= 0)
                                gid = make_kgid(current_user_ns(), option);
                        if (!gid_valid(gid)) {
-                               printk(KERN_ERR "BeFS: Invalid gid %d, "
-                                               "using default\n", option);
+                               pr_err("Invalid gid %d, "
+                                      "using default\n", option);
                                break;
                        }
                        opts->gid = gid;
@@ -740,8 +742,8 @@ parse_options(char *options, befs_mount_options * opts)
                        kfree(opts->iocharset);
                        opts->iocharset = match_strdup(&args[0]);
                        if (!opts->iocharset) {
-                               printk(KERN_ERR "BeFS: allocation failure for "
-                                               "iocharset string\n");
+                               pr_err("allocation failure for "
+                                      "iocharset string\n");
                                return 0;
                        }
                        break;
@@ -749,8 +751,8 @@ parse_options(char *options, befs_mount_options * opts)
                        opts->debug = 1;
                        break;
                default:
-                       printk(KERN_ERR "BeFS: Unrecognized mount option \"%s\" "
-                                       "or missing value\n", p);
+                       pr_err("Unrecognized mount option \"%s\" "
+                              "or missing value\n", p);
                        return 0;
                }
        }
@@ -791,22 +793,20 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
 
        save_mount_options(sb, data);
 
-       sb->s_fs_info = kmalloc(sizeof (*befs_sb), GFP_KERNEL);
+       sb->s_fs_info = kzalloc(sizeof(*befs_sb), GFP_KERNEL);
        if (sb->s_fs_info == NULL) {
-               printk(KERN_ERR
-                      "BeFS(%s): Unable to allocate memory for private "
+               pr_err("(%s): Unable to allocate memory for private "
                       "portion of superblock. Bailing.\n", sb->s_id);
                goto unacquire_none;
        }
        befs_sb = BEFS_SB(sb);
-       memset(befs_sb, 0, sizeof(befs_sb_info));
 
        if (!parse_options((char *) data, &befs_sb->mount_opts)) {
                befs_error(sb, "cannot parse mount options");
                goto unacquire_priv_sbp;
        }
 
-       befs_debug(sb, "---> befs_fill_super()");
+       befs_debug(sb, "---> %s", __func__);
 
 #ifndef CONFIG_BEFS_RW
        if (!(sb->s_flags & MS_RDONLY)) {
@@ -854,7 +854,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
                goto unacquire_priv_sbp;
 
        if( befs_sb->num_blocks > ~((sector_t)0) ) {
-               befs_error(sb, "blocks count: %Lu "
+               befs_error(sb, "blocks count: %llu "
                        "is larger than the host can use",
                        befs_sb->num_blocks);
                goto unacquire_priv_sbp;
@@ -924,7 +924,7 @@ befs_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct super_block *sb = dentry->d_sb;
        u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
-       befs_debug(sb, "---> befs_statfs()");
+       befs_debug(sb, "---> %s", __func__);
 
        buf->f_type = BEFS_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
@@ -937,7 +937,7 @@ befs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = BEFS_NAME_LEN;
 
-       befs_debug(sb, "<--- befs_statfs()");
+       befs_debug(sb, "<--- %s", __func__);
 
        return 0;
 }
@@ -963,7 +963,7 @@ init_befs_fs(void)
 {
        int err;
 
-       printk(KERN_INFO "BeFS version: %s\n", BEFS_VERSION);
+       pr_info("version: %s\n", BEFS_VERSION);
 
        err = befs_init_inodecache();
        if (err)
index 8defc6b..29aa5cf 100644 (file)
@@ -172,7 +172,7 @@ static void bfs_evict_inode(struct inode *inode)
 
        dprintf("ino=%08lx\n", ino);
 
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        invalidate_inode_buffers(inode);
        clear_inode(inode);
 
index 67be295..0f59799 100644 (file)
 #endif
 
 static int load_elf_binary(struct linux_binprm *bprm);
-static int load_elf_library(struct file *);
 static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *,
                                int, int, unsigned long);
 
+#ifdef CONFIG_USELIB
+static int load_elf_library(struct file *);
+#else
+#define load_elf_library NULL
+#endif
+
 /*
  * If we don't support core dumping, then supply a NULL so we
  * don't even try.
@@ -1005,6 +1010,7 @@ out_free_ph:
        goto out;
 }
 
+#ifdef CONFIG_USELIB
 /* This is really simpleminded and specialized - we are loading an
    a.out library that is given an ELF header. */
 static int load_elf_library(struct file *file)
@@ -1083,6 +1089,7 @@ out_free_ph:
 out:
        return error;
 }
+#endif /* #ifdef CONFIG_USELIB */
 
 #ifdef CONFIG_ELF_CORE
 /*
index 1c740e1..b605003 100644 (file)
@@ -656,6 +656,7 @@ static ssize_t bm_status_write(struct file * file, const char __user * buffer,
 
                        mutex_unlock(&root->d_inode->i_mutex);
                        dput(root);
+                       break;
                default: return res;
        }
        return count;
index 1e86823..ba0d2b0 100644 (file)
@@ -83,7 +83,7 @@ void kill_bdev(struct block_device *bdev)
 {
        struct address_space *mapping = bdev->bd_inode->i_mapping;
 
-       if (mapping->nrpages == 0)
+       if (mapping->nrpages == 0 && mapping->nrshadows == 0)
                return;
 
        invalidate_bh_lrus();
@@ -419,7 +419,7 @@ static void bdev_evict_inode(struct inode *inode)
 {
        struct block_device *bdev = &BDEV_I(inode)->bdev;
        struct list_head *p;
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        invalidate_inode_buffers(inode); /* is it needed here? */
        clear_inode(inode);
        spin_lock(&bdev_lock);
@@ -1523,7 +1523,7 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
                ssize_t err;
 
                err = generic_write_sync(file, pos, ret);
-               if (err < 0 && ret > 0)
+               if (err < 0)
                        ret = err;
        }
        blk_finish_plug(&plug);
index b01fb6c..d43c544 100644 (file)
@@ -472,7 +472,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
                rcu_read_lock();
                page = radix_tree_lookup(&mapping->page_tree, pg_index);
                rcu_read_unlock();
-               if (page) {
+               if (page && !radix_tree_exceptional_entry(page)) {
                        misses++;
                        if (misses > 4)
                                break;
index 0165b86..7331a23 100644 (file)
@@ -1797,7 +1797,7 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
        BTRFS_I(inode)->last_sub_trans = root->log_transid;
        if (num_written > 0) {
                err = generic_write_sync(file, pos, num_written);
-               if (err < 0 && num_written > 0)
+               if (err < 0)
                        num_written = err;
        }
 
index d3d4448..49ec139 100644 (file)
@@ -4593,7 +4593,7 @@ static void evict_inode_truncate_pages(struct inode *inode)
        struct rb_node *node;
 
        ASSERT(inode->i_state & I_FREEING);
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
 
        write_lock(&map_tree->lock);
        while (!RB_EMPTY_ROOT(&map_tree->map)) {
index ebaff36..4b1fb5c 100644 (file)
@@ -265,24 +265,22 @@ static int cachefiles_read_backing_file_one(struct cachefiles_object *object,
                                goto nomem_monitor;
                }
 
-               ret = add_to_page_cache(newpage, bmapping,
-                                       netpage->index, cachefiles_gfp);
+               ret = add_to_page_cache_lru(newpage, bmapping,
+                                           netpage->index, cachefiles_gfp);
                if (ret == 0)
                        goto installed_new_backing_page;
                if (ret != -EEXIST)
                        goto nomem_page;
        }
 
-       /* we've installed a new backing page, so now we need to add it
-        * to the LRU list and start it reading */
+       /* we've installed a new backing page, so now we need to start
+        * it reading */
 installed_new_backing_page:
        _debug("- new %p", newpage);
 
        backpage = newpage;
        newpage = NULL;
 
-       lru_cache_add_file(backpage);
-
 read_backing_page:
        ret = bmapping->a_ops->readpage(NULL, backpage);
        if (ret < 0)
@@ -510,24 +508,23 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
                                        goto nomem;
                        }
 
-                       ret = add_to_page_cache(newpage, bmapping,
-                                               netpage->index, cachefiles_gfp);
+                       ret = add_to_page_cache_lru(newpage, bmapping,
+                                                   netpage->index,
+                                                   cachefiles_gfp);
                        if (ret == 0)
                                goto installed_new_backing_page;
                        if (ret != -EEXIST)
                                goto nomem;
                }
 
-               /* we've installed a new backing page, so now we need to add it
-                * to the LRU list and start it reading */
+               /* we've installed a new backing page, so now we need
+                * to start it reading */
        installed_new_backing_page:
                _debug("- new %p", newpage);
 
                backpage = newpage;
                newpage = NULL;
 
-               lru_cache_add_file(backpage);
-
        reread_backing_page:
                ret = bmapping->a_ops->readpage(NULL, backpage);
                if (ret < 0)
@@ -538,8 +535,8 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
        monitor_backing_page:
                _debug("- monitor add");
 
-               ret = add_to_page_cache(netpage, op->mapping, netpage->index,
-                                       cachefiles_gfp);
+               ret = add_to_page_cache_lru(netpage, op->mapping,
+                                           netpage->index, cachefiles_gfp);
                if (ret < 0) {
                        if (ret == -EEXIST) {
                                page_cache_release(netpage);
@@ -549,8 +546,6 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
                        goto nomem;
                }
 
-               lru_cache_add_file(netpage);
-
                /* install a monitor */
                page_cache_get(netpage);
                monitor->netfs_page = netpage;
@@ -613,8 +608,8 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
        backing_page_already_uptodate:
                _debug("- uptodate");
 
-               ret = add_to_page_cache(netpage, op->mapping, netpage->index,
-                                       cachefiles_gfp);
+               ret = add_to_page_cache_lru(netpage, op->mapping,
+                                           netpage->index, cachefiles_gfp);
                if (ret < 0) {
                        if (ret == -EEXIST) {
                                page_cache_release(netpage);
@@ -631,8 +626,6 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
 
                fscache_mark_page_cached(op, netpage);
 
-               lru_cache_add_file(netpage);
-
                /* the netpage is unlocked and marked up to date here */
                fscache_end_io(op, netpage, 0);
                page_cache_release(netpage);
index 849f613..ab8ad25 100644 (file)
@@ -286,7 +286,7 @@ cifs_destroy_inode(struct inode *inode)
 static void
 cifs_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        cifs_fscache_release_inode_cookie(inode);
 }
@@ -1005,7 +1005,7 @@ cifs_init_once(void *inode)
        init_rwsem(&cifsi->lock_sem);
 }
 
-static int
+static int __init
 cifs_init_inodecache(void)
 {
        cifs_inode_cachep = kmem_cache_create("cifs_inode_cache",
index b7143cf..381c993 100644 (file)
@@ -10,7 +10,7 @@ extern int coda_hard;
 extern int coda_fake_statfs;
 
 void coda_destroy_inodecache(void);
-int coda_init_inodecache(void);
+int __init coda_init_inodecache(void);
 int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync);
 void coda_sysctl_init(void);
 void coda_sysctl_clean(void);
index 506de34..626abc0 100644 (file)
@@ -73,7 +73,7 @@ static void init_once(void *foo)
        inode_init_once(&ei->vfs_inode);
 }
 
-int coda_init_inodecache(void)
+int __init coda_init_inodecache(void)
 {
        coda_inode_cachep = kmem_cache_create("coda_inode_cache",
                                sizeof(struct coda_inode_info),
@@ -250,7 +250,7 @@ static void coda_put_super(struct super_block *sb)
 
 static void coda_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        coda_cache_clear_inode(inode);
 }
index 06610cf..a1f801c 100644 (file)
@@ -195,8 +195,7 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i
                struct page *page = NULL;
 
                if (blocknr + i < devsize) {
-                       page = read_mapping_page_async(mapping, blocknr + i,
-                                                                       NULL);
+                       page = read_mapping_page(mapping, blocknr + i, NULL);
                        /* synchronous error? */
                        if (IS_ERR(page))
                                page = NULL;
index 160a548..6e6bff3 100644 (file)
@@ -664,7 +664,6 @@ static inline int dio_new_bio(struct dio *dio, struct dio_submit *sdio,
                goto out;
        sector = start_sector << (sdio->blkbits - 9);
        nr_pages = min(sdio->pages_in_io, bio_get_nr_vecs(map_bh->b_bdev));
-       nr_pages = min(nr_pages, BIO_MAX_PAGES);
        BUG_ON(nr_pages <= 0);
        dio_bio_alloc(dio, sdio, map_bh->b_bdev, sector, nr_pages);
        sdio->boundary = 0;
index 9fd702f..9280202 100644 (file)
@@ -59,10 +59,22 @@ int drop_caches_sysctl_handler(ctl_table *table, int write,
        if (ret)
                return ret;
        if (write) {
-               if (sysctl_drop_caches & 1)
+               static int stfu;
+
+               if (sysctl_drop_caches & 1) {
                        iterate_supers(drop_pagecache_sb, NULL);
-               if (sysctl_drop_caches & 2)
+                       count_vm_event(DROP_PAGECACHE);
+               }
+               if (sysctl_drop_caches & 2) {
                        drop_slab();
+                       count_vm_event(DROP_SLAB);
+               }
+               if (!stfu) {
+                       pr_info("%s (%d): drop_caches: %d\n",
+                               current->comm, task_pid_nr(current),
+                               sysctl_drop_caches);
+               }
+               stfu |= sysctl_drop_caches & 4;
        }
        return 0;
 }
index e879cf8..afa1b81 100644 (file)
@@ -132,7 +132,7 @@ static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf)
  */
 static void ecryptfs_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        iput(ecryptfs_inode_to_lower(inode));
 }
index 50215bb..f8def1a 100644 (file)
@@ -91,7 +91,7 @@ static void init_once(void *foo)
        inode_init_once(&ei->vfs_inode);
 }
 
-static int init_inodecache(void)
+static int __init init_inodecache(void)
 {
        efs_inode_cachep = kmem_cache_create("efs_inode_cache",
                                sizeof(struct efs_inode_info),
index 4f59402..25dfeba 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -97,6 +97,7 @@ static inline void put_binfmt(struct linux_binfmt * fmt)
        module_put(fmt->module);
 }
 
+#ifdef CONFIG_USELIB
 /*
  * Note that a shared library must be both readable and executable due to
  * security reasons.
@@ -156,6 +157,7 @@ exit:
 out:
        return error;
 }
+#endif /* #ifdef CONFIG_USELIB */
 
 #ifdef CONFIG_MMU
 /*
index ee4317f..d1c244d 100644 (file)
@@ -1486,7 +1486,7 @@ void exofs_evict_inode(struct inode *inode)
        struct ore_io_state *ios;
        int ret;
 
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
 
        /* TODO: should do better here */
        if (inode->i_nlink || is_bad_inode(inode))
index 94ed368..b1d2a46 100644 (file)
@@ -78,7 +78,7 @@ void ext2_evict_inode(struct inode * inode)
                dquot_drop(inode);
        }
 
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
 
        if (want_delete) {
                sb_start_intwrite(inode->i_sb);
index 384b6eb..efce2bb 100644 (file)
@@ -228,7 +228,7 @@ void ext3_evict_inode (struct inode *inode)
                log_wait_commit(journal, commit_tid);
                filemap_write_and_wait(&inode->i_data);
        }
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
 
        ext3_discard_reservation(inode);
        rsv = ei->i_block_alloc_info;
index 1a50739..6db7f7d 100644 (file)
@@ -153,7 +153,7 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov,
                ssize_t err;
 
                err = generic_write_sync(file, iocb->ki_pos - ret, ret);
-               if (err < 0 && ret > 0)
+               if (err < 0)
                        ret = err;
        }
        blk_finish_plug(&plug);
index 24bfd7f..175c3f9 100644 (file)
@@ -215,7 +215,7 @@ void ext4_evict_inode(struct inode *inode)
                        jbd2_complete_transaction(journal, commit_tid);
                        filemap_write_and_wait(&inode->i_data);
                }
-               truncate_inode_pages(&inode->i_data, 0);
+               truncate_inode_pages_final(&inode->i_data);
 
                WARN_ON(atomic_read(&EXT4_I(inode)->i_ioend_count));
                goto no_delete;
@@ -226,7 +226,7 @@ void ext4_evict_inode(struct inode *inode)
 
        if (ext4_should_order_data(inode))
                ext4_begin_ordered_truncate(inode, 0);
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
 
        WARN_ON(atomic_read(&EXT4_I(inode)->i_ioend_count));
        if (is_bad_inode(inode))
index 4d67ed7..28cea76 100644 (file)
@@ -260,7 +260,7 @@ void f2fs_evict_inode(struct inode *inode)
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
 
        trace_f2fs_evict_inode(inode);
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
 
        if (inode->i_ino == F2FS_NODE_INO(sbi) ||
                        inode->i_ino == F2FS_META_INO(sbi))
index 854b578..c68d9f2 100644 (file)
@@ -490,7 +490,7 @@ EXPORT_SYMBOL_GPL(fat_build_inode);
 
 static void fat_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        if (!inode->i_nlink) {
                inode->i_size = 0;
                fat_truncate_blocks(inode, 0);
index 92567d9..5797d45 100644 (file)
@@ -121,6 +121,7 @@ int unregister_filesystem(struct file_system_type * fs)
 
 EXPORT_SYMBOL(unregister_filesystem);
 
+#ifdef CONFIG_SYSFS_SYSCALL
 static int fs_index(const char __user * __name)
 {
        struct file_system_type * tmp;
@@ -199,6 +200,7 @@ SYSCALL_DEFINE3(sysfs, int, option, unsigned long, arg1, unsigned long, arg2)
        }
        return retval;
 }
+#endif
 
 int __init get_filesystem_list(char *buf)
 {
index f47df72..363e3ae 100644 (file)
@@ -354,7 +354,7 @@ static void vxfs_i_callback(struct rcu_head *head)
 void
 vxfs_evict_inode(struct inode *ip)
 {
-       truncate_inode_pages(&ip->i_data, 0);
+       truncate_inode_pages_final(&ip->i_data);
        clear_inode(ip);
        call_rcu(&ip->i_rcu, vxfs_i_callback);
 }
index 25d4099..99c7f0a 100644 (file)
@@ -192,7 +192,7 @@ vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
  * vxfs_lookup - lookup pathname component
  * @dip:       dir in which we lookup
  * @dp:                dentry we lookup
- * @nd:                lookup nameidata
+ * @flags:     lookup flags
  *
  * Description:
  *   vxfs_lookup tries to lookup the pathname component described
index d754e3c..a163159 100644 (file)
@@ -89,16 +89,29 @@ static inline struct inode *wb_inode(struct list_head *head)
 #define CREATE_TRACE_POINTS
 #include <trace/events/writeback.h>
 
+static void bdi_wakeup_thread(struct backing_dev_info *bdi)
+{
+       spin_lock_bh(&bdi->wb_lock);
+       if (test_bit(BDI_registered, &bdi->state))
+               mod_delayed_work(bdi_wq, &bdi->wb.dwork, 0);
+       spin_unlock_bh(&bdi->wb_lock);
+}
+
 static void bdi_queue_work(struct backing_dev_info *bdi,
                           struct wb_writeback_work *work)
 {
        trace_writeback_queue(bdi, work);
 
        spin_lock_bh(&bdi->wb_lock);
+       if (!test_bit(BDI_registered, &bdi->state)) {
+               if (work->done)
+                       complete(work->done);
+               goto out_unlock;
+       }
        list_add_tail(&work->list, &bdi->work_list);
-       spin_unlock_bh(&bdi->wb_lock);
-
        mod_delayed_work(bdi_wq, &bdi->wb.dwork, 0);
+out_unlock:
+       spin_unlock_bh(&bdi->wb_lock);
 }
 
 static void
@@ -114,7 +127,7 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
        work = kzalloc(sizeof(*work), GFP_ATOMIC);
        if (!work) {
                trace_writeback_nowork(bdi);
-               mod_delayed_work(bdi_wq, &bdi->wb.dwork, 0);
+               bdi_wakeup_thread(bdi);
                return;
        }
 
@@ -161,7 +174,7 @@ void bdi_start_background_writeback(struct backing_dev_info *bdi)
         * writeback as soon as there is no other work to do.
         */
        trace_writeback_wake_background(bdi);
-       mod_delayed_work(bdi_wq, &bdi->wb.dwork, 0);
+       bdi_wakeup_thread(bdi);
 }
 
 /*
@@ -1017,7 +1030,7 @@ void bdi_writeback_workfn(struct work_struct *work)
        current->flags |= PF_SWAPWRITE;
 
        if (likely(!current_is_workqueue_rescuer() ||
-                  list_empty(&bdi->bdi_list))) {
+                  !test_bit(BDI_registered, &bdi->state))) {
                /*
                 * The normal path.  Keep writing back @bdi until its
                 * work_list is empty.  Note that this path is also taken
@@ -1039,10 +1052,10 @@ void bdi_writeback_workfn(struct work_struct *work)
                trace_writeback_pages_written(pages_written);
        }
 
-       if (!list_empty(&bdi->work_list) ||
-           (wb_has_dirty_io(wb) && dirty_writeback_interval))
-               queue_delayed_work(bdi_wq, &wb->dwork,
-                       msecs_to_jiffies(dirty_writeback_interval * 10));
+       if (!list_empty(&bdi->work_list))
+               mod_delayed_work(bdi_wq, &wb->dwork, 0);
+       else if (wb_has_dirty_io(wb) && dirty_writeback_interval)
+               bdi_wakeup_thread_delayed(bdi);
 
        current->flags &= ~PF_SWAPWRITE;
 }
index d468643..9c761b6 100644 (file)
@@ -123,7 +123,7 @@ static void fuse_destroy_inode(struct inode *inode)
 
 static void fuse_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        if (inode->i_sb->s_flags & MS_ACTIVE) {
                struct fuse_conn *fc = get_fuse_conn(inode);
index 60f60f6..24410cd 100644 (file)
@@ -1558,7 +1558,7 @@ out_unlock:
                fs_warn(sdp, "gfs2_evict_inode: %d\n", error);
 out:
        /* Case 3 starts here */
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        gfs2_rs_delete(ip, NULL);
        gfs2_ordered_del_inode(ip);
        clear_inode(inode);
index 380ab31..9e2fecd 100644 (file)
@@ -547,7 +547,7 @@ out:
 
 void hfs_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        if (HFS_IS_RSRC(inode) && HFS_I(inode)->rsrc_inode) {
                HFS_I(HFS_I(inode)->rsrc_inode)->rsrc_inode = NULL;
index 0f47890..caf89a7 100644 (file)
@@ -11,7 +11,7 @@
 
 static struct kmem_cache *hfsplus_attr_tree_cachep;
 
-int hfsplus_create_attr_tree_cache(void)
+int __init hfsplus_create_attr_tree_cache(void)
 {
        if (hfsplus_attr_tree_cachep)
                return -EEXIST;
index fbb212f..a7aafb3 100644 (file)
@@ -227,10 +227,8 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
        u32 ablock, dblock, mask;
        sector_t sector;
        int was_dirty = 0;
-       int shift;
 
        /* Convert inode block to disk allocation block */
-       shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits;
        ablock = iblock >> sbi->fs_shift;
 
        if (iblock >= hip->fs_blocks) {
@@ -498,11 +496,13 @@ int hfsplus_file_extend(struct inode *inode)
                        goto insert_extent;
        }
 out:
-       mutex_unlock(&hip->extents_lock);
        if (!res) {
                hip->alloc_blocks += len;
+               mutex_unlock(&hip->extents_lock);
                hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
+               return 0;
        }
+       mutex_unlock(&hip->extents_lock);
        return res;
 
 insert_extent:
@@ -556,11 +556,13 @@ void hfsplus_file_truncate(struct inode *inode)
 
        blk_cnt = (inode->i_size + HFSPLUS_SB(sb)->alloc_blksz - 1) >>
                        HFSPLUS_SB(sb)->alloc_blksz_shift;
+
+       mutex_lock(&hip->extents_lock);
+
        alloc_cnt = hip->alloc_blocks;
        if (blk_cnt == alloc_cnt)
-               goto out;
+               goto out_unlock;
 
-       mutex_lock(&hip->extents_lock);
        res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
        if (res) {
                mutex_unlock(&hip->extents_lock);
@@ -592,10 +594,10 @@ void hfsplus_file_truncate(struct inode *inode)
                hfs_brec_remove(&fd);
        }
        hfs_find_exit(&fd);
-       mutex_unlock(&hip->extents_lock);
 
        hip->alloc_blocks = blk_cnt;
-out:
+out_unlock:
+       mutex_unlock(&hip->extents_lock);
        hip->phys_size = inode->i_size;
        hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >>
                sb->s_blocksize_bits;
index 62d571e..83dc292 100644 (file)
@@ -367,7 +367,7 @@ typedef int (*search_strategy_t)(struct hfs_bnode *,
  */
 
 /* attributes.c */
-int hfsplus_create_attr_tree_cache(void);
+int __init hfsplus_create_attr_tree_cache(void);
 void hfsplus_destroy_attr_tree_cache(void);
 hfsplus_attr_entry *hfsplus_alloc_attr_entry(void);
 void hfsplus_destroy_attr_entry(hfsplus_attr_entry *entry_p);
index 80875aa..a6abf87 100644 (file)
@@ -161,7 +161,7 @@ static int hfsplus_write_inode(struct inode *inode,
 static void hfsplus_evict_inode(struct inode *inode)
 {
        hfs_dbg(INODE, "hfsplus_evict_inode: %lu\n", inode->i_ino);
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        if (HFSPLUS_IS_RSRC(inode)) {
                HFSPLUS_I(HFSPLUS_I(inode)->rsrc_inode)->rsrc_inode = NULL;
index fe649d3..9c470fd 100644 (file)
@@ -230,7 +230,7 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb)
 
 static void hostfs_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        if (HOSTFS_I(inode)->fd != -1) {
                close_file(&HOSTFS_I(inode)->fd);
index 9edeeb0..50a4273 100644 (file)
@@ -304,7 +304,7 @@ void hpfs_write_if_changed(struct inode *inode)
 
 void hpfs_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        if (!inode->i_nlink) {
                hpfs_lock(inode->i_sb);
index d19b30a..2040275 100644 (file)
@@ -366,7 +366,13 @@ static void truncate_hugepages(struct inode *inode, loff_t lstart)
 
 static void hugetlbfs_evict_inode(struct inode *inode)
 {
+       struct resv_map *resv_map;
+
        truncate_hugepages(inode, 0);
+       resv_map = (struct resv_map *)inode->i_mapping->private_data;
+       /* root inode doesn't have the resv_map, so we should check it */
+       if (resv_map)
+               resv_map_release(&resv_map->refs);
        clear_inode(inode);
 }
 
@@ -476,6 +482,11 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
                                        umode_t mode, dev_t dev)
 {
        struct inode *inode;
+       struct resv_map *resv_map;
+
+       resv_map = resv_map_alloc();
+       if (!resv_map)
+               return NULL;
 
        inode = new_inode(sb);
        if (inode) {
@@ -487,7 +498,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
                inode->i_mapping->a_ops = &hugetlbfs_aops;
                inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info;
                inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-               INIT_LIST_HEAD(&inode->i_mapping->private_list);
+               inode->i_mapping->private_data = resv_map;
                info = HUGETLBFS_I(inode);
                /*
                 * The policy is initialized here even if we are creating a
@@ -517,7 +528,9 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
                        break;
                }
                lockdep_annotate_inode_mutex_key(inode);
-       }
+       } else
+               kref_put(&resv_map->refs, resv_map_release);
+
        return inode;
 }
 
index 4bcdad3..e690515 100644 (file)
@@ -503,6 +503,7 @@ void clear_inode(struct inode *inode)
         */
        spin_lock_irq(&inode->i_data.tree_lock);
        BUG_ON(inode->i_data.nrpages);
+       BUG_ON(inode->i_data.nrshadows);
        spin_unlock_irq(&inode->i_data.tree_lock);
        BUG_ON(!list_empty(&inode->i_data.private_list));
        BUG_ON(!(inode->i_state & I_FREEING));
@@ -548,8 +549,7 @@ static void evict(struct inode *inode)
        if (op->evict_inode) {
                op->evict_inode(inode);
        } else {
-               if (inode->i_data.nrpages)
-                       truncate_inode_pages(&inode->i_data, 0);
+               truncate_inode_pages_final(&inode->i_data);
                clear_inode(inode);
        }
        if (S_ISBLK(inode->i_mode) && inode->i_bdev)
index a69e426..f739915 100644 (file)
@@ -242,7 +242,7 @@ void jffs2_evict_inode (struct inode *inode)
 
        jffs2_dbg(1, "%s(): ino #%lu mode %o\n",
                  __func__, inode->i_ino, inode->i_mode);
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        jffs2_do_clear_inode(c, f);
 }
@@ -687,7 +687,7 @@ unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
        struct inode *inode = OFNI_EDONI_2SFFJ(f);
        struct page *pg;
 
-       pg = read_cache_page_async(inode->i_mapping, offset >> PAGE_CACHE_SHIFT,
+       pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT,
                             (void *)jffs2_do_readpage_unlock, inode);
        if (IS_ERR(pg))
                return (void *)pg;
index f4aab71..6f8fe72 100644 (file)
@@ -154,7 +154,7 @@ void jfs_evict_inode(struct inode *inode)
                dquot_initialize(inode);
 
                if (JFS_IP(inode)->fileset == FILESYSTEM_I) {
-                       truncate_inode_pages(&inode->i_data, 0);
+                       truncate_inode_pages_final(&inode->i_data);
 
                        if (test_cflag(COMMIT_Freewmap, inode))
                                jfs_free_zero_link(inode);
@@ -168,7 +168,7 @@ void jfs_evict_inode(struct inode *inode)
                        dquot_free_inode(inode);
                }
        } else {
-               truncate_inode_pages(&inode->i_data, 0);
+               truncate_inode_pages_final(&inode->i_data);
        }
        clear_inode(inode);
        dquot_drop(inode);
index e55126f..abb0f1f 100644 (file)
@@ -355,7 +355,7 @@ void kernfs_evict_inode(struct inode *inode)
 {
        struct kernfs_node *kn = inode->i_private;
 
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        kernfs_put(kn);
 }
index 9a59cba..4814031 100644 (file)
@@ -2180,7 +2180,7 @@ void logfs_evict_inode(struct inode *inode)
                        do_delete_inode(inode);
                }
        }
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
 
        /* Cheaper version of write_inode.  All changes are concealed in
index 0332109..0ad2ec9 100644 (file)
@@ -26,7 +26,7 @@ static int minix_remount (struct super_block * sb, int * flags, char * data);
 
 static void minix_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        if (!inode->i_nlink) {
                inode->i_size = 0;
                minix_truncate(inode);
@@ -86,7 +86,7 @@ static void init_once(void *foo)
        inode_init_once(&ei->vfs_inode);
 }
 
-static int init_inodecache(void)
+static int __init init_inodecache(void)
 {
        minix_inode_cachep = kmem_cache_create("minix_inode_cache",
                                             sizeof(struct minix_inode_info),
index 2cf2ebe..ee59d35 100644 (file)
@@ -296,7 +296,7 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
 static void
 ncp_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
 
        if (S_ISDIR(inode->i_mode)) {
index 56ff823..65d849b 100644 (file)
@@ -1213,7 +1213,7 @@ static u64 pnfs_num_cont_bytes(struct inode *inode, pgoff_t idx)
        end = DIV_ROUND_UP(i_size_read(inode), PAGE_CACHE_SIZE);
        if (end != NFS_I(inode)->npages) {
                rcu_read_lock();
-               end = radix_tree_next_hole(&mapping->page_tree, idx + 1, ULONG_MAX);
+               end = page_cache_next_hole(mapping, idx + 1, ULONG_MAX);
                rcu_read_unlock();
        }
 
index 360114a..c4702ba 100644 (file)
@@ -128,7 +128,7 @@ EXPORT_SYMBOL_GPL(nfs_clear_inode);
 
 void nfs_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        nfs_clear_inode(inode);
 }
index 808f295..6f340f0 100644 (file)
@@ -90,7 +90,7 @@ static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc)
  */
 static void nfs4_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        pnfs_return_layout(inode);
        pnfs_destroy_layout(NFS_I(inode));
index 06cddd5..2645be4 100644 (file)
@@ -71,10 +71,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
        if (gid_eq(new->fsgid, INVALID_GID))
                new->fsgid = exp->ex_anon_gid;
 
-       ret = set_groups(new, gi);
+       set_groups(new, gi);
        put_group_info(gi);
-       if (ret < 0)
-               goto error;
 
        if (!uid_eq(new->fsuid, GLOBAL_ROOT_UID))
                new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
@@ -89,7 +87,6 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
 
 oom:
        ret = -ENOMEM;
-error:
        abort_creds(new);
        return ret;
 }
index deaa3d3..0d58075 100644 (file)
@@ -942,6 +942,18 @@ int nilfs_cpfile_read(struct super_block *sb, size_t cpsize,
        struct inode *cpfile;
        int err;
 
+       if (cpsize > sb->s_blocksize) {
+               printk(KERN_ERR
+                      "NILFS: too large checkpoint size: %zu bytes.\n",
+                      cpsize);
+               return -EINVAL;
+       } else if (cpsize < NILFS_MIN_CHECKPOINT_SIZE) {
+               printk(KERN_ERR
+                      "NILFS: too small checkpoint size: %zu bytes.\n",
+                      cpsize);
+               return -EINVAL;
+       }
+
        cpfile = nilfs_iget_locked(sb, NULL, NILFS_CPFILE_INO);
        if (unlikely(!cpfile))
                return -ENOMEM;
index fa0f803..0d5fada 100644 (file)
@@ -484,6 +484,18 @@ int nilfs_dat_read(struct super_block *sb, size_t entry_size,
        struct nilfs_dat_info *di;
        int err;
 
+       if (entry_size > sb->s_blocksize) {
+               printk(KERN_ERR
+                      "NILFS: too large DAT entry size: %zu bytes.\n",
+                      entry_size);
+               return -EINVAL;
+       } else if (entry_size < NILFS_MIN_DAT_ENTRY_SIZE) {
+               printk(KERN_ERR
+                      "NILFS: too small DAT entry size: %zu bytes.\n",
+                      entry_size);
+               return -EINVAL;
+       }
+
        dat = nilfs_iget_locked(sb, NULL, NILFS_DAT_INO);
        if (unlikely(!dat))
                return -ENOMEM;
index 7e350c5..b9c5726 100644 (file)
@@ -783,16 +783,14 @@ void nilfs_evict_inode(struct inode *inode)
        int ret;
 
        if (inode->i_nlink || !ii->i_root || unlikely(is_bad_inode(inode))) {
-               if (inode->i_data.nrpages)
-                       truncate_inode_pages(&inode->i_data, 0);
+               truncate_inode_pages_final(&inode->i_data);
                clear_inode(inode);
                nilfs_clear_inode(inode);
                return;
        }
        nilfs_transaction_begin(sb, &ti, 0); /* never fails */
 
-       if (inode->i_data.nrpages)
-               truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
 
        /* TODO: some of the following operations may fail.  */
        nilfs_truncate_bmap(ii, 0);
index 2b34021..422fb54 100644 (file)
@@ -1071,6 +1071,48 @@ out:
        return ret;
 }
 
+/**
+ * nilfs_ioctl_trim_fs() - trim ioctl handle function
+ * @inode: inode object
+ * @argp: pointer on argument from userspace
+ *
+ * Decription: nilfs_ioctl_trim_fs is the FITRIM ioctl handle function. It
+ * checks the arguments from userspace and calls nilfs_sufile_trim_fs, which
+ * performs the actual trim operation.
+ *
+ * Return Value: On success, 0 is returned or negative error code, otherwise.
+ */
+static int nilfs_ioctl_trim_fs(struct inode *inode, void __user *argp)
+{
+       struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
+       struct request_queue *q = bdev_get_queue(nilfs->ns_bdev);
+       struct fstrim_range range;
+       int ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (!blk_queue_discard(q))
+               return -EOPNOTSUPP;
+
+       if (copy_from_user(&range, argp, sizeof(range)))
+               return -EFAULT;
+
+       range.minlen = max_t(u64, range.minlen, q->limits.discard_granularity);
+
+       down_read(&nilfs->ns_segctor_sem);
+       ret = nilfs_sufile_trim_fs(nilfs->ns_sufile, &range);
+       up_read(&nilfs->ns_segctor_sem);
+
+       if (ret < 0)
+               return ret;
+
+       if (copy_to_user(argp, &range, sizeof(range)))
+               return -EFAULT;
+
+       return 0;
+}
+
 /**
  * nilfs_ioctl_set_alloc_range - limit range of segments to be allocated
  * @inode: inode object
@@ -1163,6 +1205,95 @@ static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp,
        return ret;
 }
 
+/**
+ * nilfs_ioctl_set_suinfo - set segment usage info
+ * @inode: inode object
+ * @filp: file object
+ * @cmd: ioctl's request code
+ * @argp: pointer on argument from userspace
+ *
+ * Description: Expects an array of nilfs_suinfo_update structures
+ * encapsulated in nilfs_argv and updates the segment usage info
+ * according to the flags in nilfs_suinfo_update.
+ *
+ * Return Value: On success, 0 is returned. On error, one of the
+ * following negative error codes is returned.
+ *
+ * %-EPERM - Not enough permissions
+ *
+ * %-EFAULT - Error copying input data
+ *
+ * %-EIO - I/O error.
+ *
+ * %-ENOMEM - Insufficient amount of memory available.
+ *
+ * %-EINVAL - Invalid values in input (segment number, flags or nblocks)
+ */
+static int nilfs_ioctl_set_suinfo(struct inode *inode, struct file *filp,
+                               unsigned int cmd, void __user *argp)
+{
+       struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
+       struct nilfs_transaction_info ti;
+       struct nilfs_argv argv;
+       size_t len;
+       void __user *base;
+       void *kbuf;
+       int ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       ret = mnt_want_write_file(filp);
+       if (ret)
+               return ret;
+
+       ret = -EFAULT;
+       if (copy_from_user(&argv, argp, sizeof(argv)))
+               goto out;
+
+       ret = -EINVAL;
+       if (argv.v_size < sizeof(struct nilfs_suinfo_update))
+               goto out;
+
+       if (argv.v_nmembs > nilfs->ns_nsegments)
+               goto out;
+
+       if (argv.v_nmembs >= UINT_MAX / argv.v_size)
+               goto out;
+
+       len = argv.v_size * argv.v_nmembs;
+       if (!len) {
+               ret = 0;
+               goto out;
+       }
+
+       base = (void __user *)(unsigned long)argv.v_base;
+       kbuf = vmalloc(len);
+       if (!kbuf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (copy_from_user(kbuf, base, len)) {
+               ret = -EFAULT;
+               goto out_free;
+       }
+
+       nilfs_transaction_begin(inode->i_sb, &ti, 0);
+       ret = nilfs_sufile_set_suinfo(nilfs->ns_sufile, kbuf, argv.v_size,
+                       argv.v_nmembs);
+       if (unlikely(ret < 0))
+               nilfs_transaction_abort(inode->i_sb);
+       else
+               nilfs_transaction_commit(inode->i_sb); /* never fails */
+
+out_free:
+       vfree(kbuf);
+out:
+       mnt_drop_write_file(filp);
+       return ret;
+}
+
 long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct inode *inode = file_inode(filp);
@@ -1189,6 +1320,8 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                return nilfs_ioctl_get_info(inode, filp, cmd, argp,
                                            sizeof(struct nilfs_suinfo),
                                            nilfs_ioctl_do_get_suinfo);
+       case NILFS_IOCTL_SET_SUINFO:
+               return nilfs_ioctl_set_suinfo(inode, filp, cmd, argp);
        case NILFS_IOCTL_GET_SUSTAT:
                return nilfs_ioctl_get_sustat(inode, filp, cmd, argp);
        case NILFS_IOCTL_GET_VINFO:
@@ -1205,6 +1338,8 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                return nilfs_ioctl_resize(inode, filp, argp);
        case NILFS_IOCTL_SET_ALLOC_RANGE:
                return nilfs_ioctl_set_alloc_range(inode, argp);
+       case FITRIM:
+               return nilfs_ioctl_trim_fs(inode, argp);
        default:
                return -ENOTTY;
        }
@@ -1228,6 +1363,7 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        case NILFS_IOCTL_GET_CPINFO:
        case NILFS_IOCTL_GET_CPSTAT:
        case NILFS_IOCTL_GET_SUINFO:
+       case NILFS_IOCTL_SET_SUINFO:
        case NILFS_IOCTL_GET_SUSTAT:
        case NILFS_IOCTL_GET_VINFO:
        case NILFS_IOCTL_GET_BDESCS:
@@ -1235,6 +1371,7 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        case NILFS_IOCTL_SYNC:
        case NILFS_IOCTL_RESIZE:
        case NILFS_IOCTL_SET_ALLOC_RANGE:
+       case FITRIM:
                break;
        default:
                return -ENOIOCTLCMD;
index 3127e9f..2a869c3 100644 (file)
@@ -869,6 +869,289 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
        return ret;
 }
 
+/**
+ * nilfs_sufile_set_suinfo - sets segment usage info
+ * @sufile: inode of segment usage file
+ * @buf: array of suinfo_update
+ * @supsz: byte size of suinfo_update
+ * @nsup: size of suinfo_update array
+ *
+ * Description: Takes an array of nilfs_suinfo_update structs and updates
+ * segment usage accordingly. Only the fields indicated by the sup_flags
+ * are updated.
+ *
+ * Return Value: On success, 0 is returned. On error, one of the
+ * following negative error codes is returned.
+ *
+ * %-EIO - I/O error.
+ *
+ * %-ENOMEM - Insufficient amount of memory available.
+ *
+ * %-EINVAL - Invalid values in input (segment number, flags or nblocks)
+ */
+ssize_t nilfs_sufile_set_suinfo(struct inode *sufile, void *buf,
+                               unsigned supsz, size_t nsup)
+{
+       struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
+       struct buffer_head *header_bh, *bh;
+       struct nilfs_suinfo_update *sup, *supend = buf + supsz * nsup;
+       struct nilfs_segment_usage *su;
+       void *kaddr;
+       unsigned long blkoff, prev_blkoff;
+       int cleansi, cleansu, dirtysi, dirtysu;
+       long ncleaned = 0, ndirtied = 0;
+       int ret = 0;
+
+       if (unlikely(nsup == 0))
+               return ret;
+
+       for (sup = buf; sup < supend; sup = (void *)sup + supsz) {
+               if (sup->sup_segnum >= nilfs->ns_nsegments
+                       || (sup->sup_flags &
+                               (~0UL << __NR_NILFS_SUINFO_UPDATE_FIELDS))
+                       || (nilfs_suinfo_update_nblocks(sup) &&
+                               sup->sup_sui.sui_nblocks >
+                               nilfs->ns_blocks_per_segment))
+                       return -EINVAL;
+       }
+
+       down_write(&NILFS_MDT(sufile)->mi_sem);
+
+       ret = nilfs_sufile_get_header_block(sufile, &header_bh);
+       if (ret < 0)
+               goto out_sem;
+
+       sup = buf;
+       blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
+       ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
+       if (ret < 0)
+               goto out_header;
+
+       for (;;) {
+               kaddr = kmap_atomic(bh->b_page);
+               su = nilfs_sufile_block_get_segment_usage(
+                       sufile, sup->sup_segnum, bh, kaddr);
+
+               if (nilfs_suinfo_update_lastmod(sup))
+                       su->su_lastmod = cpu_to_le64(sup->sup_sui.sui_lastmod);
+
+               if (nilfs_suinfo_update_nblocks(sup))
+                       su->su_nblocks = cpu_to_le32(sup->sup_sui.sui_nblocks);
+
+               if (nilfs_suinfo_update_flags(sup)) {
+                       /*
+                        * Active flag is a virtual flag projected by running
+                        * nilfs kernel code - drop it not to write it to
+                        * disk.
+                        */
+                       sup->sup_sui.sui_flags &=
+                                       ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
+
+                       cleansi = nilfs_suinfo_clean(&sup->sup_sui);
+                       cleansu = nilfs_segment_usage_clean(su);
+                       dirtysi = nilfs_suinfo_dirty(&sup->sup_sui);
+                       dirtysu = nilfs_segment_usage_dirty(su);
+
+                       if (cleansi && !cleansu)
+                               ++ncleaned;
+                       else if (!cleansi && cleansu)
+                               --ncleaned;
+
+                       if (dirtysi && !dirtysu)
+                               ++ndirtied;
+                       else if (!dirtysi && dirtysu)
+                               --ndirtied;
+
+                       su->su_flags = cpu_to_le32(sup->sup_sui.sui_flags);
+               }
+
+               kunmap_atomic(kaddr);
+
+               sup = (void *)sup + supsz;
+               if (sup >= supend)
+                       break;
+
+               prev_blkoff = blkoff;
+               blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
+               if (blkoff == prev_blkoff)
+                       continue;
+
+               /* get different block */
+               mark_buffer_dirty(bh);
+               put_bh(bh);
+               ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
+               if (unlikely(ret < 0))
+                       goto out_mark;
+       }
+       mark_buffer_dirty(bh);
+       put_bh(bh);
+
+ out_mark:
+       if (ncleaned || ndirtied) {
+               nilfs_sufile_mod_counter(header_bh, (u64)ncleaned,
+                               (u64)ndirtied);
+               NILFS_SUI(sufile)->ncleansegs += ncleaned;
+       }
+       nilfs_mdt_mark_dirty(sufile);
+ out_header:
+       put_bh(header_bh);
+ out_sem:
+       up_write(&NILFS_MDT(sufile)->mi_sem);
+       return ret;
+}
+
+/**
+ * nilfs_sufile_trim_fs() - trim ioctl handle function
+ * @sufile: inode of segment usage file
+ * @range: fstrim_range structure
+ *
+ * start:      First Byte to trim
+ * len:                number of Bytes to trim from start
+ * minlen:     minimum extent length in Bytes
+ *
+ * Decription: nilfs_sufile_trim_fs goes through all segments containing bytes
+ * from start to start+len. start is rounded up to the next block boundary
+ * and start+len is rounded down. For each clean segment blkdev_issue_discard
+ * function is invoked.
+ *
+ * Return Value: On success, 0 is returned or negative error code, otherwise.
+ */
+int nilfs_sufile_trim_fs(struct inode *sufile, struct fstrim_range *range)
+{
+       struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
+       struct buffer_head *su_bh;
+       struct nilfs_segment_usage *su;
+       void *kaddr;
+       size_t n, i, susz = NILFS_MDT(sufile)->mi_entry_size;
+       sector_t seg_start, seg_end, start_block, end_block;
+       sector_t start = 0, nblocks = 0;
+       u64 segnum, segnum_end, minlen, len, max_blocks, ndiscarded = 0;
+       int ret = 0;
+       unsigned int sects_per_block;
+
+       sects_per_block = (1 << nilfs->ns_blocksize_bits) /
+                       bdev_logical_block_size(nilfs->ns_bdev);
+       len = range->len >> nilfs->ns_blocksize_bits;
+       minlen = range->minlen >> nilfs->ns_blocksize_bits;
+       max_blocks = ((u64)nilfs->ns_nsegments * nilfs->ns_blocks_per_segment);
+
+       if (!len || range->start >= max_blocks << nilfs->ns_blocksize_bits)
+               return -EINVAL;
+
+       start_block = (range->start + nilfs->ns_blocksize - 1) >>
+                       nilfs->ns_blocksize_bits;
+
+       /*
+        * range->len can be very large (actually, it is set to
+        * ULLONG_MAX by default) - truncate upper end of the range
+        * carefully so as not to overflow.
+        */
+       if (max_blocks - start_block < len)
+               end_block = max_blocks - 1;
+       else
+               end_block = start_block + len - 1;
+
+       segnum = nilfs_get_segnum_of_block(nilfs, start_block);
+       segnum_end = nilfs_get_segnum_of_block(nilfs, end_block);
+
+       down_read(&NILFS_MDT(sufile)->mi_sem);
+
+       while (segnum <= segnum_end) {
+               n = nilfs_sufile_segment_usages_in_block(sufile, segnum,
+                               segnum_end);
+
+               ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0,
+                                                          &su_bh);
+               if (ret < 0) {
+                       if (ret != -ENOENT)
+                               goto out_sem;
+                       /* hole */
+                       segnum += n;
+                       continue;
+               }
+
+               kaddr = kmap_atomic(su_bh->b_page);
+               su = nilfs_sufile_block_get_segment_usage(sufile, segnum,
+                               su_bh, kaddr);
+               for (i = 0; i < n; ++i, ++segnum, su = (void *)su + susz) {
+                       if (!nilfs_segment_usage_clean(su))
+                               continue;
+
+                       nilfs_get_segment_range(nilfs, segnum, &seg_start,
+                                               &seg_end);
+
+                       if (!nblocks) {
+                               /* start new extent */
+                               start = seg_start;
+                               nblocks = seg_end - seg_start + 1;
+                               continue;
+                       }
+
+                       if (start + nblocks == seg_start) {
+                               /* add to previous extent */
+                               nblocks += seg_end - seg_start + 1;
+                               continue;
+                       }
+
+                       /* discard previous extent */
+                       if (start < start_block) {
+                               nblocks -= start_block - start;
+                               start = start_block;
+                       }
+
+                       if (nblocks >= minlen) {
+                               kunmap_atomic(kaddr);
+
+                               ret = blkdev_issue_discard(nilfs->ns_bdev,
+                                               start * sects_per_block,
+                                               nblocks * sects_per_block,
+                                               GFP_NOFS, 0);
+                               if (ret < 0) {
+                                       put_bh(su_bh);
+                                       goto out_sem;
+                               }
+
+                               ndiscarded += nblocks;
+                               kaddr = kmap_atomic(su_bh->b_page);
+                               su = nilfs_sufile_block_get_segment_usage(
+                                       sufile, segnum, su_bh, kaddr);
+                       }
+
+                       /* start new extent */
+                       start = seg_start;
+                       nblocks = seg_end - seg_start + 1;
+               }
+               kunmap_atomic(kaddr);
+               put_bh(su_bh);
+       }
+
+
+       if (nblocks) {
+               /* discard last extent */
+               if (start < start_block) {
+                       nblocks -= start_block - start;
+                       start = start_block;
+               }
+               if (start + nblocks > end_block + 1)
+                       nblocks = end_block - start + 1;
+
+               if (nblocks >= minlen) {
+                       ret = blkdev_issue_discard(nilfs->ns_bdev,
+                                       start * sects_per_block,
+                                       nblocks * sects_per_block,
+                                       GFP_NOFS, 0);
+                       if (!ret)
+                               ndiscarded += nblocks;
+               }
+       }
+
+out_sem:
+       up_read(&NILFS_MDT(sufile)->mi_sem);
+
+       range->len = ndiscarded << nilfs->ns_blocksize_bits;
+       return ret;
+}
+
 /**
  * nilfs_sufile_read - read or get sufile inode
  * @sb: super block instance
@@ -886,6 +1169,18 @@ int nilfs_sufile_read(struct super_block *sb, size_t susize,
        void *kaddr;
        int err;
 
+       if (susize > sb->s_blocksize) {
+               printk(KERN_ERR
+                      "NILFS: too large segment usage size: %zu bytes.\n",
+                      susize);
+               return -EINVAL;
+       } else if (susize < NILFS_MIN_SEGMENT_USAGE_SIZE) {
+               printk(KERN_ERR
+                      "NILFS: too small segment usage size: %zu bytes.\n",
+                      susize);
+               return -EINVAL;
+       }
+
        sufile = nilfs_iget_locked(sb, NULL, NILFS_SUFILE_INO);
        if (unlikely(!sufile))
                return -ENOMEM;
index e84bc5b..b8afd72 100644 (file)
@@ -44,6 +44,7 @@ int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
 int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *);
 ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned,
                                size_t);
+ssize_t nilfs_sufile_set_suinfo(struct inode *, void *, unsigned , size_t);
 
 int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *,
                         void (*dofunc)(struct inode *, __u64,
@@ -65,6 +66,7 @@ void nilfs_sufile_do_set_error(struct inode *, __u64, struct buffer_head *,
 int nilfs_sufile_resize(struct inode *sufile, __u64 newnsegs);
 int nilfs_sufile_read(struct super_block *sb, size_t susize,
                      struct nilfs_inode *raw_inode, struct inode **inodep);
+int nilfs_sufile_trim_fs(struct inode *sufile, struct fstrim_range *range);
 
 /**
  * nilfs_sufile_scrap - make a segment garbage
index 94c451c..8ba8229 100644 (file)
@@ -399,6 +399,16 @@ static int nilfs_store_disk_layout(struct the_nilfs *nilfs,
                return -EINVAL;
 
        nilfs->ns_inode_size = le16_to_cpu(sbp->s_inode_size);
+       if (nilfs->ns_inode_size > nilfs->ns_blocksize) {
+               printk(KERN_ERR "NILFS: too large inode size: %d bytes.\n",
+                      nilfs->ns_inode_size);
+               return -EINVAL;
+       } else if (nilfs->ns_inode_size < NILFS_MIN_INODE_SIZE) {
+               printk(KERN_ERR "NILFS: too small inode size: %d bytes.\n",
+                      nilfs->ns_inode_size);
+               return -EINVAL;
+       }
+
        nilfs->ns_first_ino = le32_to_cpu(sbp->s_first_ino);
 
        nilfs->ns_blocks_per_segment = le32_to_cpu(sbp->s_blocks_per_segment);
index dc638f7..ee9cb37 100644 (file)
@@ -60,8 +60,8 @@ static int fanotify_merge(struct list_head *list, struct fsnotify_event *event)
 }
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
-static int fanotify_get_response_from_access(struct fsnotify_group *group,
-                                            struct fanotify_event_info *event)
+static int fanotify_get_response(struct fsnotify_group *group,
+                                struct fanotify_perm_event_info *event)
 {
        int ret;
 
@@ -142,6 +142,40 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
        return false;
 }
 
+struct fanotify_event_info *fanotify_alloc_event(struct inode *inode, u32 mask,
+                                                struct path *path)
+{
+       struct fanotify_event_info *event;
+
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+       if (mask & FAN_ALL_PERM_EVENTS) {
+               struct fanotify_perm_event_info *pevent;
+
+               pevent = kmem_cache_alloc(fanotify_perm_event_cachep,
+                                         GFP_KERNEL);
+               if (!pevent)
+                       return NULL;
+               event = &pevent->fae;
+               pevent->response = 0;
+               goto init;
+       }
+#endif
+       event = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL);
+       if (!event)
+               return NULL;
+init: __maybe_unused
+       fsnotify_init_event(&event->fse, inode, mask);
+       event->tgid = get_pid(task_tgid(current));
+       if (path) {
+               event->path = *path;
+               path_get(&event->path);
+       } else {
+               event->path.mnt = NULL;
+               event->path.dentry = NULL;
+       }
+       return event;
+}
+
 static int fanotify_handle_event(struct fsnotify_group *group,
                                 struct inode *inode,
                                 struct fsnotify_mark *inode_mark,
@@ -171,25 +205,11 @@ static int fanotify_handle_event(struct fsnotify_group *group,
        pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode,
                 mask);
 
-       event = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL);
+       event = fanotify_alloc_event(inode, mask, data);
        if (unlikely(!event))
                return -ENOMEM;
 
        fsn_event = &event->fse;
-       fsnotify_init_event(fsn_event, inode, mask);
-       event->tgid = get_pid(task_tgid(current));
-       if (data_type == FSNOTIFY_EVENT_PATH) {
-               struct path *path = data;
-               event->path = *path;
-               path_get(&event->path);
-       } else {
-               event->path.mnt = NULL;
-               event->path.dentry = NULL;
-       }
-#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
-       event->response = 0;
-#endif
-
        ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge);
        if (ret) {
                /* Permission events shouldn't be merged */
@@ -202,7 +222,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
        if (mask & FAN_ALL_PERM_EVENTS) {
-               ret = fanotify_get_response_from_access(group, event);
+               ret = fanotify_get_response(group, FANOTIFY_PE(fsn_event));
                fsnotify_destroy_event(group, fsn_event);
        }
 #endif
@@ -225,6 +245,13 @@ static void fanotify_free_event(struct fsnotify_event *fsn_event)
        event = FANOTIFY_E(fsn_event);
        path_put(&event->path);
        put_pid(event->tgid);
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+       if (fsn_event->mask & FAN_ALL_PERM_EVENTS) {
+               kmem_cache_free(fanotify_perm_event_cachep,
+                               FANOTIFY_PE(fsn_event));
+               return;
+       }
+#endif
        kmem_cache_free(fanotify_event_cachep, event);
 }
 
index 32a2f03..2a5fb14 100644 (file)
@@ -3,13 +3,12 @@
 #include <linux/slab.h>
 
 extern struct kmem_cache *fanotify_event_cachep;
+extern struct kmem_cache *fanotify_perm_event_cachep;
 
 /*
- * Lifetime of the structure differs for normal and permission events. In both
- * cases the structure is allocated in fanotify_handle_event(). For normal
- * events the structure is freed immediately after reporting it to userspace.
- * For permission events we free it only after we receive response from
- * userspace.
+ * Structure for normal fanotify events. It gets allocated in
+ * fanotify_handle_event() and freed when the information is retrieved by
+ * userspace
  */
 struct fanotify_event_info {
        struct fsnotify_event fse;
@@ -19,12 +18,33 @@ struct fanotify_event_info {
         */
        struct path path;
        struct pid *tgid;
+};
+
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
-       u32 response;   /* userspace answer to question */
-#endif
+/*
+ * Structure for permission fanotify events. It gets allocated and freed in
+ * fanotify_handle_event() since we wait there for user response. When the
+ * information is retrieved by userspace the structure is moved from
+ * group->notification_list to group->fanotify_data.access_list to wait for
+ * user response.
+ */
+struct fanotify_perm_event_info {
+       struct fanotify_event_info fae;
+       int response;   /* userspace answer to question */
+       int fd;         /* fd we passed to userspace for this event */
 };
 
+static inline struct fanotify_perm_event_info *
+FANOTIFY_PE(struct fsnotify_event *fse)
+{
+       return container_of(fse, struct fanotify_perm_event_info, fae.fse);
+}
+#endif
+
 static inline struct fanotify_event_info *FANOTIFY_E(struct fsnotify_event *fse)
 {
        return container_of(fse, struct fanotify_event_info, fse);
 }
+
+struct fanotify_event_info *fanotify_alloc_event(struct inode *inode, u32 mask,
+                                                struct path *path);
index 287a22c..4e565c8 100644 (file)
 extern const struct fsnotify_ops fanotify_fsnotify_ops;
 
 static struct kmem_cache *fanotify_mark_cache __read_mostly;
-static struct kmem_cache *fanotify_response_event_cache __read_mostly;
 struct kmem_cache *fanotify_event_cachep __read_mostly;
-
-struct fanotify_response_event {
-       struct list_head list;
-       __s32 fd;
-       struct fanotify_event_info *event;
-};
+struct kmem_cache *fanotify_perm_event_cachep __read_mostly;
 
 /*
  * Get an fsnotify notification event if one exists and is small
@@ -135,33 +129,34 @@ static int fill_event_metadata(struct fsnotify_group *group,
 }
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
-static struct fanotify_response_event *dequeue_re(struct fsnotify_group *group,
-                                                 __s32 fd)
+static struct fanotify_perm_event_info *dequeue_event(
+                               struct fsnotify_group *group, int fd)
 {
-       struct fanotify_response_event *re, *return_re = NULL;
+       struct fanotify_perm_event_info *event, *return_e = NULL;
 
-       mutex_lock(&group->fanotify_data.access_mutex);
-       list_for_each_entry(re, &group->fanotify_data.access_list, list) {
-               if (re->fd != fd)
+       spin_lock(&group->fanotify_data.access_lock);
+       list_for_each_entry(event, &group->fanotify_data.access_list,
+                           fae.fse.list) {
+               if (event->fd != fd)
                        continue;
 
-               list_del_init(&re->list);
-               return_re = re;
+               list_del_init(&event->fae.fse.list);
+               return_e = event;
                break;
        }
-       mutex_unlock(&group->fanotify_data.access_mutex);
+       spin_unlock(&group->fanotify_data.access_lock);
 
-       pr_debug("%s: found return_re=%p\n", __func__, return_re);
+       pr_debug("%s: found return_re=%p\n", __func__, return_e);
 
-       return return_re;
+       return return_e;
 }
 
 static int process_access_response(struct fsnotify_group *group,
                                   struct fanotify_response *response_struct)
 {
-       struct fanotify_response_event *re;
-       __s32 fd = response_struct->fd;
-       __u32 response = response_struct->response;
+       struct fanotify_perm_event_info *event;
+       int fd = response_struct->fd;
+       int response = response_struct->response;
 
        pr_debug("%s: group=%p fd=%d response=%d\n", __func__, group,
                 fd, response);
@@ -181,58 +176,15 @@ static int process_access_response(struct fsnotify_group *group,
        if (fd < 0)
                return -EINVAL;
 
-       re = dequeue_re(group, fd);
-       if (!re)
+       event = dequeue_event(group, fd);
+       if (!event)
                return -ENOENT;
 
-       re->event->response = response;
-
+       event->response = response;
        wake_up(&group->fanotify_data.access_waitq);
 
-       kmem_cache_free(fanotify_response_event_cache, re);
-
-       return 0;
-}
-
-static int prepare_for_access_response(struct fsnotify_group *group,
-                                      struct fsnotify_event *event,
-                                      __s32 fd)
-{
-       struct fanotify_response_event *re;
-
-       if (!(event->mask & FAN_ALL_PERM_EVENTS))
-               return 0;
-
-       re = kmem_cache_alloc(fanotify_response_event_cache, GFP_KERNEL);
-       if (!re)
-               return -ENOMEM;
-
-       re->event = FANOTIFY_E(event);
-       re->fd = fd;
-
-       mutex_lock(&group->fanotify_data.access_mutex);
-
-       if (atomic_read(&group->fanotify_data.bypass_perm)) {
-               mutex_unlock(&group->fanotify_data.access_mutex);
-               kmem_cache_free(fanotify_response_event_cache, re);
-               FANOTIFY_E(event)->response = FAN_ALLOW;
-               return 0;
-       }
-               
-       list_add_tail(&re->list, &group->fanotify_data.access_list);
-       mutex_unlock(&group->fanotify_data.access_mutex);
-
-       return 0;
-}
-
-#else
-static int prepare_for_access_response(struct fsnotify_group *group,
-                                      struct fsnotify_event *event,
-                                      __s32 fd)
-{
        return 0;
 }
-
 #endif
 
 static ssize_t copy_event_to_user(struct fsnotify_group *group,
@@ -247,7 +199,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
 
        ret = fill_event_metadata(group, &fanotify_event_metadata, event, &f);
        if (ret < 0)
-               goto out;
+               return ret;
 
        fd = fanotify_event_metadata.fd;
        ret = -EFAULT;
@@ -255,9 +207,10 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
                         fanotify_event_metadata.event_len))
                goto out_close_fd;
 
-       ret = prepare_for_access_response(group, event, fd);
-       if (ret)
-               goto out_close_fd;
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+       if (event->mask & FAN_ALL_PERM_EVENTS)
+               FANOTIFY_PE(event)->fd = fd;
+#endif
 
        if (fd != FAN_NOFD)
                fd_install(fd, f);
@@ -268,13 +221,6 @@ out_close_fd:
                put_unused_fd(fd);
                fput(f);
        }
-out:
-#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
-       if (event->mask & FAN_ALL_PERM_EVENTS) {
-               FANOTIFY_E(event)->response = FAN_DENY;
-               wake_up(&group->fanotify_data.access_waitq);
-       }
-#endif
        return ret;
 }
 
@@ -314,35 +260,50 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
                kevent = get_one_event(group, count);
                mutex_unlock(&group->notification_mutex);
 
-               if (kevent) {
+               if (IS_ERR(kevent)) {
                        ret = PTR_ERR(kevent);
-                       if (IS_ERR(kevent))
+                       break;
+               }
+
+               if (!kevent) {
+                       ret = -EAGAIN;
+                       if (file->f_flags & O_NONBLOCK)
                                break;
-                       ret = copy_event_to_user(group, kevent, buf);
-                       /*
-                        * Permission events get destroyed after we
-                        * receive response
-                        */
-                       if (!(kevent->mask & FAN_ALL_PERM_EVENTS))
-                               fsnotify_destroy_event(group, kevent);
-                       if (ret < 0)
+
+                       ret = -ERESTARTSYS;
+                       if (signal_pending(current))
+                               break;
+
+                       if (start != buf)
                                break;
-                       buf += ret;
-                       count -= ret;
+                       schedule();
                        continue;
                }
 
-               ret = -EAGAIN;
-               if (file->f_flags & O_NONBLOCK)
-                       break;
-               ret = -ERESTARTSYS;
-               if (signal_pending(current))
-                       break;
-
-               if (start != buf)
-                       break;
-
-               schedule();
+               ret = copy_event_to_user(group, kevent, buf);
+               /*
+                * Permission events get queued to wait for response.  Other
+                * events can be destroyed now.
+                */
+               if (!(kevent->mask & FAN_ALL_PERM_EVENTS)) {
+                       fsnotify_destroy_event(group, kevent);
+                       if (ret < 0)
+                               break;
+               } else {
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+                       if (ret < 0) {
+                               FANOTIFY_PE(kevent)->response = FAN_DENY;
+                               wake_up(&group->fanotify_data.access_waitq);
+                               break;
+                       }
+                       spin_lock(&group->fanotify_data.access_lock);
+                       list_add_tail(&kevent->list,
+                                     &group->fanotify_data.access_list);
+                       spin_unlock(&group->fanotify_data.access_lock);
+#endif
+               }
+               buf += ret;
+               count -= ret;
        }
 
        finish_wait(&group->notification_waitq, &wait);
@@ -383,22 +344,21 @@ static int fanotify_release(struct inode *ignored, struct file *file)
        struct fsnotify_group *group = file->private_data;
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
-       struct fanotify_response_event *re, *lre;
+       struct fanotify_perm_event_info *event, *next;
 
-       mutex_lock(&group->fanotify_data.access_mutex);
+       spin_lock(&group->fanotify_data.access_lock);
 
        atomic_inc(&group->fanotify_data.bypass_perm);
 
-       list_for_each_entry_safe(re, lre, &group->fanotify_data.access_list, list) {
-               pr_debug("%s: found group=%p re=%p event=%p\n", __func__, group,
-                        re, re->event);
+       list_for_each_entry_safe(event, next, &group->fanotify_data.access_list,
+                                fae.fse.list) {
+               pr_debug("%s: found group=%p event=%p\n", __func__, group,
+                        event);
 
-               list_del_init(&re->list);
-               re->event->response = FAN_ALLOW;
-
-               kmem_cache_free(fanotify_response_event_cache, re);
+               list_del_init(&event->fae.fse.list);
+               event->response = FAN_ALLOW;
        }
-       mutex_unlock(&group->fanotify_data.access_mutex);
+       spin_unlock(&group->fanotify_data.access_lock);
 
        wake_up(&group->fanotify_data.access_waitq);
 #endif
@@ -731,21 +691,16 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
        group->fanotify_data.user = user;
        atomic_inc(&user->fanotify_listeners);
 
-       oevent = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL);
+       oevent = fanotify_alloc_event(NULL, FS_Q_OVERFLOW, NULL);
        if (unlikely(!oevent)) {
                fd = -ENOMEM;
                goto out_destroy_group;
        }
        group->overflow_event = &oevent->fse;
-       fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW);
-       oevent->tgid = get_pid(task_tgid(current));
-       oevent->path.mnt = NULL;
-       oevent->path.dentry = NULL;
 
        group->fanotify_data.f_flags = event_f_flags;
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
-       oevent->response = 0;
-       mutex_init(&group->fanotify_data.access_mutex);
+       spin_lock_init(&group->fanotify_data.access_lock);
        init_waitqueue_head(&group->fanotify_data.access_waitq);
        INIT_LIST_HEAD(&group->fanotify_data.access_list);
        atomic_set(&group->fanotify_data.bypass_perm, 0);
@@ -920,9 +875,11 @@ COMPAT_SYSCALL_DEFINE6(fanotify_mark,
 static int __init fanotify_user_setup(void)
 {
        fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC);
-       fanotify_response_event_cache = KMEM_CACHE(fanotify_response_event,
-                                                  SLAB_PANIC);
        fanotify_event_cachep = KMEM_CACHE(fanotify_event_info, SLAB_PANIC);
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+       fanotify_perm_event_cachep = KMEM_CACHE(fanotify_perm_event_info,
+                                               SLAB_PANIC);
+#endif
 
        return 0;
 }
index ffb9b36..9d8153e 100644 (file)
@@ -2259,7 +2259,7 @@ void ntfs_evict_big_inode(struct inode *vi)
 {
        ntfs_inode *ni = NTFS_I(vi);
 
-       truncate_inode_pages(&vi->i_data, 0);
+       truncate_inode_pages_final(&vi->i_data);
        clear_inode(vi);
 
 #ifdef NTFS_RW
index 555f4cd..7e8282d 100644 (file)
@@ -205,6 +205,7 @@ static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh,
        di->i_mode = cpu_to_le16(inode->i_mode);
        di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
        di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
+       ocfs2_update_inode_fsync_trans(handle, inode, 0);
 
        ocfs2_journal_dirty(handle, di_bh);
 
index e2edff3..b4deb5f 100644 (file)
@@ -5728,6 +5728,7 @@ int ocfs2_remove_btree_range(struct inode *inode,
        }
 
        ocfs2_et_update_clusters(et, -len);
+       ocfs2_update_inode_fsync_trans(handle, inode, 1);
 
        ocfs2_journal_dirty(handle, et->et_root_bh);
 
@@ -6932,6 +6933,7 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,
        di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
        spin_unlock(&oi->ip_lock);
 
+       ocfs2_update_inode_fsync_trans(handle, inode, 1);
        ocfs2_dinode_new_extent_list(inode, di);
 
        ocfs2_journal_dirty(handle, di_bh);
@@ -7208,6 +7210,7 @@ int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
        di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec);
        di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
 
+       ocfs2_update_inode_fsync_trans(handle, inode, 1);
        ocfs2_journal_dirty(handle, di_bh);
 
 out_commit:
index aeb44e8..d310d12 100644 (file)
@@ -571,7 +571,6 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
 {
        struct inode *inode = file_inode(iocb->ki_filp);
        int level;
-       wait_queue_head_t *wq = ocfs2_ioend_wq(inode);
 
        /* this io's submitter should not have unlocked this before we could */
        BUG_ON(!ocfs2_iocb_is_rw_locked(iocb));
@@ -582,10 +581,7 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
        if (ocfs2_iocb_is_unaligned_aio(iocb)) {
                ocfs2_iocb_clear_unaligned_aio(iocb);
 
-               if (atomic_dec_and_test(&OCFS2_I(inode)->ip_unaligned_aio) &&
-                   waitqueue_active(wq)) {
-                       wake_up_all(wq);
-               }
+               mutex_unlock(&OCFS2_I(inode)->ip_unaligned_aio);
        }
 
        ocfs2_iocb_clear_rw_locked(iocb);
@@ -2043,6 +2039,7 @@ out_write_size:
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        di->i_mtime = di->i_ctime = cpu_to_le64(inode->i_mtime.tv_sec);
        di->i_mtime_nsec = di->i_ctime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
+       ocfs2_update_inode_fsync_trans(handle, inode, 1);
        ocfs2_journal_dirty(handle, wc->w_di_bh);
 
        ocfs2_commit_trans(osb, handle);
index f671e49..6cae155 100644 (file)
@@ -102,9 +102,4 @@ enum ocfs2_iocb_lock_bits {
 #define ocfs2_iocb_is_unaligned_aio(iocb) \
        test_bit(OCFS2_IOCB_UNALIGNED_IO, (unsigned long *)&iocb->private)
 
-#define OCFS2_IOEND_WQ_HASH_SZ 37
-#define ocfs2_ioend_wq(v)   (&ocfs2__ioend_wq[((unsigned long)(v)) %\
-                                           OCFS2_IOEND_WQ_HASH_SZ])
-extern wait_queue_head_t ocfs2__ioend_wq[OCFS2_IOEND_WQ_HASH_SZ];
-
 #endif /* OCFS2_FILE_H */
index 5b704c6..1edcb14 100644 (file)
@@ -90,7 +90,6 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
                 * information for this bh as it's not marked locally
                 * uptodate. */
                ret = -EIO;
-               put_bh(bh);
                mlog_errno(ret);
        }
 
@@ -420,7 +419,6 @@ int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
 
        if (!buffer_uptodate(bh)) {
                ret = -EIO;
-               put_bh(bh);
                mlog_errno(ret);
        }
 
index 2cd2406..eb649d2 100644 (file)
@@ -262,17 +262,17 @@ static void o2net_update_recv_stats(struct o2net_sock_container *sc)
 
 #endif /* CONFIG_OCFS2_FS_STATS */
 
-static inline int o2net_reconnect_delay(void)
+static inline unsigned int o2net_reconnect_delay(void)
 {
        return o2nm_single_cluster->cl_reconnect_delay_ms;
 }
 
-static inline int o2net_keepalive_delay(void)
+static inline unsigned int o2net_keepalive_delay(void)
 {
        return o2nm_single_cluster->cl_keepalive_delay_ms;
 }
 
-static inline int o2net_idle_timeout(void)
+static inline unsigned int o2net_idle_timeout(void)
 {
        return o2nm_single_cluster->cl_idle_timeout_ms;
 }
@@ -1964,18 +1964,30 @@ static void o2net_listen_data_ready(struct sock *sk, int bytes)
                goto out;
        }
 
-       /* ->sk_data_ready is also called for a newly established child socket
-        * before it has been accepted and the acceptor has set up their
-        * data_ready.. we only want to queue listen work for our listening
-        * socket */
+       /* This callback may called twice when a new connection
+        * is  being established as a child socket inherits everything
+        * from a parent LISTEN socket, including the data_ready cb of
+        * the parent. This leads to a hazard. In o2net_accept_one()
+        * we are still initializing the child socket but have not
+        * changed the inherited data_ready callback yet when
+        * data starts arriving.
+        * We avoid this hazard by checking the state.
+        * For the listening socket,  the state will be TCP_LISTEN; for the new
+        * socket, will be  TCP_ESTABLISHED. Also, in this case,
+        * sk->sk_user_data is not a valid function pointer.
+        */
+
        if (sk->sk_state == TCP_LISTEN) {
                mlog(ML_TCP, "bytes: %d\n", bytes);
                queue_work(o2net_wq, &o2net_listen_work);
+       } else {
+               ready = NULL;
        }
 
 out:
        read_unlock(&sk->sk_callback_lock);
-       ready(sk, bytes);
+       if (ready != NULL)
+               ready(sk, bytes);
 }
 
 static int o2net_open_listening_sock(__be32 addr, __be16 port)
index 0d3a97d..e2e05a1 100644 (file)
@@ -37,7 +37,6 @@
 #include "dlmglue.h"
 #include "file.h"
 #include "inode.h"
-#include "super.h"
 #include "ocfs2_trace.h"
 
 void ocfs2_dentry_attach_gen(struct dentry *dentry)
@@ -346,52 +345,6 @@ out_attach:
        return ret;
 }
 
-DEFINE_SPINLOCK(dentry_list_lock);
-
-/* We limit the number of dentry locks to drop in one go. We have
- * this limit so that we don't starve other users of ocfs2_wq. */
-#define DL_INODE_DROP_COUNT 64
-
-/* Drop inode references from dentry locks */
-static void __ocfs2_drop_dl_inodes(struct ocfs2_super *osb, int drop_count)
-{
-       struct ocfs2_dentry_lock *dl;
-
-       spin_lock(&dentry_list_lock);
-       while (osb->dentry_lock_list && (drop_count < 0 || drop_count--)) {
-               dl = osb->dentry_lock_list;
-               osb->dentry_lock_list = dl->dl_next;
-               spin_unlock(&dentry_list_lock);
-               iput(dl->dl_inode);
-               kfree(dl);
-               spin_lock(&dentry_list_lock);
-       }
-       spin_unlock(&dentry_list_lock);
-}
-
-void ocfs2_drop_dl_inodes(struct work_struct *work)
-{
-       struct ocfs2_super *osb = container_of(work, struct ocfs2_super,
-                                              dentry_lock_work);
-
-       __ocfs2_drop_dl_inodes(osb, DL_INODE_DROP_COUNT);
-       /*
-        * Don't queue dropping if umount is in progress. We flush the
-        * list in ocfs2_dismount_volume
-        */
-       spin_lock(&dentry_list_lock);
-       if (osb->dentry_lock_list &&
-           !ocfs2_test_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED))
-               queue_work(ocfs2_wq, &osb->dentry_lock_work);
-       spin_unlock(&dentry_list_lock);
-}
-
-/* Flush the whole work queue */
-void ocfs2_drop_all_dl_inodes(struct ocfs2_super *osb)
-{
-       __ocfs2_drop_dl_inodes(osb, -1);
-}
-
 /*
  * ocfs2_dentry_iput() and friends.
  *
@@ -416,24 +369,16 @@ void ocfs2_drop_all_dl_inodes(struct ocfs2_super *osb)
 static void ocfs2_drop_dentry_lock(struct ocfs2_super *osb,
                                   struct ocfs2_dentry_lock *dl)
 {
+       iput(dl->dl_inode);
        ocfs2_simple_drop_lockres(osb, &dl->dl_lockres);
        ocfs2_lock_res_free(&dl->dl_lockres);
-
-       /* We leave dropping of inode reference to ocfs2_wq as that can
-        * possibly lead to inode deletion which gets tricky */
-       spin_lock(&dentry_list_lock);
-       if (!osb->dentry_lock_list &&
-           !ocfs2_test_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED))
-               queue_work(ocfs2_wq, &osb->dentry_lock_work);
-       dl->dl_next = osb->dentry_lock_list;
-       osb->dentry_lock_list = dl;
-       spin_unlock(&dentry_list_lock);
+       kfree(dl);
 }
 
 void ocfs2_dentry_lock_put(struct ocfs2_super *osb,
                           struct ocfs2_dentry_lock *dl)
 {
-       int unlock;
+       int unlock = 0;
 
        BUG_ON(dl->dl_count == 0);
 
index b79eff7..55f5889 100644 (file)
 extern const struct dentry_operations ocfs2_dentry_ops;
 
 struct ocfs2_dentry_lock {
-       /* Use count of dentry lock */
        unsigned int            dl_count;
-       union {
-               /* Linked list of dentry locks to release */
-               struct ocfs2_dentry_lock *dl_next;
-               u64                     dl_parent_blkno;
-       };
+       u64                     dl_parent_blkno;
 
        /*
         * The ocfs2_dentry_lock keeps an inode reference until
@@ -49,14 +44,9 @@ struct ocfs2_dentry_lock {
 int ocfs2_dentry_attach_lock(struct dentry *dentry, struct inode *inode,
                             u64 parent_blkno);
 
-extern spinlock_t dentry_list_lock;
-
 void ocfs2_dentry_lock_put(struct ocfs2_super *osb,
                           struct ocfs2_dentry_lock *dl);
 
-void ocfs2_drop_dl_inodes(struct work_struct *work);
-void ocfs2_drop_all_dl_inodes(struct ocfs2_super *osb);
-
 struct dentry *ocfs2_find_local_alias(struct inode *inode, u64 parent_blkno,
                                      int skip_unhashed);
 
index 91a7e85..0717662 100644 (file)
@@ -2957,6 +2957,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
                ocfs2_init_dir_trailer(dir, dirdata_bh, i);
        }
 
+       ocfs2_update_inode_fsync_trans(handle, dir, 1);
        ocfs2_journal_dirty(handle, dirdata_bh);
 
        if (ocfs2_supports_indexed_dirs(osb) && !dx_inline) {
@@ -3005,6 +3006,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
        di->i_size = cpu_to_le64(sb->s_blocksize);
        di->i_ctime = di->i_mtime = cpu_to_le64(dir->i_ctime.tv_sec);
        di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(dir->i_ctime.tv_nsec);
+       ocfs2_update_inode_fsync_trans(handle, dir, 1);
 
        /*
         * This should never fail as our extent list is empty and all
@@ -3338,6 +3340,7 @@ do_extend:
        } else {
                de->rec_len = cpu_to_le16(sb->s_blocksize);
        }
+       ocfs2_update_inode_fsync_trans(handle, dir, 1);
        ocfs2_journal_dirty(handle, new_bh);
 
        dir_i_size += dir->i_sb->s_blocksize;
@@ -3896,6 +3899,7 @@ out_commit:
                dquot_free_space_nodirty(dir,
                                ocfs2_clusters_to_bytes(dir->i_sb, 1));
 
+       ocfs2_update_inode_fsync_trans(handle, dir, 1);
        ocfs2_commit_trans(osb, handle);
 
 out:
@@ -4134,6 +4138,7 @@ static int ocfs2_expand_inline_dx_root(struct inode *dir,
                mlog_errno(ret);
        did_quota = 0;
 
+       ocfs2_update_inode_fsync_trans(handle, dir, 1);
        ocfs2_journal_dirty(handle, dx_root_bh);
 
 out_commit:
@@ -4401,6 +4406,7 @@ static int ocfs2_dx_dir_remove_index(struct inode *dir,
        di->i_dyn_features = cpu_to_le16(OCFS2_I(dir)->ip_dyn_features);
        spin_unlock(&OCFS2_I(dir)->ip_lock);
        di->i_dx_root = cpu_to_le64(0ULL);
+       ocfs2_update_inode_fsync_trans(handle, dir, 1);
 
        ocfs2_journal_dirty(handle, di_bh);
 
index 33660a4..c973690 100644 (file)
@@ -1123,7 +1123,6 @@ static int dlm_query_region_handler(struct o2net_msg *msg, u32 len,
        struct dlm_ctxt *dlm = NULL;
        char *local = NULL;
        int status = 0;
-       int locked = 0;
 
        qr = (struct dlm_query_region *) msg->buf;
 
@@ -1132,10 +1131,8 @@ static int dlm_query_region_handler(struct o2net_msg *msg, u32 len,
 
        /* buffer used in dlm_mast_regions() */
        local = kmalloc(sizeof(qr->qr_regions), GFP_KERNEL);
-       if (!local) {
-               status = -ENOMEM;
-               goto bail;
-       }
+       if (!local)
+               return -ENOMEM;
 
        status = -EINVAL;
 
@@ -1144,16 +1141,15 @@ static int dlm_query_region_handler(struct o2net_msg *msg, u32 len,
        if (!dlm) {
                mlog(ML_ERROR, "Node %d queried hb regions on domain %s "
                     "before join domain\n", qr->qr_node, qr->qr_domain);
-               goto bail;
+               goto out_domain_lock;
        }
 
        spin_lock(&dlm->spinlock);
-       locked = 1;
        if (dlm->joining_node != qr->qr_node) {
                mlog(ML_ERROR, "Node %d queried hb regions on domain %s "
                     "but joining node is %d\n", qr->qr_node, qr->qr_domain,
                     dlm->joining_node);
-               goto bail;
+               goto out_dlm_lock;
        }
 
        /* Support for global heartbeat was added in 1.1 */
@@ -1163,14 +1159,15 @@ static int dlm_query_region_handler(struct o2net_msg *msg, u32 len,
                     "but active dlm protocol is %d.%d\n", qr->qr_node,
                     qr->qr_domain, dlm->dlm_locking_proto.pv_major,
                     dlm->dlm_locking_proto.pv_minor);
-               goto bail;
+               goto out_dlm_lock;
        }
 
        status = dlm_match_regions(dlm, qr, local, sizeof(qr->qr_regions));
 
-bail:
-       if (locked)
-               spin_unlock(&dlm->spinlock);
+out_dlm_lock:
+       spin_unlock(&dlm->spinlock);
+
+out_domain_lock:
        spin_unlock(&dlm_domain_lock);
 
        kfree(local);
@@ -1877,19 +1874,19 @@ static int dlm_join_domain(struct dlm_ctxt *dlm)
                goto bail;
        }
 
-       status = dlm_debug_init(dlm);
+       status = dlm_launch_thread(dlm);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
        }
 
-       status = dlm_launch_thread(dlm);
+       status = dlm_launch_recovery_thread(dlm);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
        }
 
-       status = dlm_launch_recovery_thread(dlm);
+       status = dlm_debug_init(dlm);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
index 7035af0..fe29f79 100644 (file)
@@ -537,7 +537,10 @@ master_here:
                /* success!  see if any other nodes need recovery */
                mlog(0, "DONE mastering recovery of %s:%u here(this=%u)!\n",
                     dlm->name, dlm->reco.dead_node, dlm->node_num);
-               dlm_reset_recovery(dlm);
+               spin_lock(&dlm->spinlock);
+               __dlm_reset_recovery(dlm);
+               dlm->reco.state &= ~DLM_RECO_STATE_FINALIZE;
+               spin_unlock(&dlm->spinlock);
        }
        dlm_end_recovery(dlm);
 
@@ -695,6 +698,14 @@ static int dlm_remaster_locks(struct dlm_ctxt *dlm, u8 dead_node)
                if (all_nodes_done) {
                        int ret;
 
+                       /* Set this flag on recovery master to avoid
+                        * a new recovery for another dead node start
+                        * before the recovery is not done. That may
+                        * cause recovery hung.*/
+                       spin_lock(&dlm->spinlock);
+                       dlm->reco.state |= DLM_RECO_STATE_FINALIZE;
+                       spin_unlock(&dlm->spinlock);
+
                        /* all nodes are now in DLM_RECO_NODE_DATA_DONE state
                         * just send a finalize message to everyone and
                         * clean up */
@@ -1750,13 +1761,13 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
                                     struct dlm_migratable_lockres *mres)
 {
        struct dlm_migratable_lock *ml;
-       struct list_head *queue;
+       struct list_head *queue, *iter;
        struct list_head *tmpq = NULL;
        struct dlm_lock *newlock = NULL;
        struct dlm_lockstatus *lksb = NULL;
        int ret = 0;
        int i, j, bad;
-       struct dlm_lock *lock = NULL;
+       struct dlm_lock *lock;
        u8 from = O2NM_MAX_NODES;
        unsigned int added = 0;
        __be64 c;
@@ -1791,14 +1802,16 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
                        /* MIGRATION ONLY! */
                        BUG_ON(!(mres->flags & DLM_MRES_MIGRATION));
 
+                       lock = NULL;
                        spin_lock(&res->spinlock);
                        for (j = DLM_GRANTED_LIST; j <= DLM_BLOCKED_LIST; j++) {
                                tmpq = dlm_list_idx_to_ptr(res, j);
-                               list_for_each_entry(lock, tmpq, list) {
-                                       if (lock->ml.cookie != ml->cookie)
-                                               lock = NULL;
-                                       else
+                               list_for_each(iter, tmpq) {
+                                       lock = list_entry(iter,
+                                                 struct dlm_lock, list);
+                                       if (lock->ml.cookie == ml->cookie)
                                                break;
+                                       lock = NULL;
                                }
                                if (lock)
                                        break;
@@ -2882,8 +2895,8 @@ int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data,
                                BUG();
                        }
                        dlm->reco.state &= ~DLM_RECO_STATE_FINALIZE;
+                       __dlm_reset_recovery(dlm);
                        spin_unlock(&dlm->spinlock);
-                       dlm_reset_recovery(dlm);
                        dlm_kick_recovery_thread(dlm);
                        break;
                default:
index 1998695..6bd690b 100644 (file)
@@ -3144,22 +3144,60 @@ out:
        return 0;
 }
 
+static void ocfs2_process_blocked_lock(struct ocfs2_super *osb,
+                                      struct ocfs2_lock_res *lockres);
+
 /* Mark the lockres as being dropped. It will no longer be
  * queued if blocking, but we still may have to wait on it
  * being dequeued from the downconvert thread before we can consider
  * it safe to drop.
  *
  * You can *not* attempt to call cluster_lock on this lockres anymore. */
-void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres)
+void ocfs2_mark_lockres_freeing(struct ocfs2_super *osb,
+                               struct ocfs2_lock_res *lockres)
 {
        int status;
        struct ocfs2_mask_waiter mw;
-       unsigned long flags;
+       unsigned long flags, flags2;
 
        ocfs2_init_mask_waiter(&mw);
 
        spin_lock_irqsave(&lockres->l_lock, flags);
        lockres->l_flags |= OCFS2_LOCK_FREEING;
+       if (lockres->l_flags & OCFS2_LOCK_QUEUED && current == osb->dc_task) {
+               /*
+                * We know the downconvert is queued but not in progress
+                * because we are the downconvert thread and processing
+                * different lock. So we can just remove the lock from the
+                * queue. This is not only an optimization but also a way
+                * to avoid the following deadlock:
+                *   ocfs2_dentry_post_unlock()
+                *     ocfs2_dentry_lock_put()
+                *       ocfs2_drop_dentry_lock()
+                *         iput()
+                *           ocfs2_evict_inode()
+                *             ocfs2_clear_inode()
+                *               ocfs2_mark_lockres_freeing()
+                *                 ... blocks waiting for OCFS2_LOCK_QUEUED
+                *                 since we are the downconvert thread which
+                *                 should clear the flag.
+                */
+               spin_unlock_irqrestore(&lockres->l_lock, flags);
+               spin_lock_irqsave(&osb->dc_task_lock, flags2);
+               list_del_init(&lockres->l_blocked_list);
+               osb->blocked_lock_count--;
+               spin_unlock_irqrestore(&osb->dc_task_lock, flags2);
+               /*
+                * Warn if we recurse into another post_unlock call.  Strictly
+                * speaking it isn't a problem but we need to be careful if
+                * that happens (stack overflow, deadlocks, ...) so warn if
+                * ocfs2 grows a path for which this can happen.
+                */
+               WARN_ON_ONCE(lockres->l_ops->post_unlock);
+               /* Since the lock is freeing we don't do much in the fn below */
+               ocfs2_process_blocked_lock(osb, lockres);
+               return;
+       }
        while (lockres->l_flags & OCFS2_LOCK_QUEUED) {
                lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_QUEUED, 0);
                spin_unlock_irqrestore(&lockres->l_lock, flags);
@@ -3180,7 +3218,7 @@ void ocfs2_simple_drop_lockres(struct ocfs2_super *osb,
 {
        int ret;
 
-       ocfs2_mark_lockres_freeing(lockres);
+       ocfs2_mark_lockres_freeing(osb, lockres);
        ret = ocfs2_drop_lock(osb, lockres);
        if (ret)
                mlog_errno(ret);
index 1d596d8..d293a22 100644 (file)
@@ -157,7 +157,8 @@ int ocfs2_refcount_lock(struct ocfs2_refcount_tree *ref_tree, int ex);
 void ocfs2_refcount_unlock(struct ocfs2_refcount_tree *ref_tree, int ex);
 
 
-void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres);
+void ocfs2_mark_lockres_freeing(struct ocfs2_super *osb,
+                               struct ocfs2_lock_res *lockres);
 void ocfs2_simple_drop_lockres(struct ocfs2_super *osb,
                               struct ocfs2_lock_res *lockres);
 
index 51632c4..ff33c5e 100644 (file)
@@ -175,9 +175,13 @@ static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end,
                           int datasync)
 {
        int err = 0;
-       journal_t *journal;
        struct inode *inode = file->f_mapping->host;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       journal_t *journal = osb->journal->j_journal;
+       int ret;
+       tid_t commit_tid;
+       bool needs_barrier = false;
 
        trace_ocfs2_sync_file(inode, file, file->f_path.dentry,
                              OCFS2_I(inode)->ip_blkno,
@@ -192,29 +196,19 @@ static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end,
        if (err)
                return err;
 
-       /*
-        * Probably don't need the i_mutex at all in here, just putting it here
-        * to be consistent with how fsync used to be called, someone more
-        * familiar with the fs could possibly remove it.
-        */
-       mutex_lock(&inode->i_mutex);
-       if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) {
-               /*
-                * We still have to flush drive's caches to get data to the
-                * platter
-                */
-               if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
-                       blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
-               goto bail;
+       commit_tid = datasync ? oi->i_datasync_tid : oi->i_sync_tid;
+       if (journal->j_flags & JBD2_BARRIER &&
+           !jbd2_trans_will_send_data_barrier(journal, commit_tid))
+               needs_barrier = true;
+       err = jbd2_complete_transaction(journal, commit_tid);
+       if (needs_barrier) {
+               ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
+               if (!err)
+                       err = ret;
        }
 
-       journal = osb->journal->j_journal;
-       err = jbd2_journal_force_commit(journal);
-
-bail:
        if (err)
                mlog_errno(err);
-       mutex_unlock(&inode->i_mutex);
 
        return (err < 0) ? -EIO : 0;
 }
@@ -292,6 +286,7 @@ int ocfs2_update_inode_atime(struct inode *inode,
        inode->i_atime = CURRENT_TIME;
        di->i_atime = cpu_to_le64(inode->i_atime.tv_sec);
        di->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec);
+       ocfs2_update_inode_fsync_trans(handle, inode, 0);
        ocfs2_journal_dirty(handle, bh);
 
 out_commit:
@@ -341,6 +336,7 @@ int ocfs2_simple_size_update(struct inode *inode,
        if (ret < 0)
                mlog_errno(ret);
 
+       ocfs2_update_inode_fsync_trans(handle, inode, 0);
        ocfs2_commit_trans(osb, handle);
 out:
        return ret;
@@ -435,6 +431,7 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
        di->i_size = cpu_to_le64(new_i_size);
        di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec);
        di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
+       ocfs2_update_inode_fsync_trans(handle, inode, 0);
 
        ocfs2_journal_dirty(handle, fe_bh);
 
@@ -650,7 +647,7 @@ restarted_transaction:
                        mlog_errno(status);
                goto leave;
        }
-
+       ocfs2_update_inode_fsync_trans(handle, inode, 1);
        ocfs2_journal_dirty(handle, bh);
 
        spin_lock(&OCFS2_I(inode)->ip_lock);
@@ -743,6 +740,7 @@ static handle_t *ocfs2_zero_start_ordered_transaction(struct inode *inode,
                                      OCFS2_JOURNAL_ACCESS_WRITE);
        if (ret)
                mlog_errno(ret);
+       ocfs2_update_inode_fsync_trans(handle, inode, 1);
 
 out:
        if (ret) {
@@ -840,6 +838,7 @@ static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
                di->i_ctime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
                di->i_mtime_nsec = di->i_ctime_nsec;
                ocfs2_journal_dirty(handle, di_bh);
+               ocfs2_update_inode_fsync_trans(handle, inode, 1);
                ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
        }
 
@@ -1344,6 +1343,7 @@ static int __ocfs2_write_remove_suid(struct inode *inode,
 
        di = (struct ocfs2_dinode *) bh->b_data;
        di->i_mode = cpu_to_le16(inode->i_mode);
+       ocfs2_update_inode_fsync_trans(handle, inode, 0);
 
        ocfs2_journal_dirty(handle, bh);
 
@@ -1576,6 +1576,7 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,
                if (ret)
                        mlog_errno(ret);
        }
+       ocfs2_update_inode_fsync_trans(handle, inode, 1);
 
        ocfs2_commit_trans(osb, handle);
 out:
@@ -2061,13 +2062,6 @@ out:
        return ret;
 }
 
-static void ocfs2_aiodio_wait(struct inode *inode)
-{
-       wait_queue_head_t *wq = ocfs2_ioend_wq(inode);
-
-       wait_event(*wq, (atomic_read(&OCFS2_I(inode)->ip_unaligned_aio) == 0));
-}
-
 static int ocfs2_is_io_unaligned(struct inode *inode, size_t count, loff_t pos)
 {
        int blockmask = inode->i_sb->s_blocksize - 1;
@@ -2345,10 +2339,8 @@ relock:
                 * Wait on previous unaligned aio to complete before
                 * proceeding.
                 */
-               ocfs2_aiodio_wait(inode);
-
-               /* Mark the iocb as needing a decrement in ocfs2_dio_end_io */
-               atomic_inc(&OCFS2_I(inode)->ip_unaligned_aio);
+               mutex_lock(&OCFS2_I(inode)->ip_unaligned_aio);
+               /* Mark the iocb as needing an unlock in ocfs2_dio_end_io */
                ocfs2_iocb_set_unaligned_aio(iocb);
        }
 
@@ -2428,7 +2420,7 @@ out_dio:
 
        if (unaligned_dio) {
                ocfs2_iocb_clear_unaligned_aio(iocb);
-               atomic_dec(&OCFS2_I(inode)->ip_unaligned_aio);
+               mutex_unlock(&OCFS2_I(inode)->ip_unaligned_aio);
        }
 
 out:
@@ -2645,7 +2637,16 @@ static loff_t ocfs2_file_llseek(struct file *file, loff_t offset, int whence)
        case SEEK_SET:
                break;
        case SEEK_END:
-               offset += inode->i_size;
+               /* SEEK_END requires the OCFS2 inode lock for the file
+                * because it references the file's size.
+                */
+               ret = ocfs2_inode_lock(inode, NULL, 0);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+               offset += i_size_read(inode);
+               ocfs2_inode_unlock(inode, 0);
                break;
        case SEEK_CUR:
                if (offset == 0) {
index f29a90f..437de7f 100644 (file)
@@ -130,6 +130,7 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
        struct inode *inode = NULL;
        struct super_block *sb = osb->sb;
        struct ocfs2_find_inode_args args;
+       journal_t *journal = OCFS2_SB(sb)->journal->j_journal;
 
        trace_ocfs2_iget_begin((unsigned long long)blkno, flags,
                               sysfile_type);
@@ -169,6 +170,32 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
                goto bail;
        }
 
+       /*
+        * Set transaction id's of transactions that have to be committed
+        * to finish f[data]sync. We set them to currently running transaction
+        * as we cannot be sure that the inode or some of its metadata isn't
+        * part of the transaction - the inode could have been reclaimed and
+        * now it is reread from disk.
+        */
+       if (journal) {
+               transaction_t *transaction;
+               tid_t tid;
+               struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+               read_lock(&journal->j_state_lock);
+               if (journal->j_running_transaction)
+                       transaction = journal->j_running_transaction;
+               else
+                       transaction = journal->j_committing_transaction;
+               if (transaction)
+                       tid = transaction->t_tid;
+               else
+                       tid = journal->j_commit_sequence;
+               read_unlock(&journal->j_state_lock);
+               oi->i_sync_tid = tid;
+               oi->i_datasync_tid = tid;
+       }
+
 bail:
        if (!IS_ERR(inode)) {
                trace_ocfs2_iget_end(inode, 
@@ -804,11 +831,13 @@ static int ocfs2_inode_is_valid_to_delete(struct inode *inode)
                goto bail;
        }
 
-       /* If we're coming from downconvert_thread we can't go into our own
-        * voting [hello, deadlock city!], so unforuntately we just
-        * have to skip deleting this guy. That's OK though because
-        * the node who's doing the actual deleting should handle it
-        * anyway. */
+       /*
+        * If we're coming from downconvert_thread we can't go into our own
+        * voting [hello, deadlock city!] so we cannot delete the inode. But
+        * since we dropped last inode ref when downconverting dentry lock,
+        * we cannot have the file open and thus the node doing unlink will
+        * take care of deleting the inode.
+        */
        if (current == osb->dc_task)
                goto bail;
 
@@ -822,12 +851,6 @@ static int ocfs2_inode_is_valid_to_delete(struct inode *inode)
                goto bail_unlock;
        }
 
-       /* If we have allowd wipe of this inode for another node, it
-        * will be marked here so we can safely skip it. Recovery will
-        * cleanup any inodes we might inadvertently skip here. */
-       if (oi->ip_flags & OCFS2_INODE_SKIP_DELETE)
-               goto bail_unlock;
-
        ret = 1;
 bail_unlock:
        spin_unlock(&oi->ip_lock);
@@ -941,7 +964,7 @@ static void ocfs2_cleanup_delete_inode(struct inode *inode,
                (unsigned long long)OCFS2_I(inode)->ip_blkno, sync_data);
        if (sync_data)
                filemap_write_and_wait(inode->i_mapping);
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
 }
 
 static void ocfs2_delete_inode(struct inode *inode)
@@ -960,8 +983,6 @@ static void ocfs2_delete_inode(struct inode *inode)
        if (is_bad_inode(inode) || !OCFS2_I(inode)->ip_blkno)
                goto bail;
 
-       dquot_initialize(inode);
-
        if (!ocfs2_inode_is_valid_to_delete(inode)) {
                /* It's probably not necessary to truncate_inode_pages
                 * here but we do it for safety anyway (it will most
@@ -970,6 +991,8 @@ static void ocfs2_delete_inode(struct inode *inode)
                goto bail;
        }
 
+       dquot_initialize(inode);
+
        /* We want to block signals in delete_inode as the lock and
         * messaging paths may return us -ERESTARTSYS. Which would
         * cause us to exit early, resulting in inodes being orphaned
@@ -1057,6 +1080,7 @@ static void ocfs2_clear_inode(struct inode *inode)
 {
        int status;
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        clear_inode(inode);
        trace_ocfs2_clear_inode((unsigned long long)oi->ip_blkno,
@@ -1073,9 +1097,9 @@ static void ocfs2_clear_inode(struct inode *inode)
 
        /* Do these before all the other work so that we don't bounce
         * the downconvert thread while waiting to destroy the locks. */
-       ocfs2_mark_lockres_freeing(&oi->ip_rw_lockres);
-       ocfs2_mark_lockres_freeing(&oi->ip_inode_lockres);
-       ocfs2_mark_lockres_freeing(&oi->ip_open_lockres);
+       ocfs2_mark_lockres_freeing(osb, &oi->ip_rw_lockres);
+       ocfs2_mark_lockres_freeing(osb, &oi->ip_inode_lockres);
+       ocfs2_mark_lockres_freeing(osb, &oi->ip_open_lockres);
 
        ocfs2_resv_discard(&OCFS2_SB(inode->i_sb)->osb_la_resmap,
                           &oi->ip_la_data_resv);
@@ -1157,7 +1181,7 @@ void ocfs2_evict_inode(struct inode *inode)
            (OCFS2_I(inode)->ip_flags & OCFS2_INODE_MAYBE_ORPHANED)) {
                ocfs2_delete_inode(inode);
        } else {
-               truncate_inode_pages(&inode->i_data, 0);
+               truncate_inode_pages_final(&inode->i_data);
        }
        ocfs2_clear_inode(inode);
 }
@@ -1260,6 +1284,7 @@ int ocfs2_mark_inode_dirty(handle_t *handle,
        fe->i_mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
 
        ocfs2_journal_dirty(handle, bh);
+       ocfs2_update_inode_fsync_trans(handle, inode, 1);
 leave:
        return status;
 }
index 621fc73..a6c991c 100644 (file)
@@ -44,7 +44,7 @@ struct ocfs2_inode_info
        struct rw_semaphore             ip_xattr_sem;
 
        /* Number of outstanding AIO's which are not page aligned */
-       atomic_t                        ip_unaligned_aio;
+       struct mutex                    ip_unaligned_aio;
 
        /* These fields are protected by ip_lock */
        spinlock_t                      ip_lock;
@@ -73,6 +73,13 @@ struct ocfs2_inode_info
        u32                             ip_dir_lock_gen;
 
        struct ocfs2_alloc_reservation  ip_la_data_resv;
+
+       /*
+        * Transactions that contain inode's metadata needed to complete
+        * fsync and fdatasync, respectively.
+        */
+       tid_t i_sync_tid;
+       tid_t i_datasync_tid;
 };
 
 /*
@@ -84,8 +91,6 @@ struct ocfs2_inode_info
 #define OCFS2_INODE_BITMAP             0x00000004
 /* This inode has been wiped from disk */
 #define OCFS2_INODE_DELETED            0x00000008
-/* Another node is deleting, so our delete is a nop */
-#define OCFS2_INODE_SKIP_DELETE                0x00000010
 /* Has the inode been orphaned on another node?
  *
  * This hints to ocfs2_drop_inode that it should clear i_nlink before
@@ -100,11 +105,11 @@ struct ocfs2_inode_info
  * rely on ocfs2_delete_inode to sort things out under the proper
  * cluster locks.
  */
-#define OCFS2_INODE_MAYBE_ORPHANED     0x00000020
+#define OCFS2_INODE_MAYBE_ORPHANED     0x00000010
 /* Does someone have the file open O_DIRECT */
-#define OCFS2_INODE_OPEN_DIRECT                0x00000040
+#define OCFS2_INODE_OPEN_DIRECT                0x00000020
 /* Tell the inode wipe code it's not in orphan dir */
-#define OCFS2_INODE_SKIP_ORPHAN_DIR     0x00000080
+#define OCFS2_INODE_SKIP_ORPHAN_DIR     0x00000040
 
 static inline struct ocfs2_inode_info *OCFS2_I(struct inode *inode)
 {
index 8ca3c29..490229f 100644 (file)
@@ -413,11 +413,12 @@ int ocfs2_info_handle_freeinode(struct inode *inode,
                }
 
                status = ocfs2_info_scan_inode_alloc(osb, inode_alloc, blkno, oifi, i);
-               if (status < 0)
-                       goto bail;
 
                iput(inode_alloc);
                inode_alloc = NULL;
+
+               if (status < 0)
+                       goto bail;
        }
 
        o2info_set_request_filled(&oifi->ifi_req);
index 44fc3e5..03ea931 100644 (file)
@@ -2132,12 +2132,6 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb,
                iter = oi->ip_next_orphan;
 
                spin_lock(&oi->ip_lock);
-               /* The remote delete code may have set these on the
-                * assumption that the other node would wipe them
-                * successfully.  If they are still in the node's
-                * orphan dir, we need to reset that state. */
-               oi->ip_flags &= ~(OCFS2_INODE_DELETED|OCFS2_INODE_SKIP_DELETE);
-
                /* Set the proper information to get us going into
                 * ocfs2_delete_inode. */
                oi->ip_flags |= OCFS2_INODE_MAYBE_ORPHANED;
index 9ff4e8c..7f8cde9 100644 (file)
@@ -626,4 +626,15 @@ static inline int ocfs2_begin_ordered_truncate(struct inode *inode,
                                new_size);
 }
 
+static inline void ocfs2_update_inode_fsync_trans(handle_t *handle,
+                                                 struct inode *inode,
+                                                 int datasync)
+{
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+       oi->i_sync_tid = handle->h_transaction->t_tid;
+       if (datasync)
+               oi->i_datasync_tid = handle->h_transaction->t_tid;
+}
+
 #endif /* OCFS2_JOURNAL_H */
index e57c804..6b6d092 100644 (file)
@@ -82,6 +82,8 @@ static int ocfs2_do_flock(struct file *file, struct inode *inode,
        }
 
        ret = flock_lock_file_wait(file, fl);
+       if (ret)
+               ocfs2_file_unlock(file);
 
 out:
        mutex_unlock(&fp->fp_mutex);
index 64c304d..599eb4c 100644 (file)
@@ -151,6 +151,7 @@ static int __ocfs2_move_extent(handle_t *handle,
                                                        old_blkno, len);
        }
 
+       ocfs2_update_inode_fsync_trans(handle, inode, 0);
 out:
        ocfs2_free_path(path);
        return ret;
@@ -690,8 +691,11 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_context *context,
 
        ret = ocfs2_block_group_set_bits(handle, gb_inode, gd, gd_bh,
                                         goal_bit, len);
-       if (ret)
+       if (ret) {
+               ocfs2_rollback_alloc_dinode_counts(gb_inode, gb_bh, len,
+                                              le16_to_cpu(gd->bg_chain));
                mlog_errno(ret);
+       }
 
        /*
         * Here we should write the new page out first if we are
@@ -957,6 +961,7 @@ static int ocfs2_move_extents(struct ocfs2_move_extents_context *context)
        inode->i_ctime = CURRENT_TIME;
        di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
        di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
+       ocfs2_update_inode_fsync_trans(handle, inode, 0);
 
        ocfs2_journal_dirty(handle, di_bh);
 
index 3683643..2060fc3 100644 (file)
@@ -450,7 +450,6 @@ leave:
 
        brelse(new_fe_bh);
        brelse(parent_fe_bh);
-       kfree(si.name);
        kfree(si.value);
 
        ocfs2_free_dir_lookup_result(&lookup);
@@ -495,6 +494,7 @@ static int __ocfs2_mknod_locked(struct inode *dir,
        struct ocfs2_dinode *fe = NULL;
        struct ocfs2_extent_list *fel;
        u16 feat;
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
        *new_fe_bh = NULL;
 
@@ -576,8 +576,8 @@ static int __ocfs2_mknod_locked(struct inode *dir,
                        mlog_errno(status);
        }
 
-       status = 0; /* error in ocfs2_create_new_inode_locks is not
-                    * critical */
+       oi->i_sync_tid = handle->h_transaction->t_tid;
+       oi->i_datasync_tid = handle->h_transaction->t_tid;
 
 leave:
        if (status < 0) {
@@ -1855,7 +1855,6 @@ bail:
 
        brelse(new_fe_bh);
        brelse(parent_fe_bh);
-       kfree(si.name);
        kfree(si.value);
        ocfs2_free_dir_lookup_result(&lookup);
        if (inode_ac)
@@ -2481,6 +2480,7 @@ int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
        di->i_orphaned_slot = 0;
        set_nlink(inode, 1);
        ocfs2_set_links_count(di, inode->i_nlink);
+       ocfs2_update_inode_fsync_trans(handle, inode, 1);
        ocfs2_journal_dirty(handle, di_bh);
 
        status = ocfs2_add_entry(handle, dentry, inode,
index 553f53c..8d64a97 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/list.h>
+#include <linux/llist.h>
 #include <linux/rbtree.h>
 #include <linux/workqueue.h>
 #include <linux/kref.h>
@@ -274,19 +275,16 @@ enum ocfs2_mount_options
        OCFS2_MOUNT_HB_GLOBAL = 1 << 14, /* Global heartbeat */
 };
 
-#define OCFS2_OSB_SOFT_RO                      0x0001
-#define OCFS2_OSB_HARD_RO                      0x0002
-#define OCFS2_OSB_ERROR_FS                     0x0004
-#define OCFS2_OSB_DROP_DENTRY_LOCK_IMMED       0x0008
-
-#define OCFS2_DEFAULT_ATIME_QUANTUM            60
+#define OCFS2_OSB_SOFT_RO      0x0001
+#define OCFS2_OSB_HARD_RO      0x0002
+#define OCFS2_OSB_ERROR_FS     0x0004
+#define OCFS2_DEFAULT_ATIME_QUANTUM    60
 
 struct ocfs2_journal;
 struct ocfs2_slot_info;
 struct ocfs2_recovery_map;
 struct ocfs2_replay_map;
 struct ocfs2_quota_recovery;
-struct ocfs2_dentry_lock;
 struct ocfs2_super
 {
        struct task_struct *commit_task;
@@ -414,10 +412,9 @@ struct ocfs2_super
        struct list_head blocked_lock_list;
        unsigned long blocked_lock_count;
 
-       /* List of dentry locks to release. Anyone can add locks to
-        * the list, ocfs2_wq processes the list  */
-       struct ocfs2_dentry_lock *dentry_lock_list;
-       struct work_struct dentry_lock_work;
+       /* List of dquot structures to drop last reference to */
+       struct llist_head dquot_drop_list;
+       struct work_struct dquot_drop_work;
 
        wait_queue_head_t               osb_mount_event;
 
@@ -449,6 +446,8 @@ struct ocfs2_super
        /* rb tree root for refcount lock. */
        struct rb_root  osb_rf_lock_tree;
        struct ocfs2_refcount_tree *osb_ref_tree_lru;
+
+       struct mutex system_file_mutex;
 };
 
 #define OCFS2_SB(sb)       ((struct ocfs2_super *)(sb)->s_fs_info)
@@ -579,18 +578,6 @@ static inline void ocfs2_set_osb_flag(struct ocfs2_super *osb,
        spin_unlock(&osb->osb_lock);
 }
 
-
-static inline unsigned long  ocfs2_test_osb_flag(struct ocfs2_super *osb,
-                                                unsigned long flag)
-{
-       unsigned long ret;
-
-       spin_lock(&osb->osb_lock);
-       ret = osb->osb_flags & flag;
-       spin_unlock(&osb->osb_lock);
-       return ret;
-}
-
 static inline void ocfs2_set_ro_flag(struct ocfs2_super *osb,
                                     int hard)
 {
index d5ab56c..f266d67 100644 (file)
@@ -28,6 +28,7 @@ struct ocfs2_dquot {
        unsigned int dq_use_count;      /* Number of nodes having reference to this entry in global quota file */
        s64 dq_origspace;       /* Last globally synced space usage */
        s64 dq_originodes;      /* Last globally synced inode usage */
+       struct llist_node list; /* Member of list of dquots to drop */
 };
 
 /* Description of one chunk to recover in memory */
@@ -110,6 +111,7 @@ int ocfs2_read_quota_phys_block(struct inode *inode, u64 p_block,
 int ocfs2_create_local_dquot(struct dquot *dquot);
 int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot);
 int ocfs2_local_write_dquot(struct dquot *dquot);
+void ocfs2_drop_dquot_refs(struct work_struct *work);
 
 extern const struct dquot_operations ocfs2_quota_operations;
 extern struct quota_format_type ocfs2_quota_format;
index d7b5108..b990a62 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/jiffies.h>
 #include <linux/writeback.h>
 #include <linux/workqueue.h>
+#include <linux/llist.h>
 
 #include <cluster/masklog.h>
 
@@ -679,6 +680,27 @@ static int ocfs2_calc_qdel_credits(struct super_block *sb, int type)
               OCFS2_INODE_UPDATE_CREDITS;
 }
 
+void ocfs2_drop_dquot_refs(struct work_struct *work)
+{
+       struct ocfs2_super *osb = container_of(work, struct ocfs2_super,
+                                              dquot_drop_work);
+       struct llist_node *list;
+       struct ocfs2_dquot *odquot, *next_odquot;
+
+       list = llist_del_all(&osb->dquot_drop_list);
+       llist_for_each_entry_safe(odquot, next_odquot, list, list) {
+               /* Drop the reference we acquired in ocfs2_dquot_release() */
+               dqput(&odquot->dq_dquot);
+       }
+}
+
+/*
+ * Called when the last reference to dquot is dropped. If we are called from
+ * downconvert thread, we cannot do all the handling here because grabbing
+ * quota lock could deadlock (the node holding the quota lock could need some
+ * other cluster lock to proceed but with blocked downconvert thread we cannot
+ * release any lock).
+ */
 static int ocfs2_release_dquot(struct dquot *dquot)
 {
        handle_t *handle;
@@ -694,6 +716,19 @@ static int ocfs2_release_dquot(struct dquot *dquot)
        /* Check whether we are not racing with some other dqget() */
        if (atomic_read(&dquot->dq_count) > 1)
                goto out;
+       /* Running from downconvert thread? Postpone quota processing to wq */
+       if (current == osb->dc_task) {
+               /*
+                * Grab our own reference to dquot and queue it for delayed
+                * dropping.  Quota code rechecks after calling
+                * ->release_dquot() and won't free dquot structure.
+                */
+               dqgrab(dquot);
+               /* First entry on list -> queue work */
+               if (llist_add(&OCFS2_DQUOT(dquot)->list, &osb->dquot_drop_list))
+                       queue_work(ocfs2_wq, &osb->dquot_drop_work);
+               goto out;
+       }
        status = ocfs2_lock_global_qf(oinfo, 1);
        if (status < 0)
                goto out;
index ca5ce14..5c8343f 100644 (file)
@@ -603,11 +603,25 @@ static struct kobj_attribute ocfs2_attr_cluster_stack =
               ocfs2_cluster_stack_show,
               ocfs2_cluster_stack_store);
 
+
+
+static ssize_t ocfs2_dlm_recover_show(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "1\n");
+}
+
+static struct kobj_attribute ocfs2_attr_dlm_recover_support =
+       __ATTR(dlm_recover_callback_support, S_IRUGO,
+              ocfs2_dlm_recover_show, NULL);
+
 static struct attribute *ocfs2_attrs[] = {
        &ocfs2_attr_max_locking_protocol.attr,
        &ocfs2_attr_loaded_cluster_plugins.attr,
        &ocfs2_attr_active_cluster_plugin.attr,
        &ocfs2_attr_cluster_stack.attr,
+       &ocfs2_attr_dlm_recover_support.attr,
        NULL,
 };
 
index 47ae266..0cb889a 100644 (file)
@@ -771,6 +771,7 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
        spin_unlock(&OCFS2_I(alloc_inode)->ip_lock);
        i_size_write(alloc_inode, le64_to_cpu(fe->i_size));
        alloc_inode->i_blocks = ocfs2_inode_sector_count(alloc_inode);
+       ocfs2_update_inode_fsync_trans(handle, alloc_inode, 0);
 
        status = 0;
 
@@ -1607,6 +1608,21 @@ out:
        return ret;
 }
 
+void ocfs2_rollback_alloc_dinode_counts(struct inode *inode,
+                                      struct buffer_head *di_bh,
+                                      u32 num_bits,
+                                      u16 chain)
+{
+       u32 tmp_used;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data;
+       struct ocfs2_chain_list *cl;
+
+       cl = (struct ocfs2_chain_list *)&di->id2.i_chain;
+       tmp_used = le32_to_cpu(di->id1.bitmap1.i_used);
+       di->id1.bitmap1.i_used = cpu_to_le32(tmp_used - num_bits);
+       le32_add_cpu(&cl->cl_recs[chain].c_free, num_bits);
+}
+
 static int ocfs2_bg_discontig_fix_by_rec(struct ocfs2_suballoc_result *res,
                                         struct ocfs2_extent_rec *rec,
                                         struct ocfs2_chain_list *cl)
@@ -1707,8 +1723,12 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac,
 
        ret = ocfs2_block_group_set_bits(handle, alloc_inode, gd, group_bh,
                                         res->sr_bit_offset, res->sr_bits);
-       if (ret < 0)
+       if (ret < 0) {
+               ocfs2_rollback_alloc_dinode_counts(alloc_inode, ac->ac_bh,
+                                              res->sr_bits,
+                                              le16_to_cpu(gd->bg_chain));
                mlog_errno(ret);
+       }
 
 out_loc_only:
        *bits_left = le16_to_cpu(gd->bg_free_bits_count);
@@ -1838,6 +1858,8 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
                                            res->sr_bit_offset,
                                            res->sr_bits);
        if (status < 0) {
+               ocfs2_rollback_alloc_dinode_counts(alloc_inode,
+                                       ac->ac_bh, res->sr_bits, chain);
                mlog_errno(status);
                goto bail;
        }
@@ -2091,7 +2113,7 @@ int ocfs2_find_new_inode_loc(struct inode *dir,
 
        ac->ac_find_loc_priv = res;
        *fe_blkno = res->sr_blkno;
-
+       ocfs2_update_inode_fsync_trans(handle, dir, 0);
 out:
        if (handle)
                ocfs2_commit_trans(OCFS2_SB(dir->i_sb), handle);
@@ -2149,6 +2171,8 @@ int ocfs2_claim_new_inode_at_loc(handle_t *handle,
                                         res->sr_bit_offset,
                                         res->sr_bits);
        if (ret < 0) {
+               ocfs2_rollback_alloc_dinode_counts(ac->ac_inode,
+                                              ac->ac_bh, res->sr_bits, chain);
                mlog_errno(ret);
                goto out;
        }
@@ -2870,6 +2894,7 @@ int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res)
        status = ocfs2_inode_lock(inode_alloc_inode, &alloc_bh, 0);
        if (status < 0) {
                mutex_unlock(&inode_alloc_inode->i_mutex);
+               iput(inode_alloc_inode);
                mlog(ML_ERROR, "lock on alloc inode on slot %u failed %d\n",
                     (u32)suballoc_slot, status);
                goto bail;
index 218d803..2d25017 100644 (file)
@@ -91,6 +91,10 @@ int ocfs2_alloc_dinode_update_counts(struct inode *inode,
                         struct buffer_head *di_bh,
                         u32 num_bits,
                         u16 chain);
+void ocfs2_rollback_alloc_dinode_counts(struct inode *inode,
+                        struct buffer_head *di_bh,
+                        u32 num_bits,
+                        u16 chain);
 int ocfs2_block_group_set_bits(handle_t *handle,
                         struct inode *alloc_inode,
                         struct ocfs2_group_desc *bg,
index 49d84f8..1aecd62 100644 (file)
@@ -561,6 +561,9 @@ static struct inode *ocfs2_alloc_inode(struct super_block *sb)
        if (!oi)
                return NULL;
 
+       oi->i_sync_tid = 0;
+       oi->i_datasync_tid = 0;
+
        jbd2_journal_init_jbd_inode(&oi->ip_jinode, &oi->vfs_inode);
        return &oi->vfs_inode;
 }
@@ -1238,30 +1241,11 @@ static struct dentry *ocfs2_mount(struct file_system_type *fs_type,
        return mount_bdev(fs_type, flags, dev_name, data, ocfs2_fill_super);
 }
 
-static void ocfs2_kill_sb(struct super_block *sb)
-{
-       struct ocfs2_super *osb = OCFS2_SB(sb);
-
-       /* Failed mount? */
-       if (!osb || atomic_read(&osb->vol_state) == VOLUME_DISABLED)
-               goto out;
-
-       /* Prevent further queueing of inode drop events */
-       spin_lock(&dentry_list_lock);
-       ocfs2_set_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED);
-       spin_unlock(&dentry_list_lock);
-       /* Wait for work to finish and/or remove it */
-       cancel_work_sync(&osb->dentry_lock_work);
-out:
-       kill_block_super(sb);
-}
-
 static struct file_system_type ocfs2_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "ocfs2",
        .mount          = ocfs2_mount,
-       .kill_sb        = ocfs2_kill_sb,
-
+       .kill_sb        = kill_block_super,
        .fs_flags       = FS_REQUIRES_DEV|FS_RENAME_DOES_D_MOVE,
        .next           = NULL
 };
@@ -1612,14 +1596,9 @@ static int ocfs2_show_options(struct seq_file *s, struct dentry *root)
        return 0;
 }
 
-wait_queue_head_t ocfs2__ioend_wq[OCFS2_IOEND_WQ_HASH_SZ];
-
 static int __init ocfs2_init(void)
 {
-       int status, i;
-
-       for (i = 0; i < OCFS2_IOEND_WQ_HASH_SZ; i++)
-               init_waitqueue_head(&ocfs2__ioend_wq[i]);
+       int status;
 
        status = init_ocfs2_uptodate_cache();
        if (status < 0)
@@ -1761,7 +1740,7 @@ static void ocfs2_inode_init_once(void *data)
        ocfs2_extent_map_init(&oi->vfs_inode);
        INIT_LIST_HEAD(&oi->ip_io_markers);
        oi->ip_dir_start_lookup = 0;
-       atomic_set(&oi->ip_unaligned_aio, 0);
+       mutex_init(&oi->ip_unaligned_aio);
        init_rwsem(&oi->ip_alloc_sem);
        init_rwsem(&oi->ip_xattr_sem);
        mutex_init(&oi->ip_io_mutex);
@@ -1932,17 +1911,16 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
 
        debugfs_remove(osb->osb_ctxt);
 
-       /*
-        * Flush inode dropping work queue so that deletes are
-        * performed while the filesystem is still working
-        */
-       ocfs2_drop_all_dl_inodes(osb);
-
        /* Orphan scan should be stopped as early as possible */
        ocfs2_orphan_scan_stop(osb);
 
        ocfs2_disable_quotas(osb);
 
+       /* All dquots should be freed by now */
+       WARN_ON(!llist_empty(&osb->dquot_drop_list));
+       /* Wait for worker to be done with the work structure in osb */
+       cancel_work_sync(&osb->dquot_drop_work);
+
        ocfs2_shutdown_local_alloc(osb);
 
        /* This will disable recovery and flush any recovery work. */
@@ -2077,7 +2055,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
        struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
        struct inode *inode = NULL;
        struct ocfs2_journal *journal;
-       __le32 uuid_net_key;
        struct ocfs2_super *osb;
        u64 total_blocks;
 
@@ -2123,6 +2100,8 @@ static int ocfs2_initialize_super(struct super_block *sb,
        spin_lock_init(&osb->osb_xattr_lock);
        ocfs2_init_steal_slots(osb);
 
+       mutex_init(&osb->system_file_mutex);
+
        atomic_set(&osb->alloc_stats.moves, 0);
        atomic_set(&osb->alloc_stats.local_data, 0);
        atomic_set(&osb->alloc_stats.bitmap_data, 0);
@@ -2276,8 +2255,8 @@ static int ocfs2_initialize_super(struct super_block *sb,
        INIT_WORK(&journal->j_recovery_work, ocfs2_complete_recovery);
        journal->j_state = OCFS2_JOURNAL_FREE;
 
-       INIT_WORK(&osb->dentry_lock_work, ocfs2_drop_dl_inodes);
-       osb->dentry_lock_list = NULL;
+       INIT_WORK(&osb->dquot_drop_work, ocfs2_drop_dquot_refs);
+       init_llist_head(&osb->dquot_drop_list);
 
        /* get some pseudo constants for clustersize bits */
        osb->s_clustersize_bits =
@@ -2311,8 +2290,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
                goto bail;
        }
 
-       memcpy(&uuid_net_key, di->id2.i_super.s_uuid, sizeof(uuid_net_key));
-
        strncpy(osb->vol_label, di->id2.i_super.s_label, 63);
        osb->vol_label[63] = '\0';
        osb->root_blkno = le64_to_cpu(di->id2.i_super.s_root_blkno);
index f053688..af155c1 100644 (file)
@@ -113,9 +113,11 @@ struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
        } else
                arr = get_local_system_inode(osb, type, slot);
 
+       mutex_lock(&osb->system_file_mutex);
        if (arr && ((inode = *arr) != NULL)) {
                /* get a ref in addition to the array ref */
                inode = igrab(inode);
+               mutex_unlock(&osb->system_file_mutex);
                BUG_ON(!inode);
 
                return inode;
@@ -129,6 +131,7 @@ struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
                *arr = igrab(inode);
                BUG_ON(!*arr);
        }
+       mutex_unlock(&osb->system_file_mutex);
        return inode;
 }
 
index 185fa3b..016f01d 100644 (file)
@@ -369,7 +369,7 @@ static void ocfs2_xattr_bucket_free(struct ocfs2_xattr_bucket *bucket)
  * them fully.
  */
 static int ocfs2_init_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
-                                  u64 xb_blkno)
+                                  u64 xb_blkno, int new)
 {
        int i, rc = 0;
 
@@ -383,9 +383,16 @@ static int ocfs2_init_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
                }
 
                if (!ocfs2_buffer_uptodate(INODE_CACHE(bucket->bu_inode),
-                                          bucket->bu_bhs[i]))
-                       ocfs2_set_new_buffer_uptodate(INODE_CACHE(bucket->bu_inode),
-                                                     bucket->bu_bhs[i]);
+                                          bucket->bu_bhs[i])) {
+                       if (new)
+                               ocfs2_set_new_buffer_uptodate(INODE_CACHE(bucket->bu_inode),
+                                                             bucket->bu_bhs[i]);
+                       else {
+                               set_buffer_uptodate(bucket->bu_bhs[i]);
+                               ocfs2_set_buffer_uptodate(INODE_CACHE(bucket->bu_inode),
+                                                         bucket->bu_bhs[i]);
+                       }
+               }
        }
 
        if (rc)
@@ -2602,6 +2609,7 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh)
        oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL);
        di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
        spin_unlock(&oi->ip_lock);
+       ocfs2_update_inode_fsync_trans(handle, inode, 0);
 
        ocfs2_journal_dirty(handle, di_bh);
 out_commit:
@@ -3200,8 +3208,15 @@ meta_guess:
                        clusters_add += 1;
                }
        } else {
-               meta_add += 1;
                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);
+                       credits += ocfs2_calc_extend_credits(inode->i_sb,
+                                                            el);
+               } else {
+                       meta_add += 1;
+               }
        }
 out:
        if (clusters_need)
@@ -3614,6 +3629,7 @@ int ocfs2_xattr_set(struct inode *inode,
        }
 
        ret = __ocfs2_xattr_set_handle(inode, di, &xi, &xis, &xbs, &ctxt);
+       ocfs2_update_inode_fsync_trans(ctxt.handle, inode, 0);
 
        ocfs2_commit_trans(osb, ctxt.handle);
 
@@ -4294,7 +4310,7 @@ static int ocfs2_xattr_create_index_block(struct inode *inode,
 
        trace_ocfs2_xattr_create_index_block((unsigned long long)blkno);
 
-       ret = ocfs2_init_xattr_bucket(xs->bucket, blkno);
+       ret = ocfs2_init_xattr_bucket(xs->bucket, blkno, 1);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -4638,7 +4654,7 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode,
         * Even if !new_bucket_head, we're overwriting t_bucket.  Thus,
         * there's no need to read it.
         */
-       ret = ocfs2_init_xattr_bucket(t_bucket, new_blk);
+       ret = ocfs2_init_xattr_bucket(t_bucket, new_blk, new_bucket_head);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -4804,7 +4820,7 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode,
         * Even if !t_is_new, we're overwriting t_bucket.  Thus,
         * there's no need to read it.
         */
-       ret = ocfs2_init_xattr_bucket(t_bucket, t_blkno);
+       ret = ocfs2_init_xattr_bucket(t_bucket, t_blkno, t_is_new);
        if (ret)
                goto out;
 
@@ -5476,6 +5492,7 @@ static int ocfs2_rm_xattr_cluster(struct inode *inode,
        ret = ocfs2_truncate_log_append(osb, handle, blkno, len);
        if (ret)
                mlog_errno(ret);
+       ocfs2_update_inode_fsync_trans(handle, inode, 0);
 
 out_commit:
        ocfs2_commit_trans(osb, handle);
@@ -6830,7 +6847,7 @@ static int ocfs2_reflink_xattr_bucket(handle_t *handle,
                        break;
                }
 
-               ret = ocfs2_init_xattr_bucket(args->new_bucket, new_blkno);
+               ret = ocfs2_init_xattr_bucket(args->new_bucket, new_blkno, 1);
                if (ret) {
                        mlog_errno(ret);
                        break;
index d8b0afd..ec58c76 100644 (file)
@@ -183,7 +183,7 @@ int omfs_sync_inode(struct inode *inode)
  */
 static void omfs_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
 
        if (inode->i_nlink)
index 124fc43..8f20e34 100644 (file)
@@ -35,7 +35,7 @@ static void proc_evict_inode(struct inode *inode)
        const struct proc_ns_operations *ns_ops;
        void *ns;
 
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
 
        /* Stop tracking associated processes */
index cfc8dcc..9cd5f63 100644 (file)
@@ -528,7 +528,7 @@ restart:
                if (atomic_read(&dquot->dq_count)) {
                        DEFINE_WAIT(wait);
 
-                       atomic_inc(&dquot->dq_count);
+                       dqgrab(dquot);
                        prepare_to_wait(&dquot->dq_wait_unused, &wait,
                                        TASK_UNINTERRUPTIBLE);
                        spin_unlock(&dq_list_lock);
@@ -632,7 +632,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type)
                        /* Now we have active dquot from which someone is
                         * holding reference so we can safely just increase
                         * use count */
-                       atomic_inc(&dquot->dq_count);
+                       dqgrab(dquot);
                        spin_unlock(&dq_list_lock);
                        dqstats_inc(DQST_LOOKUPS);
                        err = sb->dq_op->write_dquot(dquot);
index ad62bdb..bc8b800 100644 (file)
@@ -35,7 +35,7 @@ void reiserfs_evict_inode(struct inode *inode)
        if (!inode->i_nlink && !is_bad_inode(inode))
                dquot_initialize(inode);
 
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        if (inode->i_nlink)
                goto no_delete;
 
index 8d06adf..83d4eac 100644 (file)
@@ -2831,6 +2831,7 @@ void reiserfs_init_alloc_options(struct super_block *s);
  */
 __le32 reiserfs_choose_packing(struct inode *dir);
 
+void show_alloc_options(struct seq_file *seq, struct super_block *s);
 int reiserfs_init_bitmap_cache(struct super_block *sb);
 void reiserfs_free_bitmap_cache(struct super_block *sb);
 void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info);
index 2c80335..ed54a04 100644 (file)
@@ -62,7 +62,6 @@ static int is_any_reiserfs_magic_string(struct reiserfs_super_block *rs)
 
 static int reiserfs_remount(struct super_block *s, int *flags, char *data);
 static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf);
-void show_alloc_options(struct seq_file *seq, struct super_block *s);
 
 static int reiserfs_sync_fs(struct super_block *s, int wait)
 {
@@ -597,7 +596,7 @@ static void init_once(void *foo)
        inode_init_once(&ei->vfs_inode);
 }
 
-static int init_inodecache(void)
+static int __init init_inodecache(void)
 {
        reiserfs_inode_cachep = kmem_cache_create("reiser_inode_cache",
                                                  sizeof(struct
index c327d4e..5625ca9 100644 (file)
@@ -295,7 +295,7 @@ int sysv_sync_inode(struct inode *inode)
 
 static void sysv_evict_inode(struct inode *inode)
 {
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        if (!inode->i_nlink) {
                inode->i_size = 0;
                sysv_truncate(inode);
index 5ded849..48f943f 100644 (file)
@@ -351,7 +351,7 @@ static void ubifs_evict_inode(struct inode *inode)
        dbg_gen("inode %lu, mode %#x", inode->i_ino, (int)inode->i_mode);
        ubifs_assert(!atomic_read(&inode->i_count));
 
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
 
        if (inode->i_nlink)
                goto done;
index 982ce05..5d64370 100644 (file)
@@ -146,8 +146,8 @@ void udf_evict_inode(struct inode *inode)
                want_delete = 1;
                udf_setsize(inode, 0);
                udf_update_inode(inode, IS_SYNC(inode));
-       } else
-               truncate_inode_pages(&inode->i_data, 0);
+       }
+       truncate_inode_pages_final(&inode->i_data);
        invalidate_inode_buffers(inode);
        clear_inode(inode);
        if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB &&
index c8ca960..61e8a9b 100644 (file)
@@ -885,7 +885,7 @@ void ufs_evict_inode(struct inode * inode)
        if (!inode->i_nlink && !is_bad_inode(inode))
                want_delete = 1;
 
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        if (want_delete) {
                loff_t old_i_size;
                /*UFS_I(inode)->i_dtime = CURRENT_TIME;*/
index d971f49..0ef5992 100644 (file)
@@ -996,7 +996,7 @@ xfs_fs_evict_inode(
 
        trace_xfs_evict_inode(ip);
 
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
        XFS_STATS_INC(vn_rele);
        XFS_STATS_INC(vn_remove);
index 2481900..e488e94 100644 (file)
@@ -95,7 +95,7 @@ struct backing_dev_info {
        unsigned int max_ratio, max_prop_frac;
 
        struct bdi_writeback wb;  /* default writeback info for this bdi */
-       spinlock_t wb_lock;       /* protects work_list */
+       spinlock_t wb_lock;       /* protects work_list & wb.dwork scheduling */
 
        struct list_head work_list;
 
index 5f9cd96..7264742 100644 (file)
@@ -9,6 +9,7 @@
 #define _LINUX_BACKLIGHT_H
 
 #include <linux/device.h>
+#include <linux/fb.h>
 #include <linux/mutex.h>
 #include <linux/notifier.h>
 
@@ -104,6 +105,11 @@ struct backlight_device {
        struct list_head entry;
 
        struct device dev;
+
+       /* Multiple framebuffers may share one backlight device */
+       bool fb_bl_on[FB_MAX];
+
+       int use_count;
 };
 
 static inline void backlight_update_status(struct backlight_device *bd)
index 3fe661f..b19d3dc 100644 (file)
@@ -87,25 +87,26 @@ extern void rebuild_sched_domains(void);
 extern void cpuset_print_task_mems_allowed(struct task_struct *p);
 
 /*
- * get_mems_allowed is required when making decisions involving mems_allowed
- * such as during page allocation. mems_allowed can be updated in parallel
- * and depending on the new value an operation can fail potentially causing
- * process failure. A retry loop with get_mems_allowed and put_mems_allowed
- * prevents these artificial failures.
+ * read_mems_allowed_begin is required when making decisions involving
+ * mems_allowed such as during page allocation. mems_allowed can be updated in
+ * parallel and depending on the new value an operation can fail potentially
+ * causing process failure. A retry loop with read_mems_allowed_begin and
+ * read_mems_allowed_retry prevents these artificial failures.
  */
-static inline unsigned int get_mems_allowed(void)
+static inline unsigned int read_mems_allowed_begin(void)
 {
        return read_seqcount_begin(&current->mems_allowed_seq);
 }
 
 /*
- * If this returns false, the operation that took place after get_mems_allowed
- * may have failed. It is up to the caller to retry the operation if
+ * If this returns true, the operation that took place after
+ * read_mems_allowed_begin may have failed artificially due to a concurrent
+ * update of mems_allowed. It is up to the caller to retry the operation if
  * appropriate.
  */
-static inline bool put_mems_allowed(unsigned int seq)
+static inline bool read_mems_allowed_retry(unsigned int seq)
 {
-       return !read_seqcount_retry(&current->mems_allowed_seq, seq);
+       return read_seqcount_retry(&current->mems_allowed_seq, seq);
 }
 
 static inline void set_mems_allowed(nodemask_t nodemask)
@@ -225,14 +226,14 @@ static inline void set_mems_allowed(nodemask_t nodemask)
 {
 }
 
-static inline unsigned int get_mems_allowed(void)
+static inline unsigned int read_mems_allowed_begin(void)
 {
        return 0;
 }
 
-static inline bool put_mems_allowed(unsigned int seq)
+static inline bool read_mems_allowed_retry(unsigned int seq)
 {
-       return true;
+       return false;
 }
 
 #endif /* !CONFIG_CPUSETS */
index 04421e8..f61d6c8 100644 (file)
@@ -66,7 +66,7 @@ extern struct group_info *groups_alloc(int);
 extern struct group_info init_groups;
 extern void groups_free(struct group_info *);
 extern int set_current_groups(struct group_info *);
-extern int set_groups(struct cred *, struct group_info *);
+extern void set_groups(struct cred *, struct group_info *);
 extern int groups_search(const struct group_info *, kgid_t);
 
 /* access the groups "array" with this macro */
index 8c0aef1..1d0aede 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef INFLATE_H
-#define INFLATE_H
+#ifndef LINUX_DECOMPRESS_INFLATE_H
+#define LINUX_DECOMPRESS_INFLATE_H
 
 int gunzip(unsigned char *inbuf, int len,
           int(*fill)(void*, unsigned int),
index 15f92e0..a729120 100644 (file)
@@ -2,12 +2,13 @@
 #define _LINUX_ERR_H
 
 #include <linux/compiler.h>
+#include <linux/types.h>
 
 #include <asm/errno.h>
 
 /*
  * Kernel pointers have redundant information, so we can use a
- * scheme where we can return either an error code or a dentry
+ * scheme where we can return either an error code or a normal
  * pointer with the same return value.
  *
  * This should be a per-architecture thing, to allow different
@@ -29,12 +30,12 @@ static inline long __must_check PTR_ERR(__force const void *ptr)
        return (long) ptr;
 }
 
-static inline long __must_check IS_ERR(__force const void *ptr)
+static inline bool __must_check IS_ERR(__force const void *ptr)
 {
        return IS_ERR_VALUE((unsigned long)ptr);
 }
 
-static inline long __must_check IS_ERR_OR_NULL(__force const void *ptr)
+static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr)
 {
        return !ptr || IS_ERR_VALUE((unsigned long)ptr);
 }
index 6e765d2..3ca9420 100644 (file)
@@ -419,6 +419,7 @@ struct address_space {
        struct mutex            i_mmap_mutex;   /* protect tree, count, list */
        /* Protected by tree_lock together with the radix tree */
        unsigned long           nrpages;        /* number of total pages */
+       unsigned long           nrshadows;      /* number of shadow entries */
        pgoff_t                 writeback_index;/* writeback starts here */
        const struct address_space_operations *a_ops;   /* methods */
        unsigned long           flags;          /* error bits/gfp mask */
index 64cf3ef..fc7718c 100644 (file)
@@ -178,7 +178,7 @@ struct fsnotify_group {
                struct fanotify_group_private_data {
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
                        /* allows a group to block waiting for a userspace response */
-                       struct mutex access_mutex;
+                       spinlock_t access_lock;
                        struct list_head access_list;
                        wait_queue_head_t access_waitq;
                        atomic_t bypass_perm;
index 8c43cc4..5b337cf 100644 (file)
@@ -6,6 +6,8 @@
 #include <linux/fs.h>
 #include <linux/hugetlb_inline.h>
 #include <linux/cgroup.h>
+#include <linux/list.h>
+#include <linux/kref.h>
 
 struct ctl_table;
 struct user_struct;
@@ -23,6 +25,14 @@ struct hugepage_subpool {
        long max_hpages, used_hpages;
 };
 
+struct resv_map {
+       struct kref refs;
+       spinlock_t lock;
+       struct list_head regions;
+};
+extern struct resv_map *resv_map_alloc(void);
+void resv_map_release(struct kref *ref);
+
 extern spinlock_t hugetlb_lock;
 extern int hugetlb_max_hstate __read_mostly;
 #define for_each_hstate(h) \
index 2a5e554..5bb4246 100644 (file)
@@ -30,8 +30,6 @@ extern void kmemleak_alloc_percpu(const void __percpu *ptr, size_t size) __ref;
 extern void kmemleak_free(const void *ptr) __ref;
 extern void kmemleak_free_part(const void *ptr, size_t size) __ref;
 extern void kmemleak_free_percpu(const void __percpu *ptr) __ref;
-extern void kmemleak_padding(const void *ptr, unsigned long offset,
-                            size_t size) __ref;
 extern void kmemleak_not_leak(const void *ptr) __ref;
 extern void kmemleak_ignore(const void *ptr) __ref;
 extern void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) __ref;
index 926afb6..f896a33 100644 (file)
@@ -119,6 +119,7 @@ struct kobj_type {
 };
 
 struct kobj_uevent_env {
+       char *argv[3];
        char *envp[UEVENT_NUM_ENVP];
        int envp_idx;
        char buf[UEVENT_BUFFER_SIZE];
index 3ce5417..f343453 100644 (file)
@@ -13,6 +13,8 @@
 /* list_lru_walk_cb has to always return one of those */
 enum lru_status {
        LRU_REMOVED,            /* item removed from list */
+       LRU_REMOVED_RETRY,      /* item removed, but lock has been
+                                  dropped and reacquired */
        LRU_ROTATE,             /* item referenced, give another pass */
        LRU_SKIP,               /* item cannot be locked, skip */
        LRU_RETRY,              /* item not freeable. May drop the lock
@@ -32,7 +34,11 @@ struct list_lru {
 };
 
 void list_lru_destroy(struct list_lru *lru);
-int list_lru_init(struct list_lru *lru);
+int list_lru_init_key(struct list_lru *lru, struct lock_class_key *key);
+static inline int list_lru_init(struct list_lru *lru)
+{
+       return list_lru_init_key(lru, NULL);
+}
 
 /**
  * list_lru_add: add an element to the lru list's tail
diff --git a/include/linux/mfd/pm8xxx/rtc.h b/include/linux/mfd/pm8xxx/rtc.h
deleted file mode 100644 (file)
index 14f1983..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __RTC_PM8XXX_H__
-#define __RTC_PM8XXX_H__
-
-#define PM8XXX_RTC_DEV_NAME     "rtc-pm8xxx"
-/**
- * struct pm8xxx_rtc_pdata - RTC driver platform data
- * @rtc_write_enable: variable stating RTC write capability
- */
-struct pm8xxx_rtc_platform_data {
-       bool rtc_write_enable;
-};
-
-#endif /* __RTC_PM8XXX_H__ */
index 2eec61f..35300f3 100644 (file)
@@ -1041,6 +1041,14 @@ extern void show_free_areas(unsigned int flags);
 extern bool skip_free_areas_node(unsigned int flags, int nid);
 
 int shmem_zero_setup(struct vm_area_struct *);
+#ifdef CONFIG_SHMEM
+bool shmem_mapping(struct address_space *mapping);
+#else
+static inline bool shmem_mapping(struct address_space *mapping)
+{
+       return false;
+}
+#endif
 
 extern int can_do_mlock(void);
 extern int user_shm_lock(size_t, struct user_struct *);
@@ -1658,10 +1666,8 @@ static inline int __early_pfn_to_nid(unsigned long pfn)
 #else
 /* please see mm/page_alloc.c */
 extern int __meminit early_pfn_to_nid(unsigned long pfn);
-#ifdef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
 /* there is a per-arch backend function. */
 extern int __meminit __early_pfn_to_nid(unsigned long pfn);
-#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
 #endif
 
 extern void set_dma_reserve(unsigned long new_dma_reserve);
@@ -1826,6 +1832,7 @@ vm_unmapped_area(struct vm_unmapped_area_info *info)
 extern void truncate_inode_pages(struct address_space *, loff_t);
 extern void truncate_inode_pages_range(struct address_space *,
                                       loff_t lstart, loff_t lend);
+extern void truncate_inode_pages_final(struct address_space *);
 
 /* generic vm_area_ops exported for stackable file systems */
 extern int filemap_fault(struct vm_area_struct *, struct vm_fault *);
index 9b61b9b..fac5509 100644 (file)
@@ -142,6 +142,9 @@ enum zone_stat_item {
        NUMA_LOCAL,             /* allocation from local node */
        NUMA_OTHER,             /* allocation from other node */
 #endif
+       WORKINGSET_REFAULT,
+       WORKINGSET_ACTIVATE,
+       WORKINGSET_NODERECLAIM,
        NR_ANON_TRANSPARENT_HUGEPAGES,
        NR_FREE_CMA_PAGES,
        NR_VM_ZONE_STAT_ITEMS };
@@ -392,6 +395,9 @@ struct zone {
        spinlock_t              lru_lock;
        struct lruvec           lruvec;
 
+       /* Evictions & activations on the inactive file list */
+       atomic_long_t           inactive_age;
+
        unsigned long           pages_scanned;     /* since last reclaim */
        unsigned long           flags;             /* zone flags, see below */
 
index 9875576..ff3fea3 100644 (file)
@@ -82,6 +82,8 @@ struct nilfs_inode {
        __le32  i_pad;
 };
 
+#define NILFS_MIN_INODE_SIZE           128
+
 /**
  * struct nilfs_super_root - structure of super root
  * @sr_sum: check sum
@@ -482,6 +484,8 @@ struct nilfs_dat_entry {
        __le64 de_rsv;
 };
 
+#define NILFS_MIN_DAT_ENTRY_SIZE       32
+
 /**
  * struct nilfs_snapshot_list - snapshot list
  * @ssl_next: next checkpoint number on snapshot list
@@ -520,6 +524,8 @@ struct nilfs_checkpoint {
        struct nilfs_inode cp_ifile_inode;
 };
 
+#define NILFS_MIN_CHECKPOINT_SIZE      (64 + NILFS_MIN_INODE_SIZE)
+
 /* checkpoint flags */
 enum {
        NILFS_CHECKPOINT_SNAPSHOT,
@@ -615,6 +621,8 @@ struct nilfs_segment_usage {
        __le32 su_flags;
 };
 
+#define NILFS_MIN_SEGMENT_USAGE_SIZE   16
+
 /* segment usage flag */
 enum {
        NILFS_SEGMENT_USAGE_ACTIVE,
@@ -710,6 +718,48 @@ static inline int nilfs_suinfo_clean(const struct nilfs_suinfo *si)
 }
 
 /* ioctl */
+/**
+ * nilfs_suinfo_update - segment usage information update
+ * @sup_segnum: segment number
+ * @sup_flags: flags for which fields are active in sup_sui
+ * @sup_reserved: reserved necessary for alignment
+ * @sup_sui: segment usage information
+ */
+struct nilfs_suinfo_update {
+       __u64 sup_segnum;
+       __u32 sup_flags;
+       __u32 sup_reserved;
+       struct nilfs_suinfo sup_sui;
+};
+
+enum {
+       NILFS_SUINFO_UPDATE_LASTMOD,
+       NILFS_SUINFO_UPDATE_NBLOCKS,
+       NILFS_SUINFO_UPDATE_FLAGS,
+       __NR_NILFS_SUINFO_UPDATE_FIELDS,
+};
+
+#define NILFS_SUINFO_UPDATE_FNS(flag, name)                            \
+static inline void                                                     \
+nilfs_suinfo_update_set_##name(struct nilfs_suinfo_update *sup)                \
+{                                                                      \
+       sup->sup_flags |= 1UL << NILFS_SUINFO_UPDATE_##flag;            \
+}                                                                      \
+static inline void                                                     \
+nilfs_suinfo_update_clear_##name(struct nilfs_suinfo_update *sup)      \
+{                                                                      \
+       sup->sup_flags &= ~(1UL << NILFS_SUINFO_UPDATE_##flag);         \
+}                                                                      \
+static inline int                                                      \
+nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup)      \
+{                                                                      \
+       return !!(sup->sup_flags & (1UL << NILFS_SUINFO_UPDATE_##flag));\
+}
+
+NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod)
+NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks)
+NILFS_SUINFO_UPDATE_FNS(FLAGS, flags)
+
 enum {
        NILFS_CHECKPOINT,
        NILFS_SNAPSHOT,
@@ -863,5 +913,7 @@ struct nilfs_bdesc {
        _IOW(NILFS_IOCTL_IDENT, 0x8B, __u64)
 #define NILFS_IOCTL_SET_ALLOC_RANGE  \
        _IOW(NILFS_IOCTL_IDENT, 0x8C, __u64[2])
+#define NILFS_IOCTL_SET_SUINFO  \
+       _IOW(NILFS_IOCTL_IDENT, 0x8D, struct nilfs_argv)
 
 #endif /* _LINUX_NILFS_FS_H */
index 1710d1b..45598f1 100644 (file)
@@ -25,6 +25,7 @@ enum mapping_flags {
        AS_MM_ALL_LOCKS = __GFP_BITS_SHIFT + 2, /* under mm_take_all_locks() */
        AS_UNEVICTABLE  = __GFP_BITS_SHIFT + 3, /* e.g., ramdisk, SHM_LOCK */
        AS_BALLOON_MAP  = __GFP_BITS_SHIFT + 4, /* balloon page special map */
+       AS_EXITING      = __GFP_BITS_SHIFT + 5, /* final truncate in progress */
 };
 
 static inline void mapping_set_error(struct address_space *mapping, int error)
@@ -69,6 +70,16 @@ static inline int mapping_balloon(struct address_space *mapping)
        return mapping && test_bit(AS_BALLOON_MAP, &mapping->flags);
 }
 
+static inline void mapping_set_exiting(struct address_space *mapping)
+{
+       set_bit(AS_EXITING, &mapping->flags);
+}
+
+static inline int mapping_exiting(struct address_space *mapping)
+{
+       return test_bit(AS_EXITING, &mapping->flags);
+}
+
 static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
 {
        return (__force gfp_t)mapping->flags & __GFP_BITS_MASK;
@@ -243,12 +254,20 @@ static inline struct page *page_cache_alloc_readahead(struct address_space *x)
 
 typedef int filler_t(void *, struct page *);
 
-extern struct page * find_get_page(struct address_space *mapping,
-                               pgoff_t index);
-extern struct page * find_lock_page(struct address_space *mapping,
-                               pgoff_t index);
-extern struct page * find_or_create_page(struct address_space *mapping,
-                               pgoff_t index, gfp_t gfp_mask);
+pgoff_t page_cache_next_hole(struct address_space *mapping,
+                            pgoff_t index, unsigned long max_scan);
+pgoff_t page_cache_prev_hole(struct address_space *mapping,
+                            pgoff_t index, unsigned long max_scan);
+
+struct page *find_get_entry(struct address_space *mapping, pgoff_t offset);
+struct page *find_get_page(struct address_space *mapping, pgoff_t offset);
+struct page *find_lock_entry(struct address_space *mapping, pgoff_t offset);
+struct page *find_lock_page(struct address_space *mapping, pgoff_t offset);
+struct page *find_or_create_page(struct address_space *mapping, pgoff_t index,
+                                gfp_t gfp_mask);
+unsigned find_get_entries(struct address_space *mapping, pgoff_t start,
+                         unsigned int nr_entries, struct page **entries,
+                         pgoff_t *indices);
 unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
                        unsigned int nr_pages, struct page **pages);
 unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t start,
@@ -270,8 +289,6 @@ static inline struct page *grab_cache_page(struct address_space *mapping,
 
 extern struct page * grab_cache_page_nowait(struct address_space *mapping,
                                pgoff_t index);
-extern struct page * read_cache_page_async(struct address_space *mapping,
-                               pgoff_t index, filler_t *filler, void *data);
 extern struct page * read_cache_page(struct address_space *mapping,
                                pgoff_t index, filler_t *filler, void *data);
 extern struct page * read_cache_page_gfp(struct address_space *mapping,
@@ -279,14 +296,6 @@ extern struct page * read_cache_page_gfp(struct address_space *mapping,
 extern int read_cache_pages(struct address_space *mapping,
                struct list_head *pages, filler_t *filler, void *data);
 
-static inline struct page *read_mapping_page_async(
-                               struct address_space *mapping,
-                               pgoff_t index, void *data)
-{
-       filler_t *filler = (filler_t *)mapping->a_ops->readpage;
-       return read_cache_page_async(mapping, index, filler, data);
-}
-
 static inline struct page *read_mapping_page(struct address_space *mapping,
                                pgoff_t index, void *data)
 {
@@ -539,7 +548,7 @@ int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
 int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
                                pgoff_t index, gfp_t gfp_mask);
 extern void delete_from_page_cache(struct page *page);
-extern void __delete_from_page_cache(struct page *page);
+extern void __delete_from_page_cache(struct page *page, void *shadow);
 int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask);
 
 /*
index e4dbfab..b45d391 100644 (file)
@@ -22,6 +22,11 @@ struct pagevec {
 
 void __pagevec_release(struct pagevec *pvec);
 void __pagevec_lru_add(struct pagevec *pvec);
+unsigned pagevec_lookup_entries(struct pagevec *pvec,
+                               struct address_space *mapping,
+                               pgoff_t start, unsigned nr_entries,
+                               pgoff_t *indices);
+void pagevec_remove_exceptionals(struct pagevec *pvec);
 unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
                pgoff_t start, unsigned nr_pages);
 unsigned pagevec_lookup_tag(struct pagevec *pvec,
index fa47e27..8752f75 100644 (file)
@@ -24,13 +24,9 @@ static inline int printk_get_level(const char *buffer)
 
 static inline const char *printk_skip_level(const char *buffer)
 {
-       if (printk_get_level(buffer)) {
-               switch (buffer[1]) {
-               case '0' ... '7':
-               case 'd':       /* KERN_DEFAULT */
-                       return buffer + 2;
-               }
-       }
+       if (printk_get_level(buffer))
+               return buffer + 2;
+
        return buffer;
 }
 
@@ -124,9 +120,9 @@ asmlinkage __printf(1, 0)
 int vprintk(const char *fmt, va_list args);
 
 asmlinkage __printf(5, 6) __cold
-asmlinkage int printk_emit(int facility, int level,
-                          const char *dict, size_t dictlen,
-                          const char *fmt, ...);
+int printk_emit(int facility, int level,
+               const char *dict, size_t dictlen,
+               const char *fmt, ...);
 
 asmlinkage __printf(1, 2) __cold
 int printk(const char *fmt, ...);
index 6965fe3..1d3eee5 100644 (file)
@@ -46,6 +46,14 @@ void inode_reclaim_rsv_space(struct inode *inode, qsize_t number);
 void dquot_initialize(struct inode *inode);
 void dquot_drop(struct inode *inode);
 struct dquot *dqget(struct super_block *sb, struct kqid qid);
+static inline struct dquot *dqgrab(struct dquot *dquot)
+{
+       /* Make sure someone else has active reference to dquot */
+       WARN_ON_ONCE(!atomic_read(&dquot->dq_count));
+       WARN_ON_ONCE(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags));
+       atomic_inc(&dquot->dq_count);
+       return dquot;
+}
 void dqput(struct dquot *dquot);
 int dquot_scan_active(struct super_block *sb,
                      int (*fn)(struct dquot *dquot, unsigned long priv),
index 4039407..33170db 100644 (file)
@@ -60,6 +60,49 @@ static inline int radix_tree_is_indirect_ptr(void *ptr)
 
 #define RADIX_TREE_MAX_TAGS 3
 
+#ifdef __KERNEL__
+#define RADIX_TREE_MAP_SHIFT   (CONFIG_BASE_SMALL ? 4 : 6)
+#else
+#define RADIX_TREE_MAP_SHIFT   3       /* For more stressful testing */
+#endif
+
+#define RADIX_TREE_MAP_SIZE    (1UL << RADIX_TREE_MAP_SHIFT)
+#define RADIX_TREE_MAP_MASK    (RADIX_TREE_MAP_SIZE-1)
+
+#define RADIX_TREE_TAG_LONGS   \
+       ((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) / BITS_PER_LONG)
+
+#define RADIX_TREE_INDEX_BITS  (8 /* CHAR_BIT */ * sizeof(unsigned long))
+#define RADIX_TREE_MAX_PATH (DIV_ROUND_UP(RADIX_TREE_INDEX_BITS, \
+                                         RADIX_TREE_MAP_SHIFT))
+
+/* Height component in node->path */
+#define RADIX_TREE_HEIGHT_SHIFT        (RADIX_TREE_MAX_PATH + 1)
+#define RADIX_TREE_HEIGHT_MASK ((1UL << RADIX_TREE_HEIGHT_SHIFT) - 1)
+
+/* Internally used bits of node->count */
+#define RADIX_TREE_COUNT_SHIFT (RADIX_TREE_MAP_SHIFT + 1)
+#define RADIX_TREE_COUNT_MASK  ((1UL << RADIX_TREE_COUNT_SHIFT) - 1)
+
+struct radix_tree_node {
+       unsigned int    path;   /* Offset in parent & height from the bottom */
+       unsigned int    count;
+       union {
+               struct {
+                       /* Used when ascending tree */
+                       struct radix_tree_node *parent;
+                       /* For tree user */
+                       void *private_data;
+               };
+               /* Used when freeing node */
+               struct rcu_head rcu_head;
+       };
+       /* For tree user */
+       struct list_head private_list;
+       void __rcu      *slots[RADIX_TREE_MAP_SIZE];
+       unsigned long   tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
+};
+
 /* root tags are stored in gfp_mask, shifted by __GFP_BITS_SHIFT */
 struct radix_tree_root {
        unsigned int            height;
@@ -101,6 +144,7 @@ do {                                                                        \
  *   concurrently with other readers.
  *
  * The notable exceptions to this rule are the following functions:
+ * __radix_tree_lookup
  * radix_tree_lookup
  * radix_tree_lookup_slot
  * radix_tree_tag_get
@@ -216,9 +260,16 @@ static inline void radix_tree_replace_slot(void **pslot, void *item)
        rcu_assign_pointer(*pslot, item);
 }
 
+int __radix_tree_create(struct radix_tree_root *root, unsigned long index,
+                       struct radix_tree_node **nodep, void ***slotp);
 int radix_tree_insert(struct radix_tree_root *, unsigned long, void *);
+void *__radix_tree_lookup(struct radix_tree_root *root, unsigned long index,
+                         struct radix_tree_node **nodep, void ***slotp);
 void *radix_tree_lookup(struct radix_tree_root *, unsigned long);
 void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long);
+bool __radix_tree_delete_node(struct radix_tree_root *root,
+                             struct radix_tree_node *node);
+void *radix_tree_delete_item(struct radix_tree_root *, unsigned long, void *);
 void *radix_tree_delete(struct radix_tree_root *, unsigned long);
 unsigned int
 radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
@@ -226,10 +277,6 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
 unsigned int radix_tree_gang_lookup_slot(struct radix_tree_root *root,
                        void ***results, unsigned long *indices,
                        unsigned long first_index, unsigned int max_items);
-unsigned long radix_tree_next_hole(struct radix_tree_root *root,
-                               unsigned long index, unsigned long max_scan);
-unsigned long radix_tree_prev_hole(struct radix_tree_root *root,
-                               unsigned long index, unsigned long max_scan);
 int radix_tree_preload(gfp_t gfp_mask);
 int radix_tree_maybe_preload(gfp_t gfp_mask);
 void radix_tree_init(void);
index 9d55438..4d1771c 100644 (file)
@@ -51,6 +51,7 @@ extern struct file *shmem_kernel_file_setup(const char *name, loff_t size,
                                            unsigned long flags);
 extern int shmem_zero_setup(struct vm_area_struct *);
 extern int shmem_lock(struct file *file, int lock, struct user_struct *user);
+extern bool shmem_mapping(struct address_space *mapping);
 extern void shmem_unlock_mapping(struct address_space *mapping);
 extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
                                        pgoff_t index, gfp_t gfp_mask);
index 46ba0c6..3507115 100644 (file)
@@ -260,6 +260,42 @@ struct swap_list_t {
        int next;       /* swapfile to be used next */
 };
 
+/* linux/mm/workingset.c */
+void *workingset_eviction(struct address_space *mapping, struct page *page);
+bool workingset_refault(void *shadow);
+void workingset_activation(struct page *page);
+extern struct list_lru workingset_shadow_nodes;
+
+static inline unsigned int workingset_node_pages(struct radix_tree_node *node)
+{
+       return node->count & RADIX_TREE_COUNT_MASK;
+}
+
+static inline void workingset_node_pages_inc(struct radix_tree_node *node)
+{
+       node->count++;
+}
+
+static inline void workingset_node_pages_dec(struct radix_tree_node *node)
+{
+       node->count--;
+}
+
+static inline unsigned int workingset_node_shadows(struct radix_tree_node *node)
+{
+       return node->count >> RADIX_TREE_COUNT_SHIFT;
+}
+
+static inline void workingset_node_shadows_inc(struct radix_tree_node *node)
+{
+       node->count += 1U << RADIX_TREE_COUNT_SHIFT;
+}
+
+static inline void workingset_node_shadows_dec(struct radix_tree_node *node)
+{
+       node->count -= 1U << RADIX_TREE_COUNT_SHIFT;
+}
+
 /* linux/mm/page_alloc.c */
 extern unsigned long totalram_pages;
 extern unsigned long totalreserve_pages;
index 1e67b7a..2aa8b74 100644 (file)
@@ -200,6 +200,8 @@ extern struct trace_event_functions exit_syscall_print_funcs;
        }                                                               \
        static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
 
+asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special,
+                              qid_t id, void __user *addr);
 asmlinkage long sys_time(time_t __user *tloc);
 asmlinkage long sys_stime(time_t __user *tptr);
 asmlinkage long sys_gettimeofday(struct timeval __user *tv,
index 3a712e2..486c397 100644 (file)
@@ -37,6 +37,7 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
                PGINODESTEAL, SLABS_SCANNED, KSWAPD_INODESTEAL,
                KSWAPD_LOW_WMARK_HIT_QUICKLY, KSWAPD_HIGH_WMARK_HIT_QUICKLY,
                PAGEOUTRUN, ALLOCSTALL, PGROTATED,
+               DROP_PAGECACHE, DROP_SLAB,
 #ifdef CONFIG_NUMA_BALANCING
                NUMA_PTE_UPDATES,
                NUMA_HUGE_PTE_UPDATES,
index 67ce70c..ea44761 100644 (file)
@@ -187,8 +187,6 @@ extern void zone_statistics(struct zone *, struct zone *, gfp_t gfp);
 #define add_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, __d)
 #define sub_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, -(__d))
 
-extern void inc_zone_state(struct zone *, enum zone_stat_item);
-
 #ifdef CONFIG_SMP
 void __mod_zone_page_state(struct zone *, enum zone_stat_item item, int);
 void __inc_zone_page_state(struct page *, enum zone_stat_item);
@@ -230,18 +228,18 @@ static inline void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
        atomic_long_inc(&vm_stat[item]);
 }
 
-static inline void __inc_zone_page_state(struct page *page,
-                       enum zone_stat_item item)
-{
-       __inc_zone_state(page_zone(page), item);
-}
-
 static inline void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
 {
        atomic_long_dec(&zone->vm_stat[item]);
        atomic_long_dec(&vm_stat[item]);
 }
 
+static inline void __inc_zone_page_state(struct page *page,
+                       enum zone_stat_item item)
+{
+       __inc_zone_state(page_zone(page), item);
+}
+
 static inline void __dec_zone_page_state(struct page *page,
                        enum zone_stat_item item)
 {
@@ -256,6 +254,9 @@ static inline void __dec_zone_page_state(struct page *page,
 #define dec_zone_page_state __dec_zone_page_state
 #define mod_zone_page_state __mod_zone_page_state
 
+#define inc_zone_state __inc_zone_state
+#define dec_zone_state __dec_zone_state
+
 #define set_pgdat_percpu_threshold(pgdat, callback) { }
 
 static inline void refresh_cpu_vm_stats(int cpu) { }
index 335e8a7..c140620 100644 (file)
 
 #endif /* _NETINET_IN_H */
 
+/* Definitions for xattr.h */
+#if defined(_SYS_XATTR_H)
+#define __UAPI_DEF_XATTR               0
+#else
+#define __UAPI_DEF_XATTR               1
+#endif
 
 /* If we did not see any headers from any supported C libraries,
  * or we are being included in the kernel, then define everything
 #define __UAPI_DEF_IPV6_MREQ           1
 #define __UAPI_DEF_IPPROTO_V6          1
 
+/* Definitions for xattr.h */
+#define __UAPI_DEF_XATTR               1
+
 #endif /* __GLIBC__ */
 
 #endif /* _UAPI_LIBC_COMPAT_H */
index 40bbc04..c38355c 100644 (file)
@@ -7,11 +7,18 @@
   Copyright (c) 2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
   Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
 */
+
+#include <linux/libc-compat.h>
+
 #ifndef _UAPI_LINUX_XATTR_H
 #define _UAPI_LINUX_XATTR_H
 
+#ifdef __UAPI_DEF_XATTR
+#define __USE_KERNEL_XATTR_DEFS
+
 #define XATTR_CREATE   0x1     /* set value, fail if attr already exists */
 #define XATTR_REPLACE  0x2     /* set value, fail if attr does not exist */
+#endif
 
 /* Namespaces */
 #define XATTR_OS2_PREFIX "os2."
index 62b66ac..8851c64 100644 (file)
@@ -273,6 +273,16 @@ config FHANDLE
          get renamed. Enables open_by_handle_at(2) and name_to_handle_at(2)
          syscalls.
 
+config USELIB
+       bool "uselib syscall"
+       default y
+       help
+         This option enables the uselib syscall, a system call used in the
+         dynamic linker from libc5 and earlier.  glibc does not use this
+         system call.  If you intend to run programs built on libc5 or
+         earlier, you may need to enable this syscall.  Current systems
+         running glibc can safely disable this.
+
 config AUDIT
        bool "Auditing support"
        depends on NET
@@ -1291,6 +1301,16 @@ config UID16
        help
          This enables the legacy 16-bit UID syscall wrappers.
 
+config SYSFS_SYSCALL
+       bool "Sysfs syscall support" if EXPERT
+       default y
+       ---help---
+         sys_sysfs is an obsolete system call no longer supported in libc.
+         Note that disabling this option is more secure but might break
+         compatibility with some systems.
+
+         If unsure say Y here.
+
 config SYSCTL_SYSCALL
        bool "Sysctl syscall support" if EXPERT
        depends on PROC_SYSCTL
index 8e5addc..82f2288 100644 (file)
@@ -102,13 +102,13 @@ no_match:
 
 /**
  * devt_from_partuuid - looks up the dev_t of a partition by its UUID
- * @uuid:      char array containing ascii UUID
+ * @uuid_str:  char array containing ascii UUID
  *
  * The function will return the first partition which contains a matching
  * UUID value in its partition_meta_info struct.  This does not search
  * by filesystem UUIDs.
  *
- * If @uuid is followed by a "/PARTNROFF=%d", then the number will be
+ * If @uuid_str is followed by a "/PARTNROFF=%d", then the number will be
  * extracted and used as an offset from the partition identified by the UUID.
  *
  * Returns the matching dev_t on success or 0 on failure.
index e2dbb60..3d54c41 100644 (file)
@@ -996,7 +996,7 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
        task_lock(tsk);
        /*
         * Determine if a loop is necessary if another thread is doing
-        * get_mems_allowed().  If at least one node remains unchanged and
+        * read_mems_allowed_begin().  If at least one node remains unchanged and
         * tsk does not have a mempolicy, then an empty nodemask will not be
         * possible when mems_allowed is larger than a word.
         */
index 90cf1c3..451698f 100644 (file)
@@ -157,17 +157,13 @@ int groups_search(const struct group_info *group_info, kgid_t grp)
  * set_groups - Change a group subscription in a set of credentials
  * @new: The newly prepared set of credentials to alter
  * @group_info: The group list to install
- *
- * Validate a group subscription and, if valid, insert it into a set
- * of credentials.
  */
-int set_groups(struct cred *new, struct group_info *group_info)
+void set_groups(struct cred *new, struct group_info *group_info)
 {
        put_group_info(new->group_info);
        groups_sort(group_info);
        get_group_info(group_info);
        new->group_info = group_info;
-       return 0;
 }
 
 EXPORT_SYMBOL(set_groups);
@@ -182,18 +178,12 @@ EXPORT_SYMBOL(set_groups);
 int set_current_groups(struct group_info *group_info)
 {
        struct cred *new;
-       int ret;
 
        new = prepare_creds();
        if (!new)
                return -ENOMEM;
 
-       ret = set_groups(new, group_info);
-       if (ret < 0) {
-               abort_creds(new);
-               return ret;
-       }
-
+       set_groups(new, group_info);
        return commit_creds(new);
 }
 
index 0b9c169..06bb141 100644 (file)
@@ -246,5 +246,4 @@ static int __init hung_task_init(void)
 
        return 0;
 }
-
-module_init(hung_task_init);
+subsys_initcall(hung_task_init);
index 45601cf..c0d261c 100644 (file)
@@ -1235,7 +1235,7 @@ static int __init crash_notes_memory_init(void)
        }
        return 0;
 }
-module_init(crash_notes_memory_init)
+subsys_initcall(crash_notes_memory_init);
 
 
 /*
@@ -1629,7 +1629,7 @@ static int __init crash_save_vmcoreinfo_init(void)
        return 0;
 }
 
-module_init(crash_save_vmcoreinfo_init)
+subsys_initcall(crash_save_vmcoreinfo_init);
 
 /*
  * Move into place and start executing a preloaded standalone
index b5ae3ee..9a130ec 100644 (file)
@@ -217,7 +217,7 @@ int tsk_fork_get_node(struct task_struct *tsk)
        if (tsk == kthreadd_task)
                return tsk->pref_node_fork;
 #endif
-       return numa_node_id();
+       return NUMA_NO_NODE;
 }
 
 static void create_kthread(struct kthread_create_info *create)
@@ -369,7 +369,7 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
 {
        struct task_struct *p;
 
-       p = kthread_create_on_node(threadfn, data, cpu_to_node(cpu), namefmt,
+       p = kthread_create_on_node(threadfn, data, cpu_to_mem(cpu), namefmt,
                                   cpu);
        if (IS_ERR(p))
                return p;
index 4dae9cb..a45b509 100644 (file)
@@ -319,7 +319,7 @@ static void log_store(int facility, int level,
                else
                        free = log_first_idx - log_next_idx;
 
-               if (free > size + sizeof(struct printk_log))
+               if (free >= size + sizeof(struct printk_log))
                        break;
 
                /* drop old messages until we have enough contiuous space */
@@ -327,7 +327,7 @@ static void log_store(int facility, int level,
                log_first_seq++;
        }
 
-       if (log_next_idx + size + sizeof(struct printk_log) >= log_buf_len) {
+       if (log_next_idx + size + sizeof(struct printk_log) > log_buf_len) {
                /*
                 * This message + an additional empty header does not fit
                 * at the end of the buffer. Add an empty header with len == 0
@@ -351,7 +351,7 @@ static void log_store(int facility, int level,
        else
                msg->ts_nsec = local_clock();
        memset(log_dict(msg) + dict_len, 0, pad_len);
-       msg->len = sizeof(struct printk_log) + text_len + dict_len + pad_len;
+       msg->len = size;
 
        /* insert message */
        log_next_idx += msg->len;
@@ -1560,9 +1560,12 @@ asmlinkage int vprintk_emit(int facility, int level,
                                        level = kern_level - '0';
                        case 'd':       /* KERN_DEFAULT */
                                lflags |= LOG_PREFIX;
-                       case 'c':       /* KERN_CONT */
-                               break;
                        }
+                       /*
+                        * No need to check length here because vscnprintf
+                        * put '\0' at the end of the string. Only valid and
+                        * newly printed level is detected.
+                        */
                        text_len -= end_of_header - text;
                        text = (char *)end_of_header;
                }
@@ -1880,6 +1883,7 @@ void suspend_console(void)
        console_lock();
        console_suspended = 1;
        up(&console_sem);
+       mutex_release(&console_lock_dep_map, 1, _RET_IP_);
 }
 
 void resume_console(void)
@@ -1887,6 +1891,7 @@ void resume_console(void)
        if (!console_suspend_enabled)
                return;
        down(&console_sem);
+       mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_);
        console_suspended = 0;
        console_unlock();
 }
index ebdd9c1..1b266db 100644 (file)
@@ -604,5 +604,5 @@ int __ref create_proc_profile(void) /* false positive from hotcpu_notifier */
        hotcpu_notifier(profile_cpu_callback, 0);
        return 0;
 }
-module_init(create_proc_profile);
+subsys_initcall(create_proc_profile);
 #endif /* CONFIG_PROC_FS */
index 673061c..8957d68 100644 (file)
@@ -511,7 +511,7 @@ static int find_resource(struct resource *root, struct resource *new,
  * @newsize: new size of the resource descriptor
  * @constraint: the size and alignment constraints to be met.
  */
-int reallocate_resource(struct resource *root, struct resource *old,
+static int reallocate_resource(struct resource *root, struct resource *old,
                        resource_size_t newsize,
                        struct resource_constraint  *constraint)
 {
index da98af3..a476bea 100644 (file)
@@ -142,4 +142,4 @@ static int __init proc_schedstat_init(void)
        proc_create("schedstat", 0, NULL, &proc_schedstat_operations);
        return 0;
 }
-module_init(proc_schedstat_init);
+subsys_initcall(proc_schedstat_init);
index 7078052..bc8d1b7 100644 (file)
@@ -146,11 +146,13 @@ cond_syscall(sys_io_destroy);
 cond_syscall(sys_io_submit);
 cond_syscall(sys_io_cancel);
 cond_syscall(sys_io_getevents);
+cond_syscall(sys_sysfs);
 cond_syscall(sys_syslog);
 cond_syscall(sys_process_vm_readv);
 cond_syscall(sys_process_vm_writev);
 cond_syscall(compat_sys_process_vm_readv);
 cond_syscall(compat_sys_process_vm_writev);
+cond_syscall(sys_uselib);
 
 /* arch-specific weak syscall entries */
 cond_syscall(sys_pciconfig_read);
index 09d2e24..5c14b54 100644 (file)
@@ -123,7 +123,7 @@ static int __maybe_unused neg_one = -1;
 static int zero;
 static int __maybe_unused one = 1;
 static int __maybe_unused two = 2;
-static int __maybe_unused three = 3;
+static int __maybe_unused four = 4;
 static unsigned long one_ul = 1;
 static int one_hundred = 100;
 #ifdef CONFIG_PRINTK
@@ -1264,7 +1264,7 @@ static struct ctl_table vm_table[] = {
                .mode           = 0644,
                .proc_handler   = drop_caches_sysctl_handler,
                .extra1         = &one,
-               .extra2         = &three,
+               .extra2         = &four,
        },
 #ifdef CONFIG_COMPACTION
        {
index c006131..294fc6a 100644 (file)
@@ -222,5 +222,4 @@ static int __init uid_cache_init(void)
 
        return 0;
 }
-
-module_init(uid_cache_init);
+subsys_initcall(uid_cache_init);
index dd06439..0d8f602 100644 (file)
@@ -902,4 +902,4 @@ static __init int user_namespaces_init(void)
        user_ns_cachep = KMEM_CACHE(user_namespace, SLAB_PANIC);
        return 0;
 }
-module_init(user_namespaces_init);
+subsys_initcall(user_namespaces_init);
index 01c6f97..e90089f 100644 (file)
@@ -158,14 +158,14 @@ void touch_all_softlockup_watchdogs(void)
 #ifdef CONFIG_HARDLOCKUP_DETECTOR
 void touch_nmi_watchdog(void)
 {
-       if (watchdog_user_enabled) {
-               unsigned cpu;
-
-               for_each_present_cpu(cpu) {
-                       if (per_cpu(watchdog_nmi_touch, cpu) != true)
-                               per_cpu(watchdog_nmi_touch, cpu) = true;
-               }
-       }
+       /*
+        * Using __raw here because some code paths have
+        * preemption enabled.  If preemption is enabled
+        * then interrupts should be enabled too, in which
+        * case we shouldn't have to worry about the watchdog
+        * going off.
+        */
+       __raw_get_cpu_var(watchdog_nmi_touch) = true;
        touch_softlockup_watchdog();
 }
 EXPORT_SYMBOL(touch_nmi_watchdog);
index a8f8379..2e11e48 100644 (file)
@@ -6,6 +6,9 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
+ * The functions in this file aren't called directly, but are required by
+ * GCC builtins such as __builtin_ctz, and therefore they can't be removed
+ * despite appearing unreferenced in kernel source.
  *
  * __c[lt]z[sd]i2 can be overridden by linking arch-specific versions.
  */
 #include <linux/export.h>
 #include <linux/kernel.h>
 
+int __weak __ctzsi2(int val);
 int __weak __ctzsi2(int val)
 {
        return __ffs(val);
 }
 EXPORT_SYMBOL(__ctzsi2);
 
+int __weak __clzsi2(int val);
 int __weak __clzsi2(int val)
 {
        return 32 - fls(val);
 }
 EXPORT_SYMBOL(__clzsi2);
 
+int __weak __clzdi2(long val);
+int __weak __ctzdi2(long val);
 #if BITS_PER_LONG == 32
 
 int __weak __clzdi2(long val)
index d619b28..0edfd74 100644 (file)
@@ -19,6 +19,7 @@
 #include "zlib_inflate/inflate.h"
 
 #include "zlib_inflate/infutil.h"
+#include <linux/decompress/inflate.h>
 
 #endif /* STATIC */
 
index 8235331..48cb3c7 100644 (file)
@@ -81,11 +81,13 @@ EXPORT_SYMBOL(devm_ioremap_nocache);
 void devm_iounmap(struct device *dev, void __iomem *addr)
 {
        WARN_ON(devres_destroy(dev, devm_ioremap_release, devm_ioremap_match,
-                              (void *)addr));
+                              (__force void *)addr));
        iounmap(addr);
 }
 EXPORT_SYMBOL(devm_iounmap);
 
+#define IOMEM_ERR_PTR(err) (__force void __iomem *)ERR_PTR(err)
+
 /**
  * devm_ioremap_resource() - check, request region, and ioremap resource
  * @dev: generic device to handle the resource for
@@ -114,7 +116,7 @@ void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
 
        if (!res || resource_type(res) != IORESOURCE_MEM) {
                dev_err(dev, "invalid resource\n");
-               return ERR_PTR(-EINVAL);
+               return IOMEM_ERR_PTR(-EINVAL);
        }
 
        size = resource_size(res);
@@ -122,7 +124,7 @@ void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
 
        if (!devm_request_mem_region(dev, res->start, size, name)) {
                dev_err(dev, "can't request region for resource %pR\n", res);
-               return ERR_PTR(-EBUSY);
+               return IOMEM_ERR_PTR(-EBUSY);
        }
 
        if (res->flags & IORESOURCE_CACHEABLE)
@@ -133,7 +135,7 @@ void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
        if (!dest_ptr) {
                dev_err(dev, "ioremap failed for resource %pR\n", res);
                devm_release_mem_region(dev, res->start, size);
-               dest_ptr = ERR_PTR(-ENOMEM);
+               dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
        }
 
        return dest_ptr;
@@ -224,7 +226,7 @@ void devm_ioport_unmap(struct device *dev, void __iomem *addr)
 {
        ioport_unmap(addr);
        WARN_ON(devres_destroy(dev, devm_ioport_map_release,
-                              devm_ioport_map_match, (void *)addr));
+                              devm_ioport_map_match, (__force void *)addr));
 }
 EXPORT_SYMBOL(devm_ioport_unmap);
 #endif /* CONFIG_HAS_IOPORT */
index 5f72767..4e3bd71 100644 (file)
@@ -124,6 +124,30 @@ static int kobj_usermode_filter(struct kobject *kobj)
        return 0;
 }
 
+static int init_uevent_argv(struct kobj_uevent_env *env, const char *subsystem)
+{
+       int len;
+
+       len = strlcpy(&env->buf[env->buflen], subsystem,
+                     sizeof(env->buf) - env->buflen);
+       if (len >= (sizeof(env->buf) - env->buflen)) {
+               WARN(1, KERN_ERR "init_uevent_argv: buffer size too small\n");
+               return -ENOMEM;
+       }
+
+       env->argv[0] = uevent_helper;
+       env->argv[1] = &env->buf[env->buflen];
+       env->argv[2] = NULL;
+
+       env->buflen += len + 1;
+       return 0;
+}
+
+static void cleanup_uevent_env(struct subprocess_info *info)
+{
+       kfree(info->data);
+}
+
 /**
  * kobject_uevent_env - send an uevent with environmental data
  *
@@ -301,11 +325,8 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 
        /* call uevent_helper, usually only enabled during early boot */
        if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
-               char *argv [3];
+               struct subprocess_info *info;
 
-               argv [0] = uevent_helper;
-               argv [1] = (char *)subsystem;
-               argv [2] = NULL;
                retval = add_uevent_var(env, "HOME=/");
                if (retval)
                        goto exit;
@@ -313,9 +334,18 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                                        "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
                if (retval)
                        goto exit;
+               retval = init_uevent_argv(env, subsystem);
+               if (retval)
+                       goto exit;
 
-               retval = call_usermodehelper(argv[0], argv,
-                                            env->envp, UMH_WAIT_EXEC);
+               retval = -ENOMEM;
+               info = call_usermodehelper_setup(env->argv[0], env->argv,
+                                                env->envp, GFP_KERNEL,
+                                                NULL, cleanup_uevent_env, env);
+               if (info) {
+                       retval = call_usermodehelper_exec(info, UMH_NO_WAIT);
+                       env = NULL;     /* freed by cleanup_uevent_env */
+               }
        }
 
 exit:
index bd4a8df..9599aa7 100644 (file)
 #include <linux/hardirq.h>             /* in_interrupt() */
 
 
-#ifdef __KERNEL__
-#define RADIX_TREE_MAP_SHIFT   (CONFIG_BASE_SMALL ? 4 : 6)
-#else
-#define RADIX_TREE_MAP_SHIFT   3       /* For more stressful testing */
-#endif
-
-#define RADIX_TREE_MAP_SIZE    (1UL << RADIX_TREE_MAP_SHIFT)
-#define RADIX_TREE_MAP_MASK    (RADIX_TREE_MAP_SIZE-1)
-
-#define RADIX_TREE_TAG_LONGS   \
-       ((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) / BITS_PER_LONG)
-
-struct radix_tree_node {
-       unsigned int    height;         /* Height from the bottom */
-       unsigned int    count;
-       union {
-               struct radix_tree_node *parent; /* Used when ascending tree */
-               struct rcu_head rcu_head;       /* Used when freeing node */
-       };
-       void __rcu      *slots[RADIX_TREE_MAP_SIZE];
-       unsigned long   tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
-};
-
-#define RADIX_TREE_INDEX_BITS  (8 /* CHAR_BIT */ * sizeof(unsigned long))
-#define RADIX_TREE_MAX_PATH (DIV_ROUND_UP(RADIX_TREE_INDEX_BITS, \
-                                         RADIX_TREE_MAP_SHIFT))
-
 /*
  * The height_to_maxindex array needs to be one deeper than the maximum
  * path as height 0 holds only 1 entry.
@@ -369,7 +342,8 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
 
                /* Increase the height.  */
                newheight = root->height+1;
-               node->height = newheight;
+               BUG_ON(newheight & ~RADIX_TREE_HEIGHT_MASK);
+               node->path = newheight;
                node->count = 1;
                node->parent = NULL;
                slot = root->rnode;
@@ -387,23 +361,28 @@ out:
 }
 
 /**
- *     radix_tree_insert    -    insert into a radix tree
+ *     __radix_tree_create     -       create a slot in a radix tree
  *     @root:          radix tree root
  *     @index:         index key
- *     @item:          item to insert
+ *     @nodep:         returns node
+ *     @slotp:         returns slot
  *
- *     Insert an item into the radix tree at position @index.
+ *     Create, if necessary, and return the node and slot for an item
+ *     at position @index in the radix tree @root.
+ *
+ *     Until there is more than one item in the tree, no nodes are
+ *     allocated and @root->rnode is used as a direct slot instead of
+ *     pointing to a node, in which case *@nodep will be NULL.
+ *
+ *     Returns -ENOMEM, or 0 for success.
  */
-int radix_tree_insert(struct radix_tree_root *root,
-                       unsigned long index, void *item)
+int __radix_tree_create(struct radix_tree_root *root, unsigned long index,
+                       struct radix_tree_node **nodep, void ***slotp)
 {
        struct radix_tree_node *node = NULL, *slot;
-       unsigned int height, shift;
-       int offset;
+       unsigned int height, shift, offset;
        int error;
 
-       BUG_ON(radix_tree_is_indirect_ptr(item));
-
        /* Make sure the tree is high enough.  */
        if (index > radix_tree_maxindex(root->height)) {
                error = radix_tree_extend(root, index);
@@ -422,11 +401,12 @@ int radix_tree_insert(struct radix_tree_root *root,
                        /* Have to add a child node.  */
                        if (!(slot = radix_tree_node_alloc(root)))
                                return -ENOMEM;
-                       slot->height = height;
+                       slot->path = height;
                        slot->parent = node;
                        if (node) {
                                rcu_assign_pointer(node->slots[offset], slot);
                                node->count++;
+                               slot->path |= offset << RADIX_TREE_HEIGHT_SHIFT;
                        } else
                                rcu_assign_pointer(root->rnode, ptr_to_indirect(slot));
                }
@@ -439,16 +419,42 @@ int radix_tree_insert(struct radix_tree_root *root,
                height--;
        }
 
-       if (slot != NULL)
+       if (nodep)
+               *nodep = node;
+       if (slotp)
+               *slotp = node ? node->slots + offset : (void **)&root->rnode;
+       return 0;
+}
+
+/**
+ *     radix_tree_insert    -    insert into a radix tree
+ *     @root:          radix tree root
+ *     @index:         index key
+ *     @item:          item to insert
+ *
+ *     Insert an item into the radix tree at position @index.
+ */
+int radix_tree_insert(struct radix_tree_root *root,
+                       unsigned long index, void *item)
+{
+       struct radix_tree_node *node;
+       void **slot;
+       int error;
+
+       BUG_ON(radix_tree_is_indirect_ptr(item));
+
+       error = __radix_tree_create(root, index, &node, &slot);
+       if (error)
+               return error;
+       if (*slot != NULL)
                return -EEXIST;
+       rcu_assign_pointer(*slot, item);
 
        if (node) {
                node->count++;
-               rcu_assign_pointer(node->slots[offset], item);
-               BUG_ON(tag_get(node, 0, offset));
-               BUG_ON(tag_get(node, 1, offset));
+               BUG_ON(tag_get(node, 0, index & RADIX_TREE_MAP_MASK));
+               BUG_ON(tag_get(node, 1, index & RADIX_TREE_MAP_MASK));
        } else {
-               rcu_assign_pointer(root->rnode, item);
                BUG_ON(root_tag_get(root, 0));
                BUG_ON(root_tag_get(root, 1));
        }
@@ -457,15 +463,26 @@ int radix_tree_insert(struct radix_tree_root *root,
 }
 EXPORT_SYMBOL(radix_tree_insert);
 
-/*
- * is_slot == 1 : search for the slot.
- * is_slot == 0 : search for the node.
+/**
+ *     __radix_tree_lookup     -       lookup an item in a radix tree
+ *     @root:          radix tree root
+ *     @index:         index key
+ *     @nodep:         returns node
+ *     @slotp:         returns slot
+ *
+ *     Lookup and return the item at position @index in the radix
+ *     tree @root.
+ *
+ *     Until there is more than one item in the tree, no nodes are
+ *     allocated and @root->rnode is used as a direct slot instead of
+ *     pointing to a node, in which case *@nodep will be NULL.
  */
-static void *radix_tree_lookup_element(struct radix_tree_root *root,
-                               unsigned long index, int is_slot)
+void *__radix_tree_lookup(struct radix_tree_root *root, unsigned long index,
+                         struct radix_tree_node **nodep, void ***slotp)
 {
+       struct radix_tree_node *node, *parent;
        unsigned int height, shift;
-       struct radix_tree_node *node, **slot;
+       void **slot;
 
        node = rcu_dereference_raw(root->rnode);
        if (node == NULL)
@@ -474,19 +491,24 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root,
        if (!radix_tree_is_indirect_ptr(node)) {
                if (index > 0)
                        return NULL;
-               return is_slot ? (void *)&root->rnode : node;
+
+               if (nodep)
+                       *nodep = NULL;
+               if (slotp)
+                       *slotp = (void **)&root->rnode;
+               return node;
        }
        node = indirect_to_ptr(node);
 
-       height = node->height;
+       height = node->path & RADIX_TREE_HEIGHT_MASK;
        if (index > radix_tree_maxindex(height))
                return NULL;
 
        shift = (height-1) * RADIX_TREE_MAP_SHIFT;
 
        do {
-               slot = (struct radix_tree_node **)
-                       (node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK));
+               parent = node;
+               slot = node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK);
                node = rcu_dereference_raw(*slot);
                if (node == NULL)
                        return NULL;
@@ -495,7 +517,11 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root,
                height--;
        } while (height > 0);
 
-       return is_slot ? (void *)slot : indirect_to_ptr(node);
+       if (nodep)
+               *nodep = parent;
+       if (slotp)
+               *slotp = slot;
+       return node;
 }
 
 /**
@@ -513,7 +539,11 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root,
  */
 void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
 {
-       return (void **)radix_tree_lookup_element(root, index, 1);
+       void **slot;
+
+       if (!__radix_tree_lookup(root, index, NULL, &slot))
+               return NULL;
+       return slot;
 }
 EXPORT_SYMBOL(radix_tree_lookup_slot);
 
@@ -531,7 +561,7 @@ EXPORT_SYMBOL(radix_tree_lookup_slot);
  */
 void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
 {
-       return radix_tree_lookup_element(root, index, 0);
+       return __radix_tree_lookup(root, index, NULL, NULL);
 }
 EXPORT_SYMBOL(radix_tree_lookup);
 
@@ -676,7 +706,7 @@ int radix_tree_tag_get(struct radix_tree_root *root,
                return (index == 0);
        node = indirect_to_ptr(node);
 
-       height = node->height;
+       height = node->path & RADIX_TREE_HEIGHT_MASK;
        if (index > radix_tree_maxindex(height))
                return 0;
 
@@ -713,7 +743,7 @@ void **radix_tree_next_chunk(struct radix_tree_root *root,
 {
        unsigned shift, tag = flags & RADIX_TREE_ITER_TAG_MASK;
        struct radix_tree_node *rnode, *node;
-       unsigned long index, offset;
+       unsigned long index, offset, height;
 
        if ((flags & RADIX_TREE_ITER_TAGGED) && !root_tag_get(root, tag))
                return NULL;
@@ -744,7 +774,8 @@ void **radix_tree_next_chunk(struct radix_tree_root *root,
                return NULL;
 
 restart:
-       shift = (rnode->height - 1) * RADIX_TREE_MAP_SHIFT;
+       height = rnode->path & RADIX_TREE_HEIGHT_MASK;
+       shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
        offset = index >> shift;
 
        /* Index outside of the tree */
@@ -946,81 +977,6 @@ next:
 }
 EXPORT_SYMBOL(radix_tree_range_tag_if_tagged);
 
-
-/**
- *     radix_tree_next_hole    -    find the next hole (not-present entry)
- *     @root:          tree root
- *     @index:         index key
- *     @max_scan:      maximum range to search
- *
- *     Search the set [index, min(index+max_scan-1, MAX_INDEX)] for the lowest
- *     indexed hole.
- *
- *     Returns: the index of the hole if found, otherwise returns an index
- *     outside of the set specified (in which case 'return - index >= max_scan'
- *     will be true). In rare cases of index wrap-around, 0 will be returned.
- *
- *     radix_tree_next_hole may be called under rcu_read_lock. However, like
- *     radix_tree_gang_lookup, this will not atomically search a snapshot of
- *     the tree at a single point in time. For example, if a hole is created
- *     at index 5, then subsequently a hole is created at index 10,
- *     radix_tree_next_hole covering both indexes may return 10 if called
- *     under rcu_read_lock.
- */
-unsigned long radix_tree_next_hole(struct radix_tree_root *root,
-                               unsigned long index, unsigned long max_scan)
-{
-       unsigned long i;
-
-       for (i = 0; i < max_scan; i++) {
-               if (!radix_tree_lookup(root, index))
-                       break;
-               index++;
-               if (index == 0)
-                       break;
-       }
-
-       return index;
-}
-EXPORT_SYMBOL(radix_tree_next_hole);
-
-/**
- *     radix_tree_prev_hole    -    find the prev hole (not-present entry)
- *     @root:          tree root
- *     @index:         index key
- *     @max_scan:      maximum range to search
- *
- *     Search backwards in the range [max(index-max_scan+1, 0), index]
- *     for the first hole.
- *
- *     Returns: the index of the hole if found, otherwise returns an index
- *     outside of the set specified (in which case 'index - return >= max_scan'
- *     will be true). In rare cases of wrap-around, ULONG_MAX will be returned.
- *
- *     radix_tree_next_hole may be called under rcu_read_lock. However, like
- *     radix_tree_gang_lookup, this will not atomically search a snapshot of
- *     the tree at a single point in time. For example, if a hole is created
- *     at index 10, then subsequently a hole is created at index 5,
- *     radix_tree_prev_hole covering both indexes may return 5 if called under
- *     rcu_read_lock.
- */
-unsigned long radix_tree_prev_hole(struct radix_tree_root *root,
-                                  unsigned long index, unsigned long max_scan)
-{
-       unsigned long i;
-
-       for (i = 0; i < max_scan; i++) {
-               if (!radix_tree_lookup(root, index))
-                       break;
-               index--;
-               if (index == ULONG_MAX)
-                       break;
-       }
-
-       return index;
-}
-EXPORT_SYMBOL(radix_tree_prev_hole);
-
 /**
  *     radix_tree_gang_lookup - perform multiple lookup on a radix tree
  *     @root:          radix tree root
@@ -1189,7 +1145,7 @@ static unsigned long __locate(struct radix_tree_node *slot, void *item,
        unsigned int shift, height;
        unsigned long i;
 
-       height = slot->height;
+       height = slot->path & RADIX_TREE_HEIGHT_MASK;
        shift = (height-1) * RADIX_TREE_MAP_SHIFT;
 
        for ( ; height > 1; height--) {
@@ -1252,7 +1208,8 @@ unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item)
                }
 
                node = indirect_to_ptr(node);
-               max_index = radix_tree_maxindex(node->height);
+               max_index = radix_tree_maxindex(node->path &
+                                               RADIX_TREE_HEIGHT_MASK);
                if (cur_index > max_index) {
                        rcu_read_unlock();
                        break;
@@ -1337,48 +1294,90 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
 }
 
 /**
- *     radix_tree_delete    -    delete an item from a radix tree
+ *     __radix_tree_delete_node    -    try to free node after clearing a slot
  *     @root:          radix tree root
  *     @index:         index key
+ *     @node:          node containing @index
  *
- *     Remove the item at @index from the radix tree rooted at @root.
+ *     After clearing the slot at @index in @node from radix tree
+ *     rooted at @root, call this function to attempt freeing the
+ *     node and shrinking the tree.
  *
- *     Returns the address of the deleted item, or NULL if it was not present.
+ *     Returns %true if @node was freed, %false otherwise.
  */
-void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
+bool __radix_tree_delete_node(struct radix_tree_root *root,
+                             struct radix_tree_node *node)
 {
-       struct radix_tree_node *node = NULL;
-       struct radix_tree_node *slot = NULL;
-       struct radix_tree_node *to_free;
-       unsigned int height, shift;
+       bool deleted = false;
+
+       do {
+               struct radix_tree_node *parent;
+
+               if (node->count) {
+                       if (node == indirect_to_ptr(root->rnode)) {
+                               radix_tree_shrink(root);
+                               if (root->height == 0)
+                                       deleted = true;
+                       }
+                       return deleted;
+               }
+
+               parent = node->parent;
+               if (parent) {
+                       unsigned int offset;
+
+                       offset = node->path >> RADIX_TREE_HEIGHT_SHIFT;
+                       parent->slots[offset] = NULL;
+                       parent->count--;
+               } else {
+                       root_tag_clear_all(root);
+                       root->height = 0;
+                       root->rnode = NULL;
+               }
+
+               radix_tree_node_free(node);
+               deleted = true;
+
+               node = parent;
+       } while (node);
+
+       return deleted;
+}
+
+/**
+ *     radix_tree_delete_item    -    delete an item from a radix tree
+ *     @root:          radix tree root
+ *     @index:         index key
+ *     @item:          expected item
+ *
+ *     Remove @item at @index from the radix tree rooted at @root.
+ *
+ *     Returns the address of the deleted item, or NULL if it was not present
+ *     or the entry at the given @index was not @item.
+ */
+void *radix_tree_delete_item(struct radix_tree_root *root,
+                            unsigned long index, void *item)
+{
+       struct radix_tree_node *node;
+       unsigned int offset;
+       void **slot;
+       void *entry;
        int tag;
-       int uninitialized_var(offset);
 
-       height = root->height;
-       if (index > radix_tree_maxindex(height))
-               goto out;
+       entry = __radix_tree_lookup(root, index, &node, &slot);
+       if (!entry)
+               return NULL;
 
-       slot = root->rnode;
-       if (height == 0) {
+       if (item && entry != item)
+               return NULL;
+
+       if (!node) {
                root_tag_clear_all(root);
                root->rnode = NULL;
-               goto out;
+               return entry;
        }
-       slot = indirect_to_ptr(slot);
-       shift = height * RADIX_TREE_MAP_SHIFT;
 
-       do {
-               if (slot == NULL)
-                       goto out;
-
-               shift -= RADIX_TREE_MAP_SHIFT;
-               offset = (index >> shift) & RADIX_TREE_MAP_MASK;
-               node = slot;
-               slot = slot->slots[offset];
-       } while (shift);
-
-       if (slot == NULL)
-               goto out;
+       offset = index & RADIX_TREE_MAP_MASK;
 
        /*
         * Clear all tags associated with the item to be deleted.
@@ -1389,40 +1388,27 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
                        radix_tree_tag_clear(root, index, tag);
        }
 
-       to_free = NULL;
-       /* Now free the nodes we do not need anymore */
-       while (node) {
-               node->slots[offset] = NULL;
-               node->count--;
-               /*
-                * Queue the node for deferred freeing after the
-                * last reference to it disappears (set NULL, above).
-                */
-               if (to_free)
-                       radix_tree_node_free(to_free);
-
-               if (node->count) {
-                       if (node == indirect_to_ptr(root->rnode))
-                               radix_tree_shrink(root);
-                       goto out;
-               }
+       node->slots[offset] = NULL;
+       node->count--;
 
-               /* Node with zero slots in use so free it */
-               to_free = node;
+       __radix_tree_delete_node(root, node);
 
-               index >>= RADIX_TREE_MAP_SHIFT;
-               offset = index & RADIX_TREE_MAP_MASK;
-               node = node->parent;
-       }
-
-       root_tag_clear_all(root);
-       root->height = 0;
-       root->rnode = NULL;
-       if (to_free)
-               radix_tree_node_free(to_free);
+       return entry;
+}
+EXPORT_SYMBOL(radix_tree_delete_item);
 
-out:
-       return slot;
+/**
+ *     radix_tree_delete    -    delete an item from a radix tree
+ *     @root:          radix tree root
+ *     @index:         index key
+ *
+ *     Remove the item at @index from the radix tree rooted at @root.
+ *
+ *     Returns the address of the deleted item, or NULL if it was not present.
+ */
+void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
+{
+       return radix_tree_delete_item(root, index, NULL);
 }
 EXPORT_SYMBOL(radix_tree_delete);
 
@@ -1438,9 +1424,12 @@ int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag)
 EXPORT_SYMBOL(radix_tree_tagged);
 
 static void
-radix_tree_node_ctor(void *node)
+radix_tree_node_ctor(void *arg)
 {
-       memset(node, 0, sizeof(struct radix_tree_node));
+       struct radix_tree_node *node = arg;
+
+       memset(node, 0, sizeof(*node));
+       INIT_LIST_HEAD(&node->private_list);
 }
 
 static __init unsigned long __maxindex(unsigned int height)
index 6148967..fa5da61 100644 (file)
@@ -1,37 +1,35 @@
 /*
-  This is a maximally equidistributed combined Tausworthe generator
-  based on code from GNU Scientific Library 1.5 (30 Jun 2004)
-
-  lfsr113 version:
-
-   x_n = (s1_n ^ s2_n ^ s3_n ^ s4_n)
-
-   s1_{n+1} = (((s1_n & 4294967294) << 18) ^ (((s1_n <<  6) ^ s1_n) >> 13))
-   s2_{n+1} = (((s2_n & 4294967288) <<  2) ^ (((s2_n <<  2) ^ s2_n) >> 27))
-   s3_{n+1} = (((s3_n & 4294967280) <<  7) ^ (((s3_n << 13) ^ s3_n) >> 21))
-   s4_{n+1} = (((s4_n & 4294967168) << 13) ^ (((s4_n <<  3) ^ s4_n) >> 12))
-
-   The period of this generator is about 2^113 (see erratum paper).
-
-   From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe
-   Generators", Mathematics of Computation, 65, 213 (1996), 203--213:
-   http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps
-   ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps
-
-   There is an erratum in the paper "Tables of Maximally
-   Equidistributed Combined LFSR Generators", Mathematics of
-   Computation, 68, 225 (1999), 261--269:
-   http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps
-
-        ... the k_j most significant bits of z_j must be non-
-        zero, for each j. (Note: this restriction also applies to the
-        computer code given in [4], but was mistakenly not mentioned in
-        that paper.)
-
-   This affects the seeding procedure by imposing the requirement
-   s1 > 1, s2 > 7, s3 > 15, s4 > 127.
-
-*/
+ * This is a maximally equidistributed combined Tausworthe generator
+ * based on code from GNU Scientific Library 1.5 (30 Jun 2004)
+ *
+ * lfsr113 version:
+ *
+ * x_n = (s1_n ^ s2_n ^ s3_n ^ s4_n)
+ *
+ * s1_{n+1} = (((s1_n & 4294967294) << 18) ^ (((s1_n <<  6) ^ s1_n) >> 13))
+ * s2_{n+1} = (((s2_n & 4294967288) <<  2) ^ (((s2_n <<  2) ^ s2_n) >> 27))
+ * s3_{n+1} = (((s3_n & 4294967280) <<  7) ^ (((s3_n << 13) ^ s3_n) >> 21))
+ * s4_{n+1} = (((s4_n & 4294967168) << 13) ^ (((s4_n <<  3) ^ s4_n) >> 12))
+ *
+ * The period of this generator is about 2^113 (see erratum paper).
+ *
+ * From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe
+ * Generators", Mathematics of Computation, 65, 213 (1996), 203--213:
+ * http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps
+ * ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps
+ *
+ * There is an erratum in the paper "Tables of Maximally Equidistributed
+ * Combined LFSR Generators", Mathematics of Computation, 68, 225 (1999),
+ * 261--269: http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps
+ *
+ *      ... the k_j most significant bits of z_j must be non-zero,
+ *      for each j. (Note: this restriction also applies to the
+ *      computer code given in [4], but was mistakenly not mentioned
+ *      in that paper.)
+ *
+ * This affects the seeding procedure by imposing the requirement
+ * s1 > 1, s2 > 7, s3 > 15, s4 > 127.
+ */
 
 #include <linux/types.h>
 #include <linux/percpu.h>
@@ -75,15 +73,17 @@ EXPORT_SYMBOL(prandom_u32_state);
  */
 u32 prandom_u32(void)
 {
-       unsigned long r;
        struct rnd_state *state = &get_cpu_var(net_rand_state);
-       r = prandom_u32_state(state);
+       u32 res;
+
+       res = prandom_u32_state(state);
        put_cpu_var(state);
-       return r;
+
+       return res;
 }
 EXPORT_SYMBOL(prandom_u32);
 
-/*
+/**
  *     prandom_bytes_state - get the requested number of pseudo-random bytes
  *
  *     @state: pointer to state structure holding seeded state.
@@ -204,6 +204,7 @@ static int __init prandom_init(void)
                prandom_seed_very_weak(state, (i + jiffies) ^ random_get_entropy());
                prandom_warmup(state);
        }
+
        return 0;
 }
 core_initcall(prandom_init);
@@ -259,6 +260,7 @@ static void __prandom_reseed(bool late)
 
        if (latch && !late)
                goto out;
+
        latch = true;
 
        for_each_possible_cpu(i) {
index 58710ee..e30e039 100644 (file)
@@ -72,4 +72,3 @@ int task_current_syscall(struct task_struct *target, long *callno,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(task_current_syscall);
index 5e2cf6f..0648291 100644 (file)
@@ -364,7 +364,6 @@ enum format_type {
        FORMAT_TYPE_SHORT,
        FORMAT_TYPE_UINT,
        FORMAT_TYPE_INT,
-       FORMAT_TYPE_NRCHARS,
        FORMAT_TYPE_SIZE_T,
        FORMAT_TYPE_PTRDIFF
 };
@@ -1538,10 +1537,6 @@ qualifier:
                return fmt - start;
                /* skip alnum */
 
-       case 'n':
-               spec->type = FORMAT_TYPE_NRCHARS;
-               return ++fmt - start;
-
        case '%':
                spec->type = FORMAT_TYPE_PERCENT_CHAR;
                return ++fmt - start;
@@ -1564,6 +1559,15 @@ qualifier:
        case 'u':
                break;
 
+       case 'n':
+               /*
+                * Since %n poses a greater security risk than utility, treat
+                * it as an invalid format specifier. Warn about its use so
+                * that new instances don't get added.
+                */
+               WARN_ONCE(1, "Please remove ignored %%n in '%s'\n", fmt);
+               /* Fall-through */
+
        default:
                spec->type = FORMAT_TYPE_INVALID;
                return fmt - start;
@@ -1737,20 +1741,6 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                        ++str;
                        break;
 
-               case FORMAT_TYPE_NRCHARS: {
-                       /*
-                        * Since %n poses a greater security risk than
-                        * utility, ignore %n and skip its argument.
-                        */
-                       void *skip_arg;
-
-                       WARN_ONCE(1, "Please remove ignored %%n in '%s'\n",
-                                       old_fmt);
-
-                       skip_arg = va_arg(args, void *);
-                       break;
-               }
-
                default:
                        switch (spec.type) {
                        case FORMAT_TYPE_LONG_LONG:
@@ -2025,19 +2015,6 @@ do {                                                                     \
                                fmt++;
                        break;
 
-               case FORMAT_TYPE_NRCHARS: {
-                       /* skip %n 's argument */
-                       u8 qualifier = spec.qualifier;
-                       void *skip_arg;
-                       if (qualifier == 'l')
-                               skip_arg = va_arg(args, long *);
-                       else if (_tolower(qualifier) == 'z')
-                               skip_arg = va_arg(args, size_t *);
-                       else
-                               skip_arg = va_arg(args, int *);
-                       break;
-               }
-
                default:
                        switch (spec.type) {
 
@@ -2196,10 +2173,6 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
                        ++str;
                        break;
 
-               case FORMAT_TYPE_NRCHARS:
-                       /* skip */
-                       break;
-
                default: {
                        unsigned long long num;
 
index 310c90a..cdd7415 100644 (file)
@@ -17,7 +17,7 @@ obj-y                 := filemap.o mempool.o oom_kill.o fadvise.o \
                           util.o mmzone.o vmstat.o backing-dev.o \
                           mm_init.o mmu_context.o percpu.o slab_common.o \
                           compaction.o balloon_compaction.o \
-                          interval_tree.o list_lru.o $(mmu-y)
+                          interval_tree.o list_lru.o workingset.o $(mmu-y)
 
 obj-y += init-mm.o
 
index ce682f7..09d9591 100644 (file)
@@ -288,13 +288,19 @@ int bdi_has_dirty_io(struct backing_dev_info *bdi)
  * Note, we wouldn't bother setting up the timer, but this function is on the
  * fast-path (used by '__mark_inode_dirty()'), so we save few context switches
  * by delaying the wake-up.
+ *
+ * We have to be careful not to postpone flush work if it is scheduled for
+ * earlier. Thus we use queue_delayed_work().
  */
 void bdi_wakeup_thread_delayed(struct backing_dev_info *bdi)
 {
        unsigned long timeout;
 
        timeout = msecs_to_jiffies(dirty_writeback_interval * 10);
-       mod_delayed_work(bdi_wq, &bdi->wb.dwork, timeout);
+       spin_lock_bh(&bdi->wb_lock);
+       if (test_bit(BDI_registered, &bdi->state))
+               queue_delayed_work(bdi_wq, &bdi->wb.dwork, timeout);
+       spin_unlock_bh(&bdi->wb_lock);
 }
 
 /*
@@ -307,9 +313,6 @@ static void bdi_remove_from_list(struct backing_dev_info *bdi)
        spin_unlock_bh(&bdi_lock);
 
        synchronize_rcu_expedited();
-
-       /* bdi_list is now unused, clear it to mark @bdi dying */
-       INIT_LIST_HEAD(&bdi->bdi_list);
 }
 
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
@@ -360,6 +363,11 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi)
         */
        bdi_remove_from_list(bdi);
 
+       /* Make sure nobody queues further work */
+       spin_lock_bh(&bdi->wb_lock);
+       clear_bit(BDI_registered, &bdi->state);
+       spin_unlock_bh(&bdi->wb_lock);
+
        /*
         * Drain work list and shutdown the delayed_work.  At this point,
         * @bdi->bdi_list is empty telling bdi_Writeback_workfn() that @bdi
index 9185775..b6ab771 100644 (file)
@@ -584,6 +584,15 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
                        continue;
                }
 
+               /*
+                * Migration will fail if an anonymous page is pinned in memory,
+                * so avoid taking lru_lock and isolating it unnecessarily in an
+                * admittedly racy check.
+                */
+               if (!page_mapping(page) &&
+                   page_count(page) > page_mapcount(page))
+                       continue;
+
                /* Check if it is ok to still hold the lock */
                locked = compact_checklock_irqsave(&zone->lru_lock, &flags,
                                                                locked, cc);
@@ -1186,6 +1195,7 @@ static void compact_node(int nid)
        struct compact_control cc = {
                .order = -1,
                .sync = true,
+               .ignore_skip_hint = true,
        };
 
        __compact_pgdat(NODE_DATA(nid), &cc);
@@ -1225,7 +1235,7 @@ int sysctl_extfrag_handler(struct ctl_table *table, int write,
 }
 
 #if defined(CONFIG_SYSFS) && defined(CONFIG_NUMA)
-ssize_t sysfs_compact_node(struct device *dev,
+static ssize_t sysfs_compact_node(struct device *dev,
                        struct device_attribute *attr,
                        const char *buf, size_t count)
 {
index 7a13f6a..21781f1 100644 (file)
  *   ->tasklist_lock            (memory_failure, collect_procs_ao)
  */
 
+static void page_cache_tree_delete(struct address_space *mapping,
+                                  struct page *page, void *shadow)
+{
+       struct radix_tree_node *node;
+       unsigned long index;
+       unsigned int offset;
+       unsigned int tag;
+       void **slot;
+
+       VM_BUG_ON(!PageLocked(page));
+
+       __radix_tree_lookup(&mapping->page_tree, page->index, &node, &slot);
+
+       if (shadow) {
+               mapping->nrshadows++;
+               /*
+                * Make sure the nrshadows update is committed before
+                * the nrpages update so that final truncate racing
+                * with reclaim does not see both counters 0 at the
+                * same time and miss a shadow entry.
+                */
+               smp_wmb();
+       }
+       mapping->nrpages--;
+
+       if (!node) {
+               /* Clear direct pointer tags in root node */
+               mapping->page_tree.gfp_mask &= __GFP_BITS_MASK;
+               radix_tree_replace_slot(slot, shadow);
+               return;
+       }
+
+       /* Clear tree tags for the removed page */
+       index = page->index;
+       offset = index & RADIX_TREE_MAP_MASK;
+       for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
+               if (test_bit(offset, node->tags[tag]))
+                       radix_tree_tag_clear(&mapping->page_tree, index, tag);
+       }
+
+       /* Delete page, swap shadow entry */
+       radix_tree_replace_slot(slot, shadow);
+       workingset_node_pages_dec(node);
+       if (shadow)
+               workingset_node_shadows_inc(node);
+       else
+               if (__radix_tree_delete_node(&mapping->page_tree, node))
+                       return;
+
+       /*
+        * Track node that only contains shadow entries.
+        *
+        * Avoid acquiring the list_lru lock if already tracked.  The
+        * list_empty() test is safe as node->private_list is
+        * protected by mapping->tree_lock.
+        */
+       if (!workingset_node_pages(node) &&
+           list_empty(&node->private_list)) {
+               node->private_data = mapping;
+               list_lru_add(&workingset_shadow_nodes, &node->private_list);
+       }
+}
+
 /*
  * Delete a page from the page cache and free it. Caller has to make
  * sure the page is locked and that nobody else uses it - or that usage
  * is safe.  The caller must hold the mapping's tree_lock.
  */
-void __delete_from_page_cache(struct page *page)
+void __delete_from_page_cache(struct page *page, void *shadow)
 {
        struct address_space *mapping = page->mapping;
 
@@ -127,10 +190,11 @@ void __delete_from_page_cache(struct page *page)
        else
                cleancache_invalidate_page(mapping, page);
 
-       radix_tree_delete(&mapping->page_tree, page->index);
+       page_cache_tree_delete(mapping, page, shadow);
+
        page->mapping = NULL;
        /* Leave page->index set: truncation lookup relies upon it */
-       mapping->nrpages--;
+
        __dec_zone_page_state(page, NR_FILE_PAGES);
        if (PageSwapBacked(page))
                __dec_zone_page_state(page, NR_SHMEM);
@@ -166,7 +230,7 @@ void delete_from_page_cache(struct page *page)
 
        freepage = mapping->a_ops->freepage;
        spin_lock_irq(&mapping->tree_lock);
-       __delete_from_page_cache(page);
+       __delete_from_page_cache(page, NULL);
        spin_unlock_irq(&mapping->tree_lock);
        mem_cgroup_uncharge_cache_page(page);
 
@@ -426,7 +490,7 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
                new->index = offset;
 
                spin_lock_irq(&mapping->tree_lock);
-               __delete_from_page_cache(old);
+               __delete_from_page_cache(old, NULL);
                error = radix_tree_insert(&mapping->page_tree, offset, new);
                BUG_ON(error);
                mapping->nrpages++;
@@ -446,18 +510,52 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
 }
 EXPORT_SYMBOL_GPL(replace_page_cache_page);
 
-/**
- * add_to_page_cache_locked - add a locked page to the pagecache
- * @page:      page to add
- * @mapping:   the page's address_space
- * @offset:    page index
- * @gfp_mask:  page allocation mode
- *
- * This function is used to add a page to the pagecache. It must be locked.
- * This function does not add the page to the LRU.  The caller must do that.
- */
-int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
-               pgoff_t offset, gfp_t gfp_mask)
+static int page_cache_tree_insert(struct address_space *mapping,
+                                 struct page *page, void **shadowp)
+{
+       struct radix_tree_node *node;
+       void **slot;
+       int error;
+
+       error = __radix_tree_create(&mapping->page_tree, page->index,
+                                   &node, &slot);
+       if (error)
+               return error;
+       if (*slot) {
+               void *p;
+
+               p = radix_tree_deref_slot_protected(slot, &mapping->tree_lock);
+               if (!radix_tree_exceptional_entry(p))
+                       return -EEXIST;
+               if (shadowp)
+                       *shadowp = p;
+               mapping->nrshadows--;
+               if (node)
+                       workingset_node_shadows_dec(node);
+       }
+       radix_tree_replace_slot(slot, page);
+       mapping->nrpages++;
+       if (node) {
+               workingset_node_pages_inc(node);
+               /*
+                * Don't track node that contains actual pages.
+                *
+                * Avoid acquiring the list_lru lock if already
+                * untracked.  The list_empty() test is safe as
+                * node->private_list is protected by
+                * mapping->tree_lock.
+                */
+               if (!list_empty(&node->private_list))
+                       list_lru_del(&workingset_shadow_nodes,
+                                    &node->private_list);
+       }
+       return 0;
+}
+
+static int __add_to_page_cache_locked(struct page *page,
+                                     struct address_space *mapping,
+                                     pgoff_t offset, gfp_t gfp_mask,
+                                     void **shadowp)
 {
        int error;
 
@@ -480,11 +578,10 @@ int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
        page->index = offset;
 
        spin_lock_irq(&mapping->tree_lock);
-       error = radix_tree_insert(&mapping->page_tree, offset, page);
+       error = page_cache_tree_insert(mapping, page, shadowp);
        radix_tree_preload_end();
        if (unlikely(error))
                goto err_insert;
-       mapping->nrpages++;
        __inc_zone_page_state(page, NR_FILE_PAGES);
        spin_unlock_irq(&mapping->tree_lock);
        trace_mm_filemap_add_to_page_cache(page);
@@ -497,16 +594,49 @@ err_insert:
        page_cache_release(page);
        return error;
 }
+
+/**
+ * add_to_page_cache_locked - add a locked page to the pagecache
+ * @page:      page to add
+ * @mapping:   the page's address_space
+ * @offset:    page index
+ * @gfp_mask:  page allocation mode
+ *
+ * This function is used to add a page to the pagecache. It must be locked.
+ * This function does not add the page to the LRU.  The caller must do that.
+ */
+int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
+               pgoff_t offset, gfp_t gfp_mask)
+{
+       return __add_to_page_cache_locked(page, mapping, offset,
+                                         gfp_mask, NULL);
+}
 EXPORT_SYMBOL(add_to_page_cache_locked);
 
 int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
                                pgoff_t offset, gfp_t gfp_mask)
 {
+       void *shadow = NULL;
        int ret;
 
-       ret = add_to_page_cache(page, mapping, offset, gfp_mask);
-       if (ret == 0)
-               lru_cache_add_file(page);
+       __set_page_locked(page);
+       ret = __add_to_page_cache_locked(page, mapping, offset,
+                                        gfp_mask, &shadow);
+       if (unlikely(ret))
+               __clear_page_locked(page);
+       else {
+               /*
+                * The page might have been evicted from cache only
+                * recently, in which case it should be activated like
+                * any other repeatedly accessed page.
+                */
+               if (shadow && workingset_refault(shadow)) {
+                       SetPageActive(page);
+                       workingset_activation(page);
+               } else
+                       ClearPageActive(page);
+               lru_cache_add(page);
+       }
        return ret;
 }
 EXPORT_SYMBOL_GPL(add_to_page_cache_lru);
@@ -520,10 +650,10 @@ struct page *__page_cache_alloc(gfp_t gfp)
        if (cpuset_do_page_mem_spread()) {
                unsigned int cpuset_mems_cookie;
                do {
-                       cpuset_mems_cookie = get_mems_allowed();
+                       cpuset_mems_cookie = read_mems_allowed_begin();
                        n = cpuset_mem_spread_node();
                        page = alloc_pages_exact_node(n, gfp, 0);
-               } while (!put_mems_allowed(cpuset_mems_cookie) && !page);
+               } while (!page && read_mems_allowed_retry(cpuset_mems_cookie));
 
                return page;
        }
@@ -686,14 +816,101 @@ int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
 }
 
 /**
- * find_get_page - find and get a page reference
+ * page_cache_next_hole - find the next hole (not-present entry)
+ * @mapping: mapping
+ * @index: index
+ * @max_scan: maximum range to search
+ *
+ * Search the set [index, min(index+max_scan-1, MAX_INDEX)] for the
+ * lowest indexed hole.
+ *
+ * Returns: the index of the hole if found, otherwise returns an index
+ * outside of the set specified (in which case 'return - index >=
+ * max_scan' will be true). In rare cases of index wrap-around, 0 will
+ * be returned.
+ *
+ * page_cache_next_hole may be called under rcu_read_lock. However,
+ * like radix_tree_gang_lookup, this will not atomically search a
+ * snapshot of the tree at a single point in time. For example, if a
+ * hole is created at index 5, then subsequently a hole is created at
+ * index 10, page_cache_next_hole covering both indexes may return 10
+ * if called under rcu_read_lock.
+ */
+pgoff_t page_cache_next_hole(struct address_space *mapping,
+                            pgoff_t index, unsigned long max_scan)
+{
+       unsigned long i;
+
+       for (i = 0; i < max_scan; i++) {
+               struct page *page;
+
+               page = radix_tree_lookup(&mapping->page_tree, index);
+               if (!page || radix_tree_exceptional_entry(page))
+                       break;
+               index++;
+               if (index == 0)
+                       break;
+       }
+
+       return index;
+}
+EXPORT_SYMBOL(page_cache_next_hole);
+
+/**
+ * page_cache_prev_hole - find the prev hole (not-present entry)
+ * @mapping: mapping
+ * @index: index
+ * @max_scan: maximum range to search
+ *
+ * Search backwards in the range [max(index-max_scan+1, 0), index] for
+ * the first hole.
+ *
+ * Returns: the index of the hole if found, otherwise returns an index
+ * outside of the set specified (in which case 'index - return >=
+ * max_scan' will be true). In rare cases of wrap-around, ULONG_MAX
+ * will be returned.
+ *
+ * page_cache_prev_hole may be called under rcu_read_lock. However,
+ * like radix_tree_gang_lookup, this will not atomically search a
+ * snapshot of the tree at a single point in time. For example, if a
+ * hole is created at index 10, then subsequently a hole is created at
+ * index 5, page_cache_prev_hole covering both indexes may return 5 if
+ * called under rcu_read_lock.
+ */
+pgoff_t page_cache_prev_hole(struct address_space *mapping,
+                            pgoff_t index, unsigned long max_scan)
+{
+       unsigned long i;
+
+       for (i = 0; i < max_scan; i++) {
+               struct page *page;
+
+               page = radix_tree_lookup(&mapping->page_tree, index);
+               if (!page || radix_tree_exceptional_entry(page))
+                       break;
+               index--;
+               if (index == ULONG_MAX)
+                       break;
+       }
+
+       return index;
+}
+EXPORT_SYMBOL(page_cache_prev_hole);
+
+/**
+ * find_get_entry - find and get a page cache entry
  * @mapping: the address_space to search
- * @offset: the page index
+ * @offset: the page cache index
+ *
+ * Looks up the page cache slot at @mapping & @offset.  If there is a
+ * page cache page, it is returned with an increased refcount.
+ *
+ * If the slot holds a shadow entry of a previously evicted page, it
+ * is returned.
  *
- * Is there a pagecache struct page at the given (mapping, offset) tuple?
- * If yes, increment its refcount and return it; if no, return NULL.
+ * Otherwise, %NULL is returned.
  */
-struct page *find_get_page(struct address_space *mapping, pgoff_t offset)
+struct page *find_get_entry(struct address_space *mapping, pgoff_t offset)
 {
        void **pagep;
        struct page *page;
@@ -734,24 +951,50 @@ out:
 
        return page;
 }
-EXPORT_SYMBOL(find_get_page);
+EXPORT_SYMBOL(find_get_entry);
 
 /**
- * find_lock_page - locate, pin and lock a pagecache page
+ * find_get_page - find and get a page reference
  * @mapping: the address_space to search
  * @offset: the page index
  *
- * Locates the desired pagecache page, locks it, increments its reference
- * count and returns its address.
+ * Looks up the page cache slot at @mapping & @offset.  If there is a
+ * page cache page, it is returned with an increased refcount.
  *
- * Returns zero if the page was not present. find_lock_page() may sleep.
+ * Otherwise, %NULL is returned.
  */
-struct page *find_lock_page(struct address_space *mapping, pgoff_t offset)
+struct page *find_get_page(struct address_space *mapping, pgoff_t offset)
+{
+       struct page *page = find_get_entry(mapping, offset);
+
+       if (radix_tree_exceptional_entry(page))
+               page = NULL;
+       return page;
+}
+EXPORT_SYMBOL(find_get_page);
+
+/**
+ * find_lock_entry - locate, pin and lock a page cache entry
+ * @mapping: the address_space to search
+ * @offset: the page cache index
+ *
+ * Looks up the page cache slot at @mapping & @offset.  If there is a
+ * page cache page, it is returned locked and with an increased
+ * refcount.
+ *
+ * If the slot holds a shadow entry of a previously evicted page, it
+ * is returned.
+ *
+ * Otherwise, %NULL is returned.
+ *
+ * find_lock_entry() may sleep.
+ */
+struct page *find_lock_entry(struct address_space *mapping, pgoff_t offset)
 {
        struct page *page;
 
 repeat:
-       page = find_get_page(mapping, offset);
+       page = find_get_entry(mapping, offset);
        if (page && !radix_tree_exception(page)) {
                lock_page(page);
                /* Has the page been truncated? */
@@ -764,6 +1007,29 @@ repeat:
        }
        return page;
 }
+EXPORT_SYMBOL(find_lock_entry);
+
+/**
+ * find_lock_page - locate, pin and lock a pagecache page
+ * @mapping: the address_space to search
+ * @offset: the page index
+ *
+ * Looks up the page cache slot at @mapping & @offset.  If there is a
+ * page cache page, it is returned locked and with an increased
+ * refcount.
+ *
+ * Otherwise, %NULL is returned.
+ *
+ * find_lock_page() may sleep.
+ */
+struct page *find_lock_page(struct address_space *mapping, pgoff_t offset)
+{
+       struct page *page = find_lock_entry(mapping, offset);
+
+       if (radix_tree_exceptional_entry(page))
+               page = NULL;
+       return page;
+}
 EXPORT_SYMBOL(find_lock_page);
 
 /**
@@ -772,16 +1038,18 @@ EXPORT_SYMBOL(find_lock_page);
  * @index: the page's index into the mapping
  * @gfp_mask: page allocation mode
  *
- * Locates a page in the pagecache.  If the page is not present, a new page
- * is allocated using @gfp_mask and is added to the pagecache and to the VM's
- * LRU list.  The returned page is locked and has its reference count
- * incremented.
+ * Looks up the page cache slot at @mapping & @offset.  If there is a
+ * page cache page, it is returned locked and with an increased
+ * refcount.
  *
- * find_or_create_page() may sleep, even if @gfp_flags specifies an atomic
- * allocation!
+ * If the page is not present, a new page is allocated using @gfp_mask
+ * and added to the page cache and the VM's LRU list.  The page is
+ * returned locked and with an increased refcount.
  *
- * find_or_create_page() returns the desired page's address, or zero on
- * memory exhaustion.
+ * On memory exhaustion, %NULL is returned.
+ *
+ * find_or_create_page() may sleep, even if @gfp_flags specifies an
+ * atomic allocation!
  */
 struct page *find_or_create_page(struct address_space *mapping,
                pgoff_t index, gfp_t gfp_mask)
@@ -813,6 +1081,76 @@ repeat:
 }
 EXPORT_SYMBOL(find_or_create_page);
 
+/**
+ * find_get_entries - gang pagecache lookup
+ * @mapping:   The address_space to search
+ * @start:     The starting page cache index
+ * @nr_entries:        The maximum number of entries
+ * @entries:   Where the resulting entries are placed
+ * @indices:   The cache indices corresponding to the entries in @entries
+ *
+ * find_get_entries() will search for and return a group of up to
+ * @nr_entries entries in the mapping.  The entries are placed at
+ * @entries.  find_get_entries() takes a reference against any actual
+ * pages it returns.
+ *
+ * The search returns a group of mapping-contiguous page cache entries
+ * with ascending indexes.  There may be holes in the indices due to
+ * not-present pages.
+ *
+ * Any shadow entries of evicted pages are included in the returned
+ * array.
+ *
+ * find_get_entries() returns the number of pages and shadow entries
+ * which were found.
+ */
+unsigned find_get_entries(struct address_space *mapping,
+                         pgoff_t start, unsigned int nr_entries,
+                         struct page **entries, pgoff_t *indices)
+{
+       void **slot;
+       unsigned int ret = 0;
+       struct radix_tree_iter iter;
+
+       if (!nr_entries)
+               return 0;
+
+       rcu_read_lock();
+restart:
+       radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
+               struct page *page;
+repeat:
+               page = radix_tree_deref_slot(slot);
+               if (unlikely(!page))
+                       continue;
+               if (radix_tree_exception(page)) {
+                       if (radix_tree_deref_retry(page))
+                               goto restart;
+                       /*
+                        * Otherwise, we must be storing a swap entry
+                        * here as an exceptional entry: so return it
+                        * without attempting to raise page count.
+                        */
+                       goto export;
+               }
+               if (!page_cache_get_speculative(page))
+                       goto repeat;
+
+               /* Has the page moved? */
+               if (unlikely(page != *slot)) {
+                       page_cache_release(page);
+                       goto repeat;
+               }
+export:
+               indices[ret] = iter.index;
+               entries[ret] = page;
+               if (++ret == nr_entries)
+                       break;
+       }
+       rcu_read_unlock();
+       return ret;
+}
+
 /**
  * find_get_pages - gang pagecache lookup
  * @mapping:   The address_space to search
@@ -1795,6 +2133,18 @@ int generic_file_readonly_mmap(struct file * file, struct vm_area_struct * vma)
 EXPORT_SYMBOL(generic_file_mmap);
 EXPORT_SYMBOL(generic_file_readonly_mmap);
 
+static struct page *wait_on_page_read(struct page *page)
+{
+       if (!IS_ERR(page)) {
+               wait_on_page_locked(page);
+               if (!PageUptodate(page)) {
+                       page_cache_release(page);
+                       page = ERR_PTR(-EIO);
+               }
+       }
+       return page;
+}
+
 static struct page *__read_cache_page(struct address_space *mapping,
                                pgoff_t index,
                                int (*filler)(void *, struct page *),
@@ -1821,6 +2171,8 @@ repeat:
                if (err < 0) {
                        page_cache_release(page);
                        page = ERR_PTR(err);
+               } else {
+                       page = wait_on_page_read(page);
                }
        }
        return page;
@@ -1857,6 +2209,10 @@ retry:
        if (err < 0) {
                page_cache_release(page);
                return ERR_PTR(err);
+       } else {
+               page = wait_on_page_read(page);
+               if (IS_ERR(page))
+                       return page;
        }
 out:
        mark_page_accessed(page);
@@ -1864,40 +2220,25 @@ out:
 }
 
 /**
- * read_cache_page_async - read into page cache, fill it if needed
+ * read_cache_page - read into page cache, fill it if needed
  * @mapping:   the page's address_space
  * @index:     the page index
  * @filler:    function to perform the read
  * @data:      first arg to filler(data, page) function, often left as NULL
  *
- * Same as read_cache_page, but don't wait for page to become unlocked
- * after submitting it to the filler.
- *
  * Read into the page cache. If a page already exists, and PageUptodate() is
- * not set, try to fill the page but don't wait for it to become unlocked.
+ * not set, try to fill the page and wait for it to become unlocked.
  *
  * If the page does not get brought uptodate, return -EIO.
  */
-struct page *read_cache_page_async(struct address_space *mapping,
+struct page *read_cache_page(struct address_space *mapping,
                                pgoff_t index,
                                int (*filler)(void *, struct page *),
                                void *data)
 {
        return do_read_cache_page(mapping, index, filler, data, mapping_gfp_mask(mapping));
 }
-EXPORT_SYMBOL(read_cache_page_async);
-
-static struct page *wait_on_page_read(struct page *page)
-{
-       if (!IS_ERR(page)) {
-               wait_on_page_locked(page);
-               if (!PageUptodate(page)) {
-                       page_cache_release(page);
-                       page = ERR_PTR(-EIO);
-               }
-       }
-       return page;
-}
+EXPORT_SYMBOL(read_cache_page);
 
 /**
  * read_cache_page_gfp - read into page cache, using specified page allocation flags.
@@ -1916,31 +2257,10 @@ struct page *read_cache_page_gfp(struct address_space *mapping,
 {
        filler_t *filler = (filler_t *)mapping->a_ops->readpage;
 
-       return wait_on_page_read(do_read_cache_page(mapping, index, filler, NULL, gfp));
+       return do_read_cache_page(mapping, index, filler, NULL, gfp);
 }
 EXPORT_SYMBOL(read_cache_page_gfp);
 
-/**
- * read_cache_page - read into page cache, fill it if needed
- * @mapping:   the page's address_space
- * @index:     the page index
- * @filler:    function to perform the read
- * @data:      first arg to filler(data, page) function, often left as NULL
- *
- * Read into the page cache. If a page already exists, and PageUptodate() is
- * not set, try to fill the page then wait for it to become unlocked.
- *
- * If the page does not get brought uptodate, return -EIO.
- */
-struct page *read_cache_page(struct address_space *mapping,
-                               pgoff_t index,
-                               int (*filler)(void *, struct page *),
-                               void *data)
-{
-       return wait_on_page_read(read_cache_page_async(mapping, index, filler, data));
-}
-EXPORT_SYMBOL(read_cache_page);
-
 static size_t __iovec_copy_from_user_inatomic(char *vaddr,
                        const struct iovec *iov, size_t base, size_t bytes)
 {
index 1546655..6ac89e9 100644 (file)
@@ -941,81 +941,6 @@ unlock:
        spin_unlock(ptl);
 }
 
-static int do_huge_pmd_wp_zero_page_fallback(struct mm_struct *mm,
-               struct vm_area_struct *vma, unsigned long address,
-               pmd_t *pmd, pmd_t orig_pmd, unsigned long haddr)
-{
-       spinlock_t *ptl;
-       pgtable_t pgtable;
-       pmd_t _pmd;
-       struct page *page;
-       int i, ret = 0;
-       unsigned long mmun_start;       /* For mmu_notifiers */
-       unsigned long mmun_end;         /* For mmu_notifiers */
-
-       page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
-       if (!page) {
-               ret |= VM_FAULT_OOM;
-               goto out;
-       }
-
-       if (mem_cgroup_newpage_charge(page, mm, GFP_KERNEL)) {
-               put_page(page);
-               ret |= VM_FAULT_OOM;
-               goto out;
-       }
-
-       clear_user_highpage(page, address);
-       __SetPageUptodate(page);
-
-       mmun_start = haddr;
-       mmun_end   = haddr + HPAGE_PMD_SIZE;
-       mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
-
-       ptl = pmd_lock(mm, pmd);
-       if (unlikely(!pmd_same(*pmd, orig_pmd)))
-               goto out_free_page;
-
-       pmdp_clear_flush(vma, haddr, pmd);
-       /* leave pmd empty until pte is filled */
-
-       pgtable = pgtable_trans_huge_withdraw(mm, pmd);
-       pmd_populate(mm, &_pmd, pgtable);
-
-       for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
-               pte_t *pte, entry;
-               if (haddr == (address & PAGE_MASK)) {
-                       entry = mk_pte(page, vma->vm_page_prot);
-                       entry = maybe_mkwrite(pte_mkdirty(entry), vma);
-                       page_add_new_anon_rmap(page, vma, haddr);
-               } else {
-                       entry = pfn_pte(my_zero_pfn(haddr), vma->vm_page_prot);
-                       entry = pte_mkspecial(entry);
-               }
-               pte = pte_offset_map(&_pmd, haddr);
-               VM_BUG_ON(!pte_none(*pte));
-               set_pte_at(mm, haddr, pte, entry);
-               pte_unmap(pte);
-       }
-       smp_wmb(); /* make pte visible before pmd */
-       pmd_populate(mm, pmd, pgtable);
-       spin_unlock(ptl);
-       put_huge_zero_page();
-       inc_mm_counter(mm, MM_ANONPAGES);
-
-       mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
-
-       ret |= VM_FAULT_WRITE;
-out:
-       return ret;
-out_free_page:
-       spin_unlock(ptl);
-       mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
-       mem_cgroup_uncharge_page(page);
-       put_page(page);
-       goto out;
-}
-
 static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
                                        struct vm_area_struct *vma,
                                        unsigned long address,
@@ -1161,8 +1086,8 @@ alloc:
 
        if (unlikely(!new_page)) {
                if (!page) {
-                       ret = do_huge_pmd_wp_zero_page_fallback(mm, vma,
-                                       address, pmd, orig_pmd, haddr);
+                       split_huge_page_pmd(vma, address, pmd);
+                       ret |= VM_FAULT_FALLBACK;
                } else {
                        ret = do_huge_pmd_wp_page_fallback(mm, vma, address,
                                        pmd, orig_pmd, page, haddr);
index c01cb9f..7c02b9d 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/swap.h>
 #include <linux/swapops.h>
 #include <linux/page-isolation.h>
+#include <linux/jhash.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -53,6 +54,13 @@ static unsigned long __initdata default_hstate_size;
  */
 DEFINE_SPINLOCK(hugetlb_lock);
 
+/*
+ * Serializes faults on the same logical page.  This is used to
+ * prevent spurious OOMs when the hugepage pool is fully utilized.
+ */
+static int num_fault_mutexes;
+static struct mutex *htlb_fault_mutex_table ____cacheline_aligned_in_smp;
+
 static inline void unlock_or_release_subpool(struct hugepage_subpool *spool)
 {
        bool free = (spool->count == 0) && (spool->used_hpages == 0);
@@ -135,15 +143,8 @@ static inline struct hugepage_subpool *subpool_vma(struct vm_area_struct *vma)
  * Region tracking -- allows tracking of reservations and instantiated pages
  *                    across the pages in a mapping.
  *
- * The region data structures are protected by a combination of the mmap_sem
- * and the hugetlb_instantiation_mutex.  To access or modify a region the caller
- * must either hold the mmap_sem for write, or the mmap_sem for read and
- * the hugetlb_instantiation_mutex:
- *
- *     down_write(&mm->mmap_sem);
- * or
- *     down_read(&mm->mmap_sem);
- *     mutex_lock(&hugetlb_instantiation_mutex);
+ * The region data structures are embedded into a resv_map and
+ * protected by a resv_map's lock
  */
 struct file_region {
        struct list_head link;
@@ -151,10 +152,12 @@ struct file_region {
        long to;
 };
 
-static long region_add(struct list_head *head, long f, long t)
+static long region_add(struct resv_map *resv, long f, long t)
 {
+       struct list_head *head = &resv->regions;
        struct file_region *rg, *nrg, *trg;
 
+       spin_lock(&resv->lock);
        /* Locate the region we are either in or before. */
        list_for_each_entry(rg, head, link)
                if (f <= rg->to)
@@ -184,14 +187,18 @@ static long region_add(struct list_head *head, long f, long t)
        }
        nrg->from = f;
        nrg->to = t;
+       spin_unlock(&resv->lock);
        return 0;
 }
 
-static long region_chg(struct list_head *head, long f, long t)
+static long region_chg(struct resv_map *resv, long f, long t)
 {
-       struct file_region *rg, *nrg;
+       struct list_head *head = &resv->regions;
+       struct file_region *rg, *nrg = NULL;
        long chg = 0;
 
+retry:
+       spin_lock(&resv->lock);
        /* Locate the region we are before or in. */
        list_for_each_entry(rg, head, link)
                if (f <= rg->to)
@@ -201,15 +208,21 @@ static long region_chg(struct list_head *head, long f, long t)
         * Subtle, allocate a new region at the position but make it zero
         * size such that we can guarantee to record the reservation. */
        if (&rg->link == head || t < rg->from) {
-               nrg = kmalloc(sizeof(*nrg), GFP_KERNEL);
-               if (!nrg)
-                       return -ENOMEM;
-               nrg->from = f;
-               nrg->to   = f;
-               INIT_LIST_HEAD(&nrg->link);
-               list_add(&nrg->link, rg->link.prev);
+               if (!nrg) {
+                       spin_unlock(&resv->lock);
+                       nrg = kmalloc(sizeof(*nrg), GFP_KERNEL);
+                       if (!nrg)
+                               return -ENOMEM;
+
+                       nrg->from = f;
+                       nrg->to   = f;
+                       INIT_LIST_HEAD(&nrg->link);
+                       goto retry;
+               }
 
-               return t - f;
+               list_add(&nrg->link, rg->link.prev);
+               chg = t - f;
+               goto out_nrg;
        }
 
        /* Round our left edge to the current segment if it encloses us. */
@@ -222,7 +235,7 @@ static long region_chg(struct list_head *head, long f, long t)
                if (&rg->link == head)
                        break;
                if (rg->from > t)
-                       return chg;
+                       goto out;
 
                /* We overlap with this area, if it extends further than
                 * us then we must extend ourselves.  Account for its
@@ -233,20 +246,30 @@ static long region_chg(struct list_head *head, long f, long t)
                }
                chg -= rg->to - rg->from;
        }
+
+out:
+       spin_unlock(&resv->lock);
+       /*  We already know we raced and no longer need the new region */
+       kfree(nrg);
+       return chg;
+out_nrg:
+       spin_unlock(&resv->lock);
        return chg;
 }
 
-static long region_truncate(struct list_head *head, long end)
+static long region_truncate(struct resv_map *resv, long end)
 {
+       struct list_head *head = &resv->regions;
        struct file_region *rg, *trg;
        long chg = 0;
 
+       spin_lock(&resv->lock);
        /* Locate the region we are either in or before. */
        list_for_each_entry(rg, head, link)
                if (end <= rg->to)
                        break;
        if (&rg->link == head)
-               return 0;
+               goto out;
 
        /* If we are in the middle of a region then adjust it. */
        if (end > rg->from) {
@@ -263,14 +286,19 @@ static long region_truncate(struct list_head *head, long end)
                list_del(&rg->link);
                kfree(rg);
        }
+
+out:
+       spin_unlock(&resv->lock);
        return chg;
 }
 
-static long region_count(struct list_head *head, long f, long t)
+static long region_count(struct resv_map *resv, long f, long t)
 {
+       struct list_head *head = &resv->regions;
        struct file_region *rg;
        long chg = 0;
 
+       spin_lock(&resv->lock);
        /* Locate each segment we overlap with, and count that overlap. */
        list_for_each_entry(rg, head, link) {
                long seg_from;
@@ -286,6 +314,7 @@ static long region_count(struct list_head *head, long f, long t)
 
                chg += seg_to - seg_from;
        }
+       spin_unlock(&resv->lock);
 
        return chg;
 }
@@ -376,39 +405,46 @@ static void set_vma_private_data(struct vm_area_struct *vma,
        vma->vm_private_data = (void *)value;
 }
 
-struct resv_map {
-       struct kref refs;
-       struct list_head regions;
-};
-
-static struct resv_map *resv_map_alloc(void)
+struct resv_map *resv_map_alloc(void)
 {
        struct resv_map *resv_map = kmalloc(sizeof(*resv_map), GFP_KERNEL);
        if (!resv_map)
                return NULL;
 
        kref_init(&resv_map->refs);
+       spin_lock_init(&resv_map->lock);
        INIT_LIST_HEAD(&resv_map->regions);
 
        return resv_map;
 }
 
-static void resv_map_release(struct kref *ref)
+void resv_map_release(struct kref *ref)
 {
        struct resv_map *resv_map = container_of(ref, struct resv_map, refs);
 
        /* Clear out any active regions before we release the map. */
-       region_truncate(&resv_map->regions, 0);
+       region_truncate(resv_map, 0);
        kfree(resv_map);
 }
 
+static inline struct resv_map *inode_resv_map(struct inode *inode)
+{
+       return inode->i_mapping->private_data;
+}
+
 static struct resv_map *vma_resv_map(struct vm_area_struct *vma)
 {
        VM_BUG_ON(!is_vm_hugetlb_page(vma));
-       if (!(vma->vm_flags & VM_MAYSHARE))
+       if (vma->vm_flags & VM_MAYSHARE) {
+               struct address_space *mapping = vma->vm_file->f_mapping;
+               struct inode *inode = mapping->host;
+
+               return inode_resv_map(inode);
+
+       } else {
                return (struct resv_map *)(get_vma_private_data(vma) &
                                                        ~HPAGE_RESV_MASK);
-       return NULL;
+       }
 }
 
 static void set_vma_resv_map(struct vm_area_struct *vma, struct resv_map *map)
@@ -540,7 +576,7 @@ static struct page *dequeue_huge_page_vma(struct hstate *h,
                goto err;
 
 retry_cpuset:
-       cpuset_mems_cookie = get_mems_allowed();
+       cpuset_mems_cookie = read_mems_allowed_begin();
        zonelist = huge_zonelist(vma, address,
                                        htlb_alloc_mask(h), &mpol, &nodemask);
 
@@ -562,7 +598,7 @@ retry_cpuset:
        }
 
        mpol_cond_put(mpol);
-       if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+       if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
                goto retry_cpuset;
        return page;
 
@@ -653,7 +689,8 @@ static void prep_new_huge_page(struct hstate *h, struct page *page, int nid)
        put_page(page); /* free it into the hugepage allocator */
 }
 
-static void prep_compound_gigantic_page(struct page *page, unsigned long order)
+static void __init prep_compound_gigantic_page(struct page *page,
+                                              unsigned long order)
 {
        int i;
        int nr_pages = 1 << order;
@@ -1150,45 +1187,34 @@ static void return_unused_surplus_pages(struct hstate *h,
 static long vma_needs_reservation(struct hstate *h,
                        struct vm_area_struct *vma, unsigned long addr)
 {
-       struct address_space *mapping = vma->vm_file->f_mapping;
-       struct inode *inode = mapping->host;
-
-       if (vma->vm_flags & VM_MAYSHARE) {
-               pgoff_t idx = vma_hugecache_offset(h, vma, addr);
-               return region_chg(&inode->i_mapping->private_list,
-                                                       idx, idx + 1);
+       struct resv_map *resv;
+       pgoff_t idx;
+       long chg;
 
-       } else if (!is_vma_resv_set(vma, HPAGE_RESV_OWNER)) {
+       resv = vma_resv_map(vma);
+       if (!resv)
                return 1;
 
-       } else  {
-               long err;
-               pgoff_t idx = vma_hugecache_offset(h, vma, addr);
-               struct resv_map *resv = vma_resv_map(vma);
+       idx = vma_hugecache_offset(h, vma, addr);
+       chg = region_chg(resv, idx, idx + 1);
 
-               err = region_chg(&resv->regions, idx, idx + 1);
-               if (err < 0)
-                       return err;
-               return 0;
-       }
+       if (vma->vm_flags & VM_MAYSHARE)
+               return chg;
+       else
+               return chg < 0 ? chg : 0;
 }
 static void vma_commit_reservation(struct hstate *h,
                        struct vm_area_struct *vma, unsigned long addr)
 {
-       struct address_space *mapping = vma->vm_file->f_mapping;
-       struct inode *inode = mapping->host;
-
-       if (vma->vm_flags & VM_MAYSHARE) {
-               pgoff_t idx = vma_hugecache_offset(h, vma, addr);
-               region_add(&inode->i_mapping->private_list, idx, idx + 1);
+       struct resv_map *resv;
+       pgoff_t idx;
 
-       } else if (is_vma_resv_set(vma, HPAGE_RESV_OWNER)) {
-               pgoff_t idx = vma_hugecache_offset(h, vma, addr);
-               struct resv_map *resv = vma_resv_map(vma);
+       resv = vma_resv_map(vma);
+       if (!resv)
+               return;
 
-               /* Mark this page used in the map. */
-               region_add(&resv->regions, idx, idx + 1);
-       }
+       idx = vma_hugecache_offset(h, vma, addr);
+       region_add(resv, idx, idx + 1);
 }
 
 static struct page *alloc_huge_page(struct vm_area_struct *vma,
@@ -1294,7 +1320,7 @@ found:
        return 1;
 }
 
-static void prep_compound_huge_page(struct page *page, int order)
+static void __init prep_compound_huge_page(struct page *page, int order)
 {
        if (unlikely(order > (MAX_ORDER - 1)))
                prep_compound_gigantic_page(page, order);
@@ -1944,11 +1970,14 @@ static void __exit hugetlb_exit(void)
        }
 
        kobject_put(hugepages_kobj);
+       kfree(htlb_fault_mutex_table);
 }
 module_exit(hugetlb_exit);
 
 static int __init hugetlb_init(void)
 {
+       int i;
+
        /* Some platform decide whether they support huge pages at boot
         * time. On these, such as powerpc, HPAGE_SHIFT is set to 0 when
         * there is no such support
@@ -1973,6 +2002,17 @@ static int __init hugetlb_init(void)
        hugetlb_register_all_nodes();
        hugetlb_cgroup_file_init();
 
+#ifdef CONFIG_SMP
+       num_fault_mutexes = roundup_pow_of_two(8 * num_possible_cpus());
+#else
+       num_fault_mutexes = 1;
+#endif
+       htlb_fault_mutex_table =
+               kmalloc(sizeof(struct mutex) * num_fault_mutexes, GFP_KERNEL);
+       BUG_ON(!htlb_fault_mutex_table);
+
+       for (i = 0; i < num_fault_mutexes; i++)
+               mutex_init(&htlb_fault_mutex_table[i]);
        return 0;
 }
 module_init(hugetlb_init);
@@ -2251,41 +2291,30 @@ static void hugetlb_vm_op_open(struct vm_area_struct *vma)
         * after this open call completes.  It is therefore safe to take a
         * new reference here without additional locking.
         */
-       if (resv)
+       if (resv && is_vma_resv_set(vma, HPAGE_RESV_OWNER))
                kref_get(&resv->refs);
 }
 
-static void resv_map_put(struct vm_area_struct *vma)
-{
-       struct resv_map *resv = vma_resv_map(vma);
-
-       if (!resv)
-               return;
-       kref_put(&resv->refs, resv_map_release);
-}
-
 static void hugetlb_vm_op_close(struct vm_area_struct *vma)
 {
        struct hstate *h = hstate_vma(vma);
        struct resv_map *resv = vma_resv_map(vma);
        struct hugepage_subpool *spool = subpool_vma(vma);
-       unsigned long reserve;
-       unsigned long start;
-       unsigned long end;
+       unsigned long reserve, start, end;
 
-       if (resv) {
-               start = vma_hugecache_offset(h, vma, vma->vm_start);
-               end = vma_hugecache_offset(h, vma, vma->vm_end);
+       if (!resv || !is_vma_resv_set(vma, HPAGE_RESV_OWNER))
+               return;
 
-               reserve = (end - start) -
-                       region_count(&resv->regions, start, end);
+       start = vma_hugecache_offset(h, vma, vma->vm_start);
+       end = vma_hugecache_offset(h, vma, vma->vm_end);
 
-               resv_map_put(vma);
+       reserve = (end - start) - region_count(resv, start, end);
 
-               if (reserve) {
-                       hugetlb_acct_memory(h, -reserve);
-                       hugepage_subpool_put_pages(spool, reserve);
-               }
+       kref_put(&resv->refs, resv_map_release);
+
+       if (reserve) {
+               hugetlb_acct_memory(h, -reserve);
+               hugepage_subpool_put_pages(spool, reserve);
        }
 }
 
@@ -2761,15 +2790,14 @@ static bool hugetlbfs_pagecache_present(struct hstate *h,
 }
 
 static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
-                       unsigned long address, pte_t *ptep, unsigned int flags)
+                          struct address_space *mapping, pgoff_t idx,
+                          unsigned long address, pte_t *ptep, unsigned int flags)
 {
        struct hstate *h = hstate_vma(vma);
        int ret = VM_FAULT_SIGBUS;
        int anon_rmap = 0;
-       pgoff_t idx;
        unsigned long size;
        struct page *page;
-       struct address_space *mapping;
        pte_t new_pte;
        spinlock_t *ptl;
 
@@ -2784,9 +2812,6 @@ static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
                return ret;
        }
 
-       mapping = vma->vm_file->f_mapping;
-       idx = vma_hugecache_offset(h, vma, address);
-
        /*
         * Use page lock to guard against racing truncation
         * before we get page_table_lock.
@@ -2896,17 +2921,53 @@ backout_unlocked:
        goto out;
 }
 
+#ifdef CONFIG_SMP
+static u32 fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
+                           struct vm_area_struct *vma,
+                           struct address_space *mapping,
+                           pgoff_t idx, unsigned long address)
+{
+       unsigned long key[2];
+       u32 hash;
+
+       if (vma->vm_flags & VM_SHARED) {
+               key[0] = (unsigned long) mapping;
+               key[1] = idx;
+       } else {
+               key[0] = (unsigned long) mm;
+               key[1] = address >> huge_page_shift(h);
+       }
+
+       hash = jhash2((u32 *)&key, sizeof(key)/sizeof(u32), 0);
+
+       return hash & (num_fault_mutexes - 1);
+}
+#else
+/*
+ * For uniprocesor systems we always use a single mutex, so just
+ * return 0 and avoid the hashing overhead.
+ */
+static u32 fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
+                           struct vm_area_struct *vma,
+                           struct address_space *mapping,
+                           pgoff_t idx, unsigned long address)
+{
+       return 0;
+}
+#endif
+
 int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                        unsigned long address, unsigned int flags)
 {
-       pte_t *ptep;
-       pte_t entry;
+       pte_t *ptep, entry;
        spinlock_t *ptl;
        int ret;
+       u32 hash;
+       pgoff_t idx;
        struct page *page = NULL;
        struct page *pagecache_page = NULL;
-       static DEFINE_MUTEX(hugetlb_instantiation_mutex);
        struct hstate *h = hstate_vma(vma);
+       struct address_space *mapping;
 
        address &= huge_page_mask(h);
 
@@ -2925,15 +2986,20 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        if (!ptep)
                return VM_FAULT_OOM;
 
+       mapping = vma->vm_file->f_mapping;
+       idx = vma_hugecache_offset(h, vma, address);
+
        /*
         * Serialize hugepage allocation and instantiation, so that we don't
         * get spurious allocation failures if two CPUs race to instantiate
         * the same page in the page cache.
         */
-       mutex_lock(&hugetlb_instantiation_mutex);
+       hash = fault_mutex_hash(h, mm, vma, mapping, idx, address);
+       mutex_lock(&htlb_fault_mutex_table[hash]);
+
        entry = huge_ptep_get(ptep);
        if (huge_pte_none(entry)) {
-               ret = hugetlb_no_page(mm, vma, address, ptep, flags);
+               ret = hugetlb_no_page(mm, vma, mapping, idx, address, ptep, flags);
                goto out_mutex;
        }
 
@@ -3002,8 +3068,7 @@ out_ptl:
        put_page(page);
 
 out_mutex:
-       mutex_unlock(&hugetlb_instantiation_mutex);
-
+       mutex_unlock(&htlb_fault_mutex_table[hash]);
        return ret;
 }
 
@@ -3161,6 +3226,7 @@ int hugetlb_reserve_pages(struct inode *inode,
        long ret, chg;
        struct hstate *h = hstate_inode(inode);
        struct hugepage_subpool *spool = subpool_inode(inode);
+       struct resv_map *resv_map;
 
        /*
         * Only apply hugepage reservation if asked. At fault time, an
@@ -3176,10 +3242,13 @@ int hugetlb_reserve_pages(struct inode *inode,
         * to reserve the full area even if read-only as mprotect() may be
         * called to make the mapping read-write. Assume !vma is a shm mapping
         */
-       if (!vma || vma->vm_flags & VM_MAYSHARE)
-               chg = region_chg(&inode->i_mapping->private_list, from, to);
-       else {
-               struct resv_map *resv_map = resv_map_alloc();
+       if (!vma || vma->vm_flags & VM_MAYSHARE) {
+               resv_map = inode_resv_map(inode);
+
+               chg = region_chg(resv_map, from, to);
+
+       } else {
+               resv_map = resv_map_alloc();
                if (!resv_map)
                        return -ENOMEM;
 
@@ -3222,20 +3291,23 @@ int hugetlb_reserve_pages(struct inode *inode,
         * else has to be done for private mappings here
         */
        if (!vma || vma->vm_flags & VM_MAYSHARE)
-               region_add(&inode->i_mapping->private_list, from, to);
+               region_add(resv_map, from, to);
        return 0;
 out_err:
-       if (vma)
-               resv_map_put(vma);
+       if (vma && is_vma_resv_set(vma, HPAGE_RESV_OWNER))
+               kref_put(&resv_map->refs, resv_map_release);
        return ret;
 }
 
 void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
 {
        struct hstate *h = hstate_inode(inode);
-       long chg = region_truncate(&inode->i_mapping->private_list, offset);
+       struct resv_map *resv_map = inode_resv_map(inode);
+       long chg = 0;
        struct hugepage_subpool *spool = subpool_inode(inode);
 
+       if (resv_map)
+               chg = region_truncate(resv_map, offset);
        spin_lock(&inode->i_lock);
        inode->i_blocks -= (blocks_per_huge_page(h) * freed);
        spin_unlock(&inode->i_lock);
index 31f01c5..91d67ea 100644 (file)
@@ -192,15 +192,15 @@ static struct kmem_cache *object_cache;
 static struct kmem_cache *scan_area_cache;
 
 /* set if tracing memory operations is enabled */
-static atomic_t kmemleak_enabled = ATOMIC_INIT(0);
+static int kmemleak_enabled;
 /* set in the late_initcall if there were no errors */
-static atomic_t kmemleak_initialized = ATOMIC_INIT(0);
+static int kmemleak_initialized;
 /* enables or disables early logging of the memory operations */
-static atomic_t kmemleak_early_log = ATOMIC_INIT(1);
+static int kmemleak_early_log = 1;
 /* set if a kmemleak warning was issued */
-static atomic_t kmemleak_warning = ATOMIC_INIT(0);
+static int kmemleak_warning;
 /* set if a fatal kmemleak error has occurred */
-static atomic_t kmemleak_error = ATOMIC_INIT(0);
+static int kmemleak_error;
 
 /* minimum and maximum address that may be valid pointers */
 static unsigned long min_addr = ULONG_MAX;
@@ -218,7 +218,8 @@ static int kmemleak_stack_scan = 1;
 static DEFINE_MUTEX(scan_mutex);
 /* setting kmemleak=on, will set this var, skipping the disable */
 static int kmemleak_skip_disable;
-
+/* If there are leaks that can be reported */
+static bool kmemleak_found_leaks;
 
 /*
  * Early object allocation/freeing logging. Kmemleak is initialized after the
@@ -267,7 +268,7 @@ static void kmemleak_disable(void);
 #define kmemleak_warn(x...)    do {            \
        pr_warning(x);                          \
        dump_stack();                           \
-       atomic_set(&kmemleak_warning, 1);       \
+       kmemleak_warning = 1;                   \
 } while (0)
 
 /*
@@ -805,7 +806,7 @@ static void __init log_early(int op_type, const void *ptr, size_t size,
        unsigned long flags;
        struct early_log *log;
 
-       if (atomic_read(&kmemleak_error)) {
+       if (kmemleak_error) {
                /* kmemleak stopped recording, just count the requests */
                crt_early_log++;
                return;
@@ -840,7 +841,7 @@ static void early_alloc(struct early_log *log)
        unsigned long flags;
        int i;
 
-       if (!atomic_read(&kmemleak_enabled) || !log->ptr || IS_ERR(log->ptr))
+       if (!kmemleak_enabled || !log->ptr || IS_ERR(log->ptr))
                return;
 
        /*
@@ -893,9 +894,9 @@ void __ref kmemleak_alloc(const void *ptr, size_t size, int min_count,
 {
        pr_debug("%s(0x%p, %zu, %d)\n", __func__, ptr, size, min_count);
 
-       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+       if (kmemleak_enabled && ptr && !IS_ERR(ptr))
                create_object((unsigned long)ptr, size, min_count, gfp);
-       else if (atomic_read(&kmemleak_early_log))
+       else if (kmemleak_early_log)
                log_early(KMEMLEAK_ALLOC, ptr, size, min_count);
 }
 EXPORT_SYMBOL_GPL(kmemleak_alloc);
@@ -919,11 +920,11 @@ void __ref kmemleak_alloc_percpu(const void __percpu *ptr, size_t size)
         * Percpu allocations are only scanned and not reported as leaks
         * (min_count is set to 0).
         */
-       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+       if (kmemleak_enabled && ptr && !IS_ERR(ptr))
                for_each_possible_cpu(cpu)
                        create_object((unsigned long)per_cpu_ptr(ptr, cpu),
                                      size, 0, GFP_KERNEL);
-       else if (atomic_read(&kmemleak_early_log))
+       else if (kmemleak_early_log)
                log_early(KMEMLEAK_ALLOC_PERCPU, ptr, size, 0);
 }
 EXPORT_SYMBOL_GPL(kmemleak_alloc_percpu);
@@ -939,9 +940,9 @@ void __ref kmemleak_free(const void *ptr)
 {
        pr_debug("%s(0x%p)\n", __func__, ptr);
 
-       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+       if (kmemleak_enabled && ptr && !IS_ERR(ptr))
                delete_object_full((unsigned long)ptr);
-       else if (atomic_read(&kmemleak_early_log))
+       else if (kmemleak_early_log)
                log_early(KMEMLEAK_FREE, ptr, 0, 0);
 }
 EXPORT_SYMBOL_GPL(kmemleak_free);
@@ -959,9 +960,9 @@ void __ref kmemleak_free_part(const void *ptr, size_t size)
 {
        pr_debug("%s(0x%p)\n", __func__, ptr);
 
-       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+       if (kmemleak_enabled && ptr && !IS_ERR(ptr))
                delete_object_part((unsigned long)ptr, size);
-       else if (atomic_read(&kmemleak_early_log))
+       else if (kmemleak_early_log)
                log_early(KMEMLEAK_FREE_PART, ptr, size, 0);
 }
 EXPORT_SYMBOL_GPL(kmemleak_free_part);
@@ -979,11 +980,11 @@ void __ref kmemleak_free_percpu(const void __percpu *ptr)
 
        pr_debug("%s(0x%p)\n", __func__, ptr);
 
-       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+       if (kmemleak_enabled && ptr && !IS_ERR(ptr))
                for_each_possible_cpu(cpu)
                        delete_object_full((unsigned long)per_cpu_ptr(ptr,
                                                                      cpu));
-       else if (atomic_read(&kmemleak_early_log))
+       else if (kmemleak_early_log)
                log_early(KMEMLEAK_FREE_PERCPU, ptr, 0, 0);
 }
 EXPORT_SYMBOL_GPL(kmemleak_free_percpu);
@@ -999,9 +1000,9 @@ void __ref kmemleak_not_leak(const void *ptr)
 {
        pr_debug("%s(0x%p)\n", __func__, ptr);
 
-       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+       if (kmemleak_enabled && ptr && !IS_ERR(ptr))
                make_gray_object((unsigned long)ptr);
-       else if (atomic_read(&kmemleak_early_log))
+       else if (kmemleak_early_log)
                log_early(KMEMLEAK_NOT_LEAK, ptr, 0, 0);
 }
 EXPORT_SYMBOL(kmemleak_not_leak);
@@ -1019,9 +1020,9 @@ void __ref kmemleak_ignore(const void *ptr)
 {
        pr_debug("%s(0x%p)\n", __func__, ptr);
 
-       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+       if (kmemleak_enabled && ptr && !IS_ERR(ptr))
                make_black_object((unsigned long)ptr);
-       else if (atomic_read(&kmemleak_early_log))
+       else if (kmemleak_early_log)
                log_early(KMEMLEAK_IGNORE, ptr, 0, 0);
 }
 EXPORT_SYMBOL(kmemleak_ignore);
@@ -1041,9 +1042,9 @@ void __ref kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp)
 {
        pr_debug("%s(0x%p)\n", __func__, ptr);
 
-       if (atomic_read(&kmemleak_enabled) && ptr && size && !IS_ERR(ptr))
+       if (kmemleak_enabled && ptr && size && !IS_ERR(ptr))
                add_scan_area((unsigned long)ptr, size, gfp);
-       else if (atomic_read(&kmemleak_early_log))
+       else if (kmemleak_early_log)
                log_early(KMEMLEAK_SCAN_AREA, ptr, size, 0);
 }
 EXPORT_SYMBOL(kmemleak_scan_area);
@@ -1061,9 +1062,9 @@ void __ref kmemleak_no_scan(const void *ptr)
 {
        pr_debug("%s(0x%p)\n", __func__, ptr);
 
-       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+       if (kmemleak_enabled && ptr && !IS_ERR(ptr))
                object_no_scan((unsigned long)ptr);
-       else if (atomic_read(&kmemleak_early_log))
+       else if (kmemleak_early_log)
                log_early(KMEMLEAK_NO_SCAN, ptr, 0, 0);
 }
 EXPORT_SYMBOL(kmemleak_no_scan);
@@ -1088,7 +1089,7 @@ static bool update_checksum(struct kmemleak_object *object)
  */
 static int scan_should_stop(void)
 {
-       if (!atomic_read(&kmemleak_enabled))
+       if (!kmemleak_enabled)
                return 1;
 
        /*
@@ -1382,9 +1383,12 @@ static void kmemleak_scan(void)
        }
        rcu_read_unlock();
 
-       if (new_leaks)
+       if (new_leaks) {
+               kmemleak_found_leaks = true;
+
                pr_info("%d new suspected memory leaks (see "
                        "/sys/kernel/debug/kmemleak)\n", new_leaks);
+       }
 
 }
 
@@ -1545,11 +1549,6 @@ static int kmemleak_open(struct inode *inode, struct file *file)
        return seq_open(file, &kmemleak_seq_ops);
 }
 
-static int kmemleak_release(struct inode *inode, struct file *file)
-{
-       return seq_release(inode, file);
-}
-
 static int dump_str_object_info(const char *str)
 {
        unsigned long flags;
@@ -1592,8 +1591,12 @@ static void kmemleak_clear(void)
                spin_unlock_irqrestore(&object->lock, flags);
        }
        rcu_read_unlock();
+
+       kmemleak_found_leaks = false;
 }
 
+static void __kmemleak_do_cleanup(void);
+
 /*
  * File write operation to configure kmemleak at run-time. The following
  * commands can be written to the /sys/kernel/debug/kmemleak file:
@@ -1606,7 +1609,8 @@ static void kmemleak_clear(void)
  *               disable it)
  *   scan      - trigger a memory scan
  *   clear     - mark all current reported unreferenced kmemleak objects as
- *               grey to ignore printing them
+ *               grey to ignore printing them, or free all kmemleak objects
+ *               if kmemleak has been disabled.
  *   dump=...  - dump information about the object found at the given address
  */
 static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
@@ -1616,9 +1620,6 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
        int buf_size;
        int ret;
 
-       if (!atomic_read(&kmemleak_enabled))
-               return -EBUSY;
-
        buf_size = min(size, (sizeof(buf) - 1));
        if (strncpy_from_user(buf, user_buf, buf_size) < 0)
                return -EFAULT;
@@ -1628,6 +1629,19 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
        if (ret < 0)
                return ret;
 
+       if (strncmp(buf, "clear", 5) == 0) {
+               if (kmemleak_enabled)
+                       kmemleak_clear();
+               else
+                       __kmemleak_do_cleanup();
+               goto out;
+       }
+
+       if (!kmemleak_enabled) {
+               ret = -EBUSY;
+               goto out;
+       }
+
        if (strncmp(buf, "off", 3) == 0)
                kmemleak_disable();
        else if (strncmp(buf, "stack=on", 8) == 0)
@@ -1651,8 +1665,6 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
                }
        } else if (strncmp(buf, "scan", 4) == 0)
                kmemleak_scan();
-       else if (strncmp(buf, "clear", 5) == 0)
-               kmemleak_clear();
        else if (strncmp(buf, "dump=", 5) == 0)
                ret = dump_str_object_info(buf + 5);
        else
@@ -1674,9 +1686,19 @@ static const struct file_operations kmemleak_fops = {
        .read           = seq_read,
        .write          = kmemleak_write,
        .llseek         = seq_lseek,
-       .release        = kmemleak_release,
+       .release        = seq_release,
 };
 
+static void __kmemleak_do_cleanup(void)
+{
+       struct kmemleak_object *object;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(object, &object_list, object_list)
+               delete_object_full(object->pointer);
+       rcu_read_unlock();
+}
+
 /*
  * Stop the memory scanning thread and free the kmemleak internal objects if
  * no previous scan thread (otherwise, kmemleak may still have some useful
@@ -1684,18 +1706,14 @@ static const struct file_operations kmemleak_fops = {
  */
 static void kmemleak_do_cleanup(struct work_struct *work)
 {
-       struct kmemleak_object *object;
-       bool cleanup = scan_thread == NULL;
-
        mutex_lock(&scan_mutex);
        stop_scan_thread();
 
-       if (cleanup) {
-               rcu_read_lock();
-               list_for_each_entry_rcu(object, &object_list, object_list)
-                       delete_object_full(object->pointer);
-               rcu_read_unlock();
-       }
+       if (!kmemleak_found_leaks)
+               __kmemleak_do_cleanup();
+       else
+               pr_info("Kmemleak disabled without freeing internal data. "
+                       "Reclaim the memory with \"echo clear > /sys/kernel/debug/kmemleak\"\n");
        mutex_unlock(&scan_mutex);
 }
 
@@ -1708,14 +1726,14 @@ static DECLARE_WORK(cleanup_work, kmemleak_do_cleanup);
 static void kmemleak_disable(void)
 {
        /* atomically check whether it was already invoked */
-       if (atomic_cmpxchg(&kmemleak_error, 0, 1))
+       if (cmpxchg(&kmemleak_error, 0, 1))
                return;
 
        /* stop any memory operation tracing */
-       atomic_set(&kmemleak_enabled, 0);
+       kmemleak_enabled = 0;
 
        /* check whether it is too early for a kernel thread */
-       if (atomic_read(&kmemleak_initialized))
+       if (kmemleak_initialized)
                schedule_work(&cleanup_work);
 
        pr_info("Kernel memory leak detector disabled\n");
@@ -1757,9 +1775,10 @@ void __init kmemleak_init(void)
        int i;
        unsigned long flags;
 
+       kmemleak_early_log = 0;
+
 #ifdef CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF
        if (!kmemleak_skip_disable) {
-               atomic_set(&kmemleak_early_log, 0);
                kmemleak_disable();
                return;
        }
@@ -1777,12 +1796,11 @@ void __init kmemleak_init(void)
 
        /* the kernel is still in UP mode, so disabling the IRQs is enough */
        local_irq_save(flags);
-       atomic_set(&kmemleak_early_log, 0);
-       if (atomic_read(&kmemleak_error)) {
+       if (kmemleak_error) {
                local_irq_restore(flags);
                return;
        } else
-               atomic_set(&kmemleak_enabled, 1);
+               kmemleak_enabled = 1;
        local_irq_restore(flags);
 
        /*
@@ -1826,9 +1844,9 @@ void __init kmemleak_init(void)
                                      log->op_type);
                }
 
-               if (atomic_read(&kmemleak_warning)) {
+               if (kmemleak_warning) {
                        print_log_trace(log);
-                       atomic_set(&kmemleak_warning, 0);
+                       kmemleak_warning = 0;
                }
        }
 }
@@ -1840,9 +1858,9 @@ static int __init kmemleak_late_init(void)
 {
        struct dentry *dentry;
 
-       atomic_set(&kmemleak_initialized, 1);
+       kmemleak_initialized = 1;
 
-       if (atomic_read(&kmemleak_error)) {
+       if (kmemleak_error) {
                /*
                 * Some error occurred and kmemleak was disabled. There is a
                 * small chance that kmemleak_disable() was called immediately
index 72f9dec..f1a0db1 100644 (file)
@@ -87,11 +87,20 @@ restart:
 
                ret = isolate(item, &nlru->lock, cb_arg);
                switch (ret) {
+               case LRU_REMOVED_RETRY:
+                       assert_spin_locked(&nlru->lock);
                case LRU_REMOVED:
                        if (--nlru->nr_items == 0)
                                node_clear(nid, lru->active_nodes);
                        WARN_ON_ONCE(nlru->nr_items < 0);
                        isolated++;
+                       /*
+                        * If the lru lock has been dropped, our list
+                        * traversal is now invalid and so we have to
+                        * restart from scratch.
+                        */
+                       if (ret == LRU_REMOVED_RETRY)
+                               goto restart;
                        break;
                case LRU_ROTATE:
                        list_move_tail(item, &nlru->list);
@@ -103,6 +112,7 @@ restart:
                         * The lru lock has been dropped, our list traversal is
                         * now invalid and so we have to restart from scratch.
                         */
+                       assert_spin_locked(&nlru->lock);
                        goto restart;
                default:
                        BUG();
@@ -114,7 +124,7 @@ restart:
 }
 EXPORT_SYMBOL_GPL(list_lru_walk_node);
 
-int list_lru_init(struct list_lru *lru)
+int list_lru_init_key(struct list_lru *lru, struct lock_class_key *key)
 {
        int i;
        size_t size = sizeof(*lru->node) * nr_node_ids;
@@ -126,12 +136,14 @@ int list_lru_init(struct list_lru *lru)
        nodes_clear(lru->active_nodes);
        for (i = 0; i < nr_node_ids; i++) {
                spin_lock_init(&lru->node[i].lock);
+               if (key)
+                       lockdep_set_class(&lru->node[i].lock, key);
                INIT_LIST_HEAD(&lru->node[i].list);
                lru->node[i].nr_items = 0;
        }
        return 0;
 }
-EXPORT_SYMBOL_GPL(list_lru_init);
+EXPORT_SYMBOL_GPL(list_lru_init_key);
 
 void list_lru_destroy(struct list_lru *lru)
 {
index 22dfa61..90cea22 100644 (file)
@@ -2586,6 +2586,38 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo
                copy_user_highpage(dst, src, va, vma);
 }
 
+/*
+ * Notify the address space that the page is about to become writable so that
+ * it can prohibit this or wait for the page to get into an appropriate state.
+ *
+ * We do this without the lock held, so that it can sleep if it needs to.
+ */
+static int do_page_mkwrite(struct vm_area_struct *vma, struct page *page,
+              unsigned long address)
+{
+       struct vm_fault vmf;
+       int ret;
+
+       vmf.virtual_address = (void __user *)(address & PAGE_MASK);
+       vmf.pgoff = page->index;
+       vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE;
+       vmf.page = page;
+
+       ret = vma->vm_ops->page_mkwrite(vma, &vmf);
+       if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))
+               return ret;
+       if (unlikely(!(ret & VM_FAULT_LOCKED))) {
+               lock_page(page);
+               if (!page->mapping) {
+                       unlock_page(page);
+                       return 0; /* retry */
+               }
+               ret |= VM_FAULT_LOCKED;
+       } else
+               VM_BUG_ON_PAGE(!PageLocked(page), page);
+       return ret;
+}
+
 /*
  * This routine handles present pages, when users try to write
  * to a shared page. It is done by copying the page to a new address
@@ -2668,42 +2700,15 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                 * get_user_pages(.write=1, .force=1).
                 */
                if (vma->vm_ops && vma->vm_ops->page_mkwrite) {
-                       struct vm_fault vmf;
                        int tmp;
-
-                       vmf.virtual_address = (void __user *)(address &
-                                                               PAGE_MASK);
-                       vmf.pgoff = old_page->index;
-                       vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE;
-                       vmf.page = old_page;
-
-                       /*
-                        * Notify the address space that the page is about to
-                        * become writable so that it can prohibit this or wait
-                        * for the page to get into an appropriate state.
-                        *
-                        * We do this without the lock held, so that it can
-                        * sleep if it needs to.
-                        */
                        page_cache_get(old_page);
                        pte_unmap_unlock(page_table, ptl);
-
-                       tmp = vma->vm_ops->page_mkwrite(vma, &vmf);
-                       if (unlikely(tmp &
-                                       (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) {
-                               ret = tmp;
-                               goto unwritable_page;
+                       tmp = do_page_mkwrite(vma, old_page, address);
+                       if (unlikely(!tmp || (tmp &
+                                       (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))) {
+                               page_cache_release(old_page);
+                               return tmp;
                        }
-                       if (unlikely(!(tmp & VM_FAULT_LOCKED))) {
-                               lock_page(old_page);
-                               if (!old_page->mapping) {
-                                       ret = 0; /* retry the fault */
-                                       unlock_page(old_page);
-                                       goto unwritable_page;
-                               }
-                       } else
-                               VM_BUG_ON_PAGE(!PageLocked(old_page), old_page);
-
                        /*
                         * Since we dropped the lock we need to revalidate
                         * the PTE as someone else may have changed it.  If
@@ -2748,7 +2753,7 @@ reuse:
                 * bit after it clear all dirty ptes, but before a racing
                 * do_wp_page installs a dirty pte.
                 *
-                * __do_fault is protected similarly.
+                * do_shared_fault is protected similarly.
                 */
                if (!page_mkwrite) {
                        wait_on_page_locked(dirty_page);
@@ -2892,10 +2897,6 @@ oom:
        if (old_page)
                page_cache_release(old_page);
        return VM_FAULT_OOM;
-
-unwritable_page:
-       page_cache_release(old_page);
-       return ret;
 }
 
 static void unmap_mapping_range_vma(struct vm_area_struct *vma,
@@ -3286,53 +3287,11 @@ oom:
        return VM_FAULT_OOM;
 }
 
-/*
- * __do_fault() tries to create a new page mapping. It aggressively
- * tries to share with existing pages, but makes a separate copy if
- * the FAULT_FLAG_WRITE is set in the flags parameter in order to avoid
- * the next page fault.
- *
- * As this is called only for pages that do not currently exist, we
- * do not need to flush old virtual caches or the TLB.
- *
- * We enter with non-exclusive mmap_sem (to exclude vma changes,
- * but allow concurrent faults), and pte neither mapped nor locked.
- * We return with mmap_sem still held, but pte unmapped and unlocked.
- */
-static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
-               unsigned long address, pmd_t *pmd,
-               pgoff_t pgoff, unsigned int flags, pte_t orig_pte)
+static int __do_fault(struct vm_area_struct *vma, unsigned long address,
+               pgoff_t pgoff, unsigned int flags, struct page **page)
 {
-       pte_t *page_table;
-       spinlock_t *ptl;
-       struct page *page;
-       struct page *cow_page;
-       pte_t entry;
-       int anon = 0;
-       struct page *dirty_page = NULL;
        struct vm_fault vmf;
        int ret;
-       int page_mkwrite = 0;
-
-       /*
-        * If we do COW later, allocate page befor taking lock_page()
-        * on the file cache page. This will reduce lock holding time.
-        */
-       if ((flags & FAULT_FLAG_WRITE) && !(vma->vm_flags & VM_SHARED)) {
-
-               if (unlikely(anon_vma_prepare(vma)))
-                       return VM_FAULT_OOM;
-
-               cow_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
-               if (!cow_page)
-                       return VM_FAULT_OOM;
-
-               if (mem_cgroup_newpage_charge(cow_page, mm, GFP_KERNEL)) {
-                       page_cache_release(cow_page);
-                       return VM_FAULT_OOM;
-               }
-       } else
-               cow_page = NULL;
 
        vmf.virtual_address = (void __user *)(address & PAGE_MASK);
        vmf.pgoff = pgoff;
@@ -3340,151 +3299,176 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        vmf.page = NULL;
 
        ret = vma->vm_ops->fault(vma, &vmf);
-       if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE |
-                           VM_FAULT_RETRY)))
-               goto uncharge_out;
+       if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))
+               return ret;
 
        if (unlikely(PageHWPoison(vmf.page))) {
                if (ret & VM_FAULT_LOCKED)
                        unlock_page(vmf.page);
-               ret = VM_FAULT_HWPOISON;
                page_cache_release(vmf.page);
-               goto uncharge_out;
+               return VM_FAULT_HWPOISON;
        }
 
-       /*
-        * For consistency in subsequent calls, make the faulted page always
-        * locked.
-        */
        if (unlikely(!(ret & VM_FAULT_LOCKED)))
                lock_page(vmf.page);
        else
                VM_BUG_ON_PAGE(!PageLocked(vmf.page), vmf.page);
 
-       /*
-        * Should we do an early C-O-W break?
-        */
-       page = vmf.page;
-       if (flags & FAULT_FLAG_WRITE) {
-               if (!(vma->vm_flags & VM_SHARED)) {
-                       page = cow_page;
-                       anon = 1;
-                       copy_user_highpage(page, vmf.page, address, vma);
-                       __SetPageUptodate(page);
-               } else {
-                       /*
-                        * If the page will be shareable, see if the backing
-                        * address space wants to know that the page is about
-                        * to become writable
-                        */
-                       if (vma->vm_ops->page_mkwrite) {
-                               int tmp;
-
-                               unlock_page(page);
-                               vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE;
-                               tmp = vma->vm_ops->page_mkwrite(vma, &vmf);
-                               if (unlikely(tmp &
-                                         (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) {
-                                       ret = tmp;
-                                       goto unwritable_page;
-                               }
-                               if (unlikely(!(tmp & VM_FAULT_LOCKED))) {
-                                       lock_page(page);
-                                       if (!page->mapping) {
-                                               ret = 0; /* retry the fault */
-                                               unlock_page(page);
-                                               goto unwritable_page;
-                                       }
-                               } else
-                                       VM_BUG_ON_PAGE(!PageLocked(page), page);
-                               page_mkwrite = 1;
-                       }
-               }
+       *page = vmf.page;
+       return ret;
+}
 
+static void do_set_pte(struct vm_area_struct *vma, unsigned long address,
+               struct page *page, pte_t *pte, bool write, bool anon)
+{
+       pte_t entry;
+
+       flush_icache_page(vma, page);
+       entry = mk_pte(page, vma->vm_page_prot);
+       if (write)
+               entry = maybe_mkwrite(pte_mkdirty(entry), vma);
+       else if (pte_file(*pte) && pte_file_soft_dirty(*pte))
+               pte_mksoft_dirty(entry);
+       if (anon) {
+               inc_mm_counter_fast(vma->vm_mm, MM_ANONPAGES);
+               page_add_new_anon_rmap(page, vma, address);
+       } else {
+               inc_mm_counter_fast(vma->vm_mm, MM_FILEPAGES);
+               page_add_file_rmap(page);
        }
+       set_pte_at(vma->vm_mm, address, pte, entry);
 
-       page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
+       /* no need to invalidate: a not-present page won't be cached */
+       update_mmu_cache(vma, address, pte);
+}
 
-       /*
-        * This silly early PAGE_DIRTY setting removes a race
-        * due to the bad i386 page protection. But it's valid
-        * for other architectures too.
-        *
-        * Note that if FAULT_FLAG_WRITE is set, we either now have
-        * an exclusive copy of the page, or this is a shared mapping,
-        * so we can make it writable and dirty to avoid having to
-        * handle that later.
-        */
-       /* Only go through if we didn't race with anybody else... */
-       if (likely(pte_same(*page_table, orig_pte))) {
-               flush_icache_page(vma, page);
-               entry = mk_pte(page, vma->vm_page_prot);
-               if (flags & FAULT_FLAG_WRITE)
-                       entry = maybe_mkwrite(pte_mkdirty(entry), vma);
-               else if (pte_file(orig_pte) && pte_file_soft_dirty(orig_pte))
-                       pte_mksoft_dirty(entry);
-               if (anon) {
-                       inc_mm_counter_fast(mm, MM_ANONPAGES);
-                       page_add_new_anon_rmap(page, vma, address);
-               } else {
-                       inc_mm_counter_fast(mm, MM_FILEPAGES);
-                       page_add_file_rmap(page);
-                       if (flags & FAULT_FLAG_WRITE) {
-                               dirty_page = page;
-                               get_page(dirty_page);
-                       }
-               }
-               set_pte_at(mm, address, page_table, entry);
+static int do_read_fault(struct mm_struct *mm, struct vm_area_struct *vma,
+               unsigned long address, pmd_t *pmd,
+               pgoff_t pgoff, unsigned int flags, pte_t orig_pte)
+{
+       struct page *fault_page;
+       spinlock_t *ptl;
+       pte_t *pte;
+       int ret;
 
-               /* no need to invalidate: a not-present page won't be cached */
-               update_mmu_cache(vma, address, page_table);
-       } else {
-               if (cow_page)
-                       mem_cgroup_uncharge_page(cow_page);
-               if (anon)
-                       page_cache_release(page);
-               else
-                       anon = 1; /* no anon but release faulted_page */
+       ret = __do_fault(vma, address, pgoff, flags, &fault_page);
+       if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))
+               return ret;
+
+       pte = pte_offset_map_lock(mm, pmd, address, &ptl);
+       if (unlikely(!pte_same(*pte, orig_pte))) {
+               pte_unmap_unlock(pte, ptl);
+               unlock_page(fault_page);
+               page_cache_release(fault_page);
+               return ret;
        }
+       do_set_pte(vma, address, fault_page, pte, false, false);
+       pte_unmap_unlock(pte, ptl);
+       unlock_page(fault_page);
+       return ret;
+}
 
-       pte_unmap_unlock(page_table, ptl);
+static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,
+               unsigned long address, pmd_t *pmd,
+               pgoff_t pgoff, unsigned int flags, pte_t orig_pte)
+{
+       struct page *fault_page, *new_page;
+       spinlock_t *ptl;
+       pte_t *pte;
+       int ret;
 
-       if (dirty_page) {
-               struct address_space *mapping = page->mapping;
-               int dirtied = 0;
+       if (unlikely(anon_vma_prepare(vma)))
+               return VM_FAULT_OOM;
 
-               if (set_page_dirty(dirty_page))
-                       dirtied = 1;
-               unlock_page(dirty_page);
-               put_page(dirty_page);
-               if ((dirtied || page_mkwrite) && mapping) {
-                       /*
-                        * Some device drivers do not set page.mapping but still
-                        * dirty their pages
-                        */
-                       balance_dirty_pages_ratelimited(mapping);
-               }
+       new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
+       if (!new_page)
+               return VM_FAULT_OOM;
 
-               /* file_update_time outside page_lock */
-               if (vma->vm_file && !page_mkwrite)
-                       file_update_time(vma->vm_file);
-       } else {
-               unlock_page(vmf.page);
-               if (anon)
-                       page_cache_release(vmf.page);
+       if (mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL)) {
+               page_cache_release(new_page);
+               return VM_FAULT_OOM;
        }
 
-       return ret;
+       ret = __do_fault(vma, address, pgoff, flags, &fault_page);
+       if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))
+               goto uncharge_out;
 
-unwritable_page:
-       page_cache_release(page);
+       copy_user_highpage(new_page, fault_page, address, vma);
+       __SetPageUptodate(new_page);
+
+       pte = pte_offset_map_lock(mm, pmd, address, &ptl);
+       if (unlikely(!pte_same(*pte, orig_pte))) {
+               pte_unmap_unlock(pte, ptl);
+               unlock_page(fault_page);
+               page_cache_release(fault_page);
+               goto uncharge_out;
+       }
+       do_set_pte(vma, address, new_page, pte, true, true);
+       pte_unmap_unlock(pte, ptl);
+       unlock_page(fault_page);
+       page_cache_release(fault_page);
        return ret;
 uncharge_out:
-       /* fs's fault handler get error */
-       if (cow_page) {
-               mem_cgroup_uncharge_page(cow_page);
-               page_cache_release(cow_page);
+       mem_cgroup_uncharge_page(new_page);
+       page_cache_release(new_page);
+       return ret;
+}
+
+static int do_shared_fault(struct mm_struct *mm, struct vm_area_struct *vma,
+               unsigned long address, pmd_t *pmd,
+               pgoff_t pgoff, unsigned int flags, pte_t orig_pte)
+{
+       struct page *fault_page;
+       struct address_space *mapping;
+       spinlock_t *ptl;
+       pte_t *pte;
+       int dirtied = 0;
+       int ret, tmp;
+
+       ret = __do_fault(vma, address, pgoff, flags, &fault_page);
+       if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))
+               return ret;
+
+       /*
+        * Check if the backing address space wants to know that the page is
+        * about to become writable
+        */
+       if (vma->vm_ops->page_mkwrite) {
+               unlock_page(fault_page);
+               tmp = do_page_mkwrite(vma, fault_page, address);
+               if (unlikely(!tmp ||
+                               (tmp & (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))) {
+                       page_cache_release(fault_page);
+                       return tmp;
+               }
        }
+
+       pte = pte_offset_map_lock(mm, pmd, address, &ptl);
+       if (unlikely(!pte_same(*pte, orig_pte))) {
+               pte_unmap_unlock(pte, ptl);
+               unlock_page(fault_page);
+               page_cache_release(fault_page);
+               return ret;
+       }
+       do_set_pte(vma, address, fault_page, pte, true, false);
+       pte_unmap_unlock(pte, ptl);
+
+       if (set_page_dirty(fault_page))
+               dirtied = 1;
+       mapping = fault_page->mapping;
+       unlock_page(fault_page);
+       if ((dirtied || vma->vm_ops->page_mkwrite) && mapping) {
+               /*
+                * Some device drivers do not set page.mapping but still
+                * dirty their pages
+                */
+               balance_dirty_pages_ratelimited(mapping);
+       }
+
+       /* file_update_time outside page_lock */
+       if (vma->vm_file && !vma->vm_ops->page_mkwrite)
+               file_update_time(vma->vm_file);
+
        return ret;
 }
 
@@ -3496,7 +3480,13 @@ static int do_linear_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                        - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
 
        pte_unmap(page_table);
-       return __do_fault(mm, vma, address, pmd, pgoff, flags, orig_pte);
+       if (!(flags & FAULT_FLAG_WRITE))
+               return do_read_fault(mm, vma, address, pmd, pgoff, flags,
+                               orig_pte);
+       if (!(vma->vm_flags & VM_SHARED))
+               return do_cow_fault(mm, vma, address, pmd, pgoff, flags,
+                               orig_pte);
+       return do_shared_fault(mm, vma, address, pmd, pgoff, flags, orig_pte);
 }
 
 /*
@@ -3528,10 +3518,16 @@ static int do_nonlinear_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        }
 
        pgoff = pte_to_pgoff(orig_pte);
-       return __do_fault(mm, vma, address, pmd, pgoff, flags, orig_pte);
+       if (!(flags & FAULT_FLAG_WRITE))
+               return do_read_fault(mm, vma, address, pmd, pgoff, flags,
+                               orig_pte);
+       if (!(vma->vm_flags & VM_SHARED))
+               return do_cow_fault(mm, vma, address, pmd, pgoff, flags,
+                               orig_pte);
+       return do_shared_fault(mm, vma, address, pmd, pgoff, flags, orig_pte);
 }
 
-int numa_migrate_prep(struct page *page, struct vm_area_struct *vma,
+static int numa_migrate_prep(struct page *page, struct vm_area_struct *vma,
                                unsigned long addr, int page_nid,
                                int *flags)
 {
@@ -3546,7 +3542,7 @@ int numa_migrate_prep(struct page *page, struct vm_area_struct *vma,
        return mpol_misplaced(page, vma, addr);
 }
 
-int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
+static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                   unsigned long addr, pte_t pte, pte_t *ptep, pmd_t *pmd)
 {
        struct page *page = NULL;
index 4755c85..e3ab028 100644 (file)
@@ -1899,7 +1899,7 @@ int node_random(const nodemask_t *maskp)
  * If the effective policy is 'BIND, returns a pointer to the mempolicy's
  * @nodemask for filtering the zonelist.
  *
- * Must be protected by get_mems_allowed()
+ * Must be protected by read_mems_allowed_begin()
  */
 struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr,
                                gfp_t gfp_flags, struct mempolicy **mpol,
@@ -2063,7 +2063,7 @@ alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma,
 
 retry_cpuset:
        pol = get_vma_policy(current, vma, addr);
-       cpuset_mems_cookie = get_mems_allowed();
+       cpuset_mems_cookie = read_mems_allowed_begin();
 
        if (unlikely(pol->mode == MPOL_INTERLEAVE)) {
                unsigned nid;
@@ -2071,7 +2071,7 @@ retry_cpuset:
                nid = interleave_nid(pol, vma, addr, PAGE_SHIFT + order);
                mpol_cond_put(pol);
                page = alloc_page_interleave(gfp, order, nid);
-               if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+               if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
                        goto retry_cpuset;
 
                return page;
@@ -2081,7 +2081,7 @@ retry_cpuset:
                                      policy_nodemask(gfp, pol));
        if (unlikely(mpol_needs_cond_ref(pol)))
                __mpol_put(pol);
-       if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+       if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
                goto retry_cpuset;
        return page;
 }
@@ -2115,7 +2115,7 @@ struct page *alloc_pages_current(gfp_t gfp, unsigned order)
                pol = &default_policy;
 
 retry_cpuset:
-       cpuset_mems_cookie = get_mems_allowed();
+       cpuset_mems_cookie = read_mems_allowed_begin();
 
        /*
         * No reference counting needed for current->mempolicy
@@ -2128,7 +2128,7 @@ retry_cpuset:
                                policy_zonelist(gfp, pol, numa_node_id()),
                                policy_nodemask(gfp, pol));
 
-       if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+       if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
                goto retry_cpuset;
 
        return page;
index 1016233..725c809 100644 (file)
@@ -70,13 +70,21 @@ static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff)
         * any other file mapping (ie. marked !present and faulted in with
         * tmpfs's .fault). So swapped out tmpfs mappings are tested here.
         */
-       page = find_get_page(mapping, pgoff);
 #ifdef CONFIG_SWAP
-       /* shmem/tmpfs may return swap: account for swapcache page too. */
-       if (radix_tree_exceptional_entry(page)) {
-               swp_entry_t swap = radix_to_swp_entry(page);
-               page = find_get_page(swap_address_space(swap), swap.val);
-       }
+       if (shmem_mapping(mapping)) {
+               page = find_get_entry(mapping, pgoff);
+               /*
+                * shmem/tmpfs may return swap: account for swapcache
+                * page too.
+                */
+               if (radix_tree_exceptional_entry(page)) {
+                       swp_entry_t swp = radix_to_swp_entry(page);
+                       page = find_get_page(swap_address_space(swp), swp.val);
+               }
+       } else
+               page = find_get_page(mapping, pgoff);
+#else
+       page = find_get_page(mapping, pgoff);
 #endif
        if (page) {
                present = PageUptodate(page);
index 81ba54f..ac1d667 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -405,7 +405,7 @@ static void validate_mm_rb(struct rb_root *root, struct vm_area_struct *ignore)
        }
 }
 
-void validate_mm(struct mm_struct *mm)
+static void validate_mm(struct mm_struct *mm)
 {
        int bug = 0;
        int i = 0;
index f73f298..04a9d94 100644 (file)
@@ -334,7 +334,7 @@ void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size,
        return ___alloc_bootmem_node_nopanic(pgdat, size, align, goal, 0);
 }
 
-void * __init ___alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
+static void * __init ___alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
                                    unsigned long align, unsigned long goal,
                                    unsigned long limit)
 {
index 3bac76a..979378d 100644 (file)
@@ -2739,7 +2739,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
                return NULL;
 
 retry_cpuset:
-       cpuset_mems_cookie = get_mems_allowed();
+       cpuset_mems_cookie = read_mems_allowed_begin();
 
        /* The preferred zone is used for statistics later */
        first_zones_zonelist(zonelist, high_zoneidx,
@@ -2777,7 +2777,7 @@ out:
         * the mask is being updated. If a page allocation is about to fail,
         * check if the cpuset changed during allocation and if so, retry.
         */
-       if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+       if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
                goto retry_cpuset;
 
        memcg_kmem_commit_charge(page, memcg, order);
@@ -3045,9 +3045,9 @@ bool skip_free_areas_node(unsigned int flags, int nid)
                goto out;
 
        do {
-               cpuset_mems_cookie = get_mems_allowed();
+               cpuset_mems_cookie = read_mems_allowed_begin();
                ret = !node_isset(nid, cpuset_current_mems_allowed);
-       } while (!put_mems_allowed(cpuset_mems_cookie));
+       } while (read_mems_allowed_retry(cpuset_mems_cookie));
 out:
        return ret;
 }
index cfd1628..3708264 100644 (file)
@@ -175,7 +175,7 @@ static void free_page_cgroup(void *addr)
        }
 }
 
-void __free_page_cgroup(unsigned long pfn)
+static void __free_page_cgroup(unsigned long pfn)
 {
        struct mem_section *ms;
        struct page_cgroup *base;
@@ -188,9 +188,9 @@ void __free_page_cgroup(unsigned long pfn)
        ms->page_cgroup = NULL;
 }
 
-int __meminit online_page_cgroup(unsigned long start_pfn,
-                       unsigned long nr_pages,
-                       int nid)
+static int __meminit online_page_cgroup(unsigned long start_pfn,
+                               unsigned long nr_pages,
+                               int nid)
 {
        unsigned long start, end, pfn;
        int fail = 0;
@@ -223,8 +223,8 @@ int __meminit online_page_cgroup(unsigned long start_pfn,
        return -ENOMEM;
 }
 
-int __meminit offline_page_cgroup(unsigned long start_pfn,
-               unsigned long nr_pages, int nid)
+static int __meminit offline_page_cgroup(unsigned long start_pfn,
+                               unsigned long nr_pages, int nid)
 {
        unsigned long start, end, pfn;
 
index 3c5cf68..cb79065 100644 (file)
@@ -412,7 +412,7 @@ SYSCALL_DEFINE6(process_vm_writev, pid_t, pid,
 
 #ifdef CONFIG_COMPAT
 
-asmlinkage ssize_t
+static ssize_t
 compat_process_vm_rw(compat_pid_t pid,
                     const struct compat_iovec __user *lvec,
                     unsigned long liovcnt,
index 0de2360..29c5e1a 100644 (file)
@@ -179,7 +179,7 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
                rcu_read_lock();
                page = radix_tree_lookup(&mapping->page_tree, page_offset);
                rcu_read_unlock();
-               if (page)
+               if (page && !radix_tree_exceptional_entry(page))
                        continue;
 
                page = page_cache_alloc_readahead(mapping);
@@ -233,14 +233,14 @@ int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
        return 0;
 }
 
+#define MAX_READAHEAD   ((512*4096)/PAGE_CACHE_SIZE)
 /*
  * Given a desired number of PAGE_CACHE_SIZE readahead pages, return a
  * sensible upper limit.
  */
 unsigned long max_sane_readahead(unsigned long nr)
 {
-       return min(nr, (node_page_state(numa_node_id(), NR_INACTIVE_FILE)
-               + node_page_state(numa_node_id(), NR_FREE_PAGES)) / 2);
+       return min(nr, MAX_READAHEAD);
 }
 
 /*
@@ -347,7 +347,7 @@ static pgoff_t count_history_pages(struct address_space *mapping,
        pgoff_t head;
 
        rcu_read_lock();
-       head = radix_tree_prev_hole(&mapping->page_tree, offset - 1, max);
+       head = page_cache_prev_hole(mapping, offset - 1, max);
        rcu_read_unlock();
 
        return offset - 1 - head;
@@ -427,7 +427,7 @@ ondemand_readahead(struct address_space *mapping,
                pgoff_t start;
 
                rcu_read_lock();
-               start = radix_tree_next_hole(&mapping->page_tree, offset+1,max);
+               start = page_cache_next_hole(mapping, offset + 1, max);
                rcu_read_unlock();
 
                if (!start || start - offset > max)
index 1f18c9d..a3ba988 100644 (file)
@@ -242,19 +242,17 @@ static int shmem_radix_tree_replace(struct address_space *mapping,
                        pgoff_t index, void *expected, void *replacement)
 {
        void **pslot;
-       void *item = NULL;
+       void *item;
 
        VM_BUG_ON(!expected);
+       VM_BUG_ON(!replacement);
        pslot = radix_tree_lookup_slot(&mapping->page_tree, index);
-       if (pslot)
-               item = radix_tree_deref_slot_protected(pslot,
-                                                       &mapping->tree_lock);
+       if (!pslot)
+               return -ENOENT;
+       item = radix_tree_deref_slot_protected(pslot, &mapping->tree_lock);
        if (item != expected)
                return -ENOENT;
-       if (replacement)
-               radix_tree_replace_slot(pslot, replacement);
-       else
-               radix_tree_delete(&mapping->page_tree, index);
+       radix_tree_replace_slot(pslot, replacement);
        return 0;
 }
 
@@ -330,85 +328,21 @@ static void shmem_delete_from_page_cache(struct page *page, void *radswap)
        BUG_ON(error);
 }
 
-/*
- * Like find_get_pages, but collecting swap entries as well as pages.
- */
-static unsigned shmem_find_get_pages_and_swap(struct address_space *mapping,
-                                       pgoff_t start, unsigned int nr_pages,
-                                       struct page **pages, pgoff_t *indices)
-{
-       void **slot;
-       unsigned int ret = 0;
-       struct radix_tree_iter iter;
-
-       if (!nr_pages)
-               return 0;
-
-       rcu_read_lock();
-restart:
-       radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
-               struct page *page;
-repeat:
-               page = radix_tree_deref_slot(slot);
-               if (unlikely(!page))
-                       continue;
-               if (radix_tree_exception(page)) {
-                       if (radix_tree_deref_retry(page))
-                               goto restart;
-                       /*
-                        * Otherwise, we must be storing a swap entry
-                        * here as an exceptional entry: so return it
-                        * without attempting to raise page count.
-                        */
-                       goto export;
-               }
-               if (!page_cache_get_speculative(page))
-                       goto repeat;
-
-               /* Has the page moved? */
-               if (unlikely(page != *slot)) {
-                       page_cache_release(page);
-                       goto repeat;
-               }
-export:
-               indices[ret] = iter.index;
-               pages[ret] = page;
-               if (++ret == nr_pages)
-                       break;
-       }
-       rcu_read_unlock();
-       return ret;
-}
-
 /*
  * Remove swap entry from radix tree, free the swap and its page cache.
  */
 static int shmem_free_swap(struct address_space *mapping,
                           pgoff_t index, void *radswap)
 {
-       int error;
+       void *old;
 
        spin_lock_irq(&mapping->tree_lock);
-       error = shmem_radix_tree_replace(mapping, index, radswap, NULL);
+       old = radix_tree_delete_item(&mapping->page_tree, index, radswap);
        spin_unlock_irq(&mapping->tree_lock);
-       if (!error)
-               free_swap_and_cache(radix_to_swp_entry(radswap));
-       return error;
-}
-
-/*
- * Pagevec may contain swap entries, so shuffle up pages before releasing.
- */
-static void shmem_deswap_pagevec(struct pagevec *pvec)
-{
-       int i, j;
-
-       for (i = 0, j = 0; i < pagevec_count(pvec); i++) {
-               struct page *page = pvec->pages[i];
-               if (!radix_tree_exceptional_entry(page))
-                       pvec->pages[j++] = page;
-       }
-       pvec->nr = j;
+       if (old != radswap)
+               return -ENOENT;
+       free_swap_and_cache(radix_to_swp_entry(radswap));
+       return 0;
 }
 
 /*
@@ -429,12 +363,12 @@ void shmem_unlock_mapping(struct address_space *mapping)
                 * Avoid pagevec_lookup(): find_get_pages() returns 0 as if it
                 * has finished, if it hits a row of PAGEVEC_SIZE swap entries.
                 */
-               pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
-                                       PAGEVEC_SIZE, pvec.pages, indices);
+               pvec.nr = find_get_entries(mapping, index,
+                                          PAGEVEC_SIZE, pvec.pages, indices);
                if (!pvec.nr)
                        break;
                index = indices[pvec.nr - 1] + 1;
-               shmem_deswap_pagevec(&pvec);
+               pagevec_remove_exceptionals(&pvec);
                check_move_unevictable_pages(pvec.pages, pvec.nr);
                pagevec_release(&pvec);
                cond_resched();
@@ -466,9 +400,9 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
        pagevec_init(&pvec, 0);
        index = start;
        while (index < end) {
-               pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
-                               min(end - index, (pgoff_t)PAGEVEC_SIZE),
-                                                       pvec.pages, indices);
+               pvec.nr = find_get_entries(mapping, index,
+                       min(end - index, (pgoff_t)PAGEVEC_SIZE),
+                       pvec.pages, indices);
                if (!pvec.nr)
                        break;
                mem_cgroup_uncharge_start();
@@ -497,7 +431,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
                        }
                        unlock_page(page);
                }
-               shmem_deswap_pagevec(&pvec);
+               pagevec_remove_exceptionals(&pvec);
                pagevec_release(&pvec);
                mem_cgroup_uncharge_end();
                cond_resched();
@@ -535,9 +469,10 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
        index = start;
        for ( ; ; ) {
                cond_resched();
-               pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
+
+               pvec.nr = find_get_entries(mapping, index,
                                min(end - index, (pgoff_t)PAGEVEC_SIZE),
-                                                       pvec.pages, indices);
+                               pvec.pages, indices);
                if (!pvec.nr) {
                        if (index == start || unfalloc)
                                break;
@@ -545,7 +480,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
                        continue;
                }
                if ((index == start || unfalloc) && indices[0] >= end) {
-                       shmem_deswap_pagevec(&pvec);
+                       pagevec_remove_exceptionals(&pvec);
                        pagevec_release(&pvec);
                        break;
                }
@@ -574,7 +509,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
                        }
                        unlock_page(page);
                }
-               shmem_deswap_pagevec(&pvec);
+               pagevec_remove_exceptionals(&pvec);
                pagevec_release(&pvec);
                mem_cgroup_uncharge_end();
                index++;
@@ -1080,7 +1015,7 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
                return -EFBIG;
 repeat:
        swap.val = 0;
-       page = find_lock_page(mapping, index);
+       page = find_lock_entry(mapping, index);
        if (radix_tree_exceptional_entry(page)) {
                swap = radix_to_swp_entry(page);
                page = NULL;
@@ -1417,6 +1352,11 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
        return inode;
 }
 
+bool shmem_mapping(struct address_space *mapping)
+{
+       return mapping->backing_dev_info == &shmem_backing_dev_info;
+}
+
 #ifdef CONFIG_TMPFS
 static const struct inode_operations shmem_symlink_inode_operations;
 static const struct inode_operations shmem_short_symlink_operations;
@@ -1729,7 +1669,7 @@ static pgoff_t shmem_seek_hole_data(struct address_space *mapping,
        pagevec_init(&pvec, 0);
        pvec.nr = 1;            /* start small: we may be there already */
        while (!done) {
-               pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
+               pvec.nr = find_get_entries(mapping, index,
                                        pvec.nr, pvec.pages, indices);
                if (!pvec.nr) {
                        if (whence == SEEK_DATA)
@@ -1756,7 +1696,7 @@ static pgoff_t shmem_seek_hole_data(struct address_space *mapping,
                                break;
                        }
                }
-               shmem_deswap_pagevec(&pvec);
+               pagevec_remove_exceptionals(&pvec);
                pagevec_release(&pvec);
                pvec.nr = PAGEVEC_SIZE;
                cond_resched();
index b264214..9153c80 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3073,7 +3073,7 @@ static void *fallback_alloc(struct kmem_cache *cache, gfp_t flags)
        local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK);
 
 retry_cpuset:
-       cpuset_mems_cookie = get_mems_allowed();
+       cpuset_mems_cookie = read_mems_allowed_begin();
        zonelist = node_zonelist(slab_node(), flags);
 
 retry:
@@ -3131,7 +3131,7 @@ retry:
                }
        }
 
-       if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !obj))
+       if (unlikely(!obj && read_mems_allowed_retry(cpuset_mems_cookie)))
                goto retry_cpuset;
        return obj;
 }
index 25f14ad..fe6d7be 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1684,7 +1684,7 @@ static void *get_any_partial(struct kmem_cache *s, gfp_t flags,
                return NULL;
 
        do {
-               cpuset_mems_cookie = get_mems_allowed();
+               cpuset_mems_cookie = read_mems_allowed_begin();
                zonelist = node_zonelist(slab_node(), flags);
                for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
                        struct kmem_cache_node *n;
@@ -1696,19 +1696,17 @@ static void *get_any_partial(struct kmem_cache *s, gfp_t flags,
                                object = get_partial_node(s, n, c, flags);
                                if (object) {
                                        /*
-                                        * Return the object even if
-                                        * put_mems_allowed indicated that
-                                        * the cpuset mems_allowed was
-                                        * updated in parallel. It's a
-                                        * harmless race between the alloc
-                                        * and the cpuset update.
+                                        * Don't check read_mems_allowed_retry()
+                                        * here - if mems_allowed was updated in
+                                        * parallel, that was a harmless race
+                                        * between allocation and the cpuset
+                                        * update
                                         */
-                                       put_mems_allowed(cpuset_mems_cookie);
                                        return object;
                                }
                        }
                }
-       } while (!put_mems_allowed(cpuset_mems_cookie));
+       } while (read_mems_allowed_retry(cpuset_mems_cookie));
 #endif
        return NULL;
 }
@@ -3239,8 +3237,9 @@ int __kmem_cache_shutdown(struct kmem_cache *s)
 
        if (!rc) {
                /*
-                * We do the same lock strategy around sysfs_slab_add, see
-                * __kmem_cache_create. Because this is pretty much the last
+                * Since slab_attr_store may take the slab_mutex, we should
+                * release the lock while removing the sysfs entry in order to
+                * avoid a deadlock. Because this is pretty much the last
                 * operation we do and the lock will be released shortly after
                 * that in slab_common.c, we could just move sysfs_slab_remove
                 * to a later point in common code. We should do that when we
@@ -3780,10 +3779,7 @@ int __kmem_cache_create(struct kmem_cache *s, unsigned long flags)
                return 0;
 
        memcg_propagate_slab_attrs(s);
-       mutex_unlock(&slab_mutex);
        err = sysfs_slab_add(s);
-       mutex_lock(&slab_mutex);
-
        if (err)
                kmem_cache_close(s);
 
index 0092097..9ce43ba 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -574,6 +574,8 @@ void mark_page_accessed(struct page *page)
                else
                        __lru_cache_activate_page(page);
                ClearPageReferenced(page);
+               if (page_is_file_cache(page))
+                       workingset_activation(page);
        } else if (!PageReferenced(page)) {
                SetPageReferenced(page);
        }
@@ -947,6 +949,57 @@ void __pagevec_lru_add(struct pagevec *pvec)
 }
 EXPORT_SYMBOL(__pagevec_lru_add);
 
+/**
+ * pagevec_lookup_entries - gang pagecache lookup
+ * @pvec:      Where the resulting entries are placed
+ * @mapping:   The address_space to search
+ * @start:     The starting entry index
+ * @nr_entries:        The maximum number of entries
+ * @indices:   The cache indices corresponding to the entries in @pvec
+ *
+ * pagevec_lookup_entries() will search for and return a group of up
+ * to @nr_entries pages and shadow entries in the mapping.  All
+ * entries are placed in @pvec.  pagevec_lookup_entries() takes a
+ * reference against actual pages in @pvec.
+ *
+ * The search returns a group of mapping-contiguous entries with
+ * ascending indexes.  There may be holes in the indices due to
+ * not-present entries.
+ *
+ * pagevec_lookup_entries() returns the number of entries which were
+ * found.
+ */
+unsigned pagevec_lookup_entries(struct pagevec *pvec,
+                               struct address_space *mapping,
+                               pgoff_t start, unsigned nr_pages,
+                               pgoff_t *indices)
+{
+       pvec->nr = find_get_entries(mapping, start, nr_pages,
+                                   pvec->pages, indices);
+       return pagevec_count(pvec);
+}
+
+/**
+ * pagevec_remove_exceptionals - pagevec exceptionals pruning
+ * @pvec:      The pagevec to prune
+ *
+ * pagevec_lookup_entries() fills both pages and exceptional radix
+ * tree entries into the pagevec.  This function prunes all
+ * exceptionals from @pvec without leaving holes, so that it can be
+ * passed on to page-only pagevec operations.
+ */
+void pagevec_remove_exceptionals(struct pagevec *pvec)
+{
+       int i, j;
+
+       for (i = 0, j = 0; i < pagevec_count(pvec); i++) {
+               struct page *page = pvec->pages[i];
+               if (!radix_tree_exceptional_entry(page))
+                       pvec->pages[j++] = page;
+       }
+       pvec->nr = j;
+}
+
 /**
  * pagevec_lookup - gang pagecache lookup
  * @pvec:      Where the resulting pages are placed
index 353b683..e5cc39a 100644 (file)
 #include <linux/cleancache.h>
 #include "internal.h"
 
+static void clear_exceptional_entry(struct address_space *mapping,
+                                   pgoff_t index, void *entry)
+{
+       struct radix_tree_node *node;
+       void **slot;
+
+       /* Handled by shmem itself */
+       if (shmem_mapping(mapping))
+               return;
+
+       spin_lock_irq(&mapping->tree_lock);
+       /*
+        * Regular page slots are stabilized by the page lock even
+        * without the tree itself locked.  These unlocked entries
+        * need verification under the tree lock.
+        */
+       if (!__radix_tree_lookup(&mapping->page_tree, index, &node, &slot))
+               goto unlock;
+       if (*slot != entry)
+               goto unlock;
+       radix_tree_replace_slot(slot, NULL);
+       mapping->nrshadows--;
+       if (!node)
+               goto unlock;
+       workingset_node_shadows_dec(node);
+       /*
+        * Don't track node without shadow entries.
+        *
+        * Avoid acquiring the list_lru lock if already untracked.
+        * The list_empty() test is safe as node->private_list is
+        * protected by mapping->tree_lock.
+        */
+       if (!workingset_node_shadows(node) &&
+           !list_empty(&node->private_list))
+               list_lru_del(&workingset_shadow_nodes, &node->private_list);
+       __radix_tree_delete_node(&mapping->page_tree, node);
+unlock:
+       spin_unlock_irq(&mapping->tree_lock);
+}
 
 /**
  * do_invalidatepage - invalidate part or all of a page
@@ -208,11 +247,12 @@ void truncate_inode_pages_range(struct address_space *mapping,
        unsigned int    partial_start;  /* inclusive */
        unsigned int    partial_end;    /* exclusive */
        struct pagevec  pvec;
+       pgoff_t         indices[PAGEVEC_SIZE];
        pgoff_t         index;
        int             i;
 
        cleancache_invalidate_inode(mapping);
-       if (mapping->nrpages == 0)
+       if (mapping->nrpages == 0 && mapping->nrshadows == 0)
                return;
 
        /* Offsets within partial pages */
@@ -238,17 +278,23 @@ void truncate_inode_pages_range(struct address_space *mapping,
 
        pagevec_init(&pvec, 0);
        index = start;
-       while (index < end && pagevec_lookup(&pvec, mapping, index,
-                       min(end - index, (pgoff_t)PAGEVEC_SIZE))) {
+       while (index < end && pagevec_lookup_entries(&pvec, mapping, index,
+                       min(end - index, (pgoff_t)PAGEVEC_SIZE),
+                       indices)) {
                mem_cgroup_uncharge_start();
                for (i = 0; i < pagevec_count(&pvec); i++) {
                        struct page *page = pvec.pages[i];
 
                        /* We rely upon deletion not changing page->index */
-                       index = page->index;
+                       index = indices[i];
                        if (index >= end)
                                break;
 
+                       if (radix_tree_exceptional_entry(page)) {
+                               clear_exceptional_entry(mapping, index, page);
+                               continue;
+                       }
+
                        if (!trylock_page(page))
                                continue;
                        WARN_ON(page->index != index);
@@ -259,6 +305,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
                        truncate_inode_page(mapping, page);
                        unlock_page(page);
                }
+               pagevec_remove_exceptionals(&pvec);
                pagevec_release(&pvec);
                mem_cgroup_uncharge_end();
                cond_resched();
@@ -307,14 +354,16 @@ void truncate_inode_pages_range(struct address_space *mapping,
        index = start;
        for ( ; ; ) {
                cond_resched();
-               if (!pagevec_lookup(&pvec, mapping, index,
-                       min(end - index, (pgoff_t)PAGEVEC_SIZE))) {
+               if (!pagevec_lookup_entries(&pvec, mapping, index,
+                       min(end - index, (pgoff_t)PAGEVEC_SIZE),
+                       indices)) {
                        if (index == start)
                                break;
                        index = start;
                        continue;
                }
-               if (index == start && pvec.pages[0]->index >= end) {
+               if (index == start && indices[0] >= end) {
+                       pagevec_remove_exceptionals(&pvec);
                        pagevec_release(&pvec);
                        break;
                }
@@ -323,16 +372,22 @@ void truncate_inode_pages_range(struct address_space *mapping,
                        struct page *page = pvec.pages[i];
 
                        /* We rely upon deletion not changing page->index */
-                       index = page->index;
+                       index = indices[i];
                        if (index >= end)
                                break;
 
+                       if (radix_tree_exceptional_entry(page)) {
+                               clear_exceptional_entry(mapping, index, page);
+                               continue;
+                       }
+
                        lock_page(page);
                        WARN_ON(page->index != index);
                        wait_on_page_writeback(page);
                        truncate_inode_page(mapping, page);
                        unlock_page(page);
                }
+               pagevec_remove_exceptionals(&pvec);
                pagevec_release(&pvec);
                mem_cgroup_uncharge_end();
                index++;
@@ -359,6 +414,53 @@ void truncate_inode_pages(struct address_space *mapping, loff_t lstart)
 }
 EXPORT_SYMBOL(truncate_inode_pages);
 
+/**
+ * truncate_inode_pages_final - truncate *all* pages before inode dies
+ * @mapping: mapping to truncate
+ *
+ * Called under (and serialized by) inode->i_mutex.
+ *
+ * Filesystems have to use this in the .evict_inode path to inform the
+ * VM that this is the final truncate and the inode is going away.
+ */
+void truncate_inode_pages_final(struct address_space *mapping)
+{
+       unsigned long nrshadows;
+       unsigned long nrpages;
+
+       /*
+        * Page reclaim can not participate in regular inode lifetime
+        * management (can't call iput()) and thus can race with the
+        * inode teardown.  Tell it when the address space is exiting,
+        * so that it does not install eviction information after the
+        * final truncate has begun.
+        */
+       mapping_set_exiting(mapping);
+
+       /*
+        * When reclaim installs eviction entries, it increases
+        * nrshadows first, then decreases nrpages.  Make sure we see
+        * this in the right order or we might miss an entry.
+        */
+       nrpages = mapping->nrpages;
+       smp_rmb();
+       nrshadows = mapping->nrshadows;
+
+       if (nrpages || nrshadows) {
+               /*
+                * As truncation uses a lockless tree lookup, cycle
+                * the tree lock to make sure any ongoing tree
+                * modification that does not see AS_EXITING is
+                * completed before starting the final truncate.
+                */
+               spin_lock_irq(&mapping->tree_lock);
+               spin_unlock_irq(&mapping->tree_lock);
+
+               truncate_inode_pages(mapping, 0);
+       }
+}
+EXPORT_SYMBOL(truncate_inode_pages_final);
+
 /**
  * invalidate_mapping_pages - Invalidate all the unlocked pages of one inode
  * @mapping: the address_space which holds the pages to invalidate
@@ -375,6 +477,7 @@ EXPORT_SYMBOL(truncate_inode_pages);
 unsigned long invalidate_mapping_pages(struct address_space *mapping,
                pgoff_t start, pgoff_t end)
 {
+       pgoff_t indices[PAGEVEC_SIZE];
        struct pagevec pvec;
        pgoff_t index = start;
        unsigned long ret;
@@ -390,17 +493,23 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
         */
 
        pagevec_init(&pvec, 0);
-       while (index <= end && pagevec_lookup(&pvec, mapping, index,
-                       min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) {
+       while (index <= end && pagevec_lookup_entries(&pvec, mapping, index,
+                       min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1,
+                       indices)) {
                mem_cgroup_uncharge_start();
                for (i = 0; i < pagevec_count(&pvec); i++) {
                        struct page *page = pvec.pages[i];
 
                        /* We rely upon deletion not changing page->index */
-                       index = page->index;
+                       index = indices[i];
                        if (index > end)
                                break;
 
+                       if (radix_tree_exceptional_entry(page)) {
+                               clear_exceptional_entry(mapping, index, page);
+                               continue;
+                       }
+
                        if (!trylock_page(page))
                                continue;
                        WARN_ON(page->index != index);
@@ -414,6 +523,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
                                deactivate_page(page);
                        count += ret;
                }
+               pagevec_remove_exceptionals(&pvec);
                pagevec_release(&pvec);
                mem_cgroup_uncharge_end();
                cond_resched();
@@ -444,7 +554,7 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page)
                goto failed;
 
        BUG_ON(page_has_private(page));
-       __delete_from_page_cache(page);
+       __delete_from_page_cache(page, NULL);
        spin_unlock_irq(&mapping->tree_lock);
        mem_cgroup_uncharge_cache_page(page);
 
@@ -481,6 +591,7 @@ static int do_launder_page(struct address_space *mapping, struct page *page)
 int invalidate_inode_pages2_range(struct address_space *mapping,
                                  pgoff_t start, pgoff_t end)
 {
+       pgoff_t indices[PAGEVEC_SIZE];
        struct pagevec pvec;
        pgoff_t index;
        int i;
@@ -491,17 +602,23 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
        cleancache_invalidate_inode(mapping);
        pagevec_init(&pvec, 0);
        index = start;
-       while (index <= end && pagevec_lookup(&pvec, mapping, index,
-                       min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1)) {
+       while (index <= end && pagevec_lookup_entries(&pvec, mapping, index,
+                       min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1,
+                       indices)) {
                mem_cgroup_uncharge_start();
                for (i = 0; i < pagevec_count(&pvec); i++) {
                        struct page *page = pvec.pages[i];
 
                        /* We rely upon deletion not changing page->index */
-                       index = page->index;
+                       index = indices[i];
                        if (index > end)
                                break;
 
+                       if (radix_tree_exceptional_entry(page)) {
+                               clear_exceptional_entry(mapping, index, page);
+                               continue;
+                       }
+
                        lock_page(page);
                        WARN_ON(page->index != index);
                        if (page->mapping != mapping) {
@@ -539,6 +656,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
                                ret = ret2;
                        unlock_page(page);
                }
+               pagevec_remove_exceptionals(&pvec);
                pagevec_release(&pvec);
                mem_cgroup_uncharge_end();
                cond_resched();
index a9c74b4..1f56a80 100644 (file)
@@ -224,15 +224,15 @@ shrink_slab_node(struct shrink_control *shrinkctl, struct shrinker *shrinker,
        unsigned long freed = 0;
        unsigned long long delta;
        long total_scan;
-       long max_pass;
+       long freeable;
        long nr;
        long new_nr;
        int nid = shrinkctl->nid;
        long batch_size = shrinker->batch ? shrinker->batch
                                          : SHRINK_BATCH;
 
-       max_pass = shrinker->count_objects(shrinker, shrinkctl);
-       if (max_pass == 0)
+       freeable = shrinker->count_objects(shrinker, shrinkctl);
+       if (freeable == 0)
                return 0;
 
        /*
@@ -244,14 +244,14 @@ shrink_slab_node(struct shrink_control *shrinkctl, struct shrinker *shrinker,
 
        total_scan = nr;
        delta = (4 * nr_pages_scanned) / shrinker->seeks;
-       delta *= max_pass;
+       delta *= freeable;
        do_div(delta, lru_pages + 1);
        total_scan += delta;
        if (total_scan < 0) {
                printk(KERN_ERR
                "shrink_slab: %pF negative objects to delete nr=%ld\n",
                       shrinker->scan_objects, total_scan);
-               total_scan = max_pass;
+               total_scan = freeable;
        }
 
        /*
@@ -260,26 +260,26 @@ shrink_slab_node(struct shrink_control *shrinkctl, struct shrinker *shrinker,
         * shrinkers to return -1 all the time. This results in a large
         * nr being built up so when a shrink that can do some work
         * comes along it empties the entire cache due to nr >>>
-        * max_pass.  This is bad for sustaining a working set in
+        * freeable. This is bad for sustaining a working set in
         * memory.
         *
         * Hence only allow the shrinker to scan the entire cache when
         * a large delta change is calculated directly.
         */
-       if (delta < max_pass / 4)
-               total_scan = min(total_scan, max_pass / 2);
+       if (delta < freeable / 4)
+               total_scan = min(total_scan, freeable / 2);
 
        /*
         * Avoid risking looping forever due to too large nr value:
         * never try to free more than twice the estimate number of
         * freeable entries.
         */
-       if (total_scan > max_pass * 2)
-               total_scan = max_pass * 2;
+       if (total_scan > freeable * 2)
+               total_scan = freeable * 2;
 
        trace_mm_shrink_slab_start(shrinker, shrinkctl, nr,
                                nr_pages_scanned, lru_pages,
-                               max_pass, delta, total_scan);
+                               freeable, delta, total_scan);
 
        /*
         * Normally, we should not scan less than batch_size objects in one
@@ -292,12 +292,12 @@ shrink_slab_node(struct shrink_control *shrinkctl, struct shrinker *shrinker,
         *
         * We detect the "tight on memory" situations by looking at the total
         * number of objects we want to scan (total_scan). If it is greater
-        * than the total number of objects on slab (max_pass), we must be
+        * than the total number of objects on slab (freeable), we must be
         * scanning at high prio and therefore should try to reclaim as much as
         * possible.
         */
        while (total_scan >= batch_size ||
-              total_scan >= max_pass) {
+              total_scan >= freeable) {
                unsigned long ret;
                unsigned long nr_to_scan = min(batch_size, total_scan);
 
@@ -523,7 +523,8 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
  * Same as remove_mapping, but if the page is removed from the mapping, it
  * gets returned with a refcount of 0.
  */
-static int __remove_mapping(struct address_space *mapping, struct page *page)
+static int __remove_mapping(struct address_space *mapping, struct page *page,
+                           bool reclaimed)
 {
        BUG_ON(!PageLocked(page));
        BUG_ON(mapping != page_mapping(page));
@@ -569,10 +570,23 @@ static int __remove_mapping(struct address_space *mapping, struct page *page)
                swapcache_free(swap, page);
        } else {
                void (*freepage)(struct page *);
+               void *shadow = NULL;
 
                freepage = mapping->a_ops->freepage;
-
-               __delete_from_page_cache(page);
+               /*
+                * Remember a shadow entry for reclaimed file cache in
+                * order to detect refaults, thus thrashing, later on.
+                *
+                * But don't store shadows in an address space that is
+                * already exiting.  This is not just an optizimation,
+                * inode reclaim needs to empty out the radix tree or
+                * the nodes are lost.  Don't plant shadows behind its
+                * back.
+                */
+               if (reclaimed && page_is_file_cache(page) &&
+                   !mapping_exiting(mapping))
+                       shadow = workingset_eviction(mapping, page);
+               __delete_from_page_cache(page, shadow);
                spin_unlock_irq(&mapping->tree_lock);
                mem_cgroup_uncharge_cache_page(page);
 
@@ -595,7 +609,7 @@ cannot_free:
  */
 int remove_mapping(struct address_space *mapping, struct page *page)
 {
-       if (__remove_mapping(mapping, page)) {
+       if (__remove_mapping(mapping, page, false)) {
                /*
                 * Unfreezing the refcount with 1 rather than 2 effectively
                 * drops the pagecache ref for us without requiring another
@@ -1065,7 +1079,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        }
                }
 
-               if (!mapping || !__remove_mapping(mapping, page))
+               if (!mapping || !__remove_mapping(mapping, page, true))
                        goto keep_locked;
 
                /*
@@ -2297,7 +2311,12 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
        struct zone *zone;
        unsigned long nr_soft_reclaimed;
        unsigned long nr_soft_scanned;
+       unsigned long lru_pages = 0;
        bool aborted_reclaim = false;
+       struct reclaim_state *reclaim_state = current->reclaim_state;
+       struct shrink_control shrink = {
+               .gfp_mask = sc->gfp_mask,
+       };
 
        /*
         * If the number of buffer_heads in the machine exceeds the maximum
@@ -2307,6 +2326,8 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
        if (buffer_heads_over_limit)
                sc->gfp_mask |= __GFP_HIGHMEM;
 
+       nodes_clear(shrink.nodes_to_scan);
+
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
                                        gfp_zone(sc->gfp_mask), sc->nodemask) {
                if (!populated_zone(zone))
@@ -2318,6 +2339,10 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                if (global_reclaim(sc)) {
                        if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
                                continue;
+
+                       lru_pages += zone_reclaimable_pages(zone);
+                       node_set(zone_to_nid(zone), shrink.nodes_to_scan);
+
                        if (sc->priority != DEF_PRIORITY &&
                            !zone_reclaimable(zone))
                                continue;       /* Let kswapd poll it */
@@ -2354,6 +2379,20 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                shrink_zone(zone, sc);
        }
 
+       /*
+        * Don't shrink slabs when reclaiming memory from over limit cgroups
+        * but do shrink slab at least once when aborting reclaim for
+        * compaction to avoid unevenly scanning file/anon LRU pages over slab
+        * pages.
+        */
+       if (global_reclaim(sc)) {
+               shrink_slab(&shrink, sc->nr_scanned, lru_pages);
+               if (reclaim_state) {
+                       sc->nr_reclaimed += reclaim_state->reclaimed_slab;
+                       reclaim_state->reclaimed_slab = 0;
+               }
+       }
+
        return aborted_reclaim;
 }
 
@@ -2394,13 +2433,9 @@ static bool all_unreclaimable(struct zonelist *zonelist,
  *             else, the number of pages reclaimed
  */
 static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
-                                       struct scan_control *sc,
-                                       struct shrink_control *shrink)
+                                         struct scan_control *sc)
 {
        unsigned long total_scanned = 0;
-       struct reclaim_state *reclaim_state = current->reclaim_state;
-       struct zoneref *z;
-       struct zone *zone;
        unsigned long writeback_threshold;
        bool aborted_reclaim;
 
@@ -2415,32 +2450,6 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                sc->nr_scanned = 0;
                aborted_reclaim = shrink_zones(zonelist, sc);
 
-               /*
-                * Don't shrink slabs when reclaiming memory from over limit
-                * cgroups but do shrink slab at least once when aborting
-                * reclaim for compaction to avoid unevenly scanning file/anon
-                * LRU pages over slab pages.
-                */
-               if (global_reclaim(sc)) {
-                       unsigned long lru_pages = 0;
-
-                       nodes_clear(shrink->nodes_to_scan);
-                       for_each_zone_zonelist(zone, z, zonelist,
-                                       gfp_zone(sc->gfp_mask)) {
-                               if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
-                                       continue;
-
-                               lru_pages += zone_reclaimable_pages(zone);
-                               node_set(zone_to_nid(zone),
-                                        shrink->nodes_to_scan);
-                       }
-
-                       shrink_slab(shrink, sc->nr_scanned, lru_pages);
-                       if (reclaim_state) {
-                               sc->nr_reclaimed += reclaim_state->reclaimed_slab;
-                               reclaim_state->reclaimed_slab = 0;
-                       }
-               }
                total_scanned += sc->nr_scanned;
                if (sc->nr_reclaimed >= sc->nr_to_reclaim)
                        goto out;
@@ -2602,9 +2611,6 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
                .target_mem_cgroup = NULL,
                .nodemask = nodemask,
        };
-       struct shrink_control shrink = {
-               .gfp_mask = sc.gfp_mask,
-       };
 
        /*
         * Do not enter reclaim if fatal signal was delivered while throttled.
@@ -2618,7 +2624,7 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
                                sc.may_writepage,
                                gfp_mask);
 
-       nr_reclaimed = do_try_to_free_pages(zonelist, &sc, &shrink);
+       nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
 
        trace_mm_vmscan_direct_reclaim_end(nr_reclaimed);
 
@@ -2685,9 +2691,6 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                .gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
                                (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK),
        };
-       struct shrink_control shrink = {
-               .gfp_mask = sc.gfp_mask,
-       };
 
        /*
         * Unlike direct reclaim via alloc_pages(), memcg's reclaim doesn't
@@ -2702,7 +2705,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                                            sc.may_writepage,
                                            sc.gfp_mask);
 
-       nr_reclaimed = do_try_to_free_pages(zonelist, &sc, &shrink);
+       nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
 
        trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed);
 
@@ -3337,9 +3340,6 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim)
                .order = 0,
                .priority = DEF_PRIORITY,
        };
-       struct shrink_control shrink = {
-               .gfp_mask = sc.gfp_mask,
-       };
        struct zonelist *zonelist = node_zonelist(numa_node_id(), sc.gfp_mask);
        struct task_struct *p = current;
        unsigned long nr_reclaimed;
@@ -3349,7 +3349,7 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim)
        reclaim_state.reclaimed_slab = 0;
        p->reclaim_state = &reclaim_state;
 
-       nr_reclaimed = do_try_to_free_pages(zonelist, &sc, &shrink);
+       nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
 
        p->reclaim_state = NULL;
        lockdep_clear_current_reclaim_state();
index def5dd2..197b4c4 100644 (file)
@@ -770,6 +770,9 @@ const char * const vmstat_text[] = {
        "numa_local",
        "numa_other",
 #endif
+       "workingset_refault",
+       "workingset_activate",
+       "workingset_nodereclaim",
        "nr_anon_transparent_hugepages",
        "nr_free_cma",
        "nr_dirty_threshold",
@@ -810,6 +813,9 @@ const char * const vmstat_text[] = {
 
        "pgrotated",
 
+       "drop_pagecache",
+       "drop_slab",
+
 #ifdef CONFIG_NUMA_BALANCING
        "numa_pte_updates",
        "numa_huge_pte_updates",
diff --git a/mm/workingset.c b/mm/workingset.c
new file mode 100644 (file)
index 0000000..f7216fa
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Workingset detection
+ *
+ * Copyright (C) 2013 Red Hat, Inc., Johannes Weiner
+ */
+
+#include <linux/memcontrol.h>
+#include <linux/writeback.h>
+#include <linux/pagemap.h>
+#include <linux/atomic.h>
+#include <linux/module.h>
+#include <linux/swap.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+
+/*
+ *             Double CLOCK lists
+ *
+ * Per zone, two clock lists are maintained for file pages: the
+ * inactive and the active list.  Freshly faulted pages start out at
+ * the head of the inactive list and page reclaim scans pages from the
+ * tail.  Pages that are accessed multiple times on the inactive list
+ * are promoted to the active list, to protect them from reclaim,
+ * whereas active pages are demoted to the inactive list when the
+ * active list grows too big.
+ *
+ *   fault ------------------------+
+ *                                 |
+ *              +--------------+   |            +-------------+
+ *   reclaim <- |   inactive   | <-+-- demotion |    active   | <--+
+ *              +--------------+                +-------------+    |
+ *                     |                                           |
+ *                     +-------------- promotion ------------------+
+ *
+ *
+ *             Access frequency and refault distance
+ *
+ * A workload is thrashing when its pages are frequently used but they
+ * are evicted from the inactive list every time before another access
+ * would have promoted them to the active list.
+ *
+ * In cases where the average access distance between thrashing pages
+ * is bigger than the size of memory there is nothing that can be
+ * done - the thrashing set could never fit into memory under any
+ * circumstance.
+ *
+ * However, the average access distance could be bigger than the
+ * inactive list, yet smaller than the size of memory.  In this case,
+ * the set could fit into memory if it weren't for the currently
+ * active pages - which may be used more, hopefully less frequently:
+ *
+ *      +-memory available to cache-+
+ *      |                           |
+ *      +-inactive------+-active----+
+ *  a b | c d e f g h i | J K L M N |
+ *      +---------------+-----------+
+ *
+ * It is prohibitively expensive to accurately track access frequency
+ * of pages.  But a reasonable approximation can be made to measure
+ * thrashing on the inactive list, after which refaulting pages can be
+ * activated optimistically to compete with the existing active pages.
+ *
+ * Approximating inactive page access frequency - Observations:
+ *
+ * 1. When a page is accessed for the first time, it is added to the
+ *    head of the inactive list, slides every existing inactive page
+ *    towards the tail by one slot, and pushes the current tail page
+ *    out of memory.
+ *
+ * 2. When a page is accessed for the second time, it is promoted to
+ *    the active list, shrinking the inactive list by one slot.  This
+ *    also slides all inactive pages that were faulted into the cache
+ *    more recently than the activated page towards the tail of the
+ *    inactive list.
+ *
+ * Thus:
+ *
+ * 1. The sum of evictions and activations between any two points in
+ *    time indicate the minimum number of inactive pages accessed in
+ *    between.
+ *
+ * 2. Moving one inactive page N page slots towards the tail of the
+ *    list requires at least N inactive page accesses.
+ *
+ * Combining these:
+ *
+ * 1. When a page is finally evicted from memory, the number of
+ *    inactive pages accessed while the page was in cache is at least
+ *    the number of page slots on the inactive list.
+ *
+ * 2. In addition, measuring the sum of evictions and activations (E)
+ *    at the time of a page's eviction, and comparing it to another
+ *    reading (R) at the time the page faults back into memory tells
+ *    the minimum number of accesses while the page was not cached.
+ *    This is called the refault distance.
+ *
+ * Because the first access of the page was the fault and the second
+ * access the refault, we combine the in-cache distance with the
+ * out-of-cache distance to get the complete minimum access distance
+ * of this page:
+ *
+ *      NR_inactive + (R - E)
+ *
+ * And knowing the minimum access distance of a page, we can easily
+ * tell if the page would be able to stay in cache assuming all page
+ * slots in the cache were available:
+ *
+ *   NR_inactive + (R - E) <= NR_inactive + NR_active
+ *
+ * which can be further simplified to
+ *
+ *   (R - E) <= NR_active
+ *
+ * Put into words, the refault distance (out-of-cache) can be seen as
+ * a deficit in inactive list space (in-cache).  If the inactive list
+ * had (R - E) more page slots, the page would not have been evicted
+ * in between accesses, but activated instead.  And on a full system,
+ * the only thing eating into inactive list space is active pages.
+ *
+ *
+ *             Activating refaulting pages
+ *
+ * All that is known about the active list is that the pages have been
+ * accessed more than once in the past.  This means that at any given
+ * time there is actually a good chance that pages on the active list
+ * are no longer in active use.
+ *
+ * So when a refault distance of (R - E) is observed and there are at
+ * least (R - E) active pages, the refaulting page is activated
+ * optimistically in the hope that (R - E) active pages are actually
+ * used less frequently than the refaulting page - or even not used at
+ * all anymore.
+ *
+ * If this is wrong and demotion kicks in, the pages which are truly
+ * used more frequently will be reactivated while the less frequently
+ * used once will be evicted from memory.
+ *
+ * But if this is right, the stale pages will be pushed out of memory
+ * and the used pages get to stay in cache.
+ *
+ *
+ *             Implementation
+ *
+ * For each zone's file LRU lists, a counter for inactive evictions
+ * and activations is maintained (zone->inactive_age).
+ *
+ * On eviction, a snapshot of this counter (along with some bits to
+ * identify the zone) is stored in the now empty page cache radix tree
+ * slot of the evicted page.  This is called a shadow entry.
+ *
+ * On cache misses for which there are shadow entries, an eligible
+ * refault distance will immediately activate the refaulting page.
+ */
+
+static void *pack_shadow(unsigned long eviction, struct zone *zone)
+{
+       eviction = (eviction << NODES_SHIFT) | zone_to_nid(zone);
+       eviction = (eviction << ZONES_SHIFT) | zone_idx(zone);
+       eviction = (eviction << RADIX_TREE_EXCEPTIONAL_SHIFT);
+
+       return (void *)(eviction | RADIX_TREE_EXCEPTIONAL_ENTRY);
+}
+
+static void unpack_shadow(void *shadow,
+                         struct zone **zone,
+                         unsigned long *distance)
+{
+       unsigned long entry = (unsigned long)shadow;
+       unsigned long eviction;
+       unsigned long refault;
+       unsigned long mask;
+       int zid, nid;
+
+       entry >>= RADIX_TREE_EXCEPTIONAL_SHIFT;
+       zid = entry & ((1UL << ZONES_SHIFT) - 1);
+       entry >>= ZONES_SHIFT;
+       nid = entry & ((1UL << NODES_SHIFT) - 1);
+       entry >>= NODES_SHIFT;
+       eviction = entry;
+
+       *zone = NODE_DATA(nid)->node_zones + zid;
+
+       refault = atomic_long_read(&(*zone)->inactive_age);
+       mask = ~0UL >> (NODES_SHIFT + ZONES_SHIFT +
+                       RADIX_TREE_EXCEPTIONAL_SHIFT);
+       /*
+        * The unsigned subtraction here gives an accurate distance
+        * across inactive_age overflows in most cases.
+        *
+        * There is a special case: usually, shadow entries have a
+        * short lifetime and are either refaulted or reclaimed along
+        * with the inode before they get too old.  But it is not
+        * impossible for the inactive_age to lap a shadow entry in
+        * the field, which can then can result in a false small
+        * refault distance, leading to a false activation should this
+        * old entry actually refault again.  However, earlier kernels
+        * used to deactivate unconditionally with *every* reclaim
+        * invocation for the longest time, so the occasional
+        * inappropriate activation leading to pressure on the active
+        * list is not a problem.
+        */
+       *distance = (refault - eviction) & mask;
+}
+
+/**
+ * workingset_eviction - note the eviction of a page from memory
+ * @mapping: address space the page was backing
+ * @page: the page being evicted
+ *
+ * Returns a shadow entry to be stored in @mapping->page_tree in place
+ * of the evicted @page so that a later refault can be detected.
+ */
+void *workingset_eviction(struct address_space *mapping, struct page *page)
+{
+       struct zone *zone = page_zone(page);
+       unsigned long eviction;
+
+       eviction = atomic_long_inc_return(&zone->inactive_age);
+       return pack_shadow(eviction, zone);
+}
+
+/**
+ * workingset_refault - evaluate the refault of a previously evicted page
+ * @shadow: shadow entry of the evicted page
+ *
+ * Calculates and evaluates the refault distance of the previously
+ * evicted page in the context of the zone it was allocated in.
+ *
+ * Returns %true if the page should be activated, %false otherwise.
+ */
+bool workingset_refault(void *shadow)
+{
+       unsigned long refault_distance;
+       struct zone *zone;
+
+       unpack_shadow(shadow, &zone, &refault_distance);
+       inc_zone_state(zone, WORKINGSET_REFAULT);
+
+       if (refault_distance <= zone_page_state(zone, NR_ACTIVE_FILE)) {
+               inc_zone_state(zone, WORKINGSET_ACTIVATE);
+               return true;
+       }
+       return false;
+}
+
+/**
+ * workingset_activation - note a page activation
+ * @page: page that is being activated
+ */
+void workingset_activation(struct page *page)
+{
+       atomic_long_inc(&page_zone(page)->inactive_age);
+}
+
+/*
+ * Shadow entries reflect the share of the working set that does not
+ * fit into memory, so their number depends on the access pattern of
+ * the workload.  In most cases, they will refault or get reclaimed
+ * along with the inode, but a (malicious) workload that streams
+ * through files with a total size several times that of available
+ * memory, while preventing the inodes from being reclaimed, can
+ * create excessive amounts of shadow nodes.  To keep a lid on this,
+ * track shadow nodes and reclaim them when they grow way past the
+ * point where they would still be useful.
+ */
+
+struct list_lru workingset_shadow_nodes;
+
+static unsigned long count_shadow_nodes(struct shrinker *shrinker,
+                                       struct shrink_control *sc)
+{
+       unsigned long shadow_nodes;
+       unsigned long max_nodes;
+       unsigned long pages;
+
+       /* list_lru lock nests inside IRQ-safe mapping->tree_lock */
+       local_irq_disable();
+       shadow_nodes = list_lru_count_node(&workingset_shadow_nodes, sc->nid);
+       local_irq_enable();
+
+       pages = node_present_pages(sc->nid);
+       /*
+        * Active cache pages are limited to 50% of memory, and shadow
+        * entries that represent a refault distance bigger than that
+        * do not have any effect.  Limit the number of shadow nodes
+        * such that shadow entries do not exceed the number of active
+        * cache pages, assuming a worst-case node population density
+        * of 1/8th on average.
+        *
+        * On 64-bit with 7 radix_tree_nodes per page and 64 slots
+        * each, this will reclaim shadow entries when they consume
+        * ~2% of available memory:
+        *
+        * PAGE_SIZE / radix_tree_nodes / node_entries / PAGE_SIZE
+        */
+       max_nodes = pages >> (1 + RADIX_TREE_MAP_SHIFT - 3);
+
+       if (shadow_nodes <= max_nodes)
+               return 0;
+
+       return shadow_nodes - max_nodes;
+}
+
+static enum lru_status shadow_lru_isolate(struct list_head *item,
+                                         spinlock_t *lru_lock,
+                                         void *arg)
+{
+       struct address_space *mapping;
+       struct radix_tree_node *node;
+       unsigned int i;
+       int ret;
+
+       /*
+        * Page cache insertions and deletions synchroneously maintain
+        * the shadow node LRU under the mapping->tree_lock and the
+        * lru_lock.  Because the page cache tree is emptied before
+        * the inode can be destroyed, holding the lru_lock pins any
+        * address_space that has radix tree nodes on the LRU.
+        *
+        * We can then safely transition to the mapping->tree_lock to
+        * pin only the address_space of the particular node we want
+        * to reclaim, take the node off-LRU, and drop the lru_lock.
+        */
+
+       node = container_of(item, struct radix_tree_node, private_list);
+       mapping = node->private_data;
+
+       /* Coming from the list, invert the lock order */
+       if (!spin_trylock(&mapping->tree_lock)) {
+               spin_unlock(lru_lock);
+               ret = LRU_RETRY;
+               goto out;
+       }
+
+       list_del_init(item);
+       spin_unlock(lru_lock);
+
+       /*
+        * The nodes should only contain one or more shadow entries,
+        * no pages, so we expect to be able to remove them all and
+        * delete and free the empty node afterwards.
+        */
+
+       BUG_ON(!node->count);
+       BUG_ON(node->count & RADIX_TREE_COUNT_MASK);
+
+       for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) {
+               if (node->slots[i]) {
+                       BUG_ON(!radix_tree_exceptional_entry(node->slots[i]));
+                       node->slots[i] = NULL;
+                       BUG_ON(node->count < (1U << RADIX_TREE_COUNT_SHIFT));
+                       node->count -= 1U << RADIX_TREE_COUNT_SHIFT;
+                       BUG_ON(!mapping->nrshadows);
+                       mapping->nrshadows--;
+               }
+       }
+       BUG_ON(node->count);
+       inc_zone_state(page_zone(virt_to_page(node)), WORKINGSET_NODERECLAIM);
+       if (!__radix_tree_delete_node(&mapping->page_tree, node))
+               BUG();
+
+       spin_unlock(&mapping->tree_lock);
+       ret = LRU_REMOVED_RETRY;
+out:
+       local_irq_enable();
+       cond_resched();
+       local_irq_disable();
+       spin_lock(lru_lock);
+       return ret;
+}
+
+static unsigned long scan_shadow_nodes(struct shrinker *shrinker,
+                                      struct shrink_control *sc)
+{
+       unsigned long ret;
+
+       /* list_lru lock nests inside IRQ-safe mapping->tree_lock */
+       local_irq_disable();
+       ret =  list_lru_walk_node(&workingset_shadow_nodes, sc->nid,
+                                 shadow_lru_isolate, NULL, &sc->nr_to_scan);
+       local_irq_enable();
+       return ret;
+}
+
+static struct shrinker workingset_shadow_shrinker = {
+       .count_objects = count_shadow_nodes,
+       .scan_objects = scan_shadow_nodes,
+       .seeks = DEFAULT_SEEKS,
+       .flags = SHRINKER_NUMA_AWARE,
+};
+
+/*
+ * Our list_lru->lock is IRQ-safe as it nests inside the IRQ-safe
+ * mapping->tree_lock.
+ */
+static struct lock_class_key shadow_nodes_key;
+
+static int __init workingset_init(void)
+{
+       int ret;
+
+       ret = list_lru_init_key(&workingset_shadow_nodes, &shadow_nodes_key);
+       if (ret)
+               goto err;
+       ret = register_shrinker(&workingset_shadow_shrinker);
+       if (ret)
+               goto err_list_lru;
+       return 0;
+err_list_lru:
+       list_lru_destroy(&workingset_shadow_nodes);
+err:
+       return ret;
+}
+module_init(workingset_init);
index 7203e66..1b4e4b8 100644 (file)
@@ -18,8 +18,8 @@ HOSTCFLAGS_bpf-direct.o += -idirafter $(objtree)/include
 bpf-direct-objs := bpf-direct.o
 
 # Try to match the kernel target.
-ifndef CONFIG_64BIT
 ifndef CROSS_COMPILE
+ifndef CONFIG_64BIT
 
 # s390 has -m31 flag to build 31 bit binaries
 ifndef CONFIG_S390
@@ -36,7 +36,13 @@ HOSTLOADLIBES_bpf-direct += $(MFLAG)
 HOSTLOADLIBES_bpf-fancy += $(MFLAG)
 HOSTLOADLIBES_dropper += $(MFLAG)
 endif
-endif
-
-# Tell kbuild to always build the programs
 always := $(hostprogs-y)
+else
+# MIPS system calls are defined based on the -mabi that is passed
+# to the toolchain which may or may not be a valid option
+# for the host toolchain. So disable tests if target architecture
+# is MIPS but the host isn't.
+ifndef CONFIG_MIPS
+always := $(hostprogs-y)
+endif
+endif
index 464dcef..34eb216 100755 (executable)
@@ -281,7 +281,7 @@ our $Attribute      = qr{
                        __weak
                  }x;
 our $Modifier;
-our $Inline    = qr{inline|__always_inline|noinline};
+our $Inline    = qr{inline|__always_inline|noinline|__inline|__inline__};
 our $Member    = qr{->$Ident|\.$Ident|\[[^]]*\]};
 our $Lval      = qr{$Ident(?:$Member)*};
 
@@ -289,13 +289,14 @@ our $Int_type     = qr{(?i)llu|ull|ll|lu|ul|l|u};
 our $Binary    = qr{(?i)0b[01]+$Int_type?};
 our $Hex       = qr{(?i)0x[0-9a-f]+$Int_type?};
 our $Int       = qr{[0-9]+$Int_type?};
+our $Octal     = qr{0[0-7]+$Int_type?};
 our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?};
 our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?};
 our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?};
 our $Float     = qr{$Float_hex|$Float_dec|$Float_int};
-our $Constant  = qr{$Float|$Binary|$Hex|$Int};
+our $Constant  = qr{$Float|$Binary|$Octal|$Hex|$Int};
 our $Assignment        = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=};
-our $Compare    = qr{<=|>=|==|!=|<|>};
+our $Compare    = qr{<=|>=|==|!=|<|(?<!-)>};
 our $Arithmetic = qr{\+|-|\*|\/|%};
 our $Operators = qr{
                        <=|>=|==|!=|
@@ -303,6 +304,8 @@ our $Operators      = qr{
                        &&|\|\||,|\^|\+\+|--|&|\||$Arithmetic
                  }x;
 
+our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x;
+
 our $NonptrType;
 our $NonptrTypeWithAttr;
 our $Type;
@@ -378,6 +381,22 @@ our @modifierList = (
        qr{fastcall},
 );
 
+our @mode_permission_funcs = (
+       ["module_param", 3],
+       ["module_param_(?:array|named|string)", 4],
+       ["module_param_array_named", 5],
+       ["debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)", 2],
+       ["proc_create(?:_data|)", 2],
+       ["(?:CLASS|DEVICE|SENSOR)_ATTR", 2],
+);
+
+#Create a search pattern for all these functions to speed up a loop below
+our $mode_perms_search = "";
+foreach my $entry (@mode_permission_funcs) {
+       $mode_perms_search .= '|' if ($mode_perms_search ne "");
+       $mode_perms_search .= $entry->[0];
+}
+
 our $allowed_asm_includes = qr{(?x:
        irq|
        memory
@@ -412,7 +431,7 @@ sub build_types {
                        (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*|\[\])+|(?:\s*\[\s*\])+)?
                        (?:\s+$Inline|\s+$Modifier)*
                  }x;
-       $Declare        = qr{(?:$Storage\s+)?$Type};
+       $Declare        = qr{(?:$Storage\s+(?:$Inline\s+)?)?$Type};
 }
 build_types();
 
@@ -423,15 +442,20 @@ our $Typecast     = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*};
 # Any use must be runtime checked with $^V
 
 our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/;
-our $LvalOrFunc        = qr{($Lval)\s*($balanced_parens{0,1})\s*};
+our $LvalOrFunc        = qr{((?:[\&\*]\s*)?$Lval)\s*($balanced_parens{0,1})\s*};
 our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant)};
 
 sub deparenthesize {
        my ($string) = @_;
        return "" if (!defined($string));
-       $string =~ s@^\s*\(\s*@@g;
-       $string =~ s@\s*\)\s*$@@g;
+
+       while ($string =~ /^\s*\(.*\)\s*$/) {
+               $string =~ s@^\s*\(\s*@@;
+               $string =~ s@\s*\)\s*$@@;
+       }
+
        $string =~ s@\s+@ @g;
+
        return $string;
 }
 
@@ -1421,21 +1445,25 @@ sub possible {
 my $prefix = '';
 
 sub show_type {
-       return defined $use_type{$_[0]} if (scalar keys %use_type > 0);
+       my ($type) = @_;
+
+       return defined $use_type{$type} if (scalar keys %use_type > 0);
 
-       return !defined $ignore_type{$_[0]};
+       return !defined $ignore_type{$type};
 }
 
 sub report {
-       if (!show_type($_[1]) ||
-           (defined $tst_only && $_[2] !~ /\Q$tst_only\E/)) {
+       my ($level, $type, $msg) = @_;
+
+       if (!show_type($type) ||
+           (defined $tst_only && $msg !~ /\Q$tst_only\E/)) {
                return 0;
        }
        my $line;
        if ($show_types) {
-               $line = "$prefix$_[0]:$_[1]: $_[2]\n";
+               $line = "$prefix$level:$type: $msg\n";
        } else {
-               $line = "$prefix$_[0]: $_[2]\n";
+               $line = "$prefix$level: $msg\n";
        }
        $line = (split('\n', $line))[0] . "\n" if ($terse);
 
@@ -1443,12 +1471,15 @@ sub report {
 
        return 1;
 }
+
 sub report_dump {
        our @report;
 }
 
 sub ERROR {
-       if (report("ERROR", $_[0], $_[1])) {
+       my ($type, $msg) = @_;
+
+       if (report("ERROR", $type, $msg)) {
                our $clean = 0;
                our $cnt_error++;
                return 1;
@@ -1456,7 +1487,9 @@ sub ERROR {
        return 0;
 }
 sub WARN {
-       if (report("WARNING", $_[0], $_[1])) {
+       my ($type, $msg) = @_;
+
+       if (report("WARNING", $type, $msg)) {
                our $clean = 0;
                our $cnt_warn++;
                return 1;
@@ -1464,7 +1497,9 @@ sub WARN {
        return 0;
 }
 sub CHK {
-       if ($check && report("CHECK", $_[0], $_[1])) {
+       my ($type, $msg) = @_;
+
+       if ($check && report("CHECK", $type, $msg)) {
                our $clean = 0;
                our $cnt_chk++;
                return 1;
@@ -1574,7 +1609,7 @@ sub pos_last_openparen {
                }
        }
 
-       return $last_openparen + 1;
+       return length(expand_tabs(substr($line, 0, $last_openparen))) + 1;
 }
 
 sub process {
@@ -1891,6 +1926,12 @@ sub process {
                        }
                }
 
+# Check for unwanted Gerrit info
+               if ($in_commit_log && $line =~ /^\s*change-id:/i) {
+                       ERROR("GERRIT_CHANGE_ID",
+                             "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr);
+               }
+
 # Check for wrappage within a valid hunk of the file
                if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
                        ERROR("CORRUPTED_PATCH",
@@ -2041,13 +2082,17 @@ sub process {
                }
 
 # check for DT compatible documentation
-               if (defined $root && $realfile =~ /\.dts/ &&
-                   $rawline =~ /^\+\s*compatible\s*=/) {
+               if (defined $root &&
+                       (($realfile =~ /\.dtsi?$/ && $line =~ /^\+\s*compatible\s*=\s*\"/) ||
+                        ($realfile =~ /\.[ch]$/ && $line =~ /^\+.*\.compatible\s*=\s*\"/))) {
+
                        my @compats = $rawline =~ /\"([a-zA-Z0-9\-\,\.\+_]+)\"/g;
 
+                       my $dt_path = $root . "/Documentation/devicetree/bindings/";
+                       my $vp_file = $dt_path . "vendor-prefixes.txt";
+
                        foreach my $compat (@compats) {
                                my $compat2 = $compat;
-                               my $dt_path =  $root . "/Documentation/devicetree/bindings/";
                                $compat2 =~ s/\,[a-z]*\-/\,<\.\*>\-/;
                                `grep -Erq "$compat|$compat2" $dt_path`;
                                if ( $? >> 8 ) {
@@ -2055,14 +2100,12 @@ sub process {
                                             "DT compatible string \"$compat\" appears un-documented -- check $dt_path\n" . $herecurr);
                                }
 
-                               my $vendor = $compat;
-                               my $vendor_path = $dt_path . "vendor-prefixes.txt";
-                               next if (! -f $vendor_path);
-                               $vendor =~ s/^([a-zA-Z0-9]+)\,.*/$1/;
-                               `grep -Eq "$vendor" $vendor_path`;
+                               next if $compat !~ /^([a-zA-Z0-9\-]+)\,/;
+                               my $vendor = $1;
+                               `grep -Eq "^$vendor\\b" $vp_file`;
                                if ( $? >> 8 ) {
                                        WARN("UNDOCUMENTED_DT_STRING",
-                                            "DT compatible string vendor \"$vendor\" appears un-documented -- check $vendor_path\n" . $herecurr);
+                                            "DT compatible string vendor \"$vendor\" appears un-documented -- check $vp_file\n" . $herecurr);
                                }
                        }
                }
@@ -2159,7 +2202,7 @@ sub process {
 
 # check multi-line statement indentation matches previous line
                if ($^V && $^V ge 5.10.0 &&
-                   $prevline =~ /^\+(\t*)(if \(|$Ident\().*(\&\&|\|\||,)\s*$/) {
+                   $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|$Ident\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) {
                        $prevline =~ /^\+(\t*)(.*)$/;
                        my $oldindent = $1;
                        my $rest = $2;
@@ -2198,7 +2241,8 @@ sub process {
 
                if ($realfile =~ m@^(drivers/net/|net/)@ &&
                    $prevrawline =~ /^\+[ \t]*\/\*[ \t]*$/ &&
-                   $rawline =~ /^\+[ \t]*\*/) {
+                   $rawline =~ /^\+[ \t]*\*/ &&
+                   $realline > 2) {
                        WARN("NETWORKING_BLOCK_COMMENT_STYLE",
                             "networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev);
                }
@@ -2221,6 +2265,21 @@ sub process {
                             "networking block comments put the trailing */ on a separate line\n" . $herecurr);
                }
 
+# check for missing blank lines after declarations
+               if ($realfile =~ m@^(drivers/net/|net/)@ &&
+                   $prevline =~ /^\+\s+$Declare\s+$Ident/ &&
+                   !($prevline =~ /(?:$Compare|$Assignment|$Operators)\s*$/ ||
+                     $prevline =~ /(?:\{\s*|\\)$/) &&          #extended lines
+                   $sline =~ /^\+\s+/ &&                       #Not at char 1
+                   !($sline =~ /^\+\s+$Declare/ ||
+                     $sline =~ /^\+\s+$Ident\s+$Ident/ ||      #eg: typedef foo
+                     $sline =~ /^\+\s+(?:union|struct|enum|typedef)\b/ ||
+                     $sline =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(])/ ||
+                     $sline =~ /^\+\s+\(?\s*(?:$Compare|$Assignment|$Operators)/)) {
+                       WARN("SPACING",
+                            "networking uses a blank line after declarations\n" . $hereprev);
+               }
+
 # check for spaces at the beginning of a line.
 # Exceptions:
 #  1) within comments
@@ -2665,6 +2724,13 @@ sub process {
                                $herecurr);
                }
 
+# check for non-global char *foo[] = {"bar", ...} declarations.
+               if ($line =~ /^.\s+(?:static\s+|const\s+)?char\s+\*\s*\w+\s*\[\s*\]\s*=\s*\{/) {
+                       WARN("STATIC_CONST_CHAR_ARRAY",
+                            "char * array declaration might be better as static const\n" .
+                               $herecurr);
+               }
+
 # check for function declarations without arguments like "int foo()"
                if ($line =~ /(\b$Type\s+$Ident)\s*\(\s*\)/) {
                        if (ERROR("FUNCTION_WITHOUT_ARGS",
@@ -2799,7 +2865,7 @@ sub process {
                        my $level2 = $level;
                        $level2 = "dbg" if ($level eq "debug");
                        WARN("PREFER_PR_LEVEL",
-                            "Prefer netdev_$level2(netdev, ... then dev_$level2(dev, ... then pr_$level(...  to printk(KERN_$orig ...\n" . $herecurr);
+                            "Prefer [subsystem eg: netdev]_$level2([subsystem]dev, ... then dev_$level2(dev, ... then pr_$level(...  to printk(KERN_$orig ...\n" . $herecurr);
                }
 
                if ($line =~ /\bpr_warning\s*\(/) {
@@ -2848,10 +2914,7 @@ sub process {
 # Function pointer declarations
 # check spacing between type, funcptr, and args
 # canonical declaration is "type (*funcptr)(args...)"
-#
-# the $Declare variable will capture all spaces after the type
-# so check it for trailing missing spaces or multiple spaces
-               if ($line =~ /^.\s*($Declare)\((\s*)\*(\s*)$Ident(\s*)\)(\s*)\(/) {
+               if ($line =~ /^.\s*($Declare)\((\s*)\*(\s*)($Ident)(\s*)\)(\s*)\(/) {
                        my $declare = $1;
                        my $pre_pointer_space = $2;
                        my $post_pointer_space = $3;
@@ -2859,16 +2922,30 @@ sub process {
                        my $post_funcname_space = $5;
                        my $pre_args_space = $6;
 
-                       if ($declare !~ /\s$/) {
+# the $Declare variable will capture all spaces after the type
+# so check it for a missing trailing missing space but pointer return types
+# don't need a space so don't warn for those.
+                       my $post_declare_space = "";
+                       if ($declare =~ /(\s+)$/) {
+                               $post_declare_space = $1;
+                               $declare = rtrim($declare);
+                       }
+                       if ($declare !~ /\*$/ && $post_declare_space =~ /^$/) {
                                WARN("SPACING",
                                     "missing space after return type\n" . $herecurr);
+                               $post_declare_space = " ";
                        }
 
 # unnecessary space "type  (*funcptr)(args...)"
-                       elsif ($declare =~ /\s{2,}$/) {
-                               WARN("SPACING",
-                                    "Multiple spaces after return type\n" . $herecurr);
-                       }
+# This test is not currently implemented because these declarations are
+# equivalent to
+#      int  foo(int bar, ...)
+# and this is form shouldn't/doesn't generate a checkpatch warning.
+#
+#                      elsif ($declare =~ /\s{2,}$/) {
+#                              WARN("SPACING",
+#                                   "Multiple spaces after return type\n" . $herecurr);
+#                      }
 
 # unnecessary space "type ( *funcptr)(args...)"
                        if (defined $pre_pointer_space &&
@@ -2900,7 +2977,7 @@ sub process {
 
                        if (show_type("SPACING") && $fix) {
                                $fixed[$linenr - 1] =~
-                                   s/^(.\s*$Declare)\(\s*\*\s*($Ident)\s*\)\s*\(/rtrim($1) . " " . "\(\*$2\)\("/ex;
+                                   s/^(.\s*)$Declare\s*\(\s*\*\s*$Ident\s*\)\s*\(/$1 . $declare . $post_declare_space . '(*' . $funcname . ')('/ex;
                        }
                }
 
@@ -3061,10 +3138,13 @@ sub process {
                                # // is a comment
                                } elsif ($op eq '//') {
 
+                               #   :   when part of a bitfield
+                               } elsif ($opv eq ':B') {
+                                       # skip the bitfield test for now
+
                                # No spaces for:
                                #   ->
-                               #   :   when part of a bitfield
-                               } elsif ($op eq '->' || $opv eq ':B') {
+                               } elsif ($op eq '->') {
                                        if ($ctx =~ /Wx.|.xW/) {
                                                if (ERROR("SPACING",
                                                          "spaces prohibited around that '$op' $at\n" . $hereptr)) {
@@ -3334,14 +3414,17 @@ sub process {
                        }
                }
 
-# Return is not a function.
+# return is not a function
                if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) {
                        my $spacing = $1;
                        if ($^V && $^V ge 5.10.0 &&
-                           $stat =~ /^.\s*return\s*$balanced_parens\s*;\s*$/) {
-                               ERROR("RETURN_PARENTHESES",
-                                     "return is not a function, parentheses are not required\n" . $herecurr);
-
+                           $stat =~ /^.\s*return\s*($balanced_parens)\s*;\s*$/) {
+                               my $value = $1;
+                               $value = deparenthesize($value);
+                               if ($value =~ m/^\s*$FuncArg\s*(?:\?|$)/) {
+                                       ERROR("RETURN_PARENTHESES",
+                                             "return is not a function, parentheses are not required\n" . $herecurr);
+                               }
                        } elsif ($spacing !~ /\s+/) {
                                ERROR("SPACING",
                                      "space required before the open parenthesis '('\n" . $herecurr);
@@ -3910,12 +3993,30 @@ sub process {
                        }
                }
 
+# don't use __constant_<foo> functions outside of include/uapi/
+               if ($realfile !~ m@^include/uapi/@ &&
+                   $line =~ /(__constant_(?:htons|ntohs|[bl]e(?:16|32|64)_to_cpu|cpu_to_[bl]e(?:16|32|64)))\s*\(/) {
+                       my $constant_func = $1;
+                       my $func = $constant_func;
+                       $func =~ s/^__constant_//;
+                       if (WARN("CONSTANT_CONVERSION",
+                                "$constant_func should be $func\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/\b$constant_func\b/$func/g;
+                       }
+               }
+
 # prefer usleep_range over udelay
                if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) {
+                       my $delay = $1;
                        # ignore udelay's < 10, however
-                       if (! ($1 < 10) ) {
+                       if (! ($delay < 10) ) {
                                CHK("USLEEP_RANGE",
-                                   "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $line);
+                                   "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $herecurr);
+                       }
+                       if ($delay > 2000) {
+                               WARN("LONG_UDELAY",
+                                    "long udelay - prefer mdelay; see arch/arm/include/asm/delay.h\n" . $herecurr);
                        }
                }
 
@@ -3923,7 +4024,7 @@ sub process {
                if ($line =~ /\bmsleep\s*\((\d+)\);/) {
                        if ($1 < 20) {
                                WARN("MSLEEP",
-                                    "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $line);
+                                    "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $herecurr);
                        }
                }
 
@@ -4149,7 +4250,7 @@ sub process {
 # check for naked sscanf
                if ($^V && $^V ge 5.10.0 &&
                    defined $stat &&
-                   $stat =~ /\bsscanf\b/ &&
+                   $line =~ /\bsscanf\b/ &&
                    ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ &&
                     $stat !~ /\bsscanf\s*$balanced_parens\s*(?:$Compare)/ &&
                     $stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) {
@@ -4240,12 +4341,6 @@ sub process {
                             "$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr);
                }
 
-# check for GFP_NOWAIT use
-               if ($line =~ /\b__GFP_NOFAIL\b/) {
-                       WARN("__GFP_NOFAIL",
-                            "Use of __GFP_NOFAIL is deprecated, no new users should be added\n" . $herecurr);
-               }
-
 # check for multiple semicolons
                if ($line =~ /;\s*;\s*$/) {
                        if (WARN("ONE_SEMICOLON",
@@ -4457,6 +4552,34 @@ sub process {
                        WARN("EXPORTED_WORLD_WRITABLE",
                             "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr);
                }
+
+# Mode permission misuses where it seems decimal should be octal
+# This uses a shortcut match to avoid unnecessary uses of a slow foreach loop
+               if ($^V && $^V ge 5.10.0 &&
+                   $line =~ /$mode_perms_search/) {
+                       foreach my $entry (@mode_permission_funcs) {
+                               my $func = $entry->[0];
+                               my $arg_pos = $entry->[1];
+
+                               my $skip_args = "";
+                               if ($arg_pos > 1) {
+                                       $arg_pos--;
+                                       $skip_args = "(?:\\s*$FuncArg\\s*,\\s*){$arg_pos,$arg_pos}";
+                               }
+                               my $test = "\\b$func\\s*\\(${skip_args}([\\d]+)\\s*[,\\)]";
+                               if ($line =~ /$test/) {
+                                       my $val = $1;
+                                       $val = $6 if ($skip_args ne "");
+
+                                       if ($val !~ /^0$/ &&
+                                           (($val =~ /^$Int$/ && $val !~ /^$Octal$/) ||
+                                            length($val) ne 4)) {
+                                               ERROR("NON_OCTAL_PERMISSIONS",
+                                                     "Use 4 digit octal (0777) not decimal permissions\n" . $herecurr);
+                                       }
+                               }
+                       }
+               }
        }
 
        # If we have no input at all, then there is nothing to report on
index 3e77a94..a9096d9 100644 (file)
@@ -23,6 +23,8 @@ __inline, INLINE_KEYW
 __inline__, INLINE_KEYW
 __signed, SIGNED_KEYW
 __signed__, SIGNED_KEYW
+__typeof, TYPEOF_KEYW
+__typeof__, TYPEOF_KEYW
 __volatile, VOLATILE_KEYW
 __volatile__, VOLATILE_KEYW
 # According to rth, c99 defines _Bool, __restrict, __restrict__, restrict.  KAO
@@ -51,9 +53,8 @@ signed, SIGNED_KEYW
 static, STATIC_KEYW
 struct, STRUCT_KEYW
 typedef, TYPEDEF_KEYW
+typeof, TYPEOF_KEYW
 union, UNION_KEYW
 unsigned, UNSIGNED_KEYW
 void, VOID_KEYW
 volatile, VOLATILE_KEYW
-typeof, TYPEOF_KEYW
-__typeof__, TYPEOF_KEYW
index 8206260..e945248 100644 (file)
@@ -34,7 +34,7 @@ struct resword;
 static const struct resword *is_reserved_word(register const char *str, register unsigned int len);
 #line 8 "scripts/genksyms/keywords.gperf"
 struct resword { const char *name; int token; };
-/* maximum key range = 64, duplicates = 0 */
+/* maximum key range = 98, duplicates = 0 */
 
 #ifdef __GNUC__
 __inline
@@ -48,32 +48,32 @@ is_reserved_hash (register const char *str, register unsigned int len)
 {
   static const unsigned char asso_values[] =
     {
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67,  0,
-      67, 67, 67, 67, 67, 67, 15, 67, 67, 67,
-       0, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67,  0, 67,  0, 67,  5,
-      25, 20, 15, 30, 67, 15, 67, 67, 10,  0,
-      10, 40, 20, 67, 10,  5,  0, 10, 15, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
-      67, 67, 67, 67, 67, 67
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101,   0,
+      101, 101, 101, 101, 101, 101,  15, 101, 101, 101,
+        0, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101,   0, 101,   0, 101,   5,
+       25,  20,  55,  30, 101,  15, 101, 101,  10,   0,
+       10,  40,  10, 101,  10,   5,   0,  10,  15, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101
     };
   return len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[0]] + asso_values[(unsigned char)str[len - 1]];
 }
@@ -89,17 +89,17 @@ is_reserved_word (register const char *str, register unsigned int len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 45,
+      TOTAL_KEYWORDS = 46,
       MIN_WORD_LENGTH = 3,
       MAX_WORD_LENGTH = 24,
       MIN_HASH_VALUE = 3,
-      MAX_HASH_VALUE = 66
+      MAX_HASH_VALUE = 100
     };
 
   static const struct resword wordlist[] =
     {
       {""}, {""}, {""},
-#line 33 "scripts/genksyms/keywords.gperf"
+#line 35 "scripts/genksyms/keywords.gperf"
       {"asm", ASM_KEYW},
       {""},
 #line 15 "scripts/genksyms/keywords.gperf"
@@ -108,7 +108,7 @@ is_reserved_word (register const char *str, register unsigned int len)
 #line 16 "scripts/genksyms/keywords.gperf"
       {"__asm__", ASM_KEYW},
       {""}, {""},
-#line 59 "scripts/genksyms/keywords.gperf"
+#line 27 "scripts/genksyms/keywords.gperf"
       {"__typeof__", TYPEOF_KEYW},
       {""},
 #line 19 "scripts/genksyms/keywords.gperf"
@@ -119,31 +119,31 @@ is_reserved_word (register const char *str, register unsigned int len)
       {"__const__", CONST_KEYW},
 #line 25 "scripts/genksyms/keywords.gperf"
       {"__signed__", SIGNED_KEYW},
-#line 51 "scripts/genksyms/keywords.gperf"
+#line 53 "scripts/genksyms/keywords.gperf"
       {"static", STATIC_KEYW},
       {""},
-#line 46 "scripts/genksyms/keywords.gperf"
+#line 48 "scripts/genksyms/keywords.gperf"
       {"int", INT_KEYW},
-#line 39 "scripts/genksyms/keywords.gperf"
+#line 41 "scripts/genksyms/keywords.gperf"
       {"char", CHAR_KEYW},
-#line 40 "scripts/genksyms/keywords.gperf"
+#line 42 "scripts/genksyms/keywords.gperf"
       {"const", CONST_KEYW},
-#line 52 "scripts/genksyms/keywords.gperf"
+#line 54 "scripts/genksyms/keywords.gperf"
       {"struct", STRUCT_KEYW},
-#line 31 "scripts/genksyms/keywords.gperf"
+#line 33 "scripts/genksyms/keywords.gperf"
       {"__restrict__", RESTRICT_KEYW},
-#line 32 "scripts/genksyms/keywords.gperf"
+#line 34 "scripts/genksyms/keywords.gperf"
       {"restrict", RESTRICT_KEYW},
 #line 12 "scripts/genksyms/keywords.gperf"
       {"EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW},
 #line 23 "scripts/genksyms/keywords.gperf"
       {"__inline__", INLINE_KEYW},
       {""},
-#line 27 "scripts/genksyms/keywords.gperf"
+#line 29 "scripts/genksyms/keywords.gperf"
       {"__volatile__", VOLATILE_KEYW},
 #line 10 "scripts/genksyms/keywords.gperf"
       {"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW},
-#line 30 "scripts/genksyms/keywords.gperf"
+#line 32 "scripts/genksyms/keywords.gperf"
       {"_restrict", RESTRICT_KEYW},
       {""},
 #line 17 "scripts/genksyms/keywords.gperf"
@@ -152,56 +152,65 @@ is_reserved_word (register const char *str, register unsigned int len)
       {"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
 #line 21 "scripts/genksyms/keywords.gperf"
       {"__extension__", EXTENSION_KEYW},
-#line 42 "scripts/genksyms/keywords.gperf"
+#line 44 "scripts/genksyms/keywords.gperf"
       {"enum", ENUM_KEYW},
 #line 13 "scripts/genksyms/keywords.gperf"
       {"EXPORT_UNUSED_SYMBOL", EXPORT_SYMBOL_KEYW},
-#line 43 "scripts/genksyms/keywords.gperf"
+#line 45 "scripts/genksyms/keywords.gperf"
       {"extern", EXTERN_KEYW},
       {""},
 #line 24 "scripts/genksyms/keywords.gperf"
       {"__signed", SIGNED_KEYW},
 #line 14 "scripts/genksyms/keywords.gperf"
       {"EXPORT_UNUSED_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
-#line 54 "scripts/genksyms/keywords.gperf"
+#line 57 "scripts/genksyms/keywords.gperf"
       {"union", UNION_KEYW},
-#line 58 "scripts/genksyms/keywords.gperf"
-      {"typeof", TYPEOF_KEYW},
-#line 53 "scripts/genksyms/keywords.gperf"
-      {"typedef", TYPEDEF_KEYW},
+      {""}, {""},
 #line 22 "scripts/genksyms/keywords.gperf"
       {"__inline", INLINE_KEYW},
-#line 38 "scripts/genksyms/keywords.gperf"
+#line 40 "scripts/genksyms/keywords.gperf"
       {"auto", AUTO_KEYW},
-#line 26 "scripts/genksyms/keywords.gperf"
+#line 28 "scripts/genksyms/keywords.gperf"
       {"__volatile", VOLATILE_KEYW},
       {""}, {""},
-#line 55 "scripts/genksyms/keywords.gperf"
+#line 58 "scripts/genksyms/keywords.gperf"
       {"unsigned", UNSIGNED_KEYW},
       {""},
-#line 49 "scripts/genksyms/keywords.gperf"
+#line 51 "scripts/genksyms/keywords.gperf"
       {"short", SHORT_KEYW},
-#line 45 "scripts/genksyms/keywords.gperf"
+#line 47 "scripts/genksyms/keywords.gperf"
       {"inline", INLINE_KEYW},
       {""},
-#line 57 "scripts/genksyms/keywords.gperf"
+#line 60 "scripts/genksyms/keywords.gperf"
       {"volatile", VOLATILE_KEYW},
-#line 47 "scripts/genksyms/keywords.gperf"
+#line 49 "scripts/genksyms/keywords.gperf"
       {"long", LONG_KEYW},
-#line 29 "scripts/genksyms/keywords.gperf"
+#line 31 "scripts/genksyms/keywords.gperf"
       {"_Bool", BOOL_KEYW},
       {""}, {""},
-#line 48 "scripts/genksyms/keywords.gperf"
+#line 50 "scripts/genksyms/keywords.gperf"
       {"register", REGISTER_KEYW},
-#line 56 "scripts/genksyms/keywords.gperf"
+#line 59 "scripts/genksyms/keywords.gperf"
       {"void", VOID_KEYW},
-#line 44 "scripts/genksyms/keywords.gperf"
-      {"float", FLOAT_KEYW},
-#line 41 "scripts/genksyms/keywords.gperf"
+      {""},
+#line 43 "scripts/genksyms/keywords.gperf"
       {"double", DOUBLE_KEYW},
+      {""},
+#line 26 "scripts/genksyms/keywords.gperf"
+      {"__typeof", TYPEOF_KEYW},
+      {""}, {""},
+#line 52 "scripts/genksyms/keywords.gperf"
+      {"signed", SIGNED_KEYW},
       {""}, {""}, {""}, {""},
-#line 50 "scripts/genksyms/keywords.gperf"
-      {"signed", SIGNED_KEYW}
+#line 56 "scripts/genksyms/keywords.gperf"
+      {"typeof", TYPEOF_KEYW},
+#line 55 "scripts/genksyms/keywords.gperf"
+      {"typedef", TYPEDEF_KEYW},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 46 "scripts/genksyms/keywords.gperf"
+      {"float", FLOAT_KEYW}
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
index f770071..e583565 100644 (file)
@@ -129,8 +129,9 @@ int
 yylex(void)
 {
   static enum {
-    ST_NOTSTARTED, ST_NORMAL, ST_ATTRIBUTE, ST_ASM, ST_BRACKET, ST_BRACE,
-    ST_EXPRESSION, ST_TABLE_1, ST_TABLE_2, ST_TABLE_3, ST_TABLE_4,
+    ST_NOTSTARTED, ST_NORMAL, ST_ATTRIBUTE, ST_ASM, ST_TYPEOF, ST_TYPEOF_1,
+    ST_BRACKET, ST_BRACE, ST_EXPRESSION,
+    ST_TABLE_1, ST_TABLE_2, ST_TABLE_3, ST_TABLE_4,
     ST_TABLE_5, ST_TABLE_6
   } lexstate = ST_NOTSTARTED;
 
@@ -198,6 +199,10 @@ repeat:
                    lexstate = ST_ASM;
                    count = 0;
                    goto repeat;
+                 case TYPEOF_KEYW:
+                   lexstate = ST_TYPEOF;
+                   count = 0;
+                   goto repeat;
 
                  case STRUCT_KEYW:
                  case UNION_KEYW:
@@ -284,6 +289,48 @@ repeat:
        }
       break;
 
+    case ST_TYPEOF:
+      switch (token)
+       {
+       case '(':
+         if ( ++count == 1 )
+           lexstate = ST_TYPEOF_1;
+         else
+           APP;
+         goto repeat;
+       case ')':
+         APP;
+         if (--count == 0)
+           {
+             lexstate = ST_NORMAL;
+             token = TYPEOF_PHRASE;
+             break;
+           }
+         goto repeat;
+       default:
+         APP;
+         goto repeat;
+       }
+      break;
+
+    case ST_TYPEOF_1:
+      if (token == IDENT)
+       {
+         if (is_reserved_word(yytext, yyleng)
+             || find_symbol(yytext, SYM_TYPEDEF, 1))
+           {
+             yyless(0);
+             unput('(');
+             lexstate = ST_NORMAL;
+             token = TYPEOF_KEYW;
+             break;
+           }
+         _APP("(", 1);
+       }
+       APP;
+       lexstate = ST_TYPEOF;
+       goto repeat;
+
     case ST_BRACKET:
       APP;
       switch (token)
index 0bf4157..f82740a 100644 (file)
@@ -1938,8 +1938,9 @@ int
 yylex(void)
 {
   static enum {
-    ST_NOTSTARTED, ST_NORMAL, ST_ATTRIBUTE, ST_ASM, ST_BRACKET, ST_BRACE,
-    ST_EXPRESSION, ST_TABLE_1, ST_TABLE_2, ST_TABLE_3, ST_TABLE_4,
+    ST_NOTSTARTED, ST_NORMAL, ST_ATTRIBUTE, ST_ASM, ST_TYPEOF, ST_TYPEOF_1,
+    ST_BRACKET, ST_BRACE, ST_EXPRESSION,
+    ST_TABLE_1, ST_TABLE_2, ST_TABLE_3, ST_TABLE_4,
     ST_TABLE_5, ST_TABLE_6
   } lexstate = ST_NOTSTARTED;
 
@@ -2007,6 +2008,10 @@ repeat:
                    lexstate = ST_ASM;
                    count = 0;
                    goto repeat;
+                 case TYPEOF_KEYW:
+                   lexstate = ST_TYPEOF;
+                   count = 0;
+                   goto repeat;
 
                  case STRUCT_KEYW:
                  case UNION_KEYW:
@@ -2093,6 +2098,48 @@ repeat:
        }
       break;
 
+    case ST_TYPEOF:
+      switch (token)
+       {
+       case '(':
+         if ( ++count == 1 )
+           lexstate = ST_TYPEOF_1;
+         else
+           APP;
+         goto repeat;
+       case ')':
+         APP;
+         if (--count == 0)
+           {
+             lexstate = ST_NORMAL;
+             token = TYPEOF_PHRASE;
+             break;
+           }
+         goto repeat;
+       default:
+         APP;
+         goto repeat;
+       }
+      break;
+
+    case ST_TYPEOF_1:
+      if (token == IDENT)
+       {
+         if (is_reserved_word(yytext, yyleng)
+             || find_symbol(yytext, SYM_TYPEDEF, 1))
+           {
+             yyless(0);
+             unput('(');
+             lexstate = ST_NORMAL;
+             token = TYPEOF_KEYW;
+             break;
+           }
+         _APP("(", 1);
+       }
+       APP;
+       lexstate = ST_TYPEOF;
+       goto repeat;
+
     case ST_BRACKET:
       APP;
       switch (token)
index ece53c7..c9f0f0c 100644 (file)
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.5.  */
+/* A Bison parser, made by GNU Bison 2.5.1.  */
 
 /* Bison implementation for Yacc-like parsers in C
    
-      Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+      Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.5"
+#define YYBISON_VERSION "2.5.1"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -117,6 +117,14 @@ static void record_compound(struct string_list **keyw,
 
 
 
+# ifndef YY_NULL
+#  if defined __cplusplus && 201103L <= __cplusplus
+#   define YY_NULL nullptr
+#  else
+#   define YY_NULL 0
+#  endif
+# endif
+
 /* Enabling traces.  */
 #ifndef YYDEBUG
 # define YYDEBUG 1
@@ -171,18 +179,19 @@ static void record_compound(struct string_list **keyw,
      EXPORT_SYMBOL_KEYW = 284,
      ASM_PHRASE = 285,
      ATTRIBUTE_PHRASE = 286,
-     BRACE_PHRASE = 287,
-     BRACKET_PHRASE = 288,
-     EXPRESSION_PHRASE = 289,
-     CHAR = 290,
-     DOTS = 291,
-     IDENT = 292,
-     INT = 293,
-     REAL = 294,
-     STRING = 295,
-     TYPE = 296,
-     OTHER = 297,
-     FILENAME = 298
+     TYPEOF_PHRASE = 287,
+     BRACE_PHRASE = 288,
+     BRACKET_PHRASE = 289,
+     EXPRESSION_PHRASE = 290,
+     CHAR = 291,
+     DOTS = 292,
+     IDENT = 293,
+     INT = 294,
+     REAL = 295,
+     STRING = 296,
+     TYPE = 297,
+     OTHER = 298,
+     FILENAME = 299
    };
 #endif
 
@@ -304,6 +313,7 @@ YYID (yyi)
 #    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 #     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
 #     ifndef EXIT_SUCCESS
 #      define EXIT_SUCCESS 0
 #     endif
@@ -395,20 +405,20 @@ union yyalloc
 #endif
 
 #if defined YYCOPY_NEEDED && YYCOPY_NEEDED
-/* Copy COUNT objects from FROM to TO.  The source and destination do
+/* Copy COUNT objects from SRC to DST.  The source and destination do
    not overlap.  */
 # ifndef YYCOPY
 #  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(To, From, Count) \
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#   define YYCOPY(Dst, Src, Count) \
+      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
 #  else
-#   define YYCOPY(To, From, Count)             \
-      do                                       \
-       {                                       \
-         YYSIZE_T yyi;                         \
-         for (yyi = 0; yyi < (Count); yyi++)   \
-           (To)[yyi] = (From)[yyi];            \
-       }                                       \
+#   define YYCOPY(Dst, Src, Count)              \
+      do                                        \
+        {                                       \
+          YYSIZE_T yyi;                         \
+          for (yyi = 0; yyi < (Count); yyi++)   \
+            (Dst)[yyi] = (Src)[yyi];            \
+        }                                       \
       while (YYID (0))
 #  endif
 # endif
@@ -417,20 +427,20 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  4
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   532
+#define YYLAST   514
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  53
+#define YYNTOKENS  54
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  49
 /* YYNRULES -- Number of rules.  */
 #define YYNRULES  132
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  188
+#define YYNSTATES  187
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   298
+#define YYMAXUTOK   299
 
 #define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -442,15 +452,15 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-      47,    49,    48,     2,    46,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    52,    44,
-       2,    50,     2,     2,     2,     2,     2,     2,     2,     2,
+      48,    49,    50,     2,    47,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    53,    45,
+       2,    51,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    51,     2,    45,     2,     2,     2,     2,
+       2,     2,     2,    52,     2,    46,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -467,7 +477,7 @@ static const yytype_uint8 yytranslate[] =
        5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
       15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
       25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,    37,    38,    39,    40,    41,    42,    43
+      35,    36,    37,    38,    39,    40,    41,    42,    43,    44
 };
 
 #if YYDEBUG
@@ -478,78 +488,77 @@ static const yytype_uint16 yyprhs[] =
        0,     0,     3,     5,     8,     9,    12,    13,    18,    19,
       23,    25,    27,    29,    31,    34,    37,    41,    42,    44,
       46,    50,    55,    56,    58,    60,    63,    65,    67,    69,
-      71,    73,    75,    77,    79,    81,    87,    92,    95,    98,
-     101,   105,   109,   113,   116,   119,   122,   124,   126,   128,
-     130,   132,   134,   136,   138,   140,   142,   144,   147,   148,
-     150,   152,   155,   157,   159,   161,   163,   166,   168,   170,
-     175,   180,   183,   187,   191,   194,   196,   198,   200,   205,
-     210,   213,   217,   221,   224,   226,   230,   231,   233,   235,
-     239,   242,   245,   247,   248,   250,   252,   257,   262,   265,
-     269,   273,   277,   278,   280,   283,   287,   291,   292,   294,
-     296,   299,   303,   306,   307,   309,   311,   315,   318,   321,
-     323,   326,   327,   330,   334,   339,   341,   345,   347,   351,
-     354,   355,   357
+      71,    73,    75,    77,    79,    81,    86,    88,    91,    94,
+      97,   101,   105,   109,   112,   115,   118,   120,   122,   124,
+     126,   128,   130,   132,   134,   136,   138,   140,   143,   144,
+     146,   148,   151,   153,   155,   157,   159,   162,   164,   166,
+     171,   176,   179,   183,   187,   190,   192,   194,   196,   201,
+     206,   209,   213,   217,   220,   222,   226,   227,   229,   231,
+     235,   238,   241,   243,   244,   246,   248,   253,   258,   261,
+     265,   269,   273,   274,   276,   279,   283,   287,   288,   290,
+     292,   295,   299,   302,   303,   305,   307,   311,   314,   317,
+     319,   322,   323,   326,   330,   335,   337,   341,   343,   347,
+     350,   351,   353
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      54,     0,    -1,    55,    -1,    54,    55,    -1,    -1,    56,
-      57,    -1,    -1,    12,    23,    58,    60,    -1,    -1,    23,
-      59,    60,    -1,    60,    -1,    84,    -1,    99,    -1,   101,
-      -1,     1,    44,    -1,     1,    45,    -1,    64,    61,    44,
-      -1,    -1,    62,    -1,    63,    -1,    62,    46,    63,    -1,
-      74,   100,    95,    85,    -1,    -1,    65,    -1,    66,    -1,
-      65,    66,    -1,    67,    -1,    68,    -1,     5,    -1,    17,
-      -1,    21,    -1,    11,    -1,    14,    -1,    69,    -1,    73,
-      -1,    28,    47,    65,    48,    49,    -1,    28,    47,    65,
-      49,    -1,    22,    37,    -1,    24,    37,    -1,    10,    37,
-      -1,    22,    37,    87,    -1,    24,    37,    87,    -1,    10,
-      37,    96,    -1,    10,    96,    -1,    22,    87,    -1,    24,
-      87,    -1,     7,    -1,    19,    -1,    15,    -1,    16,    -1,
-      20,    -1,    25,    -1,    13,    -1,     9,    -1,    26,    -1,
-       6,    -1,    41,    -1,    48,    71,    -1,    -1,    72,    -1,
-      73,    -1,    72,    73,    -1,     8,    -1,    27,    -1,    31,
-      -1,    18,    -1,    70,    74,    -1,    75,    -1,    37,    -1,
-      75,    47,    78,    49,    -1,    75,    47,     1,    49,    -1,
-      75,    33,    -1,    47,    74,    49,    -1,    47,     1,    49,
-      -1,    70,    76,    -1,    77,    -1,    37,    -1,    41,    -1,
-      77,    47,    78,    49,    -1,    77,    47,     1,    49,    -1,
-      77,    33,    -1,    47,    76,    49,    -1,    47,     1,    49,
-      -1,    79,    36,    -1,    79,    -1,    80,    46,    36,    -1,
-      -1,    80,    -1,    81,    -1,    80,    46,    81,    -1,    65,
-      82,    -1,    70,    82,    -1,    83,    -1,    -1,    37,    -1,
-      41,    -1,    83,    47,    78,    49,    -1,    83,    47,     1,
-      49,    -1,    83,    33,    -1,    47,    82,    49,    -1,    47,
-       1,    49,    -1,    64,    74,    32,    -1,    -1,    86,    -1,
-      50,    34,    -1,    51,    88,    45,    -1,    51,     1,    45,
-      -1,    -1,    89,    -1,    90,    -1,    89,    90,    -1,    64,
-      91,    44,    -1,     1,    44,    -1,    -1,    92,    -1,    93,
-      -1,    92,    46,    93,    -1,    76,    95,    -1,    37,    94,
-      -1,    94,    -1,    52,    34,    -1,    -1,    95,    31,    -1,
-      51,    97,    45,    -1,    51,    97,    46,    45,    -1,    98,
-      -1,    97,    46,    98,    -1,    37,    -1,    37,    50,    34,
-      -1,    30,    44,    -1,    -1,    30,    -1,    29,    47,    37,
-      49,    44,    -1
+      55,     0,    -1,    56,    -1,    55,    56,    -1,    -1,    57,
+      58,    -1,    -1,    12,    23,    59,    61,    -1,    -1,    23,
+      60,    61,    -1,    61,    -1,    85,    -1,   100,    -1,   102,
+      -1,     1,    45,    -1,     1,    46,    -1,    65,    62,    45,
+      -1,    -1,    63,    -1,    64,    -1,    63,    47,    64,    -1,
+      75,   101,    96,    86,    -1,    -1,    66,    -1,    67,    -1,
+      66,    67,    -1,    68,    -1,    69,    -1,     5,    -1,    17,
+      -1,    21,    -1,    11,    -1,    14,    -1,    70,    -1,    74,
+      -1,    28,    48,    82,    49,    -1,    32,    -1,    22,    38,
+      -1,    24,    38,    -1,    10,    38,    -1,    22,    38,    88,
+      -1,    24,    38,    88,    -1,    10,    38,    97,    -1,    10,
+      97,    -1,    22,    88,    -1,    24,    88,    -1,     7,    -1,
+      19,    -1,    15,    -1,    16,    -1,    20,    -1,    25,    -1,
+      13,    -1,     9,    -1,    26,    -1,     6,    -1,    42,    -1,
+      50,    72,    -1,    -1,    73,    -1,    74,    -1,    73,    74,
+      -1,     8,    -1,    27,    -1,    31,    -1,    18,    -1,    71,
+      75,    -1,    76,    -1,    38,    -1,    76,    48,    79,    49,
+      -1,    76,    48,     1,    49,    -1,    76,    34,    -1,    48,
+      75,    49,    -1,    48,     1,    49,    -1,    71,    77,    -1,
+      78,    -1,    38,    -1,    42,    -1,    78,    48,    79,    49,
+      -1,    78,    48,     1,    49,    -1,    78,    34,    -1,    48,
+      77,    49,    -1,    48,     1,    49,    -1,    80,    37,    -1,
+      80,    -1,    81,    47,    37,    -1,    -1,    81,    -1,    82,
+      -1,    81,    47,    82,    -1,    66,    83,    -1,    71,    83,
+      -1,    84,    -1,    -1,    38,    -1,    42,    -1,    84,    48,
+      79,    49,    -1,    84,    48,     1,    49,    -1,    84,    34,
+      -1,    48,    83,    49,    -1,    48,     1,    49,    -1,    65,
+      75,    33,    -1,    -1,    87,    -1,    51,    35,    -1,    52,
+      89,    46,    -1,    52,     1,    46,    -1,    -1,    90,    -1,
+      91,    -1,    90,    91,    -1,    65,    92,    45,    -1,     1,
+      45,    -1,    -1,    93,    -1,    94,    -1,    93,    47,    94,
+      -1,    77,    96,    -1,    38,    95,    -1,    95,    -1,    53,
+      35,    -1,    -1,    96,    31,    -1,    52,    98,    46,    -1,
+      52,    98,    47,    46,    -1,    99,    -1,    98,    47,    99,
+      -1,    38,    -1,    38,    51,    35,    -1,    30,    45,    -1,
+      -1,    30,    -1,    29,    48,    38,    49,    45,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   123,   123,   124,   128,   128,   134,   134,   136,   136,
-     138,   139,   140,   141,   142,   143,   147,   161,   162,   166,
-     174,   187,   193,   194,   198,   199,   203,   209,   213,   214,
-     215,   216,   217,   221,   222,   223,   224,   228,   230,   232,
-     236,   238,   240,   245,   248,   249,   253,   254,   255,   256,
-     257,   258,   259,   260,   261,   262,   263,   267,   272,   273,
-     277,   278,   282,   282,   282,   283,   291,   292,   296,   305,
-     307,   309,   311,   313,   320,   321,   325,   326,   327,   329,
-     331,   333,   335,   340,   341,   342,   346,   347,   351,   352,
-     357,   362,   364,   368,   369,   377,   381,   383,   385,   387,
-     389,   394,   403,   404,   409,   414,   415,   419,   420,   424,
-     425,   429,   431,   436,   437,   441,   442,   446,   447,   448,
-     452,   456,   457,   461,   462,   466,   467,   470,   475,   483,
-     487,   488,   492
+       0,   124,   124,   125,   129,   129,   135,   135,   137,   137,
+     139,   140,   141,   142,   143,   144,   148,   162,   163,   167,
+     175,   188,   194,   195,   199,   200,   204,   210,   214,   215,
+     216,   217,   218,   222,   223,   224,   225,   229,   231,   233,
+     237,   239,   241,   246,   249,   250,   254,   255,   256,   257,
+     258,   259,   260,   261,   262,   263,   264,   268,   273,   274,
+     278,   279,   283,   283,   283,   284,   292,   293,   297,   306,
+     308,   310,   312,   314,   321,   322,   326,   327,   328,   330,
+     332,   334,   336,   341,   342,   343,   347,   348,   352,   353,
+     358,   363,   365,   369,   370,   378,   382,   384,   386,   388,
+     390,   395,   404,   405,   410,   415,   416,   420,   421,   425,
+     426,   430,   432,   437,   438,   442,   443,   447,   448,   449,
+     453,   457,   458,   462,   463,   467,   468,   471,   476,   484,
+     488,   489,   493
 };
 #endif
 
@@ -565,9 +574,9 @@ static const char *const yytname[] =
   "SHORT_KEYW", "SIGNED_KEYW", "STATIC_KEYW", "STRUCT_KEYW",
   "TYPEDEF_KEYW", "UNION_KEYW", "UNSIGNED_KEYW", "VOID_KEYW",
   "VOLATILE_KEYW", "TYPEOF_KEYW", "EXPORT_SYMBOL_KEYW", "ASM_PHRASE",
-  "ATTRIBUTE_PHRASE", "BRACE_PHRASE", "BRACKET_PHRASE",
+  "ATTRIBUTE_PHRASE", "TYPEOF_PHRASE", "BRACE_PHRASE", "BRACKET_PHRASE",
   "EXPRESSION_PHRASE", "CHAR", "DOTS", "IDENT", "INT", "REAL", "STRING",
-  "TYPE", "OTHER", "FILENAME", "';'", "'}'", "','", "'('", "'*'", "')'",
+  "TYPE", "OTHER", "FILENAME", "';'", "'}'", "','", "'('", "')'", "'*'",
   "'='", "'{'", "':'", "$accept", "declaration_seq", "declaration", "$@1",
   "declaration1", "$@2", "$@3", "simple_declaration",
   "init_declarator_list_opt", "init_declarator_list", "init_declarator",
@@ -584,7 +593,7 @@ static const char *const yytname[] =
   "member_declarator_list_opt", "member_declarator_list",
   "member_declarator", "member_bitfield_declarator", "attribute_opt",
   "enum_body", "enumerator_list", "enumerator", "asm_definition",
-  "asm_phrase_opt", "export_definition", 0
+  "asm_phrase_opt", "export_definition", YY_NULL
 };
 #endif
 
@@ -597,28 +606,28 @@ static const yytype_uint16 yytoknum[] =
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
      275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
      285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
-     295,   296,   297,   298,    59,   125,    44,    40,    42,    41,
-      61,   123,    58
+     295,   296,   297,   298,   299,    59,   125,    44,    40,    41,
+      42,    61,   123,    58
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    53,    54,    54,    56,    55,    58,    57,    59,    57,
-      57,    57,    57,    57,    57,    57,    60,    61,    61,    62,
-      62,    63,    64,    64,    65,    65,    66,    66,    67,    67,
-      67,    67,    67,    68,    68,    68,    68,    68,    68,    68,
-      68,    68,    68,    68,    68,    68,    69,    69,    69,    69,
-      69,    69,    69,    69,    69,    69,    69,    70,    71,    71,
-      72,    72,    73,    73,    73,    73,    74,    74,    75,    75,
-      75,    75,    75,    75,    76,    76,    77,    77,    77,    77,
-      77,    77,    77,    78,    78,    78,    79,    79,    80,    80,
-      81,    82,    82,    83,    83,    83,    83,    83,    83,    83,
-      83,    84,    85,    85,    86,    87,    87,    88,    88,    89,
-      89,    90,    90,    91,    91,    92,    92,    93,    93,    93,
-      94,    95,    95,    96,    96,    97,    97,    98,    98,    99,
-     100,   100,   101
+       0,    54,    55,    55,    57,    56,    59,    58,    60,    58,
+      58,    58,    58,    58,    58,    58,    61,    62,    62,    63,
+      63,    64,    65,    65,    66,    66,    67,    67,    68,    68,
+      68,    68,    68,    69,    69,    69,    69,    69,    69,    69,
+      69,    69,    69,    69,    69,    69,    70,    70,    70,    70,
+      70,    70,    70,    70,    70,    70,    70,    71,    72,    72,
+      73,    73,    74,    74,    74,    74,    75,    75,    76,    76,
+      76,    76,    76,    76,    77,    77,    78,    78,    78,    78,
+      78,    78,    78,    79,    79,    79,    80,    80,    81,    81,
+      82,    83,    83,    84,    84,    84,    84,    84,    84,    84,
+      84,    85,    86,    86,    87,    88,    88,    89,    89,    90,
+      90,    91,    91,    92,    92,    93,    93,    94,    94,    94,
+      95,    96,    96,    97,    97,    98,    98,    99,    99,   100,
+     101,   101,   102
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -627,7 +636,7 @@ static const yytype_uint8 yyr2[] =
        0,     2,     1,     2,     0,     2,     0,     4,     0,     3,
        1,     1,     1,     1,     2,     2,     3,     0,     1,     1,
        3,     4,     0,     1,     1,     2,     1,     1,     1,     1,
-       1,     1,     1,     1,     1,     5,     4,     2,     2,     2,
+       1,     1,     1,     1,     1,     4,     1,     2,     2,     2,
        3,     3,     3,     2,     2,     2,     1,     1,     1,     1,
        1,     1,     1,     1,     1,     1,     1,     2,     0,     1,
        1,     2,     1,     1,     1,     1,     2,     1,     1,     4,
@@ -648,68 +657,68 @@ static const yytype_uint8 yydefact[] =
        4,     4,     2,     0,     1,     3,     0,    28,    55,    46,
       62,    53,     0,    31,     0,    52,    32,    48,    49,    29,
       65,    47,    50,    30,     0,     8,     0,    51,    54,    63,
-       0,     0,     0,    64,    56,     5,    10,    17,    23,    24,
-      26,    27,    33,    34,    11,    12,    13,    14,    15,    39,
-       0,    43,     6,    37,     0,    44,    22,    38,    45,     0,
-       0,   129,    68,     0,    58,     0,    18,    19,     0,   130,
-      67,    25,    42,   127,     0,   125,    22,    40,     0,   113,
-       0,     0,   109,     9,    17,    41,     0,     0,     0,     0,
-      57,    59,    60,    16,     0,    66,   131,   101,   121,    71,
-       0,     0,   123,     0,     7,   112,   106,    76,    77,     0,
-       0,     0,   121,    75,     0,   114,   115,   119,   105,     0,
-     110,   130,     0,    36,     0,    73,    72,    61,    20,   102,
-       0,    93,     0,    84,    87,    88,   128,   124,   126,   118,
-       0,    76,     0,   120,    74,   117,    80,     0,   111,     0,
-      35,   132,   122,     0,    21,   103,    70,    94,    56,     0,
-      93,    90,    92,    69,    83,     0,    82,    81,     0,     0,
-     116,   104,     0,    95,     0,    91,    98,     0,    85,    89,
-      79,    78,   100,    99,     0,     0,    97,    96
+       0,     0,     0,    64,    36,    56,     5,    10,    17,    23,
+      24,    26,    27,    33,    34,    11,    12,    13,    14,    15,
+      39,     0,    43,     6,    37,     0,    44,    22,    38,    45,
+       0,     0,   129,    68,     0,    58,     0,    18,    19,     0,
+     130,    67,    25,    42,   127,     0,   125,    22,    40,     0,
+     113,     0,     0,   109,     9,    17,    41,    93,     0,     0,
+       0,     0,    57,    59,    60,    16,     0,    66,   131,   101,
+     121,    71,     0,     0,   123,     0,     7,   112,   106,    76,
+      77,     0,     0,     0,   121,    75,     0,   114,   115,   119,
+     105,     0,   110,   130,    94,    56,     0,    93,    90,    92,
+      35,     0,    73,    72,    61,    20,   102,     0,     0,    84,
+      87,    88,   128,   124,   126,   118,     0,    76,     0,   120,
+      74,   117,    80,     0,   111,     0,     0,    95,     0,    91,
+      98,     0,   132,   122,     0,    21,   103,    70,    69,    83,
+       0,    82,    81,     0,     0,   116,   100,    99,     0,     0,
+     104,    85,    89,    79,    78,    97,    96
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     1,     2,     3,    35,    76,    56,    36,    65,    66,
-      67,    79,    38,    39,    40,    41,    42,    68,    90,    91,
-      43,   121,    70,   112,   113,   132,   133,   134,   135,   161,
-     162,    44,   154,   155,    55,    80,    81,    82,   114,   115,
-     116,   117,   129,    51,    74,    75,    45,    98,    46
+      -1,     1,     2,     3,    36,    77,    57,    37,    66,    67,
+      68,    80,    39,    40,    41,    42,    43,    69,    92,    93,
+      44,   123,    71,   114,   115,   138,   139,   140,   141,   128,
+     129,    45,   165,   166,    56,    81,    82,    83,   116,   117,
+     118,   119,   136,    52,    75,    76,    46,   100,    47
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -135
+#define YYPACT_NINF -140
 static const yytype_int16 yypact[] =
 {
-    -135,    20,  -135,   321,  -135,  -135,    30,  -135,  -135,  -135,
-    -135,  -135,   -28,  -135,     2,  -135,  -135,  -135,  -135,  -135,
-    -135,  -135,  -135,  -135,    -6,  -135,     9,  -135,  -135,  -135,
-      -5,    15,   -17,  -135,  -135,  -135,  -135,    18,   491,  -135,
-    -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,   -22,
-      31,  -135,  -135,    19,   106,  -135,   491,    19,  -135,   491,
-      50,  -135,  -135,    11,    -3,    51,    57,  -135,    18,   -14,
-      14,  -135,  -135,    48,    46,  -135,   491,  -135,    33,    32,
-      59,   154,  -135,  -135,    18,  -135,   365,    56,    60,    61,
-    -135,    -3,  -135,  -135,    18,  -135,  -135,  -135,  -135,  -135,
-     202,    74,  -135,   -23,  -135,  -135,  -135,    77,  -135,    16,
-     101,    49,  -135,    34,    92,    93,  -135,  -135,  -135,    94,
-    -135,   110,    95,  -135,    97,  -135,  -135,  -135,  -135,   -20,
-      96,   410,    99,   113,   100,  -135,  -135,  -135,  -135,  -135,
-     103,  -135,   107,  -135,  -135,   111,  -135,   239,  -135,    32,
-    -135,  -135,  -135,   123,  -135,  -135,  -135,  -135,  -135,     3,
-      52,  -135,    38,  -135,  -135,   454,  -135,  -135,   117,   128,
-    -135,  -135,   134,  -135,   135,  -135,  -135,   276,  -135,  -135,
-    -135,  -135,  -135,  -135,   137,   138,  -135,  -135
+    -140,    29,  -140,   207,  -140,  -140,    40,  -140,  -140,  -140,
+    -140,  -140,   -27,  -140,    44,  -140,  -140,  -140,  -140,  -140,
+    -140,  -140,  -140,  -140,   -22,  -140,   -18,  -140,  -140,  -140,
+      -9,    22,    28,  -140,  -140,  -140,  -140,  -140,    42,   472,
+    -140,  -140,  -140,  -140,  -140,  -140,  -140,  -140,  -140,  -140,
+      46,    43,  -140,  -140,    47,   107,  -140,   472,    47,  -140,
+     472,    62,  -140,  -140,    16,    -3,    57,    56,  -140,    42,
+      35,   -11,  -140,  -140,    53,    48,  -140,   472,  -140,    51,
+      21,    59,   157,  -140,  -140,    42,  -140,   388,    58,    60,
+      70,    81,  -140,    -3,  -140,  -140,    42,  -140,  -140,  -140,
+    -140,  -140,   253,    71,  -140,   -20,  -140,  -140,  -140,    83,
+    -140,     5,   102,    34,  -140,    12,    95,    94,  -140,  -140,
+    -140,    97,  -140,   113,  -140,  -140,     2,    41,  -140,    27,
+    -140,    99,  -140,  -140,  -140,  -140,   -24,    98,   101,   109,
+     104,  -140,  -140,  -140,  -140,  -140,   105,  -140,   110,  -140,
+    -140,   117,  -140,   298,  -140,    21,   112,  -140,   120,  -140,
+    -140,   343,  -140,  -140,   121,  -140,  -140,  -140,  -140,  -140,
+     434,  -140,  -140,   131,   137,  -140,  -140,  -140,   138,   141,
+    -140,  -140,  -140,  -140,  -140,  -140,  -140
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-    -135,  -135,   187,  -135,  -135,  -135,  -135,   -50,  -135,  -135,
-      98,     0,   -59,   -37,  -135,  -135,  -135,   -77,  -135,  -135,
-     -54,   -30,  -135,   -90,  -135,  -134,  -135,  -135,    24,   -58,
-    -135,  -135,  -135,  -135,   -18,  -135,  -135,   109,  -135,  -135,
-      44,    87,    84,   148,  -135,   102,  -135,  -135,  -135
+    -140,  -140,   190,  -140,  -140,  -140,  -140,   -45,  -140,  -140,
+      96,     1,   -60,   -31,  -140,  -140,  -140,   -78,  -140,  -140,
+     -55,    -7,  -140,   -92,  -140,  -139,  -140,  -140,   -59,   -39,
+    -140,  -140,  -140,  -140,   -13,  -140,  -140,   111,  -140,  -140,
+      39,    87,    84,   147,  -140,   106,  -140,  -140,  -140
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -718,149 +727,145 @@ static const yytype_int16 yypgoto[] =
 #define YYTABLE_NINF -109
 static const yytype_int16 yytable[] =
 {
-      86,    71,   111,    37,   172,    10,    83,    69,    58,    49,
-      92,   152,    88,   169,    73,    20,    96,   140,    97,   142,
-       4,   144,   137,    50,    29,    52,   104,    61,    33,    50,
-     153,    53,   111,    89,   111,    77,   -93,   127,    95,    85,
-     157,   131,    59,   185,   173,    54,    57,    99,    62,    71,
-     159,    64,   -93,   141,   160,    62,    84,   108,    63,    64,
-      54,   100,    60,   109,    64,    63,    64,   146,    73,   107,
-      54,   176,   111,   108,    47,    48,    84,   105,   106,   109,
-      64,   147,   160,   160,   110,   177,   141,    87,   131,   157,
-     108,   102,   103,   173,    71,    93,   109,    64,   101,   159,
-      64,   174,   175,    94,   118,   124,   131,    78,   136,   125,
-     126,     7,     8,     9,    10,    11,    12,    13,   131,    15,
-      16,    17,    18,    19,    20,    21,    22,    23,    24,   110,
-      26,    27,    28,    29,    30,   143,   148,    33,   105,   149,
-      96,   151,   152,   -22,   150,   156,   165,    34,   163,   164,
-     -22,  -107,   166,   -22,   -22,   119,   167,   171,   -22,     7,
-       8,     9,    10,    11,    12,    13,   180,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,   181,    26,    27,
-      28,    29,    30,   182,   183,    33,   186,   187,     5,   179,
-     120,   -22,   128,   170,   139,    34,   145,    72,   -22,  -108,
-       0,   -22,   -22,   130,     0,   138,   -22,     7,     8,     9,
-      10,    11,    12,    13,     0,    15,    16,    17,    18,    19,
-      20,    21,    22,    23,    24,     0,    26,    27,    28,    29,
-      30,     0,     0,    33,     0,     0,     0,     0,   -86,     0,
-     168,     0,     0,    34,     7,     8,     9,    10,    11,    12,
-      13,   -86,    15,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,     0,    26,    27,    28,    29,    30,     0,     0,
-      33,     0,     0,     0,     0,   -86,     0,   184,     0,     0,
-      34,     7,     8,     9,    10,    11,    12,    13,   -86,    15,
-      16,    17,    18,    19,    20,    21,    22,    23,    24,     0,
-      26,    27,    28,    29,    30,     0,     0,    33,     0,     0,
-       0,     0,   -86,     0,     0,     0,     0,    34,     0,     0,
-       0,     0,     6,     0,     0,   -86,     7,     8,     9,    10,
-      11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
-      31,    32,    33,     0,     0,     0,     0,     0,   -22,     0,
-       0,     0,    34,     0,     0,   -22,     0,     0,   -22,   -22,
-       7,     8,     9,    10,    11,    12,    13,     0,    15,    16,
-      17,    18,    19,    20,    21,    22,    23,    24,     0,    26,
-      27,    28,    29,    30,     0,     0,    33,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,    34,     0,     0,     0,
-       0,     0,     0,   122,   123,     7,     8,     9,    10,    11,
-      12,    13,     0,    15,    16,    17,    18,    19,    20,    21,
-      22,    23,    24,     0,    26,    27,    28,    29,    30,     0,
-       0,    33,     0,     0,     0,     0,     0,   157,     0,     0,
-       0,   158,     0,     0,     0,     0,     0,   159,    64,     7,
+      87,    88,   113,   156,    38,    10,   146,   163,    72,   127,
+      94,    50,    84,    59,   174,    20,    54,    90,    74,   148,
+      58,   150,   179,   101,    29,    51,   143,   164,    33,     4,
+      55,    70,   106,   113,    55,   113,   -93,   102,   134,    60,
+     124,    78,    87,   147,   157,    86,   152,   110,   127,   127,
+     126,   -93,    65,   111,    63,    65,    72,    91,    85,   109,
+     153,   160,    97,   110,    64,    98,    65,    53,    99,   111,
+      61,    65,   147,    62,   112,   161,   110,   113,    85,   124,
+      63,    74,   111,   157,    65,    48,    49,   158,   159,   126,
+      64,    65,    65,    87,   104,   105,   107,   108,    51,    55,
+      89,    87,    95,    96,   103,   120,   142,   130,    79,   131,
+      87,   182,     7,     8,     9,    10,    11,    12,    13,   132,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+     133,    26,    27,    28,    29,    30,   112,   149,    33,    34,
+     154,   155,   107,    98,   162,   -22,   169,   167,   163,    35,
+     168,   170,   -22,  -107,   171,   -22,   180,   -22,   121,   172,
+     -22,   176,     7,     8,     9,    10,    11,    12,    13,   177,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+     183,    26,    27,    28,    29,    30,   184,   185,    33,    34,
+     186,     5,   135,   122,   175,   -22,   145,    73,   151,    35,
+       0,     0,   -22,  -108,     0,   -22,     0,   -22,     6,     0,
+     -22,   144,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+       0,     0,     0,     0,     0,   -22,     0,     0,     0,    35,
+       0,     0,   -22,     0,   137,   -22,     0,   -22,     7,     8,
+       9,    10,    11,    12,    13,     0,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,     0,    26,    27,    28,
+      29,    30,     0,     0,    33,    34,     0,     0,     0,     0,
+     -86,     0,     0,     0,     0,    35,     0,     0,     0,   173,
+       0,     0,   -86,     7,     8,     9,    10,    11,    12,    13,
+       0,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,     0,    26,    27,    28,    29,    30,     0,     0,    33,
+      34,     0,     0,     0,     0,   -86,     0,     0,     0,     0,
+      35,     0,     0,     0,   178,     0,     0,   -86,     7,     8,
+       9,    10,    11,    12,    13,     0,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,     0,    26,    27,    28,
+      29,    30,     0,     0,    33,    34,     0,     0,     0,     0,
+     -86,     0,     0,     0,     0,    35,     0,     0,     0,     0,
+       0,     0,   -86,     7,     8,     9,    10,    11,    12,    13,
+       0,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,     0,    26,    27,    28,    29,    30,     0,     0,    33,
+      34,     0,     0,     0,     0,     0,   124,     0,     0,     0,
+     125,     0,     0,     0,     0,     0,   126,     0,    65,     7,
        8,     9,    10,    11,    12,    13,     0,    15,    16,    17,
       18,    19,    20,    21,    22,    23,    24,     0,    26,    27,
-      28,    29,    30,     0,     0,    33,     0,     0,     0,     0,
-     178,     0,     0,     0,     0,    34,     7,     8,     9,    10,
-      11,    12,    13,     0,    15,    16,    17,    18,    19,    20,
-      21,    22,    23,    24,     0,    26,    27,    28,    29,    30,
-       0,     0,    33,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,    34
+      28,    29,    30,     0,     0,    33,    34,     0,     0,     0,
+       0,   181,     0,     0,     0,     0,    35,     7,     8,     9,
+      10,    11,    12,    13,     0,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,    24,     0,    26,    27,    28,    29,
+      30,     0,     0,    33,    34,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,    35
 };
 
 #define yypact_value_is_default(yystate) \
-  ((yystate) == (-135))
+  ((yystate) == (-140))
 
 #define yytable_value_is_error(yytable_value) \
   YYID (0)
 
 static const yytype_int16 yycheck[] =
 {
-      59,    38,    79,     3,     1,     8,    56,    37,    26,    37,
-      64,    31,     1,   147,    37,    18,    30,     1,    32,   109,
-       0,   111,    45,    51,    27,    23,    76,    44,    31,    51,
-      50,    37,   109,    63,   111,    53,    33,    91,    68,    57,
-      37,   100,    47,   177,    41,    51,    37,    33,    37,    86,
-      47,    48,    49,    37,   131,    37,    56,    41,    47,    48,
-      51,    47,    47,    47,    48,    47,    48,    33,    37,    37,
-      51,    33,   149,    41,    44,    45,    76,    44,    45,    47,
-      48,    47,   159,   160,    52,    47,    37,    37,   147,    37,
-      41,    45,    46,    41,   131,    44,    47,    48,    50,    47,
-      48,   159,   160,    46,    45,    49,   165,     1,    34,    49,
-      49,     5,     6,     7,     8,     9,    10,    11,   177,    13,
-      14,    15,    16,    17,    18,    19,    20,    21,    22,    52,
-      24,    25,    26,    27,    28,    34,    44,    31,    44,    46,
-      30,    44,    31,    37,    49,    49,    46,    41,    49,    36,
-      44,    45,    49,    47,    48,     1,    49,    34,    52,     5,
-       6,     7,     8,     9,    10,    11,    49,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,    49,    24,    25,
-      26,    27,    28,    49,    49,    31,    49,    49,     1,   165,
-      81,    37,    94,   149,   107,    41,   112,    49,    44,    45,
-      -1,    47,    48,     1,    -1,   103,    52,     5,     6,     7,
-       8,     9,    10,    11,    -1,    13,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    -1,    24,    25,    26,    27,
-      28,    -1,    -1,    31,    -1,    -1,    -1,    -1,    36,    -1,
-       1,    -1,    -1,    41,     5,     6,     7,     8,     9,    10,
-      11,    49,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,    -1,    24,    25,    26,    27,    28,    -1,    -1,
-      31,    -1,    -1,    -1,    -1,    36,    -1,     1,    -1,    -1,
-      41,     5,     6,     7,     8,     9,    10,    11,    49,    13,
-      14,    15,    16,    17,    18,    19,    20,    21,    22,    -1,
-      24,    25,    26,    27,    28,    -1,    -1,    31,    -1,    -1,
-      -1,    -1,    36,    -1,    -1,    -1,    -1,    41,    -1,    -1,
-      -1,    -1,     1,    -1,    -1,    49,     5,     6,     7,     8,
-       9,    10,    11,    12,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
-      29,    30,    31,    -1,    -1,    -1,    -1,    -1,    37,    -1,
-      -1,    -1,    41,    -1,    -1,    44,    -1,    -1,    47,    48,
-       5,     6,     7,     8,     9,    10,    11,    -1,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    -1,    24,
-      25,    26,    27,    28,    -1,    -1,    31,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    41,    -1,    -1,    -1,
-      -1,    -1,    -1,    48,    49,     5,     6,     7,     8,     9,
-      10,    11,    -1,    13,    14,    15,    16,    17,    18,    19,
-      20,    21,    22,    -1,    24,    25,    26,    27,    28,    -1,
-      -1,    31,    -1,    -1,    -1,    -1,    -1,    37,    -1,    -1,
-      -1,    41,    -1,    -1,    -1,    -1,    -1,    47,    48,     5,
+      60,    60,    80,     1,     3,     8,     1,    31,    39,    87,
+      65,    38,    57,    26,   153,    18,    38,     1,    38,   111,
+      38,   113,   161,    34,    27,    52,    46,    51,    31,     0,
+      52,    38,    77,   111,    52,   113,    34,    48,    93,    48,
+      38,    54,   102,    38,    42,    58,    34,    42,   126,   127,
+      48,    49,    50,    48,    38,    50,    87,    64,    57,    38,
+      48,    34,    69,    42,    48,    30,    50,    23,    33,    48,
+      48,    50,    38,    45,    53,    48,    42,   155,    77,    38,
+      38,    38,    48,    42,    50,    45,    46,   126,   127,    48,
+      48,    50,    50,   153,    46,    47,    45,    46,    52,    52,
+      38,   161,    45,    47,    51,    46,    35,    49,     1,    49,
+     170,   170,     5,     6,     7,     8,     9,    10,    11,    49,
+      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      49,    24,    25,    26,    27,    28,    53,    35,    31,    32,
+      45,    47,    45,    30,    45,    38,    37,    49,    31,    42,
+      49,    47,    45,    46,    49,    48,    35,    50,     1,    49,
+      53,    49,     5,     6,     7,     8,     9,    10,    11,    49,
+      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      49,    24,    25,    26,    27,    28,    49,    49,    31,    32,
+      49,     1,    96,    82,   155,    38,   109,    50,   114,    42,
+      -1,    -1,    45,    46,    -1,    48,    -1,    50,     1,    -1,
+      53,   105,     5,     6,     7,     8,     9,    10,    11,    12,
+      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
+      -1,    -1,    -1,    -1,    -1,    38,    -1,    -1,    -1,    42,
+      -1,    -1,    45,    -1,     1,    48,    -1,    50,     5,     6,
+       7,     8,     9,    10,    11,    -1,    13,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    -1,    24,    25,    26,
+      27,    28,    -1,    -1,    31,    32,    -1,    -1,    -1,    -1,
+      37,    -1,    -1,    -1,    -1,    42,    -1,    -1,    -1,     1,
+      -1,    -1,    49,     5,     6,     7,     8,     9,    10,    11,
+      -1,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    -1,    24,    25,    26,    27,    28,    -1,    -1,    31,
+      32,    -1,    -1,    -1,    -1,    37,    -1,    -1,    -1,    -1,
+      42,    -1,    -1,    -1,     1,    -1,    -1,    49,     5,     6,
+       7,     8,     9,    10,    11,    -1,    13,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    -1,    24,    25,    26,
+      27,    28,    -1,    -1,    31,    32,    -1,    -1,    -1,    -1,
+      37,    -1,    -1,    -1,    -1,    42,    -1,    -1,    -1,    -1,
+      -1,    -1,    49,     5,     6,     7,     8,     9,    10,    11,
+      -1,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    -1,    24,    25,    26,    27,    28,    -1,    -1,    31,
+      32,    -1,    -1,    -1,    -1,    -1,    38,    -1,    -1,    -1,
+      42,    -1,    -1,    -1,    -1,    -1,    48,    -1,    50,     5,
        6,     7,     8,     9,    10,    11,    -1,    13,    14,    15,
       16,    17,    18,    19,    20,    21,    22,    -1,    24,    25,
-      26,    27,    28,    -1,    -1,    31,    -1,    -1,    -1,    -1,
-      36,    -1,    -1,    -1,    -1,    41,     5,     6,     7,     8,
-       9,    10,    11,    -1,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,    22,    -1,    24,    25,    26,    27,    28,
-      -1,    -1,    31,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    41
+      26,    27,    28,    -1,    -1,    31,    32,    -1,    -1,    -1,
+      -1,    37,    -1,    -1,    -1,    -1,    42,     5,     6,     7,
+       8,     9,    10,    11,    -1,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    -1,    24,    25,    26,    27,
+      28,    -1,    -1,    31,    32,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    42
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,    54,    55,    56,     0,    55,     1,     5,     6,     7,
+       0,    55,    56,    57,     0,    56,     1,     5,     6,     7,
        8,     9,    10,    11,    12,    13,    14,    15,    16,    17,
       18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    31,    41,    57,    60,    64,    65,    66,
-      67,    68,    69,    73,    84,    99,   101,    44,    45,    37,
-      51,    96,    23,    37,    51,    87,    59,    37,    87,    47,
-      47,    44,    37,    47,    48,    61,    62,    63,    70,    74,
-      75,    66,    96,    37,    97,    98,    58,    87,     1,    64,
-      88,    89,    90,    60,    64,    87,    65,    37,     1,    74,
-      71,    72,    73,    44,    46,    74,    30,    32,   100,    33,
-      47,    50,    45,    46,    60,    44,    45,    37,    41,    47,
-      52,    70,    76,    77,    91,    92,    93,    94,    45,     1,
-      90,    74,    48,    49,    49,    49,    49,    73,    63,    95,
-       1,    65,    78,    79,    80,    81,    34,    45,    98,    94,
-       1,    37,    76,    34,    76,    95,    33,    47,    44,    46,
-      49,    44,    31,    50,    85,    86,    49,    37,    41,    47,
-      70,    82,    83,    49,    36,    46,    49,    49,     1,    78,
-      93,    34,     1,    41,    82,    82,    33,    47,    36,    81,
-      49,    49,    49,    49,     1,    78,    49,    49
+      28,    29,    30,    31,    32,    42,    58,    61,    65,    66,
+      67,    68,    69,    70,    74,    85,   100,   102,    45,    46,
+      38,    52,    97,    23,    38,    52,    88,    60,    38,    88,
+      48,    48,    45,    38,    48,    50,    62,    63,    64,    71,
+      75,    76,    67,    97,    38,    98,    99,    59,    88,     1,
+      65,    89,    90,    91,    61,    65,    88,    66,    82,    38,
+       1,    75,    72,    73,    74,    45,    47,    75,    30,    33,
+     101,    34,    48,    51,    46,    47,    61,    45,    46,    38,
+      42,    48,    53,    71,    77,    78,    92,    93,    94,    95,
+      46,     1,    91,    75,    38,    42,    48,    71,    83,    84,
+      49,    49,    49,    49,    74,    64,    96,     1,    79,    80,
+      81,    82,    35,    46,    99,    95,     1,    38,    77,    35,
+      77,    96,    34,    48,    45,    47,     1,    42,    83,    83,
+      34,    48,    45,    31,    51,    86,    87,    49,    49,    37,
+      47,    49,    49,     1,    79,    94,    49,    49,     1,    79,
+      35,    37,    82,    49,    49,    49,    49
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -890,17 +895,18 @@ static const yytype_uint8 yystos[] =
 
 #define YYRECOVERING()  (!!yyerrstatus)
 
-#define YYBACKUP(Token, Value)                                 \
-do                                                             \
-  if (yychar == YYEMPTY && yylen == 1)                         \
-    {                                                          \
-      yychar = (Token);                                                \
-      yylval = (Value);                                                \
-      YYPOPSTACK (1);                                          \
-      goto yybackup;                                           \
-    }                                                          \
-  else                                                         \
-    {                                                          \
+#define YYBACKUP(Token, Value)                                  \
+do                                                              \
+  if (yychar == YYEMPTY)                                        \
+    {                                                           \
+      yychar = (Token);                                         \
+      yylval = (Value);                                         \
+      YYPOPSTACK (yylen);                                       \
+      yystate = *yyssp;                                         \
+      goto yybackup;                                            \
+    }                                                           \
+  else                                                          \
+    {                                                           \
       yyerror (YY_("syntax error: cannot back up")); \
       YYERROR;                                                 \
     }                                                          \
@@ -995,6 +1001,8 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
     YYSTYPE const * const yyvaluep;
 #endif
 {
+  FILE *yyo = yyoutput;
+  YYUSE (yyo);
   if (!yyvaluep)
     return;
 # ifdef YYPRINT
@@ -1246,12 +1254,12 @@ static int
 yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
                 yytype_int16 *yyssp, int yytoken)
 {
-  YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+  YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
   YYSIZE_T yysize = yysize0;
   YYSIZE_T yysize1;
   enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
   /* Internationalized format string. */
-  const char *yyformat = 0;
+  const char *yyformat = YY_NULL;
   /* Arguments of yyformat. */
   char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
   /* Number of reported tokens (one for the "unexpected", one per
@@ -1311,7 +1319,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
                     break;
                   }
                 yyarg[yycount++] = yytname[yyx];
-                yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+                yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
                 if (! (yysize <= yysize1
                        && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
                   return 2;
@@ -1463,7 +1471,7 @@ yyparse ()
        `yyss': related to states.
        `yyvs': related to semantic values.
 
-       Refer to the stacks thru separate pointers, to allow yyoverflow
+       Refer to the stacks through separate pointers, to allow yyoverflow
        to reallocate them elsewhere.  */
 
     /* The state stack.  */
@@ -2346,7 +2354,7 @@ yyabortlab:
   yyresult = 1;
   goto yyreturn;
 
-#if !defined(yyoverflow) || YYERROR_VERBOSE
+#if !defined yyoverflow || YYERROR_VERBOSE
 /*-------------------------------------------------.
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
index 93240a3..a4737de 100644 (file)
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.5.  */
+/* A Bison parser, made by GNU Bison 2.5.1.  */
 
 /* Bison interface for Yacc-like parsers in C
    
-      Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+      Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
      EXPORT_SYMBOL_KEYW = 284,
      ASM_PHRASE = 285,
      ATTRIBUTE_PHRASE = 286,
-     BRACE_PHRASE = 287,
-     BRACKET_PHRASE = 288,
-     EXPRESSION_PHRASE = 289,
-     CHAR = 290,
-     DOTS = 291,
-     IDENT = 292,
-     INT = 293,
-     REAL = 294,
-     STRING = 295,
-     TYPE = 296,
-     OTHER = 297,
-     FILENAME = 298
+     TYPEOF_PHRASE = 287,
+     BRACE_PHRASE = 288,
+     BRACKET_PHRASE = 289,
+     EXPRESSION_PHRASE = 290,
+     CHAR = 291,
+     DOTS = 292,
+     IDENT = 293,
+     INT = 294,
+     REAL = 295,
+     STRING = 296,
+     TYPE = 297,
+     OTHER = 298,
+     FILENAME = 299
    };
 #endif
 
index 23c3999..b9f4cf2 100644 (file)
@@ -103,6 +103,7 @@ static void record_compound(struct string_list **keyw,
 
 %token ASM_PHRASE
 %token ATTRIBUTE_PHRASE
+%token TYPEOF_PHRASE
 %token BRACE_PHRASE
 %token BRACKET_PHRASE
 %token EXPRESSION_PHRASE
@@ -220,8 +221,8 @@ storage_class_specifier:
 type_specifier:
        simple_type_specifier
        | cvar_qualifier
-       | TYPEOF_KEYW '(' decl_specifier_seq '*' ')'
-       | TYPEOF_KEYW '(' decl_specifier_seq ')'
+       | TYPEOF_KEYW '(' parameter_declaration ')'
+       | TYPEOF_PHRASE
 
        /* References to s/u/e's defined elsewhere.  Rearrange things
           so that it is easier to expand the definition fully later.  */