Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Dec 2008 23:57:56 +0000 (15:57 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Dec 2008 23:57:56 +0000 (15:57 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (34 commits)
  nfsd race fixes: jfs
  nfsd race fixes: reiserfs
  nfsd race fixes: ext4
  nfsd race fixes: ext3
  nfsd race fixes: ext2
  nfsd/create race fixes, infrastructure
  filesystem notification: create fs/notify to contain all fs notification
  fs/block_dev.c: __read_mostly improvement and sb_is_blkdev_sb utilization
  kill ->dir_notify()
  filp_cachep can be static in fs/file_table.c
  fix f_count description in Documentation/filesystems/files.txt
  make INIT_FS use the __RW_LOCK_UNLOCKED initialization
  take init_fs to saner place
  kill vfs_permission
  pass a struct path * to may_open
  kill walk_init_root
  remove incorrect comment in inode_permission
  expand some comments (d_path / seq_path)
  correct wrong function name of d_put in kernel document and source comment
  fix switch_names() breakage in short-to-short case
  ...

81 files changed:
Documentation/filesystems/Locking
Documentation/filesystems/files.txt
Documentation/filesystems/vfs.txt
arch/alpha/kernel/init_task.c
arch/arm/kernel/init_task.c
arch/avr32/kernel/init_task.c
arch/blackfin/kernel/init_task.c
arch/cris/kernel/process.c
arch/frv/kernel/init_task.c
arch/h8300/kernel/init_task.c
arch/ia64/kernel/init_task.c
arch/m32r/kernel/init_task.c
arch/m68k/kernel/process.c
arch/m68knommu/kernel/init_task.c
arch/mips/kernel/init_task.c
arch/mn10300/kernel/init_task.c
arch/parisc/kernel/init_task.c
arch/powerpc/kernel/init_task.c
arch/powerpc/oprofile/cell/spu_task_sync.c
arch/s390/kernel/init_task.c
arch/sh/kernel/init_task.c
arch/sparc/kernel/init_task.c
arch/um/kernel/init_task.c
arch/x86/kernel/init_task.c
arch/xtensa/kernel/init_task.c
drivers/oprofile/buffer_sync.c
fs/Kconfig
fs/Makefile
fs/bad_inode.c
fs/befs/linuxvfs.c
fs/block_dev.c
fs/cifs/Makefile
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/fcntl.c [deleted file]
fs/dcache.c
fs/dcookies.c
fs/ecryptfs/inode.c
fs/exec.c
fs/ext2/ialloc.c
fs/ext2/inode.c
fs/ext2/namei.c
fs/ext3/ialloc.c
fs/ext3/inode.c
fs/ext3/namei.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/file_table.c
fs/freevxfs/vxfs_inode.c
fs/inode.c
fs/jfs/jfs_inode.c
fs/jfs/namei.c
fs/namei.c
fs/namespace.c
fs/nfsctl.c
fs/notify/Kconfig [new file with mode: 0644]
fs/notify/Makefile [new file with mode: 0644]
fs/notify/dnotify/Kconfig [new file with mode: 0644]
fs/notify/dnotify/Makefile [new file with mode: 0644]
fs/notify/dnotify/dnotify.c [moved from fs/dnotify.c with 98% similarity]
fs/notify/inotify/Kconfig [new file with mode: 0644]
fs/notify/inotify/Makefile [new file with mode: 0644]
fs/notify/inotify/inotify.c [moved from fs/inotify.c with 100% similarity]
fs/notify/inotify/inotify_user.c [moved from fs/inotify_user.c with 100% similarity]
fs/open.c
fs/reiserfs/inode.c
fs/reiserfs/namei.c
fs/seq_file.c
fs/sysv/inode.c
include/linux/dcache.h
include/linux/fdtable.h
include/linux/fs.h
include/linux/fs_struct.h
include/linux/init_task.h
include/linux/namei.h
include/linux/security.h
net/unix/af_unix.c
security/Kconfig
security/capability.c
security/security.c

index 23d2f4460debf2122676e83a6d4c9139df889253..ccec55394380393ccf69a0272078ebd5465ceae3 100644 (file)
@@ -394,7 +394,6 @@ prototypes:
        unsigned long (*get_unmapped_area)(struct file *, unsigned long,
                        unsigned long, unsigned long, unsigned long);
        int (*check_flags)(int);
-       int (*dir_notify)(struct file *, unsigned long);
 };
 
 locking rules:
@@ -424,7 +423,6 @@ sendfile:           no
 sendpage:              no
 get_unmapped_area:     no
 check_flags:           no
-dir_notify:            no
 
 ->llseek() locking has moved from llseek to the individual llseek
 implementations.  If your fs is not using generic_file_llseek, you
index bb0142f6108458f6ccd27b90e965a6bdf820e501..ac2facc50d2a2b2914d10a3268c3ae375ae57d6c 100644 (file)
@@ -76,13 +76,13 @@ the fdtable structure -
 5. Handling of the file structures is special. Since the look-up
    of the fd (fget()/fget_light()) are lock-free, it is possible
    that look-up may race with the last put() operation on the
-   file structure. This is avoided using atomic_inc_not_zero()
+   file structure. This is avoided using atomic_long_inc_not_zero()
    on ->f_count :
 
        rcu_read_lock();
        file = fcheck_files(files, fd);
        if (file) {
-               if (atomic_inc_not_zero(&file->f_count))
+               if (atomic_long_inc_not_zero(&file->f_count))
                        *fput_needed = 1;
                else
                /* Didn't get the reference, someone's freed */
@@ -92,7 +92,7 @@ the fdtable structure -
        ....
        return file;
 
-   atomic_inc_not_zero() detects if refcounts is already zero or
+   atomic_long_inc_not_zero() detects if refcounts is already zero or
    goes to zero during increment. If it does, we fail
    fget()/fget_light().
 
index 5579bda58a6dadc3b793b208e032e1cc6456ad33..ef19afa186a9dd81a973d624940a30c4e5d4bb83 100644 (file)
@@ -733,7 +733,6 @@ struct file_operations {
        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
        unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
        int (*check_flags)(int);
-       int (*dir_notify)(struct file *filp, unsigned long arg);
        int (*flock) (struct file *, int, struct file_lock *);
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int);
        ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int);
@@ -800,8 +799,6 @@ otherwise noted.
 
   check_flags: called by the fcntl(2) system call for F_SETFL command
 
-  dir_notify: called by the fcntl(2) system call for F_NOTIFY command
-
   flock: called by the flock(2) system call
 
   splice_write: called by the VFS to splice data from a pipe to a file. This
@@ -931,7 +928,7 @@ manipulate dentries:
   d_lookup: look up a dentry given its parent and path name component
        It looks up the child of that given name from the dcache
        hash table. If it is found, the reference count is incremented
-       and the dentry is returned. The caller must use d_put()
+       and the dentry is returned. The caller must use dput()
        to free the dentry when it finishes using it.
 
 For further information on dentry locking, please refer to the document
index 1f762189fa64f1f158e6d1d1664cabb14f58264e..c2938e574a40c2de349556430bc83fc0038569c0 100644 (file)
@@ -8,7 +8,6 @@
 #include <asm/uaccess.h>
 
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 0bbf806253954c1ac42c9f8fd634f1b7e5cfe63c..e859af349467420e3107074cfa94f7d993125c70 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 44058469c6ec905c2cad58fca1e315f0b395474c..993d56ee3cf303375a57328680fdc23aa25728f6 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 6bdba7b21109e0872c8589d123439335a1073a50..2c228c020978eee16b8edecc047d12689fb1c016 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/mqueue.h>
 #include <linux/fs.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 
index 5933656db5a2ca58b9a2f583ce5945a57d1b832b..60816e876455112047e21d6191a1a2380aa27dd0 100644 (file)
@@ -37,7 +37,6 @@
  * setup.
  */
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index e2198815b630e5dafd7084ffbac233026fe3ea2f..29429a8b7f6a44b0a6e52629c9b134d0f72317e3 100644 (file)
@@ -10,7 +10,6 @@
 #include <asm/pgtable.h>
 
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 93a4899e46c23d24923920a85d8977448ad4644e..cb5dc552da97899e4f443b40efd5fae50de4f3f1 100644 (file)
@@ -12,7 +12,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 9d7e1c66faf403ecfc154dc7597248892b1f38f8..5b0e830c6f33212d48b28ec74f24113f6c1bc5ef 100644 (file)
@@ -17,7 +17,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 0d658dbb676693f13ef978ae07772951ba75a32c..016885c6f26094b3191fc8f790410d7a99b5c143 100644 (file)
@@ -11,7 +11,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 3042c2bc8c58490083ef4a2718c6a839c4e7e978..632ce016014d27d6190d1776d86ecaa1503aeca6 100644 (file)
@@ -40,7 +40,6 @@
  * alignment requirements and potentially different initial
  * setup.
  */
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 344c01aede08b3e85b1b3f7b0b454ca8ae78d879..fe282de1d596dcb4b93d4077ba8c5fe4c6f3aaee 100644 (file)
@@ -12,7 +12,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index d72487ad7c15526fa79722ad4325c38aa8602ecd..149cd914526e8e2e2d1c407852879cf2111fa822 100644 (file)
@@ -9,7 +9,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index af16f6e5c918870d9545419bcba180fcfe1f9e8f..5ac3566f8c98b62c5a96673665b09f12d5a48696 100644 (file)
@@ -18,7 +18,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index f5941c086551e09c2578821988037dd3628db712..1e25a45d64c17fd48d461489c3f2e950ed29ee53 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 4c85b8d564783b7a695aaad977ddd3c96b2ae197..688b329800bd25f559c75f2ea6f0dcdd22ade3b1 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/mqueue.h>
 #include <asm/uaccess.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 2949126d28d1f8c9f45bef32d45b96df86f959fa..6b793aeda72ea041ac2a68f1ca2e2ece7f46badc 100644 (file)
@@ -297,7 +297,7 @@ static inline unsigned long fast_get_dcookie(struct path *path)
 {
        unsigned long cookie;
 
-       if (path->dentry->d_cookie)
+       if (path->dentry->d_flags & DCACHE_COOKIE)
                return (unsigned long)path->dentry;
        get_dcookie(path, &cookie);
        return cookie;
index e807168436194c81fe0f4892f9be5a7e4bed685b..7db95c0b86938603176baf5496f23338cd455bc2 100644 (file)
@@ -16,7 +16,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index b151a25cb14de25f455e7ec26eebe124a23b2207..80c35ff71d564d524cf01c752efd0618fa868308 100644 (file)
@@ -7,7 +7,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct pt_regs fake_swapper_regs;
index 62126e4cec54c53c2572a93d3bf4055fe22ba709..f28cb8278e98abb6f2fb79c634b2e74e52cfac84 100644 (file)
@@ -8,7 +8,6 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 910eda8fca188526cf564ec0e35c137079e4c339..806d381947bf1c704dc584e5b29360abb7b40a88 100644 (file)
@@ -10,7 +10,6 @@
 #include "linux/mqueue.h"
 #include "asm/uaccess.h"
 
-static struct fs_struct init_fs = INIT_FS;
 struct mm_struct init_mm = INIT_MM(init_mm);
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
index d39918076bb48a4b70e5b911736f84ec817fd420..df3bf269beab96466785764b619bc737fd0f5d55 100644 (file)
@@ -10,7 +10,6 @@
 #include <asm/pgtable.h>
 #include <asm/desc.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 3df469dbe81438c760960cb36a0a4e1d76ff8012..e07f5c9fcd3500727efdd0a734b4cfcf654412fc 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <asm/uaccess.h>
 
-static struct fs_struct init_fs = INIT_FS;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
index 737bd9484822498d9db077640ed7acc0859babb9..65e8294a9e29db35cfcff8a493682804e9dcffe3 100644 (file)
@@ -200,7 +200,7 @@ static inline unsigned long fast_get_dcookie(struct path *path)
 {
        unsigned long cookie;
 
-       if (path->dentry->d_cookie)
+       if (path->dentry->d_flags & DCACHE_COOKIE)
                return (unsigned long)path->dentry;
        get_dcookie(path, &cookie);
        return cookie;
index 522469a7eca391e51f5b0648027785dff24d3569..ff0e81980207a75727d9a845cf8e7fcfbfedd7ec 100644 (file)
@@ -270,44 +270,7 @@ config OCFS2_COMPAT_JBD
 
 endif # BLOCK
 
-config DNOTIFY
-       bool "Dnotify support"
-       default y
-       help
-         Dnotify is a directory-based per-fd file change notification system
-         that uses signals to communicate events to user-space.  There exist
-         superior alternatives, but some applications may still rely on
-         dnotify.
-
-         If unsure, say Y.
-
-config INOTIFY
-       bool "Inotify file change notification support"
-       default y
-       ---help---
-         Say Y here to enable inotify support.  Inotify is a file change
-         notification system and a replacement for dnotify.  Inotify fixes
-         numerous shortcomings in dnotify and introduces several new features
-         including multiple file events, one-shot support, and unmount
-         notification.
-
-         For more information, see <file:Documentation/filesystems/inotify.txt>
-
-         If unsure, say Y.
-
-config INOTIFY_USER
-       bool "Inotify support for userspace"
-       depends on INOTIFY
-       default y
-       ---help---
-         Say Y here to enable inotify support for userspace, including the
-         associated system calls.  Inotify allows monitoring of both files and
-         directories via a single open fd.  Events are read from the file
-         descriptor, which is also select()- and poll()-able.
-
-         For more information, see <file:Documentation/filesystems/inotify.txt>
-
-         If unsure, say Y.
+source "fs/notify/Kconfig"
 
 config QUOTA
        bool "Quota support"
index d9f8afe6f0c4b806ab7af81f8bcbc286758297cd..e6f423d1d228fc449d7f8559f291ca531d518674 100644 (file)
@@ -20,8 +20,7 @@ obj-y +=      no-block.o
 endif
 
 obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o
-obj-$(CONFIG_INOTIFY)          += inotify.o
-obj-$(CONFIG_INOTIFY_USER)     += inotify_user.o
+obj-y                          += notify/
 obj-$(CONFIG_EPOLL)            += eventpoll.o
 obj-$(CONFIG_ANON_INODES)      += anon_inodes.o
 obj-$(CONFIG_SIGNALFD)         += signalfd.o
@@ -57,8 +56,6 @@ obj-$(CONFIG_QFMT_V1)         += quota_v1.o
 obj-$(CONFIG_QFMT_V2)          += quota_v2.o
 obj-$(CONFIG_QUOTACTL)         += quota.o
 
-obj-$(CONFIG_DNOTIFY)          += dnotify.o
-
 obj-$(CONFIG_PROC_FS)          += proc/
 obj-y                          += partitions/
 obj-$(CONFIG_SYSFS)            += sysfs/
index 5f1538c03b1bbeb068c089146cc28fc502bb0d83..a05287a23f62e1d28d66b28dc101b74db3690971 100644 (file)
@@ -132,11 +132,6 @@ static int bad_file_check_flags(int flags)
        return -EIO;
 }
 
-static int bad_file_dir_notify(struct file *file, unsigned long arg)
-{
-       return -EIO;
-}
-
 static int bad_file_flock(struct file *filp, int cmd, struct file_lock *fl)
 {
        return -EIO;
@@ -179,7 +174,6 @@ static const struct file_operations bad_file_ops =
        .sendpage       = bad_file_sendpage,
        .get_unmapped_area = bad_file_get_unmapped_area,
        .check_flags    = bad_file_check_flags,
-       .dir_notify     = bad_file_dir_notify,
        .flock          = bad_file_flock,
        .splice_write   = bad_file_splice_write,
        .splice_read    = bad_file_splice_read,
index b6dfee37c7b71776201aa320ac6e450e00290cd7..d06cb023ad028a000a2f41db1208fa46991d7f47 100644 (file)
@@ -378,7 +378,8 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
                inode->i_size = 0;
                inode->i_blocks = befs_sb->block_size / VFS_BLOCK_SIZE;
                strncpy(befs_ino->i_data.symlink, raw_inode->data.symlink,
-                       BEFS_SYMLINK_LEN);
+                       BEFS_SYMLINK_LEN - 1);
+               befs_ino->i_data.symlink[BEFS_SYMLINK_LEN - 1] = '\0';
        } else {
                int num_blks;
 
@@ -477,6 +478,8 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd)
                        kfree(link);
                        befs_error(sb, "Failed to read entire long symlink");
                        link = ERR_PTR(-EIO);
+               } else {
+                       link[len - 1] = '\0';
                }
        } else {
                link = befs_ino->i_data.symlink;
index 99e0ae1a4c789fff59aae0e32207755e38fa7e41..349a26c10001d929c57c9a54eca0acb164ba8161 100644 (file)
@@ -326,12 +326,13 @@ static struct file_system_type bd_type = {
        .kill_sb        = kill_anon_super,
 };
 
-static struct vfsmount *bd_mnt __read_mostly;
-struct super_block *blockdev_superblock;
+struct super_block *blockdev_superblock __read_mostly;
 
 void __init bdev_cache_init(void)
 {
        int err;
+       struct vfsmount *bd_mnt;
+
        bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),
                        0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
                                SLAB_MEM_SPREAD|SLAB_PANIC),
@@ -373,7 +374,7 @@ struct block_device *bdget(dev_t dev)
        struct block_device *bdev;
        struct inode *inode;
 
-       inode = iget5_locked(bd_mnt->mnt_sb, hash(dev),
+       inode = iget5_locked(blockdev_superblock, hash(dev),
                        bdev_test, bdev_set, &dev);
 
        if (!inode)
@@ -463,7 +464,7 @@ void bd_forget(struct inode *inode)
 
        spin_lock(&bdev_lock);
        if (inode->i_bdev) {
-               if (inode->i_sb != blockdev_superblock)
+               if (!sb_is_blkdev_sb(inode->i_sb))
                        bdev = inode->i_bdev;
                __bd_forget(inode);
        }
index 6ba43fb346fb22ae25c9221e86a3db671273b971..9948c0030e86df5ad020785341f514b814fed5ee 100644 (file)
@@ -5,7 +5,7 @@ obj-$(CONFIG_CIFS) += cifs.o
 
 cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
          link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \
-         md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o \
+         md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o \
          readdir.o ioctl.o sess.o export.o cifsacl.o
 
 cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
index 0005a194a75cd44e12a4226896c2209da42fb05b..13ea53251dcf934518889696e7222286c13aefde 100644 (file)
@@ -747,7 +747,6 @@ const struct file_operations cifs_file_ops = {
 #endif /* CONFIG_CIFS_POSIX */
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-       .dir_notify = cifs_dir_notify,
        .setlease = cifs_setlease,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
 };
@@ -768,7 +767,6 @@ const struct file_operations cifs_file_direct_ops = {
 #endif /* CONFIG_CIFS_POSIX */
        .llseek = cifs_llseek,
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-       .dir_notify = cifs_dir_notify,
        .setlease = cifs_setlease,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
 };
@@ -789,7 +787,6 @@ const struct file_operations cifs_file_nobrl_ops = {
 #endif /* CONFIG_CIFS_POSIX */
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-       .dir_notify = cifs_dir_notify,
        .setlease = cifs_setlease,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
 };
@@ -809,7 +806,6 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
 #endif /* CONFIG_CIFS_POSIX */
        .llseek = cifs_llseek,
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-       .dir_notify = cifs_dir_notify,
        .setlease = cifs_setlease,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
 };
@@ -818,9 +814,6 @@ const struct file_operations cifs_dir_ops = {
        .readdir = cifs_readdir,
        .release = cifs_closedir,
        .read    = generic_read_dir,
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-       .dir_notify = cifs_dir_notify,
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
        .unlocked_ioctl  = cifs_ioctl,
        .llseek = generic_file_llseek,
 };
index 2ce04c73d74e74dfe816d7adb7bb762a7d90b1a7..7ac481841f8726a272068a730235d0cd322bc799 100644 (file)
@@ -76,7 +76,6 @@ extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
 extern const struct file_operations cifs_dir_ops;
 extern int cifs_dir_open(struct inode *inode, struct file *file);
 extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
-extern int cifs_dir_notify(struct file *, unsigned long arg);
 
 /* Functions related to dir entries */
 extern struct dentry_operations cifs_dentry_ops;
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c
deleted file mode 100644 (file)
index 5a57581..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- *   fs/cifs/fcntl.c
- *
- *   vfs operations that deal with the file control API
- *
- *   Copyright (C) International Business Machines  Corp., 2003,2004
- *   Author(s): Steve French (sfrench@us.ibm.com)
- *
- *   This library is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU Lesser General Public License as published
- *   by the Free Software Foundation; either version 2.1 of the License, or
- *   (at your option) any later version.
- *
- *   This library 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 Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public License
- *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include "cifsglob.h"
-#include "cifsproto.h"
-#include "cifs_unicode.h"
-#include "cifs_debug.h"
-#include "cifsfs.h"
-
-static __u32 convert_to_cifs_notify_flags(unsigned long fcntl_notify_flags)
-{
-       __u32 cifs_ntfy_flags = 0;
-
-       /* No way on Linux VFS to ask to monitor xattr
-       changes (and no stream support either */
-       if (fcntl_notify_flags & DN_ACCESS)
-               cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
-       if (fcntl_notify_flags & DN_MODIFY) {
-               /* What does this mean on directories? */
-               cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE |
-                       FILE_NOTIFY_CHANGE_SIZE;
-       }
-       if (fcntl_notify_flags & DN_CREATE) {
-               cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_CREATION |
-                       FILE_NOTIFY_CHANGE_LAST_WRITE;
-       }
-       if (fcntl_notify_flags & DN_DELETE)
-               cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE;
-       if (fcntl_notify_flags & DN_RENAME) {
-               /* BB review this - checking various server behaviors */
-               cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_DIR_NAME |
-                       FILE_NOTIFY_CHANGE_FILE_NAME;
-       }
-       if (fcntl_notify_flags & DN_ATTRIB) {
-               cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_SECURITY |
-                       FILE_NOTIFY_CHANGE_ATTRIBUTES;
-       }
-/*     if (fcntl_notify_flags & DN_MULTISHOT) {
-               cifs_ntfy_flags |= ;
-       } */ /* BB fixme - not sure how to handle this with CIFS yet */
-
-       return cifs_ntfy_flags;
-}
-
-int cifs_dir_notify(struct file *file, unsigned long arg)
-{
-       int xid;
-       int rc = -EINVAL;
-       int oplock = 0;
-       struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *pTcon;
-       char *full_path = NULL;
-       __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES;
-       __u16 netfid;
-
-       if (experimEnabled == 0)
-               return 0;
-
-       xid = GetXid();
-       cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-       pTcon = cifs_sb->tcon;
-
-       full_path = build_path_from_dentry(file->f_path.dentry);
-
-       if (full_path == NULL) {
-               rc = -ENOMEM;
-       } else {
-               cFYI(1, ("dir notify on file %s Arg 0x%lx", full_path, arg));
-               rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
-                       GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
-                       &netfid, &oplock, NULL, cifs_sb->local_nls,
-                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-               /* BB fixme - add this handle to a notify handle list */
-               if (rc) {
-                       cFYI(1, ("Could not open directory for notify"));
-               } else {
-                       filter = convert_to_cifs_notify_flags(arg);
-                       if (filter != 0) {
-                               rc = CIFSSMBNotify(xid, pTcon,
-                                       0 /* no subdirs */, netfid,
-                                       filter, file, arg & DN_MULTISHOT,
-                                       cifs_sb->local_nls);
-                       } else {
-                               rc = -EINVAL;
-                       }
-                       /* BB add code to close file eventually (at unmount
-                       it would close automatically but may be a way
-                       to do it easily when inode freed or when
-                       notify info is cleared/changed */
-                       cFYI(1, ("notify rc %d", rc));
-               }
-       }
-
-       FreeXid(xid);
-       return rc;
-}
index a1d86c7f3e6644c8914edeae67a0ba02b3df6ada..e88c23b85a32d4456bf7741a7f218315189153e1 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/bootmem.h>
 #include "internal.h"
 
-
 int sysctl_vfs_cache_pressure __read_mostly = 100;
 EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
 
@@ -948,9 +947,6 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
        dentry->d_op = NULL;
        dentry->d_fsdata = NULL;
        dentry->d_mounted = 0;
-#ifdef CONFIG_PROFILING
-       dentry->d_cookie = NULL;
-#endif
        INIT_HLIST_NODE(&dentry->d_hash);
        INIT_LIST_HEAD(&dentry->d_lru);
        INIT_LIST_HEAD(&dentry->d_subdirs);
@@ -1336,7 +1332,7 @@ err_out:
  *
  * Searches the children of the parent dentry for the name in question. If
  * the dentry is found its reference count is incremented and the dentry
- * is returned. The caller must use d_put to free the entry when it has
+ * is returned. The caller must use dput to free the entry when it has
  * finished using it. %NULL is returned on failure.
  *
  * __d_lookup is dcache_lock free. The hash list is protected using RCU.
@@ -1620,8 +1616,11 @@ static void switch_names(struct dentry *dentry, struct dentry *target)
                         */
                        memcpy(dentry->d_iname, target->d_name.name,
                                        target->d_name.len + 1);
+                       dentry->d_name.len = target->d_name.len;
+                       return;
                }
        }
+       do_switch(dentry->d_name.len, target->d_name.len);
 }
 
 /*
@@ -1681,7 +1680,6 @@ already_unhashed:
 
        /* Switch the names.. */
        switch_names(dentry, target);
-       do_switch(dentry->d_name.len, target->d_name.len);
        do_switch(dentry->d_name.hash, target->d_name.hash);
 
        /* ... and switch the parents */
@@ -1791,7 +1789,6 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon)
        struct dentry *dparent, *aparent;
 
        switch_names(dentry, anon);
-       do_switch(dentry->d_name.len, anon->d_name.len);
        do_switch(dentry->d_name.hash, anon->d_name.hash);
 
        dparent = dentry->d_parent;
@@ -1911,7 +1908,8 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
  * Convert a dentry into an ASCII path name. If the entry has been deleted
  * the string " (deleted)" is appended. Note that this is ambiguous.
  *
- * Returns the buffer or an error code if the path was too long.
+ * Returns a pointer into the buffer or an error code if the
+ * path was too long.
  *
  * "buflen" should be positive. Caller holds the dcache_lock.
  *
@@ -1987,7 +1985,10 @@ Elong:
  * Convert a dentry into an ASCII path name. If the entry has been deleted
  * the string " (deleted)" is appended. Note that this is ambiguous.
  *
- * Returns the buffer or an error code if the path was too long.
+ * Returns a pointer into the buffer or an error code if the path was
+ * too long. Note: Callers should use the returned pointer, not the passed
+ * in buffer, to use the name! The implementation often starts at an offset
+ * into the buffer, and may leave 0 bytes at the start.
  *
  * "buflen" should be positive.
  */
@@ -2313,9 +2314,6 @@ static void __init dcache_init(void)
 /* SLAB cache for __getname() consumers */
 struct kmem_cache *names_cachep __read_mostly;
 
-/* SLAB cache for file structures */
-struct kmem_cache *filp_cachep __read_mostly;
-
 EXPORT_SYMBOL(d_genocide);
 
 void __init vfs_caches_init_early(void)
@@ -2337,9 +2335,6 @@ void __init vfs_caches_init(unsigned long mempages)
        names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
                        SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 
-       filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
-
        dcache_init();
        inode_init();
        files_init(mempages);
index 855d4b1d619aec6244b182c3669b6efe2ec1f726..180e9fec4ad832763bbf6344ecf74265bc1d144b 100644 (file)
@@ -93,10 +93,15 @@ static struct dcookie_struct *alloc_dcookie(struct path *path)
 {
        struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache,
                                                        GFP_KERNEL);
+       struct dentry *d;
        if (!dcs)
                return NULL;
 
-       path->dentry->d_cookie = dcs;
+       d = path->dentry;
+       spin_lock(&d->d_lock);
+       d->d_flags |= DCACHE_COOKIE;
+       spin_unlock(&d->d_lock);
+
        dcs->path = *path;
        path_get(path);
        hash_dcookie(dcs);
@@ -119,14 +124,14 @@ int get_dcookie(struct path *path, unsigned long *cookie)
                goto out;
        }
 
-       dcs = path->dentry->d_cookie;
-
-       if (!dcs)
+       if (path->dentry->d_flags & DCACHE_COOKIE) {
+               dcs = find_dcookie((unsigned long)path->dentry);
+       } else {
                dcs = alloc_dcookie(path);
-
-       if (!dcs) {
-               err = -ENOMEM;
-               goto out;
+               if (!dcs) {
+                       err = -ENOMEM;
+                       goto out;
+               }
        }
 
        *cookie = dcookie_value(dcs);
@@ -251,7 +256,12 @@ out_kmem:
 
 static void free_dcookie(struct dcookie_struct * dcs)
 {
-       dcs->path.dentry->d_cookie = NULL;
+       struct dentry *d = dcs->path.dentry;
+
+       spin_lock(&d->d_lock);
+       d->d_flags &= ~DCACHE_COOKIE;
+       spin_unlock(&d->d_lock);
+
        path_put(&dcs->path);
        kmem_cache_free(dcookie_cache, dcs);
 }
index 89209f00f9c74ecc752ed944f26ecff6e2f5c974..5e78fc179886e6364f4a0d3a7019ee2d5274d9fb 100644 (file)
@@ -673,10 +673,11 @@ static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
        ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ "
                        "dentry->d_name.name = [%s]\n", dentry->d_name.name);
        rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len);
-       buf[rc] = '\0';
        set_fs(old_fs);
        if (rc < 0)
                goto out_free;
+       else
+               buf[rc] = '\0';
        rc = 0;
        nd_set_link(nd, buf);
        goto out;
index 02d2e120542d76ca26ee233e638749e53bc227f0..dfbf7009fbe78893a9516227629018dea44e85f4 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -127,7 +127,8 @@ asmlinkage long sys_uselib(const char __user * library)
        if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
                goto exit;
 
-       error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN);
+       error = inode_permission(nd.path.dentry->d_inode,
+                                MAY_READ | MAY_EXEC | MAY_OPEN);
        if (error)
                goto exit;
 
@@ -680,7 +681,7 @@ struct file *open_exec(const char *name)
        if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
                goto out_path_put;
 
-       err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN);
+       err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN);
        if (err)
                goto out_path_put;
 
index 8d0add62587020ab8299e33dd8a6b5ac4edae500..c454d5db28a5aef07d2585d3a672bb5310c3fa4b 100644 (file)
@@ -585,7 +585,10 @@ got:
        spin_lock(&sbi->s_next_gen_lock);
        inode->i_generation = sbi->s_next_generation++;
        spin_unlock(&sbi->s_next_gen_lock);
-       insert_inode_hash(inode);
+       if (insert_inode_locked(inode) < 0) {
+               err = -EINVAL;
+               goto fail_drop;
+       }
 
        if (DQUOT_ALLOC_INODE(inode)) {
                err = -EDQUOT;
@@ -612,6 +615,7 @@ fail_drop:
        DQUOT_DROP(inode);
        inode->i_flags |= S_NOQUOTA;
        inode->i_nlink = 0;
+       unlock_new_inode(inode);
        iput(inode);
        return ERR_PTR(err);
 
index 7658b33e2653c5da7eb0c00c8fc7dc12313f7745..02b39a5deb74033d62deb7c5ccd86d96b6ddf9b9 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/buffer_head.h>
 #include <linux/mpage.h>
 #include <linux/fiemap.h>
+#include <linux/namei.h>
 #include "ext2.h"
 #include "acl.h"
 #include "xip.h"
@@ -1286,9 +1287,11 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
                else
                        inode->i_mapping->a_ops = &ext2_aops;
        } else if (S_ISLNK(inode->i_mode)) {
-               if (ext2_inode_is_fast_symlink(inode))
+               if (ext2_inode_is_fast_symlink(inode)) {
                        inode->i_op = &ext2_fast_symlink_inode_operations;
-               else {
+                       nd_terminate_link(ei->i_data, inode->i_size,
+                               sizeof(ei->i_data) - 1);
+               } else {
                        inode->i_op = &ext2_symlink_inode_operations;
                        if (test_opt(inode->i_sb, NOBH))
                                inode->i_mapping->a_ops = &ext2_nobh_aops;
index 2a747252ec1204776d7ba99d9b7147872c060743..90ea17998a7390afa2cb9bb03ffc14d440f6a51e 100644 (file)
@@ -41,9 +41,11 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
        int err = ext2_add_link(dentry, inode);
        if (!err) {
                d_instantiate(dentry, inode);
+               unlock_new_inode(inode);
                return 0;
        }
        inode_dec_link_count(inode);
+       unlock_new_inode(inode);
        iput(inode);
        return err;
 }
@@ -170,6 +172,7 @@ out:
 
 out_fail:
        inode_dec_link_count(inode);
+       unlock_new_inode(inode);
        iput (inode);
        goto out;
 }
@@ -178,6 +181,7 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
        struct dentry *dentry)
 {
        struct inode *inode = old_dentry->d_inode;
+       int err;
 
        if (inode->i_nlink >= EXT2_LINK_MAX)
                return -EMLINK;
@@ -186,7 +190,14 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
        inode_inc_link_count(inode);
        atomic_inc(&inode->i_count);
 
-       return ext2_add_nondir(dentry, inode);
+       err = ext2_add_link(dentry, inode);
+       if (!err) {
+               d_instantiate(dentry, inode);
+               return 0;
+       }
+       inode_dec_link_count(inode);
+       iput(inode);
+       return err;
 }
 
 static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
@@ -222,12 +233,14 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
                goto out_fail;
 
        d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
 out:
        return err;
 
 out_fail:
        inode_dec_link_count(inode);
        inode_dec_link_count(inode);
+       unlock_new_inode(inode);
        iput(inode);
 out_dir:
        inode_dec_link_count(dir);
index 490bd0ed789693dbb65ec6deb318541d06ed3911..5655fbcbd11f564b82c31eea45a6c8fe33b41f58 100644 (file)
@@ -579,7 +579,10 @@ got:
        ext3_set_inode_flags(inode);
        if (IS_DIRSYNC(inode))
                handle->h_sync = 1;
-       insert_inode_hash(inode);
+       if (insert_inode_locked(inode) < 0) {
+               err = -EINVAL;
+               goto fail_drop;
+       }
        spin_lock(&sbi->s_next_gen_lock);
        inode->i_generation = sbi->s_next_generation++;
        spin_unlock(&sbi->s_next_gen_lock);
@@ -627,6 +630,7 @@ fail_drop:
        DQUOT_DROP(inode);
        inode->i_flags |= S_NOQUOTA;
        inode->i_nlink = 0;
+       unlock_new_inode(inode);
        iput(inode);
        brelse(bitmap_bh);
        return ERR_PTR(err);
index f8424ad8997195f0cdd2d2c1c53196f16651d7c8..c4bdccf976b59a6d8988b05273dc4df2162e125e 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/uio.h>
 #include <linux/bio.h>
 #include <linux/fiemap.h>
+#include <linux/namei.h>
 #include "xattr.h"
 #include "acl.h"
 
@@ -2817,9 +2818,11 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
                inode->i_op = &ext3_dir_inode_operations;
                inode->i_fop = &ext3_dir_operations;
        } else if (S_ISLNK(inode->i_mode)) {
-               if (ext3_inode_is_fast_symlink(inode))
+               if (ext3_inode_is_fast_symlink(inode)) {
                        inode->i_op = &ext3_fast_symlink_inode_operations;
-               else {
+                       nd_terminate_link(ei->i_data, inode->i_size,
+                               sizeof(ei->i_data) - 1);
+               } else {
                        inode->i_op = &ext3_symlink_inode_operations;
                        ext3_set_aops(inode);
                }
index 3e5edc92aa0b088071d1711c4bcf620d585e0416..297ea8dfac7cc8a6a65a8be491b9de8ac5346bce 100644 (file)
@@ -1652,9 +1652,11 @@ static int ext3_add_nondir(handle_t *handle,
        if (!err) {
                ext3_mark_inode_dirty(handle, inode);
                d_instantiate(dentry, inode);
+               unlock_new_inode(inode);
                return 0;
        }
        drop_nlink(inode);
+       unlock_new_inode(inode);
        iput(inode);
        return err;
 }
@@ -1765,6 +1767,7 @@ retry:
        dir_block = ext3_bread (handle, inode, 0, 1, &err);
        if (!dir_block) {
                drop_nlink(inode); /* is this nlink == 0? */
+               unlock_new_inode(inode);
                ext3_mark_inode_dirty(handle, inode);
                iput (inode);
                goto out_stop;
@@ -1792,6 +1795,7 @@ retry:
        err = ext3_add_entry (handle, dentry, inode);
        if (err) {
                inode->i_nlink = 0;
+               unlock_new_inode(inode);
                ext3_mark_inode_dirty(handle, inode);
                iput (inode);
                goto out_stop;
@@ -1800,6 +1804,7 @@ retry:
        ext3_update_dx_flag(dir);
        ext3_mark_inode_dirty(handle, dir);
        d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
 out_stop:
        ext3_journal_stop(handle);
        if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
@@ -2174,6 +2179,7 @@ retry:
                                mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
                if (err) {
                        drop_nlink(inode);
+                       unlock_new_inode(inode);
                        ext3_mark_inode_dirty(handle, inode);
                        iput (inode);
                        goto out_stop;
@@ -2221,7 +2227,14 @@ retry:
        inc_nlink(inode);
        atomic_inc(&inode->i_count);
 
-       err = ext3_add_nondir(handle, dentry, inode);
+       err = ext3_add_entry(handle, dentry, inode);
+       if (!err) {
+               ext3_mark_inode_dirty(handle, inode);
+               d_instantiate(dentry, inode);
+       } else {
+               drop_nlink(inode);
+               iput(inode);
+       }
        ext3_journal_stop(handle);
        if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
index 08cac9fcace287e9c9fbd29677a4ba8e84009290..6e6052879aa2af27710993fd8cc367fef5c4fd84 100644 (file)
@@ -826,7 +826,10 @@ got:
        ext4_set_inode_flags(inode);
        if (IS_DIRSYNC(inode))
                handle->h_sync = 1;
-       insert_inode_hash(inode);
+       if (insert_inode_locked(inode) < 0) {
+               err = -EINVAL;
+               goto fail_drop;
+       }
        spin_lock(&sbi->s_next_gen_lock);
        inode->i_generation = sbi->s_next_generation++;
        spin_unlock(&sbi->s_next_gen_lock);
@@ -881,6 +884,7 @@ fail_drop:
        DQUOT_DROP(inode);
        inode->i_flags |= S_NOQUOTA;
        inode->i_nlink = 0;
+       unlock_new_inode(inode);
        iput(inode);
        brelse(bitmap_bh);
        return ERR_PTR(err);
index be21a5ae33cb01261a8fe1ce0e2377654a940d3b..7c3325e0b005e152606f04bb8062fab18ab333ac 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/writeback.h>
 #include <linux/pagevec.h>
 #include <linux/mpage.h>
+#include <linux/namei.h>
 #include <linux/uio.h>
 #include <linux/bio.h>
 #include "ext4_jbd2.h"
@@ -4164,9 +4165,11 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                inode->i_op = &ext4_dir_inode_operations;
                inode->i_fop = &ext4_dir_operations;
        } else if (S_ISLNK(inode->i_mode)) {
-               if (ext4_inode_is_fast_symlink(inode))
+               if (ext4_inode_is_fast_symlink(inode)) {
                        inode->i_op = &ext4_fast_symlink_inode_operations;
-               else {
+                       nd_terminate_link(ei->i_data, inode->i_size,
+                               sizeof(ei->i_data) - 1);
+               } else {
                        inode->i_op = &ext4_symlink_inode_operations;
                        ext4_set_aops(inode);
                }
index 63adcb792988016d642a6e341bcbca2f694b68d1..da98a9012fa587a1583d9d714b888cc6ba321e27 100644 (file)
@@ -1693,9 +1693,11 @@ static int ext4_add_nondir(handle_t *handle,
        if (!err) {
                ext4_mark_inode_dirty(handle, inode);
                d_instantiate(dentry, inode);
+               unlock_new_inode(inode);
                return 0;
        }
        drop_nlink(inode);
+       unlock_new_inode(inode);
        iput(inode);
        return err;
 }
@@ -1830,6 +1832,7 @@ retry:
        if (err) {
 out_clear_inode:
                clear_nlink(inode);
+               unlock_new_inode(inode);
                ext4_mark_inode_dirty(handle, inode);
                iput(inode);
                goto out_stop;
@@ -1838,6 +1841,7 @@ out_clear_inode:
        ext4_update_dx_flag(dir);
        ext4_mark_inode_dirty(handle, dir);
        d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
 out_stop:
        ext4_journal_stop(handle);
        if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
@@ -2212,6 +2216,7 @@ retry:
                                mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
                if (err) {
                        clear_nlink(inode);
+                       unlock_new_inode(inode);
                        ext4_mark_inode_dirty(handle, inode);
                        iput(inode);
                        goto out_stop;
@@ -2262,7 +2267,14 @@ retry:
        ext4_inc_count(handle, inode);
        atomic_inc(&inode->i_count);
 
-       err = ext4_add_nondir(handle, dentry, inode);
+       err = ext4_add_entry(handle, dentry, inode);
+       if (!err) {
+               ext4_mark_inode_dirty(handle, inode);
+               d_instantiate(dentry, inode);
+       } else {
+               drop_nlink(inode);
+               iput(inode);
+       }
        ext4_journal_stop(handle);
        if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
index 0fbcacc3ea754a01e92e2529f7955ea1fcf08c13..bbeeac6efa1a85eca90bd59e85c620022502f3d7 100644 (file)
@@ -32,6 +32,9 @@ struct files_stat_struct files_stat = {
 /* public. Not pretty! */
 __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock);
 
+/* SLAB cache for file structures */
+static struct kmem_cache *filp_cachep __read_mostly;
+
 static struct percpu_counter nr_files __cacheline_aligned_in_smp;
 
 static inline void file_free_rcu(struct rcu_head *head)
@@ -397,7 +400,12 @@ too_bad:
 void __init files_init(unsigned long mempages)
 { 
        int n; 
-       /* One file with associated inode and dcache is very roughly 1K. 
+
+       filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
+                       SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+
+       /*
+        * One file with associated inode and dcache is very roughly 1K.
         * Per default don't use more than 10% of our memory for files. 
         */ 
 
index 9f3f2ceb73f00743f0869e086a2e3cb557065748..03a6ea5e99f776c062b1daad14cffbb7d87cde4b 100644 (file)
@@ -325,8 +325,10 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
                if (!VXFS_ISIMMED(vip)) {
                        ip->i_op = &page_symlink_inode_operations;
                        ip->i_mapping->a_ops = &vxfs_aops;
-               } else
+               } else {
                        ip->i_op = &vxfs_immed_symlink_iops;
+                       vip->vii_immed.vi_immed[ip->i_size] = '\0';
+               }
        } else
                init_special_inode(ip, ip->i_mode, old_decode_dev(vip->vii_rdev));
 
index 098a2443196f20cacd3c1a4c38964646a14c6e74..7de1cda9248911241ead5c5c08f6033956bbe343 100644 (file)
@@ -1032,6 +1032,65 @@ struct inode *iget_locked(struct super_block *sb, unsigned long ino)
 
 EXPORT_SYMBOL(iget_locked);
 
+int insert_inode_locked(struct inode *inode)
+{
+       struct super_block *sb = inode->i_sb;
+       ino_t ino = inode->i_ino;
+       struct hlist_head *head = inode_hashtable + hash(sb, ino);
+       struct inode *old;
+
+       inode->i_state |= I_LOCK|I_NEW;
+       while (1) {
+               spin_lock(&inode_lock);
+               old = find_inode_fast(sb, head, ino);
+               if (likely(!old)) {
+                       hlist_add_head(&inode->i_hash, head);
+                       spin_unlock(&inode_lock);
+                       return 0;
+               }
+               __iget(old);
+               spin_unlock(&inode_lock);
+               wait_on_inode(old);
+               if (unlikely(!hlist_unhashed(&old->i_hash))) {
+                       iput(old);
+                       return -EBUSY;
+               }
+               iput(old);
+       }
+}
+
+EXPORT_SYMBOL(insert_inode_locked);
+
+int insert_inode_locked4(struct inode *inode, unsigned long hashval,
+               int (*test)(struct inode *, void *), void *data)
+{
+       struct super_block *sb = inode->i_sb;
+       struct hlist_head *head = inode_hashtable + hash(sb, hashval);
+       struct inode *old;
+
+       inode->i_state |= I_LOCK|I_NEW;
+
+       while (1) {
+               spin_lock(&inode_lock);
+               old = find_inode(sb, head, test, data);
+               if (likely(!old)) {
+                       hlist_add_head(&inode->i_hash, head);
+                       spin_unlock(&inode_lock);
+                       return 0;
+               }
+               __iget(old);
+               spin_unlock(&inode_lock);
+               wait_on_inode(old);
+               if (unlikely(!hlist_unhashed(&old->i_hash))) {
+                       iput(old);
+                       return -EBUSY;
+               }
+               iput(old);
+       }
+}
+
+EXPORT_SYMBOL(insert_inode_locked4);
+
 /**
  *     __insert_inode_hash - hash an inode
  *     @inode: unhashed inode
index 70022fd1c5399f0b6c85ec0d5ceee8e13269cb0d..d4d142c2edd40be792ab9bf602967ee2f61ea7f8 100644 (file)
@@ -79,7 +79,8 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
        inode = new_inode(sb);
        if (!inode) {
                jfs_warn("ialloc: new_inode returned NULL!");
-               return ERR_PTR(-ENOMEM);
+               rc = -ENOMEM;
+               goto fail;
        }
 
        jfs_inode = JFS_IP(inode);
@@ -89,8 +90,12 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
                jfs_warn("ialloc: diAlloc returned %d!", rc);
                if (rc == -EIO)
                        make_bad_inode(inode);
-               iput(inode);
-               return ERR_PTR(rc);
+               goto fail_put;
+       }
+
+       if (insert_inode_locked(inode) < 0) {
+               rc = -EINVAL;
+               goto fail_unlock;
        }
 
        inode->i_uid = current_fsuid();
@@ -112,11 +117,8 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
         * Allocate inode to quota.
         */
        if (DQUOT_ALLOC_INODE(inode)) {
-               DQUOT_DROP(inode);
-               inode->i_flags |= S_NOQUOTA;
-               inode->i_nlink = 0;
-               iput(inode);
-               return ERR_PTR(-EDQUOT);
+               rc = -EDQUOT;
+               goto fail_drop;
        }
 
        inode->i_mode = mode;
@@ -158,4 +160,15 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
        jfs_info("ialloc returns inode = 0x%p\n", inode);
 
        return inode;
+
+fail_drop:
+       DQUOT_DROP(inode);
+       inode->i_flags |= S_NOQUOTA;
+fail_unlock:
+       inode->i_nlink = 0;
+       unlock_new_inode(inode);
+fail_put:
+       iput(inode);
+fail:
+       return ERR_PTR(rc);
 }
index cc3cedffbfa11d69b4c6b5bb4b4a5ab96e99dc4c..b4de56b851e430e74ac97cefce7b3536a372854e 100644 (file)
@@ -155,7 +155,6 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
        ip->i_fop = &jfs_file_operations;
        ip->i_mapping->a_ops = &jfs_aops;
 
-       insert_inode_hash(ip);
        mark_inode_dirty(ip);
 
        dip->i_ctime = dip->i_mtime = CURRENT_TIME;
@@ -171,9 +170,12 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
        if (rc) {
                free_ea_wmap(ip);
                ip->i_nlink = 0;
+               unlock_new_inode(ip);
                iput(ip);
-       } else
+       } else {
                d_instantiate(dentry, ip);
+               unlock_new_inode(ip);
+       }
 
       out2:
        free_UCSname(&dname);
@@ -289,7 +291,6 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
        ip->i_op = &jfs_dir_inode_operations;
        ip->i_fop = &jfs_dir_operations;
 
-       insert_inode_hash(ip);
        mark_inode_dirty(ip);
 
        /* update parent directory inode */
@@ -306,9 +307,12 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
        if (rc) {
                free_ea_wmap(ip);
                ip->i_nlink = 0;
+               unlock_new_inode(ip);
                iput(ip);
-       } else
+       } else {
                d_instantiate(dentry, ip);
+               unlock_new_inode(ip);
+       }
 
       out2:
        free_UCSname(&dname);
@@ -1019,7 +1023,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
                goto out3;
        }
 
-       insert_inode_hash(ip);
        mark_inode_dirty(ip);
 
        dip->i_ctime = dip->i_mtime = CURRENT_TIME;
@@ -1039,9 +1042,12 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
        if (rc) {
                free_ea_wmap(ip);
                ip->i_nlink = 0;
+               unlock_new_inode(ip);
                iput(ip);
-       } else
+       } else {
                d_instantiate(dentry, ip);
+               unlock_new_inode(ip);
+       }
 
       out2:
        free_UCSname(&dname);
@@ -1399,7 +1405,6 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
        jfs_ip->dev = new_encode_dev(rdev);
        init_special_inode(ip, ip->i_mode, rdev);
 
-       insert_inode_hash(ip);
        mark_inode_dirty(ip);
 
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -1417,9 +1422,12 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
        if (rc) {
                free_ea_wmap(ip);
                ip->i_nlink = 0;
+               unlock_new_inode(ip);
                iput(ip);
-       } else
+       } else {
                d_instantiate(dentry, ip);
+               unlock_new_inode(ip);
+       }
 
       out1:
        free_UCSname(&dname);
index af3783fff1de66ee922411dac7d5ad92811291d7..dd5c9f0bf82994d39020b6b9ad534cc094170ad9 100644 (file)
@@ -226,6 +226,16 @@ int generic_permission(struct inode *inode, int mask,
        return -EACCES;
 }
 
+/**
+ * inode_permission  -  check for access rights to a given inode
+ * @inode:     inode to check permission on
+ * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
+ *
+ * Used to check for read/write/execute permissions on an inode.
+ * We use "fsuid" for this, letting us set arbitrary permissions
+ * for filesystem access without changing the "normal" uids which
+ * are used for other things.
+ */
 int inode_permission(struct inode *inode, int mask)
 {
        int retval;
@@ -247,7 +257,6 @@ int inode_permission(struct inode *inode, int mask)
                        return -EACCES;
        }
 
-       /* Ordinary permission routines do not understand MAY_APPEND. */
        if (inode->i_op && inode->i_op->permission)
                retval = inode->i_op->permission(inode, mask);
        else
@@ -264,21 +273,6 @@ int inode_permission(struct inode *inode, int mask)
                        mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
 }
 
-/**
- * vfs_permission  -  check for access rights to a given path
- * @nd:                lookup result that describes the path
- * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
- *
- * Used to check for read/write/execute permissions on a path.
- * We use "fsuid" for this, letting us set arbitrary permissions
- * for filesystem access without changing the "normal" uids which
- * are used for other things.
- */
-int vfs_permission(struct nameidata *nd, int mask)
-{
-       return inode_permission(nd->path.dentry->d_inode, mask);
-}
-
 /**
  * file_permission  -  check for additional access rights to a given file
  * @file:      file to check access rights for
@@ -289,7 +283,7 @@ int vfs_permission(struct nameidata *nd, int mask)
  *
  * Note:
  *     Do not use this function in new code.  All access checks should
- *     be done using vfs_permission().
+ *     be done using inode_permission().
  */
 int file_permission(struct file *file, int mask)
 {
@@ -527,18 +521,6 @@ out_unlock:
        return result;
 }
 
-/* SMP-safe */
-static __always_inline void
-walk_init_root(const char *name, struct nameidata *nd)
-{
-       struct fs_struct *fs = current->fs;
-
-       read_lock(&fs->lock);
-       nd->path = fs->root;
-       path_get(&fs->root);
-       read_unlock(&fs->lock);
-}
-
 /*
  * Wrapper to retry pathname resolution whenever the underlying
  * file system returns an ESTALE.
@@ -576,9 +558,16 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l
                goto fail;
 
        if (*link == '/') {
+               struct fs_struct *fs = current->fs;
+
                path_put(&nd->path);
-               walk_init_root(link, nd);
+
+               read_lock(&fs->lock);
+               nd->path = fs->root;
+               path_get(&fs->root);
+               read_unlock(&fs->lock);
        }
+
        res = link_path_walk(link, nd);
        if (nd->depth || res || nd->last_type!=LAST_NORM)
                return res;
@@ -859,7 +848,8 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
                nd->flags |= LOOKUP_CONTINUE;
                err = exec_permission_lite(inode);
                if (err == -EAGAIN)
-                       err = vfs_permission(nd, MAY_EXEC);
+                       err = inode_permission(nd->path.dentry->d_inode,
+                                              MAY_EXEC);
                if (err)
                        break;
 
@@ -1493,9 +1483,9 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
        return error;
 }
 
-int may_open(struct nameidata *nd, int acc_mode, int flag)
+int may_open(struct path *path, int acc_mode, int flag)
 {
-       struct dentry *dentry = nd->path.dentry;
+       struct dentry *dentry = path->dentry;
        struct inode *inode = dentry->d_inode;
        int error;
 
@@ -1516,13 +1506,13 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
        if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
                flag &= ~O_TRUNC;
        } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
-               if (nd->path.mnt->mnt_flags & MNT_NODEV)
+               if (path->mnt->mnt_flags & MNT_NODEV)
                        return -EACCES;
 
                flag &= ~O_TRUNC;
        }
 
-       error = vfs_permission(nd, acc_mode);
+       error = inode_permission(inode, acc_mode);
        if (error)
                return error;
        /*
@@ -1556,6 +1546,9 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
                 * Refuse to truncate files with mandatory locks held on them.
                 */
                error = locks_verify_locked(inode);
+               if (!error)
+                       error = security_path_truncate(path, 0,
+                                              ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
                if (!error) {
                        DQUOT_INIT(inode);
 
@@ -1586,14 +1579,18 @@ static int __open_namei_create(struct nameidata *nd, struct path *path,
 
        if (!IS_POSIXACL(dir->d_inode))
                mode &= ~current->fs->umask;
+       error = security_path_mknod(&nd->path, path->dentry, mode, 0);
+       if (error)
+               goto out_unlock;
        error = vfs_create(dir->d_inode, path->dentry, mode, nd);
+out_unlock:
        mutex_unlock(&dir->d_inode->i_mutex);
        dput(nd->path.dentry);
        nd->path.dentry = path->dentry;
        if (error)
                return error;
        /* Don't check for write permission, don't truncate */
-       return may_open(nd, 0, flag & ~O_TRUNC);
+       return may_open(&nd->path, 0, flag & ~O_TRUNC);
 }
 
 /*
@@ -1779,7 +1776,7 @@ ok:
                if (error)
                        goto exit;
        }
-       error = may_open(&nd, acc_mode, flag);
+       error = may_open(&nd.path, acc_mode, flag);
        if (error) {
                if (will_write)
                        mnt_drop_write(nd.path.mnt);
@@ -1999,6 +1996,9 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
        error = mnt_want_write(nd.path.mnt);
        if (error)
                goto out_dput;
+       error = security_path_mknod(&nd.path, dentry, mode, dev);
+       if (error)
+               goto out_drop_write;
        switch (mode & S_IFMT) {
                case 0: case S_IFREG:
                        error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
@@ -2011,6 +2011,7 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
                        error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
                        break;
        }
+out_drop_write:
        mnt_drop_write(nd.path.mnt);
 out_dput:
        dput(dentry);
@@ -2070,7 +2071,11 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode)
        error = mnt_want_write(nd.path.mnt);
        if (error)
                goto out_dput;
+       error = security_path_mkdir(&nd.path, dentry, mode);
+       if (error)
+               goto out_drop_write;
        error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
+out_drop_write:
        mnt_drop_write(nd.path.mnt);
 out_dput:
        dput(dentry);
@@ -2180,7 +2185,11 @@ static long do_rmdir(int dfd, const char __user *pathname)
        error = mnt_want_write(nd.path.mnt);
        if (error)
                goto exit3;
+       error = security_path_rmdir(&nd.path, dentry);
+       if (error)
+               goto exit4;
        error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
+exit4:
        mnt_drop_write(nd.path.mnt);
 exit3:
        dput(dentry);
@@ -2265,7 +2274,11 @@ static long do_unlinkat(int dfd, const char __user *pathname)
                error = mnt_want_write(nd.path.mnt);
                if (error)
                        goto exit2;
+               error = security_path_unlink(&nd.path, dentry);
+               if (error)
+                       goto exit3;
                error = vfs_unlink(nd.path.dentry->d_inode, dentry);
+exit3:
                mnt_drop_write(nd.path.mnt);
        exit2:
                dput(dentry);
@@ -2346,7 +2359,11 @@ asmlinkage long sys_symlinkat(const char __user *oldname,
        error = mnt_want_write(nd.path.mnt);
        if (error)
                goto out_dput;
+       error = security_path_symlink(&nd.path, dentry, from);
+       if (error)
+               goto out_drop_write;
        error = vfs_symlink(nd.path.dentry->d_inode, dentry, from);
+out_drop_write:
        mnt_drop_write(nd.path.mnt);
 out_dput:
        dput(dentry);
@@ -2443,7 +2460,11 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
        error = mnt_want_write(nd.path.mnt);
        if (error)
                goto out_dput;
+       error = security_path_link(old_path.dentry, &nd.path, new_dentry);
+       if (error)
+               goto out_drop_write;
        error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
+out_drop_write:
        mnt_drop_write(nd.path.mnt);
 out_dput:
        dput(new_dentry);
@@ -2679,8 +2700,13 @@ asmlinkage long sys_renameat(int olddfd, const char __user *oldname,
        error = mnt_want_write(oldnd.path.mnt);
        if (error)
                goto exit5;
+       error = security_path_rename(&oldnd.path, old_dentry,
+                                    &newnd.path, new_dentry);
+       if (error)
+               goto exit6;
        error = vfs_rename(old_dir->d_inode, old_dentry,
                                   new_dir->d_inode, new_dentry);
+exit6:
        mnt_drop_write(oldnd.path.mnt);
 exit5:
        dput(new_dentry);
@@ -2750,13 +2776,16 @@ int vfs_follow_link(struct nameidata *nd, const char *link)
 /* get the link contents into pagecache */
 static char *page_getlink(struct dentry * dentry, struct page **ppage)
 {
-       struct page * page;
+       char *kaddr;
+       struct page *page;
        struct address_space *mapping = dentry->d_inode->i_mapping;
        page = read_mapping_page(mapping, 0, NULL);
        if (IS_ERR(page))
                return (char*)page;
        *ppage = page;
-       return kmap(page);
+       kaddr = kmap(page);
+       nd_terminate_link(kaddr, dentry->d_inode->i_size, PAGE_SIZE - 1);
+       return kaddr;
 }
 
 int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
@@ -2849,7 +2878,6 @@ EXPORT_SYMBOL(path_lookup);
 EXPORT_SYMBOL(kern_path);
 EXPORT_SYMBOL(vfs_path_lookup);
 EXPORT_SYMBOL(inode_permission);
-EXPORT_SYMBOL(vfs_permission);
 EXPORT_SYMBOL(file_permission);
 EXPORT_SYMBOL(unlock_rename);
 EXPORT_SYMBOL(vfs_create);
@@ -2865,3 +2893,10 @@ EXPORT_SYMBOL(vfs_symlink);
 EXPORT_SYMBOL(vfs_unlink);
 EXPORT_SYMBOL(dentry_unhash);
 EXPORT_SYMBOL(generic_readlink);
+
+/* to be mentioned only in INIT_TASK */
+struct fs_struct init_fs = {
+       .count          = ATOMIC_INIT(1),
+       .lock           = __RW_LOCK_UNLOCKED(init_fs.lock),
+       .umask          = 0022,
+};
index 1c09cab8f7cf7c4faea9b1e0e4aa8fc6382824c4..a40685d800a84395db6c585bc55bb01b3e20ce0e 100644 (file)
@@ -1990,7 +1990,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
        if (!new_ns->root) {
                up_write(&namespace_sem);
                kfree(new_ns);
-               return ERR_PTR(-ENOMEM);;
+               return ERR_PTR(-ENOMEM);
        }
        spin_lock(&vfsmount_lock);
        list_add_tail(&new_ns->list, &new_ns->root->mnt_list);
index b1acbd6ab6fb07c857b910f518a53736d8bd3631..b27451909dff0d17b2f148adad84f964214bac83 100644 (file)
@@ -38,9 +38,10 @@ static struct file *do_open(char *name, int flags)
                return ERR_PTR(error);
 
        if (flags == O_RDWR)
-               error = may_open(&nd,MAY_READ|MAY_WRITE,FMODE_READ|FMODE_WRITE);
+               error = may_open(&nd.path, MAY_READ|MAY_WRITE,
+                                          FMODE_READ|FMODE_WRITE);
        else
-               error = may_open(&nd, MAY_WRITE, FMODE_WRITE);
+               error = may_open(&nd.path, MAY_WRITE, FMODE_WRITE);
 
        if (!error)
                return dentry_open(nd.path.dentry, nd.path.mnt, flags,
diff --git a/fs/notify/Kconfig b/fs/notify/Kconfig
new file mode 100644 (file)
index 0000000..50914d7
--- /dev/null
@@ -0,0 +1,2 @@
+source "fs/notify/dnotify/Kconfig"
+source "fs/notify/inotify/Kconfig"
diff --git a/fs/notify/Makefile b/fs/notify/Makefile
new file mode 100644 (file)
index 0000000..5a95b60
--- /dev/null
@@ -0,0 +1,2 @@
+obj-y                  += dnotify/
+obj-y                  += inotify/
diff --git a/fs/notify/dnotify/Kconfig b/fs/notify/dnotify/Kconfig
new file mode 100644 (file)
index 0000000..26adf5d
--- /dev/null
@@ -0,0 +1,10 @@
+config DNOTIFY
+       bool "Dnotify support"
+       default y
+       help
+         Dnotify is a directory-based per-fd file change notification system
+         that uses signals to communicate events to user-space.  There exist
+         superior alternatives, but some applications may still rely on
+         dnotify.
+
+         If unsure, say Y.
diff --git a/fs/notify/dnotify/Makefile b/fs/notify/dnotify/Makefile
new file mode 100644 (file)
index 0000000..f145251
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_DNOTIFY)          += dnotify.o
similarity index 98%
rename from fs/dnotify.c
rename to fs/notify/dnotify/dnotify.c
index 676073b8dda57659202b123dde8adb90e0fb416b..b0aa2cde80bd8f2e44df93d828c29df7abe473a7 100644 (file)
@@ -115,9 +115,6 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
        dn->dn_next = inode->i_dnotify;
        inode->i_dnotify = dn;
        spin_unlock(&inode->i_lock);
-
-       if (filp->f_op && filp->f_op->dir_notify)
-               return filp->f_op->dir_notify(filp, arg);
        return 0;
 
 out_free:
diff --git a/fs/notify/inotify/Kconfig b/fs/notify/inotify/Kconfig
new file mode 100644 (file)
index 0000000..4467928
--- /dev/null
@@ -0,0 +1,27 @@
+config INOTIFY
+       bool "Inotify file change notification support"
+       default y
+       ---help---
+         Say Y here to enable inotify support.  Inotify is a file change
+         notification system and a replacement for dnotify.  Inotify fixes
+         numerous shortcomings in dnotify and introduces several new features
+         including multiple file events, one-shot support, and unmount
+         notification.
+
+         For more information, see <file:Documentation/filesystems/inotify.txt>
+
+         If unsure, say Y.
+
+config INOTIFY_USER
+       bool "Inotify support for userspace"
+       depends on INOTIFY
+       default y
+       ---help---
+         Say Y here to enable inotify support for userspace, including the
+         associated system calls.  Inotify allows monitoring of both files and
+         directories via a single open fd.  Events are read from the file
+         descriptor, which is also select()- and poll()-able.
+
+         For more information, see <file:Documentation/filesystems/inotify.txt>
+
+         If unsure, say Y.
diff --git a/fs/notify/inotify/Makefile b/fs/notify/inotify/Makefile
new file mode 100644 (file)
index 0000000..e290f3b
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_INOTIFY)          += inotify.o
+obj-$(CONFIG_INOTIFY_USER)     += inotify_user.o
similarity index 100%
rename from fs/inotify.c
rename to fs/notify/inotify/inotify.c
similarity index 100%
rename from fs/inotify_user.c
rename to fs/notify/inotify/inotify_user.c
index e2425bbd871f8bc5cd2fd80e962d5638f28e5832..400f8064a548cc7777ca605db6477fc4b2379891 100644 (file)
@@ -76,10 +76,10 @@ struct inotify_device {
        struct mutex            ev_mutex;       /* protects event queue */
        struct mutex            up_mutex;       /* synchronizes watch updates */
        struct list_head        events;         /* list of queued events */
-       atomic_t                count;          /* reference count */
        struct user_struct      *user;          /* user who opened this dev */
        struct inotify_handle   *ih;            /* inotify handle */
        struct fasync_struct    *fa;            /* async notification */
+       atomic_t                count;          /* reference count */
        unsigned int            queue_size;     /* size of the queue (bytes) */
        unsigned int            event_count;    /* number of pending events */
        unsigned int            max_events;     /* maximum number of events */
index c0a426d5766cfb451434b8555be388b9bddd8d47..1cd7d40e99915df06a996f4b738401f663544442 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -272,6 +272,8 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
                goto put_write_and_out;
 
        error = locks_verify_truncate(inode, NULL, length);
+       if (!error)
+               error = security_path_truncate(&path, length, 0);
        if (!error) {
                DQUOT_INIT(inode);
                error = do_truncate(path.dentry, length, 0, NULL);
@@ -328,6 +330,9 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
                goto out_putf;
 
        error = locks_verify_truncate(inode, file, length);
+       if (!error)
+               error = security_path_truncate(&file->f_path, length,
+                                              ATTR_MTIME|ATTR_CTIME);
        if (!error)
                error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
 out_putf:
index 6c4c2c69449f6bc74dddf5c42a0daea09ccf6adf..145c2d3e5e0107a911e0127ba4f65a1a75d2c903 100644 (file)
@@ -1753,6 +1753,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
                       struct inode *inode)
 {
        struct super_block *sb;
+       struct reiserfs_iget_args args;
        INITIALIZE_PATH(path_to_key);
        struct cpu_key key;
        struct item_head ih;
@@ -1780,6 +1781,14 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
                err = -ENOMEM;
                goto out_bad_inode;
        }
+       args.objectid = inode->i_ino = le32_to_cpu(ih.ih_key.k_objectid);
+       memcpy(INODE_PKEY(inode), &(ih.ih_key), KEY_SIZE);
+       args.dirid = le32_to_cpu(ih.ih_key.k_dir_id);
+       if (insert_inode_locked4(inode, args.objectid,
+                            reiserfs_find_actor, &args) < 0) {
+               err = -EINVAL;
+               goto out_bad_inode;
+       }
        if (old_format_only(sb))
                /* not a perfect generation count, as object ids can be reused, but 
                 ** this is as good as reiserfs can do right now.
@@ -1859,13 +1868,9 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
        } else {
                inode2sd(&sd, inode, inode->i_size);
        }
-       // these do not go to on-disk stat data
-       inode->i_ino = le32_to_cpu(ih.ih_key.k_objectid);
-
        // store in in-core inode the key of stat data and version all
        // object items will have (directory items will have old offset
        // format, other new objects will consist of new items)
-       memcpy(INODE_PKEY(inode), &(ih.ih_key), KEY_SIZE);
        if (old_format_only(sb) || S_ISDIR(mode) || S_ISLNK(mode))
                set_inode_item_key_version(inode, KEY_FORMAT_3_5);
        else
@@ -1929,7 +1934,6 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
                reiserfs_mark_inode_private(inode);
        }
 
-       insert_inode_hash(inode);
        reiserfs_update_sd(th, inode);
        reiserfs_check_path(&path_to_key);
 
@@ -1956,6 +1960,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
       out_inserted_sd:
        inode->i_nlink = 0;
        th->t_trans_id = 0;     /* so the caller can't use this handle later */
+       unlock_new_inode(inode); /* OK to do even if we hadn't locked it */
 
        /* If we were inheriting an ACL, we need to release the lock so that
         * iput doesn't deadlock in reiserfs_delete_xattrs. The locking
index 4f322e5ed8405f63e3f980256de23b9acc2c9849..738967f6c8eec38229c30935dfb028eb120f66d1 100644 (file)
@@ -646,6 +646,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
                err = journal_end(&th, dir->i_sb, jbegin_count);
                if (err)
                        retval = err;
+               unlock_new_inode(inode);
                iput(inode);
                goto out_failed;
        }
@@ -653,6 +654,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
        reiserfs_update_inode_transaction(dir);
 
        d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
        retval = journal_end(&th, dir->i_sb, jbegin_count);
 
       out_failed:
@@ -727,11 +729,13 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
                err = journal_end(&th, dir->i_sb, jbegin_count);
                if (err)
                        retval = err;
+               unlock_new_inode(inode);
                iput(inode);
                goto out_failed;
        }
 
        d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
        retval = journal_end(&th, dir->i_sb, jbegin_count);
 
       out_failed:
@@ -812,6 +816,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                err = journal_end(&th, dir->i_sb, jbegin_count);
                if (err)
                        retval = err;
+               unlock_new_inode(inode);
                iput(inode);
                goto out_failed;
        }
@@ -819,6 +824,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        reiserfs_update_sd(&th, dir);
 
        d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
        retval = journal_end(&th, dir->i_sb, jbegin_count);
       out_failed:
        if (locked)
@@ -1096,11 +1102,13 @@ static int reiserfs_symlink(struct inode *parent_dir,
                err = journal_end(&th, parent_dir->i_sb, jbegin_count);
                if (err)
                        retval = err;
+               unlock_new_inode(inode);
                iput(inode);
                goto out_failed;
        }
 
        d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
        retval = journal_end(&th, parent_dir->i_sb, jbegin_count);
       out_failed:
        reiserfs_write_unlock(parent_dir->i_sb);
index 16c211558c2253f38b51af2f9eca76a2d52cb19f..99d8b8cfc9b78673e1040d0e690f33cf43361bdf 100644 (file)
@@ -389,8 +389,14 @@ char *mangle_path(char *s, char *p, char *esc)
 }
 EXPORT_SYMBOL(mangle_path);
 
-/*
- * return the absolute path of 'dentry' residing in mount 'mnt'.
+/**
+ * seq_path - seq_file interface to print a pathname
+ * @m: the seq_file handle
+ * @path: the struct path to print
+ * @esc: set of characters to escape in the output
+ *
+ * return the absolute path of 'path', as represented by the
+ * dentry / mnt pair in the path parameter.
  */
 int seq_path(struct seq_file *m, struct path *path, char *esc)
 {
index df0d435baa48da3088b16cad08d982c329bc1227..3d81bf58dae2d5ebef8f430914d3cc06d5bb9302 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/init.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
+#include <linux/namei.h>
 #include <asm/byteorder.h>
 #include "sysv.h"
 
@@ -163,8 +164,11 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
                if (inode->i_blocks) {
                        inode->i_op = &sysv_symlink_inode_operations;
                        inode->i_mapping->a_ops = &sysv_aops;
-               } else
+               } else {
                        inode->i_op = &sysv_fast_symlink_inode_operations;
+                       nd_terminate_link(SYSV_I(inode)->i_data, inode->i_size,
+                               sizeof(SYSV_I(inode)->i_data) - 1);
+               }
        } else
                init_special_inode(inode, inode->i_mode, rdev);
 }
index a37359d0bad11613d7baa9ee0401fa79106c5576..c66d22487bf8c53e7dfb0ee6c34b8cbe726cae56 100644 (file)
@@ -75,14 +75,22 @@ full_name_hash(const unsigned char *name, unsigned int len)
        return end_name_hash(hash);
 }
 
-struct dcookie_struct;
-
-#define DNAME_INLINE_LEN_MIN 36
+/*
+ * Try to keep struct dentry aligned on 64 byte cachelines (this will
+ * give reasonable cacheline footprint with larger lines without the
+ * large memory footprint increase).
+ */
+#ifdef CONFIG_64BIT
+#define DNAME_INLINE_LEN_MIN 32 /* 192 bytes */
+#else
+#define DNAME_INLINE_LEN_MIN 40 /* 128 bytes */
+#endif
 
 struct dentry {
        atomic_t d_count;
        unsigned int d_flags;           /* protected by d_lock */
        spinlock_t d_lock;              /* per dentry lock */
+       int d_mounted;
        struct inode *d_inode;          /* Where the name belongs to - NULL is
                                         * negative */
        /*
@@ -107,10 +115,7 @@ struct dentry {
        struct dentry_operations *d_op;
        struct super_block *d_sb;       /* The root of the dentry tree */
        void *d_fsdata;                 /* fs-specific data */
-#ifdef CONFIG_PROFILING
-       struct dcookie_struct *d_cookie; /* cookie, if any */
-#endif
-       int d_mounted;
+
        unsigned char d_iname[DNAME_INLINE_LEN_MIN];    /* small names */
 };
 
@@ -177,6 +182,8 @@ d_iput:             no              no              no       yes
 
 #define DCACHE_INOTIFY_PARENT_WATCHED  0x0020 /* Parent inode is watched */
 
+#define DCACHE_COOKIE          0x0040  /* For use by dcookie subsystem */
+
 extern spinlock_t dcache_lock;
 extern seqlock_t rename_lock;
 
index 4aab6f12cfab1cb32a13c220916a9710cb42cb7d..09d6c5bbdddd50c9ba4248dc30e023c936c2404b 100644 (file)
@@ -57,8 +57,6 @@ struct files_struct {
 
 #define files_fdtable(files) (rcu_dereference((files)->fdt))
 
-extern struct kmem_cache *filp_cachep;
-
 struct file_operations;
 struct vfsmount;
 struct dentry;
index 001ded4845b4b9d4e1a5105fbbb1682d7961efca..e2170ee21e185bbfe6d4a7c4b3605402e634eca2 100644 (file)
@@ -21,7 +21,6 @@
 
 /* Fixed constants first: */
 #undef NR_OPEN
-extern int sysctl_nr_open;
 #define INR_OPEN 1024          /* Initial setting for nfile rlimits */
 
 #define BLOCK_SIZE_BITS 10
@@ -38,21 +37,13 @@ struct files_stat_struct {
        int nr_free_files;      /* read only */
        int max_files;          /* tunable */
 };
-extern struct files_stat_struct files_stat;
-extern int get_max_files(void);
 
 struct inodes_stat_t {
        int nr_inodes;
        int nr_unused;
        int dummy[5];           /* padding for sysctl ABI compatibility */
 };
-extern struct inodes_stat_t inodes_stat;
 
-extern int leases_enable, lease_break_time;
-
-#ifdef CONFIG_DNOTIFY
-extern int dir_notify_enable;
-#endif
 
 #define NR_FILE  8192  /* this can well be larger on a larger system */
 
@@ -330,6 +321,15 @@ extern void __init inode_init(void);
 extern void __init inode_init_early(void);
 extern void __init files_init(unsigned long);
 
+extern struct files_stat_struct files_stat;
+extern int get_max_files(void);
+extern int sysctl_nr_open;
+extern struct inodes_stat_t inodes_stat;
+extern int leases_enable, lease_break_time;
+#ifdef CONFIG_DNOTIFY
+extern int dir_notify_enable;
+#endif
+
 struct buffer_head;
 typedef int (get_block_t)(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh_result, int create);
@@ -1212,7 +1212,6 @@ extern void unlock_super(struct super_block *);
 /*
  * VFS helper functions..
  */
-extern int vfs_permission(struct nameidata *, int);
 extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
 extern int vfs_mkdir(struct inode *, struct dentry *, int);
 extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
@@ -1310,7 +1309,6 @@ struct file_operations {
        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
        unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
        int (*check_flags)(int);
-       int (*dir_notify)(struct file *filp, unsigned long arg);
        int (*flock) (struct file *, int, struct file_lock *);
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
        ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
@@ -1869,7 +1867,7 @@ extern void free_write_pipe(struct file *);
 
 extern struct file *do_filp_open(int dfd, const char *pathname,
                int open_flag, int mode);
-extern int may_open(struct nameidata *, int, int);
+extern int may_open(struct path *, int, int);
 
 extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
 extern struct file * open_exec(const char *);
@@ -1904,6 +1902,8 @@ extern struct inode *ilookup(struct super_block *sb, unsigned long ino);
 
 extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *);
 extern struct inode * iget_locked(struct super_block *, unsigned long);
+extern int insert_inode_locked4(struct inode *, unsigned long, int (*test)(struct inode *, void *), void *);
+extern int insert_inode_locked(struct inode *);
 extern void unlock_new_inode(struct inode *);
 
 extern void __iget(struct inode * inode);
index 9e5a06e78d0290870a5504e0ba277de476beae5a..a97c053d3a9ae2b9063da2b67c374be3145fd05a 100644 (file)
@@ -10,12 +10,6 @@ struct fs_struct {
        struct path root, pwd;
 };
 
-#define INIT_FS {                              \
-       .count          = ATOMIC_INIT(1),       \
-       .lock           = RW_LOCK_UNLOCKED,     \
-       .umask          = 0022, \
-}
-
 extern struct kmem_cache *fs_cachep;
 
 extern void exit_fs(struct task_struct *);
index 959f5522d10aab9cde46808f1449eeeed3c0fb4e..2f3c2d4ef73b1b0df8b4e96998a9021480d5706e 100644 (file)
@@ -12,6 +12,7 @@
 #include <net/net_namespace.h>
 
 extern struct files_struct init_files;
+extern struct fs_struct init_fs;
 
 #define INIT_KIOCTX(name, which_mm) \
 {                                                      \
index 99eb80306dc5bba4fab74b9a1693222209d619ea..fc2e035798776a5f65a813a4c1cf55778d2d700e 100644 (file)
@@ -94,4 +94,9 @@ static inline char *nd_get_link(struct nameidata *nd)
        return nd->saved_names[nd->depth];
 }
 
+static inline void nd_terminate_link(void *name, size_t len, size_t maxlen)
+{
+       ((char *) name)[min(len, maxlen)] = '\0';
+}
+
 #endif /* _LINUX_NAMEI_H */
index 3416cb85e77becc52a5c702904d4cc51bdbcdfbe..b92b5e453f64c4690c2abe07194cdf653a95d60a 100644 (file)
@@ -335,17 +335,37 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @dir contains the inode structure of the parent directory of the new link.
  *     @new_dentry contains the dentry structure for the new link.
  *     Return 0 if permission is granted.
+ * @path_link:
+ *     Check permission before creating a new hard link to a file.
+ *     @old_dentry contains the dentry structure for an existing link
+ *     to the file.
+ *     @new_dir contains the path structure of the parent directory of
+ *     the new link.
+ *     @new_dentry contains the dentry structure for the new link.
+ *     Return 0 if permission is granted.
  * @inode_unlink:
  *     Check the permission to remove a hard link to a file.
  *     @dir contains the inode structure of parent directory of the file.
  *     @dentry contains the dentry structure for file to be unlinked.
  *     Return 0 if permission is granted.
+ * @path_unlink:
+ *     Check the permission to remove a hard link to a file.
+ *     @dir contains the path structure of parent directory of the file.
+ *     @dentry contains the dentry structure for file to be unlinked.
+ *     Return 0 if permission is granted.
  * @inode_symlink:
  *     Check the permission to create a symbolic link to a file.
  *     @dir contains the inode structure of parent directory of the symbolic link.
  *     @dentry contains the dentry structure of the symbolic link.
  *     @old_name contains the pathname of file.
  *     Return 0 if permission is granted.
+ * @path_symlink:
+ *     Check the permission to create a symbolic link to a file.
+ *     @dir contains the path structure of parent directory of
+ *     the symbolic link.
+ *     @dentry contains the dentry structure of the symbolic link.
+ *     @old_name contains the pathname of file.
+ *     Return 0 if permission is granted.
  * @inode_mkdir:
  *     Check permissions to create a new directory in the existing directory
  *     associated with inode strcture @dir.
@@ -353,11 +373,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @dentry contains the dentry structure of new directory.
  *     @mode contains the mode of new directory.
  *     Return 0 if permission is granted.
+ * @path_mkdir:
+ *     Check permissions to create a new directory in the existing directory
+ *     associated with path strcture @path.
+ *     @dir containst the path structure of parent of the directory
+ *     to be created.
+ *     @dentry contains the dentry structure of new directory.
+ *     @mode contains the mode of new directory.
+ *     Return 0 if permission is granted.
  * @inode_rmdir:
  *     Check the permission to remove a directory.
  *     @dir contains the inode structure of parent of the directory to be removed.
  *     @dentry contains the dentry structure of directory to be removed.
  *     Return 0 if permission is granted.
+ * @path_rmdir:
+ *     Check the permission to remove a directory.
+ *     @dir contains the path structure of parent of the directory to be
+ *     removed.
+ *     @dentry contains the dentry structure of directory to be removed.
+ *     Return 0 if permission is granted.
  * @inode_mknod:
  *     Check permissions when creating a special file (or a socket or a fifo
  *     file created via the mknod system call).  Note that if mknod operation
@@ -368,6 +402,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @mode contains the mode of the new file.
  *     @dev contains the device number.
  *     Return 0 if permission is granted.
+ * @path_mknod:
+ *     Check permissions when creating a file. Note that this hook is called
+ *     even if mknod operation is being done for a regular file.
+ *     @dir contains the path structure of parent of the new file.
+ *     @dentry contains the dentry structure of the new file.
+ *     @mode contains the mode of the new file.
+ *     @dev contains the undecoded device number. Use new_decode_dev() to get
+ *     the decoded device number.
+ *     Return 0 if permission is granted.
  * @inode_rename:
  *     Check for permission to rename a file or directory.
  *     @old_dir contains the inode structure for parent of the old link.
@@ -375,6 +418,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @new_dir contains the inode structure for parent of the new link.
  *     @new_dentry contains the dentry structure of the new link.
  *     Return 0 if permission is granted.
+ * @path_rename:
+ *     Check for permission to rename a file or directory.
+ *     @old_dir contains the path structure for parent of the old link.
+ *     @old_dentry contains the dentry structure of the old link.
+ *     @new_dir contains the path structure for parent of the new link.
+ *     @new_dentry contains the dentry structure of the new link.
+ *     Return 0 if permission is granted.
  * @inode_readlink:
  *     Check the permission to read the symbolic link.
  *     @dentry contains the dentry structure for the file link.
@@ -403,6 +453,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @dentry contains the dentry structure for the file.
  *     @attr is the iattr structure containing the new file attributes.
  *     Return 0 if permission is granted.
+ * @path_truncate:
+ *     Check permission before truncating a file.
+ *     @path contains the path structure for the file.
+ *     @length is the new length of the file.
+ *     @time_attrs is the flags passed to do_truncate().
+ *     Return 0 if permission is granted.
  * @inode_getattr:
  *     Check permission before obtaining file attributes.
  *     @mnt is the vfsmount where the dentry was looked up
@@ -1331,6 +1387,22 @@ struct security_operations {
                                   struct super_block *newsb);
        int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
 
+#ifdef CONFIG_SECURITY_PATH
+       int (*path_unlink) (struct path *dir, struct dentry *dentry);
+       int (*path_mkdir) (struct path *dir, struct dentry *dentry, int mode);
+       int (*path_rmdir) (struct path *dir, struct dentry *dentry);
+       int (*path_mknod) (struct path *dir, struct dentry *dentry, int mode,
+                          unsigned int dev);
+       int (*path_truncate) (struct path *path, loff_t length,
+                             unsigned int time_attrs);
+       int (*path_symlink) (struct path *dir, struct dentry *dentry,
+                            const char *old_name);
+       int (*path_link) (struct dentry *old_dentry, struct path *new_dir,
+                         struct dentry *new_dentry);
+       int (*path_rename) (struct path *old_dir, struct dentry *old_dentry,
+                           struct path *new_dir, struct dentry *new_dentry);
+#endif
+
        int (*inode_alloc_security) (struct inode *inode);
        void (*inode_free_security) (struct inode *inode);
        int (*inode_init_security) (struct inode *inode, struct inode *dir,
@@ -2705,6 +2777,71 @@ static inline void security_skb_classify_flow(struct sk_buff *skb, struct flowi
 
 #endif /* CONFIG_SECURITY_NETWORK_XFRM */
 
+#ifdef CONFIG_SECURITY_PATH
+int security_path_unlink(struct path *dir, struct dentry *dentry);
+int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode);
+int security_path_rmdir(struct path *dir, struct dentry *dentry);
+int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
+                       unsigned int dev);
+int security_path_truncate(struct path *path, loff_t length,
+                          unsigned int time_attrs);
+int security_path_symlink(struct path *dir, struct dentry *dentry,
+                         const char *old_name);
+int security_path_link(struct dentry *old_dentry, struct path *new_dir,
+                      struct dentry *new_dentry);
+int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
+                        struct path *new_dir, struct dentry *new_dentry);
+#else  /* CONFIG_SECURITY_PATH */
+static inline int security_path_unlink(struct path *dir, struct dentry *dentry)
+{
+       return 0;
+}
+
+static inline int security_path_mkdir(struct path *dir, struct dentry *dentry,
+                                     int mode)
+{
+       return 0;
+}
+
+static inline int security_path_rmdir(struct path *dir, struct dentry *dentry)
+{
+       return 0;
+}
+
+static inline int security_path_mknod(struct path *dir, struct dentry *dentry,
+                                     int mode, unsigned int dev)
+{
+       return 0;
+}
+
+static inline int security_path_truncate(struct path *path, loff_t length,
+                                        unsigned int time_attrs)
+{
+       return 0;
+}
+
+static inline int security_path_symlink(struct path *dir, struct dentry *dentry,
+                                       const char *old_name)
+{
+       return 0;
+}
+
+static inline int security_path_link(struct dentry *old_dentry,
+                                    struct path *new_dir,
+                                    struct dentry *new_dentry)
+{
+       return 0;
+}
+
+static inline int security_path_rename(struct path *old_dir,
+                                      struct dentry *old_dentry,
+                                      struct path *new_dir,
+                                      struct dentry *new_dentry)
+{
+       return 0;
+}
+#endif /* CONFIG_SECURITY_PATH */
+
 #ifdef CONFIG_KEYS
 #ifdef CONFIG_SECURITY
 
index c6250d0055d2f1badce36d7d27e2f4edeed3bf00..d1b89820ab4f34bc5ad8d00d7fa221691f7876c5 100644 (file)
@@ -836,7 +836,11 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                err = mnt_want_write(nd.path.mnt);
                if (err)
                        goto out_mknod_dput;
+               err = security_path_mknod(&nd.path, dentry, mode, 0);
+               if (err)
+                       goto out_mknod_drop_write;
                err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0);
+out_mknod_drop_write:
                mnt_drop_write(nd.path.mnt);
                if (err)
                        goto out_mknod_dput;
index d9f47ce7e2076877064e50eb2e34fd0f9c9fbd2a..9438535d7fd0f2bec51905538bd27b7f73f3ad25 100644 (file)
@@ -81,6 +81,15 @@ config SECURITY_NETWORK_XFRM
          IPSec.
          If you are unsure how to answer this question, answer N.
 
+config SECURITY_PATH
+       bool "Security hooks for pathname based access control"
+       depends on SECURITY
+       help
+         This enables the security hooks for pathname based access control.
+         If enabled, a security module can use these hooks to
+         implement pathname based access controls.
+         If you are unsure how to answer this question, answer N.
+
 config SECURITY_FILE_CAPABILITIES
        bool "File POSIX Capabilities"
        default n
index 2dce66fcb992a106196054847c21f93cd87c5eeb..c545bd1300b5f77d0278be05b546297141251d5d 100644 (file)
@@ -263,6 +263,53 @@ static void cap_inode_getsecid(const struct inode *inode, u32 *secid)
        *secid = 0;
 }
 
+#ifdef CONFIG_SECURITY_PATH
+static int cap_path_mknod(struct path *dir, struct dentry *dentry, int mode,
+                         unsigned int dev)
+{
+       return 0;
+}
+
+static int cap_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
+{
+       return 0;
+}
+
+static int cap_path_rmdir(struct path *dir, struct dentry *dentry)
+{
+       return 0;
+}
+
+static int cap_path_unlink(struct path *dir, struct dentry *dentry)
+{
+       return 0;
+}
+
+static int cap_path_symlink(struct path *dir, struct dentry *dentry,
+                           const char *old_name)
+{
+       return 0;
+}
+
+static int cap_path_link(struct dentry *old_dentry, struct path *new_dir,
+                        struct dentry *new_dentry)
+{
+       return 0;
+}
+
+static int cap_path_rename(struct path *old_path, struct dentry *old_dentry,
+                          struct path *new_path, struct dentry *new_dentry)
+{
+       return 0;
+}
+
+static int cap_path_truncate(struct path *path, loff_t length,
+                            unsigned int time_attrs)
+{
+       return 0;
+}
+#endif
+
 static int cap_file_permission(struct file *file, int mask)
 {
        return 0;
@@ -883,6 +930,16 @@ void security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, inode_setsecurity);
        set_to_cap_if_null(ops, inode_listsecurity);
        set_to_cap_if_null(ops, inode_getsecid);
+#ifdef CONFIG_SECURITY_PATH
+       set_to_cap_if_null(ops, path_mknod);
+       set_to_cap_if_null(ops, path_mkdir);
+       set_to_cap_if_null(ops, path_rmdir);
+       set_to_cap_if_null(ops, path_unlink);
+       set_to_cap_if_null(ops, path_symlink);
+       set_to_cap_if_null(ops, path_link);
+       set_to_cap_if_null(ops, path_rename);
+       set_to_cap_if_null(ops, path_truncate);
+#endif
        set_to_cap_if_null(ops, file_permission);
        set_to_cap_if_null(ops, file_alloc_security);
        set_to_cap_if_null(ops, file_free_security);
index d85dbb37c97261a37b96e5ddfee3e8ea1599ff3d..678d4d07b8523a7fb5af1ef9ddbc8e40d38ce985 100644 (file)
@@ -355,6 +355,72 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
 }
 EXPORT_SYMBOL(security_inode_init_security);
 
+#ifdef CONFIG_SECURITY_PATH
+int security_path_mknod(struct path *path, struct dentry *dentry, int mode,
+                       unsigned int dev)
+{
+       if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+               return 0;
+       return security_ops->path_mknod(path, dentry, mode, dev);
+}
+EXPORT_SYMBOL(security_path_mknod);
+
+int security_path_mkdir(struct path *path, struct dentry *dentry, int mode)
+{
+       if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+               return 0;
+       return security_ops->path_mkdir(path, dentry, mode);
+}
+
+int security_path_rmdir(struct path *path, struct dentry *dentry)
+{
+       if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+               return 0;
+       return security_ops->path_rmdir(path, dentry);
+}
+
+int security_path_unlink(struct path *path, struct dentry *dentry)
+{
+       if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+               return 0;
+       return security_ops->path_unlink(path, dentry);
+}
+
+int security_path_symlink(struct path *path, struct dentry *dentry,
+                         const char *old_name)
+{
+       if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+               return 0;
+       return security_ops->path_symlink(path, dentry, old_name);
+}
+
+int security_path_link(struct dentry *old_dentry, struct path *new_dir,
+                      struct dentry *new_dentry)
+{
+       if (unlikely(IS_PRIVATE(old_dentry->d_inode)))
+               return 0;
+       return security_ops->path_link(old_dentry, new_dir, new_dentry);
+}
+
+int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
+                        struct path *new_dir, struct dentry *new_dentry)
+{
+       if (unlikely(IS_PRIVATE(old_dentry->d_inode) ||
+                    (new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode))))
+               return 0;
+       return security_ops->path_rename(old_dir, old_dentry, new_dir,
+                                        new_dentry);
+}
+
+int security_path_truncate(struct path *path, loff_t length,
+                          unsigned int time_attrs)
+{
+       if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+               return 0;
+       return security_ops->path_truncate(path, length, time_attrs);
+}
+#endif
+
 int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)
 {
        if (unlikely(IS_PRIVATE(dir)))