]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Jul 2013 16:10:19 +0000 (09:10 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Jul 2013 16:10:19 +0000 (09:10 -0700)
Pull second set of VFS changes from Al Viro:
 "Assorted f_pos race fixes, making do_splice_direct() safe to call with
  i_mutex on parent, O_TMPFILE support, Jeff's locks.c series,
  ->d_hash/->d_compare calling conventions changes from Linus, misc
  stuff all over the place."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (63 commits)
  Document ->tmpfile()
  ext4: ->tmpfile() support
  vfs: export lseek_execute() to modules
  lseek_execute() doesn't need an inode passed to it
  block_dev: switch to fixed_size_llseek()
  cpqphp_sysfs: switch to fixed_size_llseek()
  tile-srom: switch to fixed_size_llseek()
  proc_powerpc: switch to fixed_size_llseek()
  ubi/cdev: switch to fixed_size_llseek()
  pci/proc: switch to fixed_size_llseek()
  isapnp: switch to fixed_size_llseek()
  lpfc: switch to fixed_size_llseek()
  locks: give the blocked_hash its own spinlock
  locks: add a new "lm_owner_key" lock operation
  locks: turn the blocked_list into a hashtable
  locks: convert fl_link to a hlist_node
  locks: avoid taking global lock if possible when waking up blocked waiters
  locks: protect most of the file_lock handling with i_lock
  locks: encapsulate the fl_link list handling
  locks: make "added" in __posix_lock_file a bool
  ...

98 files changed:
Documentation/filesystems/Locking
Documentation/filesystems/vfs.txt
arch/alpha/include/uapi/asm/fcntl.h
arch/arc/kernel/troubleshoot.c
arch/parisc/include/uapi/asm/fcntl.h
arch/powerpc/kernel/proc_powerpc.c
arch/sparc/include/uapi/asm/fcntl.h
drivers/char/ps3flash.c
drivers/char/tile-srom.c
drivers/mtd/mtdchar.c
drivers/mtd/ubi/cdev.c
drivers/net/ethernet/brocade/bna/bnad_debugfs.c
drivers/net/wireless/ti/wlcore/debugfs.c
drivers/parisc/eisa_eeprom.c
drivers/pci/hotplug/cpqphp_sysfs.c
drivers/pci/proc.c
drivers/pnp/isapnp/proc.c
drivers/scsi/bfa/bfad_debugfs.c
drivers/scsi/fnic/fnic_debugfs.c
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/staging/android/logger.c
drivers/staging/comedi/comedi_fops.c
drivers/tty/vt/vc_screen.c
drivers/zorro/proc.c
fs/adfs/dir.c
fs/affs/namei.c
fs/afs/flock.c
fs/aio.c
fs/block_dev.c
fs/btrfs/file.c
fs/btrfs/ioctl.c
fs/ceph/file.c
fs/ceph/locks.c
fs/ceph/mds_client.c
fs/cifs/cifsfs.c
fs/cifs/dir.c
fs/cifs/file.c
fs/coda/dir.c
fs/dcache.c
fs/ecryptfs/crypto.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/file.c
fs/ecryptfs/inode.c
fs/efivarfs/super.c
fs/exec.c
fs/ext2/namei.c
fs/ext3/namei.c
fs/ext4/file.c
fs/ext4/namei.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/file_table.c
fs/fuse/file.c
fs/gfs2/dentry.c
fs/gfs2/file.c
fs/hfs/hfs_fs.h
fs/hfs/string.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/unicode.c
fs/hpfs/dentry.c
fs/inode.c
fs/internal.h
fs/isofs/inode.c
fs/isofs/namei.c
fs/jfs/namei.c
fs/lockd/svclock.c
fs/lockd/svcsubs.c
fs/locks.c
fs/minix/dir.c
fs/minix/namei.c
fs/namei.c
fs/ncpfs/dir.c
fs/ncpfs/inode.c
fs/nfs/delegation.c
fs/nfs/nfs4state.c
fs/nfsd/nfs4state.c
fs/notify/fanotify/fanotify_user.c
fs/ocfs2/file.c
fs/open.c
fs/proc/base.c
fs/proc/fd.c
fs/proc/internal.h
fs/proc/namespaces.c
fs/proc/proc_sysctl.c
fs/read_write.c
fs/splice.c
fs/sysv/namei.c
fs/udf/namei.c
fs/xfs/xfs_file.c
include/linux/dcache.h
include/linux/fs.h
include/linux/fsnotify.h
include/uapi/asm-generic/fcntl.h
mm/shmem.c
net/sunrpc/auth_gss/svcauth_gss.c
security/integrity/ima/ima_main.c
security/selinux/hooks.c
sound/core/pcm_native.c

index 9858f337529c1c6edec3444cf0ac145ec331ed07..fe7afe22538149706eab5727c989d91a8530c387 100644 (file)
@@ -11,10 +11,8 @@ be able to use diff(1).
 prototypes:
        int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_weak_revalidate)(struct dentry *, unsigned int);
-       int (*d_hash)(const struct dentry *, const struct inode *,
-                       struct qstr *);
-       int (*d_compare)(const struct dentry *, const struct inode *,
-                       const struct dentry *, const struct inode *,
+       int (*d_hash)(const struct dentry *, struct qstr *);
+       int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(struct dentry *);
        void (*d_release)(struct dentry *);
@@ -66,6 +64,7 @@ prototypes:
        int (*atomic_open)(struct inode *, struct dentry *,
                                struct file *, unsigned open_flag,
                                umode_t create_mode, int *opened);
+       int (*tmpfile) (struct inode *, struct dentry *, umode_t);
 
 locking rules:
        all may block
@@ -93,6 +92,7 @@ removexattr:  yes
 fiemap:                no
 update_time:   no
 atomic_open:   yes
+tmpfile:       no
 
        Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
 victim.
@@ -344,25 +344,38 @@ prototypes:
 
 
 locking rules:
-                       file_lock_lock  may block
+                       inode->i_lock   may block
 fl_copy_lock:          yes             no
 fl_release_private:    maybe           no
 
 ----------------------- lock_manager_operations ---------------------------
 prototypes:
        int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
+       unsigned long (*lm_owner_key)(struct file_lock *);
        void (*lm_notify)(struct file_lock *);  /* unblock callback */
        int (*lm_grant)(struct file_lock *, struct file_lock *, int);
        void (*lm_break)(struct file_lock *); /* break_lease callback */
        int (*lm_change)(struct file_lock **, int);
 
 locking rules:
-                       file_lock_lock  may block
-lm_compare_owner:      yes             no
-lm_notify:             yes             no
-lm_grant:              no              no
-lm_break:              yes             no
-lm_change              yes             no
+
+                       inode->i_lock   blocked_lock_lock       may block
+lm_compare_owner:      yes[1]          maybe                   no
+lm_owner_key           yes[1]          yes                     no
+lm_notify:             yes             yes                     no
+lm_grant:              no              no                      no
+lm_break:              yes             no                      no
+lm_change              yes             no                      no
+
+[1]:   ->lm_compare_owner and ->lm_owner_key are generally called with
+*an* inode->i_lock held. It may not be the i_lock of the inode
+associated with either file_lock argument! This is the case with deadlock
+detection, since the code has to chase down the owners of locks that may
+be entirely unrelated to the one on which the lock is being acquired.
+For deadlock detection however, the blocked_lock_lock is also held. The
+fact that these locks are held ensures that the file_locks do not
+disappear out from under you while doing the comparison or generating an
+owner key.
 
 --------------------------- buffer_head -----------------------------------
 prototypes:
index e6bd1ffd821e28fe05f8046836074b2f6976b6d8..1f0ba30ae47e62ff05c4191f10b6b16dd210a1ea 100644 (file)
@@ -360,6 +360,8 @@ struct inode_operations {
        int (*removexattr) (struct dentry *, const char *);
        void (*update_time)(struct inode *, struct timespec *, int);
        int (*atomic_open)(struct inode *, struct dentry *,
+       int (*tmpfile) (struct inode *, struct dentry *, umode_t);
+} ____cacheline_aligned;
                                struct file *, unsigned open_flag,
                                umode_t create_mode, int *opened);
 };
@@ -472,6 +474,9 @@ otherwise noted.
        component is negative or needs lookup.  Cached positive dentries are
        still handled by f_op->open().
 
+  tmpfile: called in the end of O_TMPFILE open().  Optional, equivalent to
+       atomically creating, opening and unlinking a file in given directory.
+
 The Address Space Object
 ========================
 
@@ -901,10 +906,8 @@ defined:
 struct dentry_operations {
        int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_weak_revalidate)(struct dentry *, unsigned int);
-       int (*d_hash)(const struct dentry *, const struct inode *,
-                       struct qstr *);
-       int (*d_compare)(const struct dentry *, const struct inode *,
-                       const struct dentry *, const struct inode *,
+       int (*d_hash)(const struct dentry *, struct qstr *);
+       int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(const struct dentry *);
        void (*d_release)(struct dentry *);
@@ -949,25 +952,24 @@ struct dentry_operations {
 
   d_hash: called when the VFS adds a dentry to the hash table. The first
        dentry passed to d_hash is the parent directory that the name is
-       to be hashed into. The inode is the dentry's inode.
+       to be hashed into.
 
        Same locking and synchronisation rules as d_compare regarding
        what is safe to dereference etc.
 
   d_compare: called to compare a dentry name with a given name. The first
        dentry is the parent of the dentry to be compared, the second is
-       the parent's inode, then the dentry and inode (may be NULL) of the
-       child dentry. len and name string are properties of the dentry to be
-       compared. qstr is the name to compare it with.
+       the child dentry. len and name string are properties of the dentry
+       to be compared. qstr is the name to compare it with.
 
        Must be constant and idempotent, and should not take locks if
-       possible, and should not or store into the dentry or inodes.
-       Should not dereference pointers outside the dentry or inodes without
+       possible, and should not or store into the dentry.
+       Should not dereference pointers outside the dentry without
        lots of care (eg.  d_parent, d_inode, d_name should not be used).
 
        However, our vfsmount is pinned, and RCU held, so the dentries and
        inodes won't disappear, neither will our sb or filesystem module.
-       ->i_sb and ->d_sb may be used.
+       ->d_sb may be used.
 
        It is a tricky calling convention because it needs to be called under
        "rcu-walk", ie. without any locks or references on things.
index 6d9e805f18a77266504ab8217eaeb2310ec9532c..dfdadb0b4befa6619568d8179dd68f1850ef6151 100644 (file)
@@ -32,6 +32,7 @@
 #define O_SYNC         (__O_SYNC|O_DSYNC)
 
 #define O_PATH         040000000
+#define O_TMPFILE      0100000000
 
 #define F_GETLK                7
 #define F_SETLK                8
index 11c301b81c92bfb7def6577a869c4e0f2c0432a3..a03528ecd276b19916b3a0f4f70e39ecd6e3a191 100644 (file)
@@ -101,7 +101,7 @@ static void show_faulting_vma(unsigned long address, char *buf)
                if (file) {
                        struct path *path = &file->f_path;
                        nm = d_path(path, buf, PAGE_SIZE - 1);
-                       inode = vma->vm_file->f_path.dentry->d_inode;
+                       inode = file_inode(vma->vm_file);
                        dev = inode->i_sb->s_dev;
                        ino = inode->i_ino;
                }
index 0304b92ccfeaf245f2f403b7163c70a8ec037b6c..cc61c475f2779198e45e72dc16dcc4f51e691dec 100644 (file)
@@ -20,6 +20,7 @@
 #define O_INVISIBLE    004000000 /* invisible I/O, for DMAPI/XDSM */
 
 #define O_PATH         020000000
+#define O_TMPFILE      040000000
 
 #define F_GETLK64      8
 #define F_SETLK64      9
index feb8580fdc843acc485df310ed1c072907dc7159..c30612aad68ebd5f239776a3b4c6cf66ea94bf1e 100644 (file)
 
 #ifdef CONFIG_PPC64
 
-static loff_t page_map_seek( struct file *file, loff_t off, int whence)
+static loff_t page_map_seek(struct file *file, loff_t off, int whence)
 {
-       loff_t new;
-       switch(whence) {
-       case 0:
-               new = off;
-               break;
-       case 1:
-               new = file->f_pos + off;
-               break;
-       case 2:
-               new = PAGE_SIZE + off;
-               break;
-       default:
-               return -EINVAL;
-       }
-       if ( new < 0 || new > PAGE_SIZE )
-               return -EINVAL;
-       return (file->f_pos = new);
+       return fixed_size_llseek(file, off, whence, PAGE_SIZE);
 }
 
 static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes,
index d0b83f66f356402a651249a2bed2079e98a85d76..d73e5e008b0de953d5e7eaf958d5c7bfed0c45c8 100644 (file)
@@ -35,6 +35,7 @@
 #define O_SYNC         (__O_SYNC|O_DSYNC)
 
 #define O_PATH         0x1000000
+#define O_TMPFILE      0x2000000
 
 #define F_GETOWN       5       /*  for sockets. */
 #define F_SETOWN       6       /*  for sockets. */
index 8cafa9ccd43f0e7805a86fb0edb8f6ffa526363b..0b311fa277ef097f485d9aa92da18c262a7f10dd 100644 (file)
@@ -98,32 +98,8 @@ static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
 static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
 {
        struct ps3_storage_device *dev = ps3flash_dev;
-       loff_t res;
-
-       mutex_lock(&file->f_mapping->host->i_mutex);
-       switch (origin) {
-       case 0:
-               break;
-       case 1:
-               offset += file->f_pos;
-               break;
-       case 2:
-               offset += dev->regions[dev->region_idx].size*dev->blk_size;
-               break;
-       default:
-               offset = -1;
-       }
-       if (offset < 0) {
-               res = -EINVAL;
-               goto out;
-       }
-
-       file->f_pos = offset;
-       res = file->f_pos;
-
-out:
-       mutex_unlock(&file->f_mapping->host->i_mutex);
-       return res;
+       return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE,
+                       dev->regions[dev->region_idx].size*dev->blk_size);
 }
 
 static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
index 2e2036e940fcafc2c52af4552da1cfd5d984d938..7faeb1cde97d3e10a128326295b9570a3bfb9912 100644 (file)
@@ -273,32 +273,10 @@ static ssize_t srom_write(struct file *filp, const char __user *buf,
 }
 
 /* Provide our own implementation so we can use srom->total_size. */
-loff_t srom_llseek(struct file *filp, loff_t offset, int origin)
+loff_t srom_llseek(struct file *file, loff_t offset, int origin)
 {
-       struct srom_dev *srom = filp->private_data;
-
-       if (mutex_lock_interruptible(&srom->lock))
-               return -ERESTARTSYS;
-
-       switch (origin) {
-       case SEEK_END:
-               offset += srom->total_size;
-               break;
-       case SEEK_CUR:
-               offset += filp->f_pos;
-               break;
-       }
-
-       if (offset < 0 || offset > srom->total_size) {
-               offset = -EINVAL;
-       } else {
-               filp->f_pos = offset;
-               filp->f_version = 0;
-       }
-
-       mutex_unlock(&srom->lock);
-
-       return offset;
+       struct srom_dev *srom = file->private_data;
+       return fixed_size_llseek(file, offset, origin, srom->total_size);
 }
 
 static ssize_t total_show(struct device *dev,
index c719879284bd7b9921a254a70831a39bae644a7d..684bfa39e4ee4892f901874c52c699fa71fd572a 100644 (file)
@@ -55,25 +55,7 @@ struct mtd_file_info {
 static loff_t mtdchar_lseek(struct file *file, loff_t offset, int orig)
 {
        struct mtd_file_info *mfi = file->private_data;
-       struct mtd_info *mtd = mfi->mtd;
-
-       switch (orig) {
-       case SEEK_SET:
-               break;
-       case SEEK_CUR:
-               offset += file->f_pos;
-               break;
-       case SEEK_END:
-               offset += mtd->size;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (offset >= 0 && offset <= mtd->size)
-               return file->f_pos = offset;
-
-       return -EINVAL;
+       return fixed_size_llseek(file, offset, orig, mfi->mtd->size);
 }
 
 static int count;
index 4f02848bb2bc5d843900d6762b10edec23e3dd84..8ca49f2043e4b8a7fe41109129de5760995b59d4 100644 (file)
@@ -155,7 +155,6 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
 {
        struct ubi_volume_desc *desc = file->private_data;
        struct ubi_volume *vol = desc->vol;
-       loff_t new_offset;
 
        if (vol->updating) {
                /* Update is in progress, seeking is prohibited */
@@ -163,30 +162,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
                return -EBUSY;
        }
 
-       switch (origin) {
-       case 0: /* SEEK_SET */
-               new_offset = offset;
-               break;
-       case 1: /* SEEK_CUR */
-               new_offset = file->f_pos + offset;
-               break;
-       case 2: /* SEEK_END */
-               new_offset = vol->used_bytes + offset;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (new_offset < 0 || new_offset > vol->used_bytes) {
-               ubi_err("bad seek %lld", new_offset);
-               return -EINVAL;
-       }
-
-       dbg_gen("seek volume %d, offset %lld, origin %d, new offset %lld",
-               vol->vol_id, offset, origin, new_offset);
-
-       file->f_pos = new_offset;
-       return new_offset;
+       return fixed_size_llseek(file, offset, origin, vol->used_bytes);
 }
 
 static int vol_cdev_fsync(struct file *file, loff_t start, loff_t end,
index 94d957d203a6466b9b809d49962f6630ed2bc7cb..7d6aa8c87df84747bea056019a89517846817b21 100644 (file)
@@ -230,32 +230,12 @@ bnad_debugfs_open_drvinfo(struct inode *inode, struct file *file)
 static loff_t
 bnad_debugfs_lseek(struct file *file, loff_t offset, int orig)
 {
-       loff_t pos = file->f_pos;
        struct bnad_debug_info *debug = file->private_data;
 
        if (!debug)
                return -EINVAL;
 
-       switch (orig) {
-       case 0:
-               file->f_pos = offset;
-               break;
-       case 1:
-               file->f_pos += offset;
-               break;
-       case 2:
-               file->f_pos = debug->buffer_len + offset;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (file->f_pos < 0 || file->f_pos > debug->buffer_len) {
-               file->f_pos = pos;
-               return -EINVAL;
-       }
-
-       return file->f_pos;
+       return fixed_size_llseek(file, offset, orig, debug->buffer_len);
 }
 
 static ssize_t
index c3e1f79c785697d95dfc9ccfac1e49410f263d8f..e17630c2a84948d40bb5d0f2c05f4ce1e8ccea2c 100644 (file)
@@ -1056,7 +1056,7 @@ static ssize_t dev_mem_read(struct file *file,
                return -EINVAL;
 
        memset(&part, 0, sizeof(part));
-       part.mem.start = file->f_pos;
+       part.mem.start = *ppos;
        part.mem.size = bytes;
 
        buf = kmalloc(bytes, GFP_KERNEL);
@@ -1137,7 +1137,7 @@ static ssize_t dev_mem_write(struct file *file, const char __user *user_buf,
                return -EINVAL;
 
        memset(&part, 0, sizeof(part));
-       part.mem.start = file->f_pos;
+       part.mem.start = *ppos;
        part.mem.size = bytes;
 
        buf = kmalloc(bytes, GFP_KERNEL);
index af212c6a615840e7bf777fb931ff2770d490fb5d..783906fe659a2824987fe4b5cc9397c866ba91f7 100644 (file)
 
 #define        EISA_EEPROM_MINOR 241
 
-static loff_t eisa_eeprom_llseek(struct file *file, loff_t offset, int origin )
+static loff_t eisa_eeprom_llseek(struct file *file, loff_t offset, int origin)
 {
-       switch (origin) {
-         case 0:
-               /* nothing to do */
-               break;
-         case 1:
-               offset += file->f_pos;
-               break;
-         case 2:
-               offset += HPEE_MAX_LENGTH;
-               break;
-       }
-       return (offset >= 0 && offset < HPEE_MAX_LENGTH) ? (file->f_pos = offset) : -EINVAL;
+       return fixed_size_llseek(file, offset, origin, HPEE_MAX_LENGTH);
 }
 
 static ssize_t eisa_eeprom_read(struct file * file,
index 4cb30447a4860cf684155f18c79faad88f3989c6..17c1f36315d191b46bf81734efa69fff344bfa84 100644 (file)
@@ -167,26 +167,8 @@ exit:
 
 static loff_t lseek(struct file *file, loff_t off, int whence)
 {
-       struct ctrl_dbg *dbg;
-       loff_t new = -1;
-
-       mutex_lock(&cpqphp_mutex);
-       dbg = file->private_data;
-
-       switch (whence) {
-       case 0:
-               new = off;
-               break;
-       case 1:
-               new = file->f_pos + off;
-               break;
-       }
-       if (new < 0 || new > dbg->size) {
-               mutex_unlock(&cpqphp_mutex);
-               return -EINVAL;
-       }
-       mutex_unlock(&cpqphp_mutex);
-       return (file->f_pos = new);
+       struct ctrl_dbg *dbg = file->private_data;
+       return fixed_size_llseek(file, off, whence, dbg->size);
 }
 
 static ssize_t read(struct file *file, char __user *buf,
index 08126087ec3125c29de84c5b9e5f68d45d2b0328..cdc7836d7e3de3ab710341b3feef63c1ff3b3a47 100644 (file)
@@ -20,27 +20,8 @@ static int proc_initialized; /* = 0 */
 static loff_t
 proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
 {
-       loff_t new = -1;
-       struct inode *inode = file_inode(file);
-
-       mutex_lock(&inode->i_mutex);
-       switch (whence) {
-       case 0:
-               new = off;
-               break;
-       case 1:
-               new = file->f_pos + off;
-               break;
-       case 2:
-               new = inode->i_size + off;
-               break;
-       }
-       if (new < 0 || new > inode->i_size)
-               new = -EINVAL;
-       else
-               file->f_pos = new;
-       mutex_unlock(&inode->i_mutex);
-       return new;
+       struct pci_dev *dev = PDE_DATA(file_inode(file));
+       return fixed_size_llseek(file, off, whence, dev->cfg_size);
 }
 
 static ssize_t
index 2365ef37ae2466b18620fff5e209c3352a6e08f6..5edee645d890e6037578da6f26aa0be5daaf61d0 100644 (file)
@@ -29,27 +29,7 @@ static struct proc_dir_entry *isapnp_proc_bus_dir = NULL;
 
 static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence)
 {
-       loff_t new = -1;
-       struct inode *inode = file_inode(file);
-
-       mutex_lock(&inode->i_mutex);
-       switch (whence) {
-       case 0:
-               new = off;
-               break;
-       case 1:
-               new = file->f_pos + off;
-               break;
-       case 2:
-               new = 256 + off;
-               break;
-       }
-       if (new < 0 || new > 256)
-               new = -EINVAL;
-       else
-               file->f_pos = new;
-       mutex_unlock(&inode->i_mutex);
-       return new;
+       return fixed_size_llseek(file, off, whence, 256);
 }
 
 static ssize_t isapnp_proc_bus_read(struct file *file, char __user * buf,
index b63d534192e33a8defea70b6c0195293392ea98e..8e83d0474fe7c57560714dd488d4db1fcc1f4d15 100644 (file)
@@ -173,31 +173,9 @@ bfad_debugfs_open_reg(struct inode *inode, struct file *file)
 static loff_t
 bfad_debugfs_lseek(struct file *file, loff_t offset, int orig)
 {
-       struct bfad_debug_info *debug;
-       loff_t pos = file->f_pos;
-
-       debug = file->private_data;
-
-       switch (orig) {
-       case 0:
-               file->f_pos = offset;
-               break;
-       case 1:
-               file->f_pos += offset;
-               break;
-       case 2:
-               file->f_pos = debug->buffer_len + offset;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (file->f_pos < 0 || file->f_pos > debug->buffer_len) {
-               file->f_pos = pos;
-               return -EINVAL;
-       }
-
-       return file->f_pos;
+       struct bfad_debug_info *debug = file->private_data;
+       return fixed_size_llseek(file, offset, orig,
+                               debug->buffer_len);
 }
 
 static ssize_t
index 85e1ffd0e5c5af17e53305ad016f28898d65c8f7..cbcb0121c84de5557852e641bcff6248881480e2 100644 (file)
@@ -164,20 +164,8 @@ static loff_t fnic_trace_debugfs_lseek(struct file *file,
                                        int howto)
 {
        fnic_dbgfs_t *fnic_dbg_prt = file->private_data;
-       loff_t pos = -1;
-
-       switch (howto) {
-       case 0:
-               pos = offset;
-               break;
-       case 1:
-               pos = file->f_pos + offset;
-               break;
-       case 2:
-               pos = fnic_dbg_prt->buffer_len + offset;
-       }
-       return (pos < 0 || pos > fnic_dbg_prt->buffer_len) ?
-                         -EINVAL : (file->f_pos = pos);
+       return fixed_size_llseek(file, offset, howto,
+                               fnic_dbg_prt->buffer_len);
 }
 
 /*
index f525ecb7a9c6e187bf1097a6baf7aabad96377a4..60084e6ad2f24331c6bab3e74d4869f13a5dca0c 100644 (file)
@@ -1165,22 +1165,8 @@ out:
 static loff_t
 lpfc_debugfs_lseek(struct file *file, loff_t off, int whence)
 {
-       struct lpfc_debug *debug;
-       loff_t pos = -1;
-
-       debug = file->private_data;
-
-       switch (whence) {
-       case 0:
-               pos = off;
-               break;
-       case 1:
-               pos = file->f_pos + off;
-               break;
-       case 2:
-               pos = debug->len + off;
-       }
-       return (pos < 0 || pos > debug->len) ? -EINVAL : (file->f_pos = pos);
+       struct lpfc_debug *debug = file->private_data;
+       return fixed_size_llseek(file, off, whence, debug->len);
 }
 
 /**
index 9bd874789ce5fc93906a78f62a68e542541bd288..080abf2faf972ab3b999ac58f923c03dbec7e9b8 100644 (file)
@@ -696,7 +696,7 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        ret = -EBADF;
                        break;
                }
-               if (!(in_egroup_p(file->f_dentry->d_inode->i_gid) ||
+               if (!(in_egroup_p(file_inode(file)->i_gid) ||
                                capable(CAP_SYSLOG))) {
                        ret = -EPERM;
                        break;
index 0794aacc928ad649bc9f2fe7370ed7fb30c1aa1a..8647518259f6dd5ab3379babc218d5ef6cf24831 100644 (file)
@@ -2329,9 +2329,6 @@ static int comedi_close(struct inode *inode, struct file *file)
 
        mutex_unlock(&dev->mutex);
 
-       if (file->f_flags & FASYNC)
-               comedi_fasync(-1, file, 0);
-
        return 0;
 }
 
index d7799deacb21a66805d8e4308bcc199b64894fbf..14a2b5f11bcab9739ea6bc23c5bb4134f1b37f1c 100644 (file)
@@ -188,22 +188,7 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
        console_unlock();
        if (size < 0)
                return size;
-       switch (orig) {
-               default:
-                       return -EINVAL;
-               case 2:
-                       offset += size;
-                       break;
-               case 1:
-                       offset += file->f_pos;
-               case 0:
-                       break;
-       }
-       if (offset < 0 || offset > size) {
-               return -EINVAL;
-       }
-       file->f_pos = offset;
-       return file->f_pos;
+       return fixed_size_llseek(file, offset, orig, size);
 }
 
 
index 1c15ee7456b6cdce859189daaafd9dd7177f831e..ea1ce822a8e0437120184a8e559bd0495860c7b7 100644 (file)
 static loff_t
 proc_bus_zorro_lseek(struct file *file, loff_t off, int whence)
 {
-       loff_t new = -1;
-       struct inode *inode = file_inode(file);
-
-       mutex_lock(&inode->i_mutex);
-       switch (whence) {
-       case 0:
-               new = off;
-               break;
-       case 1:
-               new = file->f_pos + off;
-               break;
-       case 2:
-               new = sizeof(struct ConfigDev) + off;
-               break;
-       }
-       if (new < 0 || new > sizeof(struct ConfigDev))
-               new = -EINVAL;
-       else
-               file->f_pos = new;
-       mutex_unlock(&inode->i_mutex);
-       return new;
+       return fixed_size_llseek(file, off, whence, sizeof(struct ConfigDev));
 }
 
 static ssize_t
index ade28bb058e311dc3b2f120e2405884c4e090f7d..0d138c0de293ed3512046058b5ff96cac8c744ad 100644 (file)
@@ -191,8 +191,7 @@ const struct file_operations adfs_dir_operations = {
 };
 
 static int
-adfs_hash(const struct dentry *parent, const struct inode *inode,
-               struct qstr *qstr)
+adfs_hash(const struct dentry *parent, struct qstr *qstr)
 {
        const unsigned int name_len = ADFS_SB(parent->d_sb)->s_namelen;
        const unsigned char *name;
@@ -228,8 +227,7 @@ adfs_hash(const struct dentry *parent, const struct inode *inode,
  * requirements of the underlying filesystem.
  */
 static int
-adfs_compare(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+adfs_compare(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        int i;
index ff65884a7839974ca472a64097ac996245c96346..c36cbb4537a26e0348a44f0ec7a65f64ac3204bf 100644 (file)
 typedef int (*toupper_t)(int);
 
 static int      affs_toupper(int ch);
-static int      affs_hash_dentry(const struct dentry *,
-               const struct inode *, struct qstr *);
-static int       affs_compare_dentry(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int      affs_hash_dentry(const struct dentry *, struct qstr *);
+static int       affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 static int      affs_intl_toupper(int ch);
-static int      affs_intl_hash_dentry(const struct dentry *,
-               const struct inode *, struct qstr *);
-static int       affs_intl_compare_dentry(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int      affs_intl_hash_dentry(const struct dentry *, struct qstr *);
+static int       affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 
 const struct dentry_operations affs_dentry_operations = {
@@ -86,14 +80,12 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper)
 }
 
 static int
-affs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 {
        return __affs_hash_dentry(qstr, affs_toupper);
 }
 static int
-affs_intl_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 {
        return __affs_hash_dentry(qstr, affs_intl_toupper);
 }
@@ -131,15 +123,13 @@ static inline int __affs_compare_dentry(unsigned int len,
 }
 
 static int
-affs_compare_dentry(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return __affs_compare_dentry(len, str, name, affs_toupper);
 }
 static int
-affs_intl_compare_dentry(const struct dentry *parent,const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return __affs_compare_dentry(len, str, name, affs_intl_toupper);
index 2497bf306c70e4593d552f6e427bfaa81a7d7ccc..a8cf2cff836c337fa64f22009c7cc15e4aa8b6bf 100644 (file)
@@ -252,7 +252,8 @@ static void afs_defer_unlock(struct afs_vnode *vnode, struct key *key)
  */
 static int afs_do_setlk(struct file *file, struct file_lock *fl)
 {
-       struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host);
+       struct inode *inode = file_inode(file);
+       struct afs_vnode *vnode = AFS_FS_I(inode);
        afs_lock_type_t type;
        struct key *key = file->private_data;
        int ret;
@@ -273,7 +274,7 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
 
        type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
 
        /* make sure we've got a callback on this file and that our view of the
         * data version is up to date */
@@ -420,7 +421,7 @@ given_lock:
        afs_vnode_fetch_status(vnode, NULL, key);
 
 error:
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        _leave(" = %d", ret);
        return ret;
 
index 2bbcacf74d0c64f8814cb68d8c4eff423dfe98d4..a8ecc8313fb08d310276e72043e671c186ad1565 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -39,6 +39,8 @@
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
 
+#include "internal.h"
+
 #define AIO_RING_MAGIC                 0xa10a10a1
 #define AIO_RING_COMPAT_FEATURES       1
 #define AIO_RING_INCOMPAT_FEATURES     0
index 2091db8cdd783a2287ce9165a7223cfe59cf5a2b..431b6a04ebfdb6783e479c14fe25fcfe0253c6ff 100644 (file)
@@ -325,31 +325,10 @@ static int blkdev_write_end(struct file *file, struct address_space *mapping,
 static loff_t block_llseek(struct file *file, loff_t offset, int whence)
 {
        struct inode *bd_inode = file->f_mapping->host;
-       loff_t size;
        loff_t retval;
 
        mutex_lock(&bd_inode->i_mutex);
-       size = i_size_read(bd_inode);
-
-       retval = -EINVAL;
-       switch (whence) {
-               case SEEK_END:
-                       offset += size;
-                       break;
-               case SEEK_CUR:
-                       offset += file->f_pos;
-               case SEEK_SET:
-                       break;
-               default:
-                       goto out;
-       }
-       if (offset >= 0 && offset <= size) {
-               if (offset != file->f_pos) {
-                       file->f_pos = offset;
-               }
-               retval = offset;
-       }
-out:
+       retval = fixed_size_llseek(file, offset, whence, i_size_read(bd_inode));
        mutex_unlock(&bd_inode->i_mutex);
        return retval;
 }
index 4205ba752d40ccbadfb0fa0b1f053b1022c553c0..89da56a58b635c9bf80197c0cf32e2dc3f698442 100644 (file)
@@ -2425,20 +2425,7 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence)
                }
        }
 
-       if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) {
-               offset = -EINVAL;
-               goto out;
-       }
-       if (offset > inode->i_sb->s_maxbytes) {
-               offset = -EINVAL;
-               goto out;
-       }
-
-       /* Special lock needed here? */
-       if (offset != file->f_pos) {
-               file->f_pos = offset;
-               file->f_version = 0;
-       }
+       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 out:
        mutex_unlock(&inode->i_mutex);
        return offset;
index 0f81d67cdc8da651890df1a89c01df9188667d97..cd7e96c73cb71df0589f1866346ab5ff2714eb96 100644 (file)
@@ -3881,7 +3881,7 @@ drop_write:
 
 static long btrfs_ioctl_quota_rescan(struct file *file, void __user *arg)
 {
-       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
+       struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
        struct btrfs_ioctl_quota_rescan_args *qsa;
        int ret;
 
@@ -3914,7 +3914,7 @@ drop_write:
 
 static long btrfs_ioctl_quota_rescan_status(struct file *file, void __user *arg)
 {
-       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
+       struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
        struct btrfs_ioctl_quota_rescan_args *qsa;
        int ret = 0;
 
@@ -4020,7 +4020,7 @@ out:
 
 static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg)
 {
-       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
+       struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
        const char *label = root->fs_info->super_copy->label;
        size_t len = strnlen(label, BTRFS_LABEL_SIZE);
        int ret;
@@ -4039,7 +4039,7 @@ static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg)
 
 static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg)
 {
-       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
+       struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
        struct btrfs_super_block *super_block = root->fs_info->super_copy;
        struct btrfs_trans_handle *trans;
        char label[BTRFS_LABEL_SIZE];
index 656e169074305f12d34859ca07ee710c4c1a954d..16c989d3e23c762e52904419a81beae943332ea0 100644 (file)
@@ -866,16 +866,7 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int whence)
                break;
        }
 
-       if (offset < 0 || offset > inode->i_sb->s_maxbytes) {
-               offset = -EINVAL;
-               goto out;
-       }
-
-       /* Special lock needed here? */
-       if (offset != file->f_pos) {
-               file->f_pos = offset;
-               file->f_version = 0;
-       }
+       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out:
        mutex_unlock(&inode->i_mutex);
index ebbf680378e2ad3ad956babeb5b521e619830bcb..690f73f42425f1021727bad475fef24ae92b5f55 100644 (file)
@@ -192,7 +192,7 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
 
 /**
  * Encode the flock and fcntl locks for the given inode into the ceph_filelock
- * array. Must be called with lock_flocks() already held.
+ * array. Must be called with inode->i_lock already held.
  * If we encounter more of a specific lock type than expected, return -ENOSPC.
  */
 int ceph_encode_locks_to_buffer(struct inode *inode,
index 4d2920304be8e7e9075fd1f1b80b954cb26718f9..74fd2898b2ab43012ab1c3fbf25f619fbd7df3b2 100644 (file)
@@ -2481,20 +2481,20 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
                struct ceph_filelock *flocks;
 
 encode_again:
-               lock_flocks();
+               spin_lock(&inode->i_lock);
                ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks);
-               unlock_flocks();
+               spin_unlock(&inode->i_lock);
                flocks = kmalloc((num_fcntl_locks+num_flock_locks) *
                                 sizeof(struct ceph_filelock), GFP_NOFS);
                if (!flocks) {
                        err = -ENOMEM;
                        goto out_free;
                }
-               lock_flocks();
+               spin_lock(&inode->i_lock);
                err = ceph_encode_locks_to_buffer(inode, flocks,
                                                  num_fcntl_locks,
                                                  num_flock_locks);
-               unlock_flocks();
+               spin_unlock(&inode->i_lock);
                if (err) {
                        kfree(flocks);
                        if (err == -ENOSPC)
index 540c1ccfcdb28a310614f24b873f81f4c4e652d3..a445e71746fabdcaf308d6a2fbe9365e40cba849 100644 (file)
@@ -765,7 +765,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
 
 static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
 {
-       /* note that this is called by vfs setlease with lock_flocks held
+       /* note that this is called by vfs setlease with i_lock held
           to protect *lease from going away */
        struct inode *inode = file_inode(file);
        struct cifsFileInfo *cfile = file->private_data;
index 5699b5036ed805189d367796d9a673730e773b8b..5175aebf6737953983c3da59671657660ec5641f 100644 (file)
@@ -822,8 +822,7 @@ const struct dentry_operations cifs_dentry_ops = {
 /* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
 };
 
-static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *q)
+static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
 {
        struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
        unsigned long hash;
@@ -838,12 +837,10 @@ static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
        return 0;
 }
 
-static int cifs_ci_compare(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int cifs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
-       struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls;
+       struct nls_table *codepage = CIFS_SB(parent->d_sb)->local_nls;
 
        if ((name->len == len) &&
            (nls_strnicmp(codepage, name->name, str, len) == 0))
index 4d8ba8d491e5d0be27bfbf8506175f7ffd8ce476..91d8629e69a24137e48422cb2620361b4e8e47c2 100644 (file)
@@ -999,7 +999,7 @@ try_again:
                rc = wait_event_interruptible(flock->fl_wait, !flock->fl_next);
                if (!rc)
                        goto try_again;
-               locks_delete_block(flock);
+               posix_unblock_lock(flock);
        }
        return rc;
 }
@@ -1092,6 +1092,7 @@ struct lock_to_push {
 static int
 cifs_push_posix_locks(struct cifsFileInfo *cfile)
 {
+       struct inode *inode = cfile->dentry->d_inode;
        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
        struct file_lock *flock, **before;
        unsigned int count = 0, i = 0;
@@ -1102,12 +1103,12 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
 
        xid = get_xid();
 
-       lock_flocks();
-       cifs_for_each_lock(cfile->dentry->d_inode, before) {
+       spin_lock(&inode->i_lock);
+       cifs_for_each_lock(inode, before) {
                if ((*before)->fl_flags & FL_POSIX)
                        count++;
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 
        INIT_LIST_HEAD(&locks_to_send);
 
@@ -1126,8 +1127,8 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
        }
 
        el = locks_to_send.next;
-       lock_flocks();
-       cifs_for_each_lock(cfile->dentry->d_inode, before) {
+       spin_lock(&inode->i_lock);
+       cifs_for_each_lock(inode, before) {
                flock = *before;
                if ((flock->fl_flags & FL_POSIX) == 0)
                        continue;
@@ -1152,7 +1153,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
                lck->offset = flock->fl_start;
                el = el->next;
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 
        list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
                int stored_rc;
index 87e0ee9f4465e5b0bfc7bde48657314be18258b3..14a14808320cf1e555d8ca14fdd604590d8b723f 100644 (file)
@@ -487,13 +487,7 @@ static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
 
                /* skip null entries */
                if (vdir->d_fileno && name.len) {
-                       /* try to look up this entry in the dcache, that way
-                        * userspace doesn't have to worry about breaking
-                        * getcwd by having mismatched inode numbers for
-                        * internal volume mountpoints. */
-                       ino = find_inode_number(de, &name);
-                       if (!ino) ino = vdir->d_fileno;
-
+                       ino = vdir->d_fileno;
                        type = CDT2DT(vdir->d_type);
                        if (!dir_emit(ctx, name.name, name.len, ino, type))
                                break;
index 5a23073138dfe310fb076e81567bac97cd0be9b6..87bdb5329c3c90b99d67f4b5bab3ae0b347d2acf 100644 (file)
@@ -1730,7 +1730,7 @@ EXPORT_SYMBOL(d_add_ci);
  * Do the slow-case of the dentry name compare.
  *
  * Unlike the dentry_cmp() function, we need to atomically
- * load the name, length and inode information, so that the
+ * load the name and length information, so that the
  * filesystem can rely on them, and can use the 'name' and
  * 'len' information without worrying about walking off the
  * end of memory etc.
@@ -1748,22 +1748,18 @@ enum slow_d_compare {
 
 static noinline enum slow_d_compare slow_dentry_cmp(
                const struct dentry *parent,
-               struct inode *inode,
                struct dentry *dentry,
                unsigned int seq,
                const struct qstr *name)
 {
        int tlen = dentry->d_name.len;
        const char *tname = dentry->d_name.name;
-       struct inode *i = dentry->d_inode;
 
        if (read_seqcount_retry(&dentry->d_seq, seq)) {
                cpu_relax();
                return D_COMP_SEQRETRY;
        }
-       if (parent->d_op->d_compare(parent, inode,
-                               dentry, i,
-                               tlen, tname, name))
+       if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
                return D_COMP_NOMATCH;
        return D_COMP_OK;
 }
@@ -1773,7 +1769,6 @@ static noinline enum slow_d_compare slow_dentry_cmp(
  * @parent: parent dentry
  * @name: qstr of name we wish to find
  * @seqp: returns d_seq value at the point where the dentry was found
- * @inode: returns dentry->d_inode when the inode was found valid.
  * Returns: dentry, or NULL
  *
  * __d_lookup_rcu is the dcache lookup function for rcu-walk name
@@ -1800,7 +1795,7 @@ static noinline enum slow_d_compare slow_dentry_cmp(
  */
 struct dentry *__d_lookup_rcu(const struct dentry *parent,
                                const struct qstr *name,
-                               unsigned *seqp, struct inode *inode)
+                               unsigned *seqp)
 {
        u64 hashlen = name->hash_len;
        const unsigned char *str = name->name;
@@ -1834,11 +1829,10 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
 seqretry:
                /*
                 * The dentry sequence count protects us from concurrent
-                * renames, and thus protects inode, parent and name fields.
+                * renames, and thus protects parent and name fields.
                 *
                 * The caller must perform a seqcount check in order
-                * to do anything useful with the returned dentry,
-                * including using the 'd_inode' pointer.
+                * to do anything useful with the returned dentry.
                 *
                 * NOTE! We do a "raw" seqcount_begin here. That means that
                 * we don't wait for the sequence count to stabilize if it
@@ -1852,12 +1846,12 @@ seqretry:
                        continue;
                if (d_unhashed(dentry))
                        continue;
-               *seqp = seq;
 
                if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) {
                        if (dentry->d_name.hash != hashlen_hash(hashlen))
                                continue;
-                       switch (slow_dentry_cmp(parent, inode, dentry, seq, name)) {
+                       *seqp = seq;
+                       switch (slow_dentry_cmp(parent, dentry, seq, name)) {
                        case D_COMP_OK:
                                return dentry;
                        case D_COMP_NOMATCH:
@@ -1869,6 +1863,7 @@ seqretry:
 
                if (dentry->d_name.hash_len != hashlen)
                        continue;
+               *seqp = seq;
                if (!dentry_cmp(dentry, str, hashlen_len(hashlen)))
                        return dentry;
        }
@@ -1966,9 +1961,7 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
                if (parent->d_flags & DCACHE_OP_COMPARE) {
                        int tlen = dentry->d_name.len;
                        const char *tname = dentry->d_name.name;
-                       if (parent->d_op->d_compare(parent, parent->d_inode,
-                                               dentry, dentry->d_inode,
-                                               tlen, tname, name))
+                       if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
                                goto next;
                } else {
                        if (dentry->d_name.len != len)
@@ -2005,7 +1998,7 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)
         */
        name->hash = full_name_hash(name->name, name->len);
        if (dir->d_flags & DCACHE_OP_HASH) {
-               int err = dir->d_op->d_hash(dir, dir->d_inode, name);
+               int err = dir->d_op->d_hash(dir, name);
                if (unlikely(err < 0))
                        return ERR_PTR(err);
        }
@@ -2975,34 +2968,21 @@ rename_retry:
        goto again;
 }
 
-/**
- * find_inode_number - check for dentry with name
- * @dir: directory to check
- * @name: Name to find.
- *
- * Check whether a dentry already exists for the given name,
- * and return the inode number if it has an inode. Otherwise
- * 0 is returned.
- *
- * This routine is used to post-process directory listings for
- * filesystems using synthetic inode numbers, and is necessary
- * to keep getcwd() working.
- */
-ino_t find_inode_number(struct dentry *dir, struct qstr *name)
+void d_tmpfile(struct dentry *dentry, struct inode *inode)
 {
-       struct dentry * dentry;
-       ino_t ino = 0;
-
-       dentry = d_hash_and_lookup(dir, name);
-       if (!IS_ERR_OR_NULL(dentry)) {
-               if (dentry->d_inode)
-                       ino = dentry->d_inode->i_ino;
-               dput(dentry);
-       }
-       return ino;
+       inode_dec_link_count(inode);
+       BUG_ON(dentry->d_name.name != dentry->d_iname ||
+               !hlist_unhashed(&dentry->d_alias) ||
+               !d_unlinked(dentry));
+       spin_lock(&dentry->d_parent->d_lock);
+       spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+       dentry->d_name.len = sprintf(dentry->d_iname, "#%llu",
+                               (unsigned long long)inode->i_ino);
+       spin_unlock(&dentry->d_lock);
+       spin_unlock(&dentry->d_parent->d_lock);
+       d_instantiate(dentry, inode);
 }
-EXPORT_SYMBOL(find_inode_number);
+EXPORT_SYMBOL(d_tmpfile);
 
 static __initdata unsigned long dhash_entries;
 static int __init set_dhash_entries(char *str)
index f71ec125290db7da87355f444f7308826ee1c034..cfa109a4d5a21ac6f784f1a4e8a16b534c9e8d0d 100644 (file)
@@ -2243,12 +2243,11 @@ out:
  */
 int ecryptfs_decode_and_decrypt_filename(char **plaintext_name,
                                         size_t *plaintext_name_size,
-                                        struct dentry *ecryptfs_dir_dentry,
+                                        struct super_block *sb,
                                         const char *name, size_t name_size)
 {
        struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
-               &ecryptfs_superblock_to_private(
-                       ecryptfs_dir_dentry->d_sb)->mount_crypt_stat;
+               &ecryptfs_superblock_to_private(sb)->mount_crypt_stat;
        char *decoded_name;
        size_t decoded_name_size;
        size_t packet_size;
index f622a733f7adc3ff1778e4f74790db507c61c824..df19d34a033b9521de8623bb33ff2de6c0d9361a 100644 (file)
@@ -575,7 +575,7 @@ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
                             struct inode *ecryptfs_inode);
 int ecryptfs_decode_and_decrypt_filename(char **decrypted_name,
                                         size_t *decrypted_name_size,
-                                        struct dentry *ecryptfs_dentry,
+                                        struct super_block *sb,
                                         const char *name, size_t name_size);
 int ecryptfs_fill_zeros(struct file *file, loff_t new_length);
 int ecryptfs_encrypt_and_encode_filename(
index 9aa05e08060b507f05f17a5b464fb1f695c7e3e4..24f1105fda3ab5edfccc7a748f97dd624bf6f0fb 100644 (file)
@@ -70,7 +70,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
 struct ecryptfs_getdents_callback {
        struct dir_context ctx;
        struct dir_context *caller;
-       struct dentry *dentry;
+       struct super_block *sb;
        int filldir_called;
        int entries_written;
 };
@@ -88,7 +88,7 @@ ecryptfs_filldir(void *dirent, const char *lower_name, int lower_namelen,
 
        buf->filldir_called++;
        rc = ecryptfs_decode_and_decrypt_filename(&name, &name_size,
-                                                 buf->dentry, lower_name,
+                                                 buf->sb, lower_name,
                                                  lower_namelen);
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to decode and decrypt "
@@ -114,15 +114,14 @@ static int ecryptfs_readdir(struct file *file, struct dir_context *ctx)
 {
        int rc;
        struct file *lower_file;
-       struct inode *inode;
+       struct inode *inode = file_inode(file);
        struct ecryptfs_getdents_callback buf = {
                .ctx.actor = ecryptfs_filldir,
                .caller = ctx,
-               .dentry = file->f_path.dentry
+               .sb = inode->i_sb,
        };
        lower_file = ecryptfs_file_to_lower(file);
        lower_file->f_pos = ctx->pos;
-       inode = file_inode(file);
        rc = iterate_dir(lower_file, &buf.ctx);
        ctx->pos = buf.ctx.pos;
        if (rc < 0)
index 5eab400e25903b71641d4a056254c79f3a776885..a2f2bb2c256dd24cf8a9e597cbbe7f97a290f282 100644 (file)
@@ -679,7 +679,7 @@ static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf,
        set_fs(old_fs);
        if (rc < 0)
                goto out;
-       rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry,
+       rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry->d_sb,
                                                  lower_buf, rc);
 out:
        kfree(lower_buf);
index 141aee31884fffd06c7903b442ebbd7a03c6a704..a8766b880c0783b3adca66bac0e5f0ba76840c70 100644 (file)
@@ -45,8 +45,8 @@ static struct super_block *efivarfs_sb;
  * So we need to perform a case-sensitive match on part 1 and a
  * case-insensitive match on part 2.
  */
-static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode,
-                             const struct dentry *dentry, const struct inode *inode,
+static int efivarfs_d_compare(const struct dentry *parent,
+                             const struct dentry *dentry,
                              unsigned int len, const char *str,
                              const struct qstr *name)
 {
@@ -63,8 +63,7 @@ static int efivarfs_d_compare(const struct dentry *parent, const struct inode *p
        return strncasecmp(name->name + guid, str + guid, EFI_VARIABLE_GUID_LEN);
 }
 
-static int efivarfs_d_hash(const struct dentry *dentry,
-                          const struct inode *inode, struct qstr *qstr)
+static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr)
 {
        unsigned long hash = init_name_hash();
        const unsigned char *s = qstr->name;
@@ -108,7 +107,7 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
        q.name = name;
        q.len = strlen(name);
 
-       err = efivarfs_d_hash(NULL, NULL, &q);
+       err = efivarfs_d_hash(NULL, &q);
        if (err)
                return ERR_PTR(err);
 
index ffd7a813ad3d06ee1e1de4e996c72282c24e7039..03b907cfd76523c690ca7d58ed0448e58ab99b42 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -110,13 +110,14 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
        static const struct open_flags uselib_flags = {
                .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
                .acc_mode = MAY_READ | MAY_EXEC | MAY_OPEN,
-               .intent = LOOKUP_OPEN
+               .intent = LOOKUP_OPEN,
+               .lookup_flags = LOOKUP_FOLLOW,
        };
 
        if (IS_ERR(tmp))
                goto out;
 
-       file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW);
+       file = do_filp_open(AT_FDCWD, tmp, &uselib_flags);
        putname(tmp);
        error = PTR_ERR(file);
        if (IS_ERR(file))
@@ -756,10 +757,11 @@ struct file *open_exec(const char *name)
        static const struct open_flags open_exec_flags = {
                .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
                .acc_mode = MAY_EXEC | MAY_OPEN,
-               .intent = LOOKUP_OPEN
+               .intent = LOOKUP_OPEN,
+               .lookup_flags = LOOKUP_FOLLOW,
        };
 
-       file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags, LOOKUP_FOLLOW);
+       file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags);
        if (IS_ERR(file))
                goto out;
 
index 73b0d9519836e1181b5b9227bd78ccead322a4d3..256dd5f4c1c4ade3f1ba160726ed0defabfccaf8 100644 (file)
@@ -119,6 +119,29 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode
        return ext2_add_nondir(dentry, inode);
 }
 
+static int ext2_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       struct inode *inode = ext2_new_inode(dir, mode, NULL);
+       if (IS_ERR(inode))
+               return PTR_ERR(inode);
+
+       inode->i_op = &ext2_file_inode_operations;
+       if (ext2_use_xip(inode->i_sb)) {
+               inode->i_mapping->a_ops = &ext2_aops_xip;
+               inode->i_fop = &ext2_xip_file_operations;
+       } else if (test_opt(inode->i_sb, NOBH)) {
+               inode->i_mapping->a_ops = &ext2_nobh_aops;
+               inode->i_fop = &ext2_file_operations;
+       } else {
+               inode->i_mapping->a_ops = &ext2_aops;
+               inode->i_fop = &ext2_file_operations;
+       }
+       mark_inode_dirty(inode);
+       d_tmpfile(dentry, inode);
+       unlock_new_inode(inode);
+       return 0;
+}
+
 static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev)
 {
        struct inode * inode;
@@ -398,6 +421,7 @@ const struct inode_operations ext2_dir_inode_operations = {
 #endif
        .setattr        = ext2_setattr,
        .get_acl        = ext2_get_acl,
+       .tmpfile        = ext2_tmpfile,
 };
 
 const struct inode_operations ext2_special_inode_operations = {
index cea8ecf3e76e47efb977127a95cb7b70a9d5f377..998ea111e537e8502dd33b15d5d9eb5f5374306d 100644 (file)
@@ -1759,6 +1759,45 @@ retry:
        return err;
 }
 
+static int ext3_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       handle_t *handle;
+       struct inode *inode;
+       int err, retries = 0;
+
+       dquot_initialize(dir);
+
+retry:
+       handle = ext3_journal_start(dir, EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
+                         4 + EXT3_XATTR_TRANS_BLOCKS);
+
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       inode = ext3_new_inode (handle, dir, NULL, mode);
+       err = PTR_ERR(inode);
+       if (!IS_ERR(inode)) {
+               inode->i_op = &ext3_file_inode_operations;
+               inode->i_fop = &ext3_file_operations;
+               ext3_set_aops(inode);
+               err = ext3_orphan_add(handle, inode);
+               if (err)
+                       goto err_drop_inode;
+               mark_inode_dirty(inode);
+               d_tmpfile(dentry, inode);
+               unlock_new_inode(inode);
+       }
+       ext3_journal_stop(handle);
+       if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
+               goto retry;
+       return err;
+err_drop_inode:
+       ext3_journal_stop(handle);
+       unlock_new_inode(inode);
+       iput(inode);
+       return err;
+}
+
 static int ext3_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
 {
        handle_t *handle;
@@ -2300,7 +2339,7 @@ static int ext3_link (struct dentry * old_dentry,
 
 retry:
        handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
-                                       EXT3_INDEX_EXTRA_TRANS_BLOCKS);
+                                       EXT3_INDEX_EXTRA_TRANS_BLOCKS + 1);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -2314,6 +2353,11 @@ retry:
        err = ext3_add_entry(handle, dentry, inode);
        if (!err) {
                ext3_mark_inode_dirty(handle, inode);
+               /* this can happen only for tmpfile being
+                * linked the first time
+                */
+               if (inode->i_nlink == 1)
+                       ext3_orphan_del(handle, inode);
                d_instantiate(dentry, inode);
        } else {
                drop_nlink(inode);
@@ -2516,6 +2560,7 @@ const struct inode_operations ext3_dir_inode_operations = {
        .mkdir          = ext3_mkdir,
        .rmdir          = ext3_rmdir,
        .mknod          = ext3_mknod,
+       .tmpfile        = ext3_tmpfile,
        .rename         = ext3_rename,
        .setattr        = ext3_setattr,
 #ifdef CONFIG_EXT3_FS_XATTR
index b19f0a457f329c5fb0f6974f7afff8dc79f1e31c..6f4cc567c382b7289e2b35a7038756a581b4cd95 100644 (file)
@@ -494,17 +494,7 @@ static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize)
        if (dataoff > isize)
                return -ENXIO;
 
-       if (dataoff < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
-               return -EINVAL;
-       if (dataoff > maxsize)
-               return -EINVAL;
-
-       if (dataoff != file->f_pos) {
-               file->f_pos = dataoff;
-               file->f_version = 0;
-       }
-
-       return dataoff;
+       return vfs_setpos(file, dataoff, maxsize);
 }
 
 /*
@@ -580,17 +570,7 @@ static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize)
        if (holeoff > isize)
                holeoff = isize;
 
-       if (holeoff < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
-               return -EINVAL;
-       if (holeoff > maxsize)
-               return -EINVAL;
-
-       if (holeoff != file->f_pos) {
-               file->f_pos = holeoff;
-               file->f_version = 0;
-       }
-
-       return holeoff;
+       return vfs_setpos(file, holeoff, maxsize);
 }
 
 /*
index ab2f6dc44b3abf88b62902433f48a1aa78ba8561..234b834d5a9749991e30a97e24e6017124c4e51d 100644 (file)
@@ -2296,6 +2296,45 @@ retry:
        return err;
 }
 
+static int ext4_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       handle_t *handle;
+       struct inode *inode;
+       int err, retries = 0;
+
+       dquot_initialize(dir);
+
+retry:
+       inode = ext4_new_inode_start_handle(dir, mode,
+                                           NULL, 0, NULL,
+                                           EXT4_HT_DIR,
+                       EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
+                         4 + EXT4_XATTR_TRANS_BLOCKS);
+       handle = ext4_journal_current_handle();
+       err = PTR_ERR(inode);
+       if (!IS_ERR(inode)) {
+               inode->i_op = &ext4_file_inode_operations;
+               inode->i_fop = &ext4_file_operations;
+               ext4_set_aops(inode);
+               err = ext4_orphan_add(handle, inode);
+               if (err)
+                       goto err_drop_inode;
+               mark_inode_dirty(inode);
+               d_tmpfile(dentry, inode);
+               unlock_new_inode(inode);
+       }
+       if (handle)
+               ext4_journal_stop(handle);
+       if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
+               goto retry;
+       return err;
+err_drop_inode:
+       ext4_journal_stop(handle);
+       unlock_new_inode(inode);
+       iput(inode);
+       return err;
+}
+
 struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
                          struct ext4_dir_entry_2 *de,
                          int blocksize, int csum_size,
@@ -2903,7 +2942,7 @@ static int ext4_link(struct dentry *old_dentry,
 retry:
        handle = ext4_journal_start(dir, EXT4_HT_DIR,
                (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
-                EXT4_INDEX_EXTRA_TRANS_BLOCKS));
+                EXT4_INDEX_EXTRA_TRANS_BLOCKS) + 1);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -2917,6 +2956,11 @@ retry:
        err = ext4_add_entry(handle, dentry, inode);
        if (!err) {
                ext4_mark_inode_dirty(handle, inode);
+               /* this can happen only for tmpfile being
+                * linked the first time
+                */
+               if (inode->i_nlink == 1)
+                       ext4_orphan_del(handle, inode);
                d_instantiate(dentry, inode);
        } else {
                drop_nlink(inode);
@@ -3169,6 +3213,7 @@ const struct inode_operations ext4_dir_inode_operations = {
        .mkdir          = ext4_mkdir,
        .rmdir          = ext4_rmdir,
        .mknod          = ext4_mknod,
+       .tmpfile        = ext4_tmpfile,
        .rename         = ext4_rename,
        .setattr        = ext4_setattr,
        .setxattr       = generic_setxattr,
index 081b759cff83fee7dc4fa3ba901b2ba9f92c888b..a783b0e1272ad16b3bb638e35867e130a0f455b3 100644 (file)
@@ -148,8 +148,7 @@ static int msdos_find(struct inode *dir, const unsigned char *name, int len,
  * that the existing dentry can be used. The msdos fs routines will
  * return ENOENT or EINVAL as appropriate.
  */
-static int msdos_hash(const struct dentry *dentry, const struct inode *inode,
-              struct qstr *qstr)
+static int msdos_hash(const struct dentry *dentry, struct qstr *qstr)
 {
        struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
        unsigned char msdos_name[MSDOS_NAME];
@@ -165,8 +164,7 @@ static int msdos_hash(const struct dentry *dentry, const struct inode *inode,
  * Compare two msdos names. If either of the names are invalid,
  * we fall back to doing the standard name comparison.
  */
-static int msdos_cmp(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int msdos_cmp(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options;
index 2da952036a3d7527d98b527ff7114b6d14ec4d43..6df8d3d885e5a56374dfeb61c90a7b6d6e148e15 100644 (file)
@@ -107,8 +107,7 @@ static unsigned int vfat_striptail_len(const struct qstr *qstr)
  * that the existing dentry can be used. The vfat fs routines will
  * return ENOENT or EINVAL as appropriate.
  */
-static int vfat_hash(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+static int vfat_hash(const struct dentry *dentry, struct qstr *qstr)
 {
        qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr));
        return 0;
@@ -120,8 +119,7 @@ static int vfat_hash(const struct dentry *dentry, const struct inode *inode,
  * that the existing dentry can be used. The vfat fs routines will
  * return ENOENT or EINVAL as appropriate.
  */
-static int vfat_hashi(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+static int vfat_hashi(const struct dentry *dentry, struct qstr *qstr)
 {
        struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io;
        const unsigned char *name;
@@ -142,8 +140,7 @@ static int vfat_hashi(const struct dentry *dentry, const struct inode *inode,
 /*
  * Case insensitive compare of two vfat names.
  */
-static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int vfat_cmpi(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io;
@@ -162,8 +159,7 @@ static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode,
 /*
  * Case sensitive compare of two vfat names.
  */
-static int vfat_cmp(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int vfat_cmp(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        unsigned int alen, blen;
index 485dc0eddd6707839120324ab552d94ef5ed5ab9..08e719b884ca31320bbcded23f6963ae0268779d 100644 (file)
@@ -227,7 +227,7 @@ static void __fput(struct file *file)
 {
        struct dentry *dentry = file->f_path.dentry;
        struct vfsmount *mnt = file->f_path.mnt;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_inode;
 
        might_sleep();
 
index 35f2810331427b9c4b660cc6b83ec1b889d6910b..5c121fe19c5f9b6122b687cc14bbcd7b1bbe0dc9 100644 (file)
@@ -548,8 +548,7 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
                        res = io->bytes < 0 ? io->size : io->bytes;
 
                        if (!is_sync_kiocb(io->iocb)) {
-                               struct path *path = &io->iocb->ki_filp->f_path;
-                               struct inode *inode = path->dentry->d_inode;
+                               struct inode *inode = file_inode(io->iocb->ki_filp);
                                struct fuse_conn *fc = get_fuse_conn(inode);
                                struct fuse_inode *fi = get_fuse_inode(inode);
 
index 4fddb3c22d258ca6da35b4e743ec80fc20ee2e08..f2448ab2aac54d99306140a192afa1c1d9e3dc46 100644 (file)
@@ -109,8 +109,7 @@ fail:
        return 0;
 }
 
-static int gfs2_dhash(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *str)
+static int gfs2_dhash(const struct dentry *dentry, struct qstr *str)
 {
        str->hash = gfs2_disk_hash(str->name, str->len);
        return 0;
index f99f9e8a325fa1cd37abcae7f2a09cb21ce6dd14..72c3866a73205217b9fe57d7863ce2376ce8002b 100644 (file)
@@ -912,7 +912,7 @@ out_uninit:
  * cluster; until we do, disable leases (by just returning -EINVAL),
  * unless the administrator has requested purely local locking.
  *
- * Locking: called under lock_flocks
+ * Locking: called under i_lock
  *
  * Returns: errno
  */
index a73b11839a41b24bf300075f2918dc2ec7b063b2..0524cda47a6e72db892c53c7da294aa212a4c17c 100644 (file)
@@ -229,13 +229,10 @@ extern int hfs_part_find(struct super_block *, sector_t *, sector_t *);
 /* string.c */
 extern const struct dentry_operations hfs_dentry_operations;
 
-extern int hfs_hash_dentry(const struct dentry *, const struct inode *,
-               struct qstr *);
+extern int hfs_hash_dentry(const struct dentry *, struct qstr *);
 extern int hfs_strcmp(const unsigned char *, unsigned int,
                      const unsigned char *, unsigned int);
-extern int hfs_compare_dentry(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+extern int hfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 
 /* trans.c */
index 495a976a3cc9aa0a0b6e56194ae8f91243129ae5..85b610c3909fbad5b5da73343f29cd9b2b84b96d 100644 (file)
@@ -51,8 +51,7 @@ static unsigned char caseorder[256] = {
 /*
  * Hash a string to an integer in a case-independent way
  */
-int hfs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *this)
+int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this)
 {
        const unsigned char *name = this->name;
        unsigned int hash, len = this->len;
@@ -93,8 +92,7 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1,
  * Test for equality of two strings in the HFS filename character ordering.
  * return 1 on failure and 0 on success
  */
-int hfs_compare_dentry(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+int hfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        const unsigned char *n1, *n2;
index 60b0a3388b262bcdfd2a02d449505e81b40e1d6b..ede79317cfb8cf5fa521dd187465a8cd63787979 100644 (file)
@@ -495,11 +495,8 @@ int hfsplus_uni2asc(struct super_block *,
                const struct hfsplus_unistr *, char *, int *);
 int hfsplus_asc2uni(struct super_block *,
                struct hfsplus_unistr *, int, const char *, int);
-int hfsplus_hash_dentry(const struct dentry *dentry,
-               const struct inode *inode, struct qstr *str);
-int hfsplus_compare_dentry(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str);
+int hfsplus_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 
 /* wrapper.c */
index 2c2e47dcfdd8aaceb0b297e7e340f02e8df6fe5d..e8ef121a4d8b5be7ca35bfe18aa4de4b925dfb59 100644 (file)
@@ -334,8 +334,7 @@ int hfsplus_asc2uni(struct super_block *sb,
  * Composed unicode characters are decomposed and case-folding is performed
  * if the appropriate bits are (un)set on the superblock.
  */
-int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *str)
+int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
 {
        struct super_block *sb = dentry->d_sb;
        const char *astr;
@@ -386,9 +385,7 @@ int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
  * Composed unicode characters are decomposed and case-folding is performed
  * if the appropriate bits are (un)set on the superblock.
  */
-int hfsplus_compare_dentry(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+int hfsplus_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        struct super_block *sb = parent->d_sb;
index 05d4816e4e774abd72e738c1d62761ceb824885f..fa27980f2229216c47c2378ce7431f18bd5a793e 100644 (file)
@@ -12,8 +12,7 @@
  * Note: the dentry argument is the parent dentry.
  */
 
-static int hpfs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+static int hpfs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 {
        unsigned long    hash;
        int              i;
@@ -35,9 +34,7 @@ static int hpfs_hash_dentry(const struct dentry *dentry, const struct inode *ino
        return 0;
 }
 
-static int hpfs_compare_dentry(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int hpfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        unsigned al = len;
index 00d5fc3b86e12419d2d350032b173009bddcd2cd..d6dfb09c828083b8ba64d3e8aacb2b6a64581038 100644 (file)
@@ -333,8 +333,10 @@ EXPORT_SYMBOL(set_nlink);
  */
 void inc_nlink(struct inode *inode)
 {
-       if (WARN_ON(inode->i_nlink == 0))
+       if (unlikely(inode->i_nlink == 0)) {
+               WARN_ON(!(inode->i_state & I_LINKABLE));
                atomic_long_dec(&inode->i_sb->s_remove_count);
+       }
 
        inode->__i_nlink++;
 }
index 68121584ae37d40a074bf81e55184ecb1674d882..7c5f01cf619d689d76ab51cc7cc221bead874cf4 100644 (file)
@@ -96,11 +96,12 @@ struct open_flags {
        umode_t mode;
        int acc_mode;
        int intent;
+       int lookup_flags;
 };
 extern struct file *do_filp_open(int dfd, struct filename *pathname,
-               const struct open_flags *op, int flags);
+               const struct open_flags *op);
 extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,
-               const char *, const struct open_flags *, int lookup_flags);
+               const char *, const struct open_flags *);
 
 extern long do_handle_open(int mountdirfd,
                           struct file_handle __user *ufh, int open_flag);
@@ -130,6 +131,7 @@ extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);
  * read_write.c
  */
 extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *);
+extern int rw_verify_area(int, struct file *, const loff_t *, size_t);
 
 /*
  * splice.c
index d9b8aebdeb22b467eb9717996b823734f8446300..c348d6d886240cb0354dbc71faf88fef2395db67 100644 (file)
 
 #define BEQUIET
 
-static int isofs_hashi(const struct dentry *parent, const struct inode *inode,
-               struct qstr *qstr);
-static int isofs_hash(const struct dentry *parent, const struct inode *inode,
-               struct qstr *qstr);
+static int isofs_hashi(const struct dentry *parent, struct qstr *qstr);
+static int isofs_hash(const struct dentry *parent, struct qstr *qstr);
 static int isofs_dentry_cmpi(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+               const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 static int isofs_dentry_cmp(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+               const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 
 #ifdef CONFIG_JOLIET
-static int isofs_hashi_ms(const struct dentry *parent, const struct inode *inode,
-               struct qstr *qstr);
-static int isofs_hash_ms(const struct dentry *parent, const struct inode *inode,
-               struct qstr *qstr);
+static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr);
+static int isofs_hash_ms(const struct dentry *parent, struct qstr *qstr);
 static int isofs_dentry_cmpi_ms(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+               const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 static int isofs_dentry_cmp_ms(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+               const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 #endif
 
@@ -265,30 +257,26 @@ static int isofs_dentry_cmp_common(
 }
 
 static int
-isofs_hash(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+isofs_hash(const struct dentry *dentry, struct qstr *qstr)
 {
        return isofs_hash_common(dentry, qstr, 0);
 }
 
 static int
-isofs_hashi(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+isofs_hashi(const struct dentry *dentry, struct qstr *qstr)
 {
        return isofs_hashi_common(dentry, qstr, 0);
 }
 
 static int
-isofs_dentry_cmp(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+isofs_dentry_cmp(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return isofs_dentry_cmp_common(len, str, name, 0, 0);
 }
 
 static int
-isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return isofs_dentry_cmp_common(len, str, name, 0, 1);
@@ -296,30 +284,26 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode,
 
 #ifdef CONFIG_JOLIET
 static int
-isofs_hash_ms(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr)
 {
        return isofs_hash_common(dentry, qstr, 1);
 }
 
 static int
-isofs_hashi_ms(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+isofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr)
 {
        return isofs_hashi_common(dentry, qstr, 1);
 }
 
 static int
-isofs_dentry_cmp_ms(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+isofs_dentry_cmp_ms(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return isofs_dentry_cmp_common(len, str, name, 1, 0);
 }
 
 static int
-isofs_dentry_cmpi_ms(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+isofs_dentry_cmpi_ms(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return isofs_dentry_cmp_common(len, str, name, 1, 1);
index c167028844ed539fca2b25931ccfb51a8d32d962..95295640d9c8b0a36c4f6fae469e59488c21a52e 100644 (file)
@@ -37,8 +37,7 @@ isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
 
        qstr.name = compare;
        qstr.len = dlen;
-       return dentry->d_op->d_compare(NULL, NULL, NULL, NULL,
-                       dentry->d_name.len, dentry->d_name.name, &qstr);
+       return dentry->d_op->d_compare(NULL, NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
 }
 
 /*
index 89186b7b9002145d268aa7054559b384422dd1d2..8b19027291d6b14b667757256499a750df5312ef 100644 (file)
@@ -1538,8 +1538,7 @@ const struct file_operations jfs_dir_operations = {
        .llseek         = generic_file_llseek,
 };
 
-static int jfs_ci_hash(const struct dentry *dir, const struct inode *inode,
-               struct qstr *this)
+static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
 {
        unsigned long hash;
        int i;
@@ -1552,9 +1551,7 @@ static int jfs_ci_hash(const struct dentry *dir, const struct inode *inode,
        return 0;
 }
 
-static int jfs_ci_compare(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int jfs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        int i, result = 1;
index e703318c41dface91c09b100a3c88bacd63f6751..067778b0ccc9dddd878277d6ca88e9c5d2fddc5b 100644 (file)
@@ -276,7 +276,7 @@ static int nlmsvc_unlink_block(struct nlm_block *block)
        dprintk("lockd: unlinking block %p...\n", block);
 
        /* Remove block from list */
-       status = posix_unblock_lock(block->b_file->f_file, &block->b_call->a_args.lock.fl);
+       status = posix_unblock_lock(&block->b_call->a_args.lock.fl);
        nlmsvc_remove_block(block);
        return status;
 }
@@ -744,8 +744,20 @@ static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2)
        return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid;
 }
 
+/*
+ * Since NLM uses two "keys" for tracking locks, we need to hash them down
+ * to one for the blocked_hash. Here, we're just xor'ing the host address
+ * with the pid in order to create a key value for picking a hash bucket.
+ */
+static unsigned long
+nlmsvc_owner_key(struct file_lock *fl)
+{
+       return (unsigned long)fl->fl_owner ^ (unsigned long)fl->fl_pid;
+}
+
 const struct lock_manager_operations nlmsvc_lock_operations = {
        .lm_compare_owner = nlmsvc_same_owner,
+       .lm_owner_key = nlmsvc_owner_key,
        .lm_notify = nlmsvc_notify_blocked,
        .lm_grant = nlmsvc_grant_deferred,
 };
index 97e87415b145f7a6a0ed0e1a37c40a657209bf89..dc5c75930f0fea94145c9556f2aab6dbc8ea91a3 100644 (file)
@@ -169,7 +169,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
 
 again:
        file->f_locks = 0;
-       lock_flocks(); /* protects i_flock list */
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl; fl = fl->fl_next) {
                if (fl->fl_lmops != &nlmsvc_lock_operations)
                        continue;
@@ -181,7 +181,7 @@ again:
                if (match(lockhost, host)) {
                        struct file_lock lock = *fl;
 
-                       unlock_flocks();
+                       spin_unlock(&inode->i_lock);
                        lock.fl_type  = F_UNLCK;
                        lock.fl_start = 0;
                        lock.fl_end   = OFFSET_MAX;
@@ -193,7 +193,7 @@ again:
                        goto again;
                }
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 
        return 0;
 }
@@ -228,14 +228,14 @@ nlm_file_inuse(struct nlm_file *file)
        if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
                return 1;
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl; fl = fl->fl_next) {
                if (fl->fl_lmops == &nlmsvc_lock_operations) {
-                       unlock_flocks();
+                       spin_unlock(&inode->i_lock);
                        return 1;
                }
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        file->f_locks = 0;
        return 0;
 }
index cb424a4fed71a42d237b72d16de8318bbbeb0fbd..04e2c1fdb157afeb0bc8fe278a74909cd239126b 100644 (file)
 #include <linux/time.h>
 #include <linux/rcupdate.h>
 #include <linux/pid_namespace.h>
+#include <linux/hashtable.h>
 
 #include <asm/uaccess.h>
 
@@ -153,30 +154,51 @@ int lease_break_time = 45;
 #define for_each_lock(inode, lockp) \
        for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next)
 
-static LIST_HEAD(file_lock_list);
-static LIST_HEAD(blocked_list);
+/*
+ * The global file_lock_list is only used for displaying /proc/locks. Protected
+ * by the file_lock_lock.
+ */
+static HLIST_HEAD(file_lock_list);
 static DEFINE_SPINLOCK(file_lock_lock);
 
 /*
- * Protects the two list heads above, plus the inode->i_flock list
+ * The blocked_hash is used to find POSIX lock loops for deadlock detection.
+ * It is protected by blocked_lock_lock.
+ *
+ * We hash locks by lockowner in order to optimize searching for the lock a
+ * particular lockowner is waiting on.
+ *
+ * FIXME: make this value scale via some heuristic? We generally will want more
+ * buckets when we have more lockowners holding locks, but that's a little
+ * difficult to determine without knowing what the workload will look like.
  */
-void lock_flocks(void)
-{
-       spin_lock(&file_lock_lock);
-}
-EXPORT_SYMBOL_GPL(lock_flocks);
+#define BLOCKED_HASH_BITS      7
+static DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS);
 
-void unlock_flocks(void)
-{
-       spin_unlock(&file_lock_lock);
-}
-EXPORT_SYMBOL_GPL(unlock_flocks);
+/*
+ * This lock protects the blocked_hash. Generally, if you're accessing it, you
+ * want to be holding this lock.
+ *
+ * In addition, it also protects the fl->fl_block list, and the fl->fl_next
+ * pointer for file_lock structures that are acting as lock requests (in
+ * contrast to those that are acting as records of acquired locks).
+ *
+ * Note that when we acquire this lock in order to change the above fields,
+ * we often hold the i_lock as well. In certain cases, when reading the fields
+ * protected by this lock, we can skip acquiring it iff we already hold the
+ * i_lock.
+ *
+ * In particular, adding an entry to the fl_block list requires that you hold
+ * both the i_lock and the blocked_lock_lock (acquired in that order). Deleting
+ * an entry from the list however only requires the file_lock_lock.
+ */
+static DEFINE_SPINLOCK(blocked_lock_lock);
 
 static struct kmem_cache *filelock_cache __read_mostly;
 
 static void locks_init_lock_heads(struct file_lock *fl)
 {
-       INIT_LIST_HEAD(&fl->fl_link);
+       INIT_HLIST_NODE(&fl->fl_link);
        INIT_LIST_HEAD(&fl->fl_block);
        init_waitqueue_head(&fl->fl_wait);
 }
@@ -210,7 +232,7 @@ void locks_free_lock(struct file_lock *fl)
 {
        BUG_ON(waitqueue_active(&fl->fl_wait));
        BUG_ON(!list_empty(&fl->fl_block));
-       BUG_ON(!list_empty(&fl->fl_link));
+       BUG_ON(!hlist_unhashed(&fl->fl_link));
 
        locks_release_private(fl);
        kmem_cache_free(filelock_cache, fl);
@@ -484,47 +506,108 @@ static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
        return fl1->fl_owner == fl2->fl_owner;
 }
 
+static inline void
+locks_insert_global_locks(struct file_lock *fl)
+{
+       spin_lock(&file_lock_lock);
+       hlist_add_head(&fl->fl_link, &file_lock_list);
+       spin_unlock(&file_lock_lock);
+}
+
+static inline void
+locks_delete_global_locks(struct file_lock *fl)
+{
+       spin_lock(&file_lock_lock);
+       hlist_del_init(&fl->fl_link);
+       spin_unlock(&file_lock_lock);
+}
+
+static unsigned long
+posix_owner_key(struct file_lock *fl)
+{
+       if (fl->fl_lmops && fl->fl_lmops->lm_owner_key)
+               return fl->fl_lmops->lm_owner_key(fl);
+       return (unsigned long)fl->fl_owner;
+}
+
+static inline void
+locks_insert_global_blocked(struct file_lock *waiter)
+{
+       hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter));
+}
+
+static inline void
+locks_delete_global_blocked(struct file_lock *waiter)
+{
+       hash_del(&waiter->fl_link);
+}
+
 /* Remove waiter from blocker's block list.
  * When blocker ends up pointing to itself then the list is empty.
+ *
+ * Must be called with blocked_lock_lock held.
  */
 static void __locks_delete_block(struct file_lock *waiter)
 {
+       locks_delete_global_blocked(waiter);
        list_del_init(&waiter->fl_block);
-       list_del_init(&waiter->fl_link);
        waiter->fl_next = NULL;
 }
 
-/*
- */
-void locks_delete_block(struct file_lock *waiter)
+static void locks_delete_block(struct file_lock *waiter)
 {
-       lock_flocks();
+       spin_lock(&blocked_lock_lock);
        __locks_delete_block(waiter);
-       unlock_flocks();
+       spin_unlock(&blocked_lock_lock);
 }
-EXPORT_SYMBOL(locks_delete_block);
 
 /* Insert waiter into blocker's block list.
  * We use a circular list so that processes can be easily woken up in
  * the order they blocked. The documentation doesn't require this but
  * it seems like the reasonable thing to do.
+ *
+ * Must be called with both the i_lock and blocked_lock_lock held. The fl_block
+ * list itself is protected by the file_lock_list, but by ensuring that the
+ * i_lock is also held on insertions we can avoid taking the blocked_lock_lock
+ * in some cases when we see that the fl_block list is empty.
  */
-static void locks_insert_block(struct file_lock *blocker, 
-                              struct file_lock *waiter)
+static void __locks_insert_block(struct file_lock *blocker,
+                                       struct file_lock *waiter)
 {
        BUG_ON(!list_empty(&waiter->fl_block));
-       list_add_tail(&waiter->fl_block, &blocker->fl_block);
        waiter->fl_next = blocker;
+       list_add_tail(&waiter->fl_block, &blocker->fl_block);
        if (IS_POSIX(blocker))
-               list_add(&waiter->fl_link, &blocked_list);
+               locks_insert_global_blocked(waiter);
 }
 
-/* Wake up processes blocked waiting for blocker.
- * If told to wait then schedule the processes until the block list
- * is empty, otherwise empty the block list ourselves.
+/* Must be called with i_lock held. */
+static void locks_insert_block(struct file_lock *blocker,
+                                       struct file_lock *waiter)
+{
+       spin_lock(&blocked_lock_lock);
+       __locks_insert_block(blocker, waiter);
+       spin_unlock(&blocked_lock_lock);
+}
+
+/*
+ * Wake up processes blocked waiting for blocker.
+ *
+ * Must be called with the inode->i_lock held!
  */
 static void locks_wake_up_blocks(struct file_lock *blocker)
 {
+       /*
+        * Avoid taking global lock if list is empty. This is safe since new
+        * blocked requests are only added to the list under the i_lock, and
+        * the i_lock is always held here. Note that removal from the fl_block
+        * list does not require the i_lock, so we must recheck list_empty()
+        * after acquiring the blocked_lock_lock.
+        */
+       if (list_empty(&blocker->fl_block))
+               return;
+
+       spin_lock(&blocked_lock_lock);
        while (!list_empty(&blocker->fl_block)) {
                struct file_lock *waiter;
 
@@ -536,20 +619,23 @@ static void locks_wake_up_blocks(struct file_lock *blocker)
                else
                        wake_up(&waiter->fl_wait);
        }
+       spin_unlock(&blocked_lock_lock);
 }
 
 /* Insert file lock fl into an inode's lock list at the position indicated
  * by pos. At the same time add the lock to the global file lock list.
+ *
+ * Must be called with the i_lock held!
  */
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
 {
-       list_add(&fl->fl_link, &file_lock_list);
-
        fl->fl_nspid = get_pid(task_tgid(current));
 
        /* insert into file's list */
        fl->fl_next = *pos;
        *pos = fl;
+
+       locks_insert_global_locks(fl);
 }
 
 /*
@@ -557,14 +643,17 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
  * Wake up processes that are blocked waiting for this lock,
  * notify the FS that the lock has been cleared and
  * finally free the lock.
+ *
+ * Must be called with the i_lock held!
  */
 static void locks_delete_lock(struct file_lock **thisfl_p)
 {
        struct file_lock *fl = *thisfl_p;
 
+       locks_delete_global_locks(fl);
+
        *thisfl_p = fl->fl_next;
        fl->fl_next = NULL;
-       list_del_init(&fl->fl_link);
 
        if (fl->fl_nspid) {
                put_pid(fl->fl_nspid);
@@ -625,8 +714,9 @@ void
 posix_test_lock(struct file *filp, struct file_lock *fl)
 {
        struct file_lock *cfl;
+       struct inode *inode = file_inode(filp);
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        for (cfl = file_inode(filp)->i_flock; cfl; cfl = cfl->fl_next) {
                if (!IS_POSIX(cfl))
                        continue;
@@ -639,7 +729,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
                        fl->fl_pid = pid_vnr(cfl->fl_nspid);
        } else
                fl->fl_type = F_UNLCK;
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        return;
 }
 EXPORT_SYMBOL(posix_test_lock);
@@ -676,13 +766,14 @@ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl)
 {
        struct file_lock *fl;
 
-       list_for_each_entry(fl, &blocked_list, fl_link) {
+       hash_for_each_possible(blocked_hash, fl, fl_link, posix_owner_key(block_fl)) {
                if (posix_same_owner(fl, block_fl))
                        return fl->fl_next;
        }
        return NULL;
 }
 
+/* Must be called with the blocked_lock_lock held! */
 static int posix_locks_deadlock(struct file_lock *caller_fl,
                                struct file_lock *block_fl)
 {
@@ -718,7 +809,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
                        return -ENOMEM;
        }
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        if (request->fl_flags & FL_ACCESS)
                goto find_conflict;
 
@@ -748,9 +839,9 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
         * give it the opportunity to lock the file.
         */
        if (found) {
-               unlock_flocks();
+               spin_unlock(&inode->i_lock);
                cond_resched();
-               lock_flocks();
+               spin_lock(&inode->i_lock);
        }
 
 find_conflict:
@@ -777,7 +868,7 @@ find_conflict:
        error = 0;
 
 out:
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        if (new_fl)
                locks_free_lock(new_fl);
        return error;
@@ -791,7 +882,8 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
        struct file_lock *left = NULL;
        struct file_lock *right = NULL;
        struct file_lock **before;
-       int error, added = 0;
+       int error;
+       bool added = false;
 
        /*
         * We may need two file_lock structures for this operation,
@@ -806,7 +898,12 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                new_fl2 = locks_alloc_lock();
        }
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
+       /*
+        * New lock request. Walk all POSIX locks and look for conflicts. If
+        * there are any, either return error or put the request on the
+        * blocker's list of waiters and the global blocked_hash.
+        */
        if (request->fl_type != F_UNLCK) {
                for_each_lock(inode, before) {
                        fl = *before;
@@ -819,11 +916,17 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                        error = -EAGAIN;
                        if (!(request->fl_flags & FL_SLEEP))
                                goto out;
+                       /*
+                        * Deadlock detection and insertion into the blocked
+                        * locks list must be done while holding the same lock!
+                        */
                        error = -EDEADLK;
-                       if (posix_locks_deadlock(request, fl))
-                               goto out;
-                       error = FILE_LOCK_DEFERRED;
-                       locks_insert_block(fl, request);
+                       spin_lock(&blocked_lock_lock);
+                       if (likely(!posix_locks_deadlock(request, fl))) {
+                               error = FILE_LOCK_DEFERRED;
+                               __locks_insert_block(fl, request);
+                       }
+                       spin_unlock(&blocked_lock_lock);
                        goto out;
                }
        }
@@ -845,7 +948,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                before = &fl->fl_next;
        }
 
-       /* Process locks with this owner.  */
+       /* Process locks with this owner. */
        while ((fl = *before) && posix_same_owner(request, fl)) {
                /* Detect adjacent or overlapping regions (if same lock type)
                 */
@@ -880,7 +983,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                                continue;
                        }
                        request = fl;
-                       added = 1;
+                       added = true;
                }
                else {
                        /* Processing for different lock types is a bit
@@ -891,7 +994,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                        if (fl->fl_start > request->fl_end)
                                break;
                        if (request->fl_type == F_UNLCK)
-                               added = 1;
+                               added = true;
                        if (fl->fl_start < request->fl_start)
                                left = fl;
                        /* If the next lock in the list has a higher end
@@ -921,7 +1024,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                                locks_release_private(fl);
                                locks_copy_private(fl, request);
                                request = fl;
-                               added = 1;
+                               added = true;
                        }
                }
                /* Go on to next lock.
@@ -931,10 +1034,9 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
        }
 
        /*
-        * The above code only modifies existing locks in case of
-        * merging or replacing.  If new lock(s) need to be inserted
-        * all modifications are done bellow this, so it's safe yet to
-        * bail out.
+        * The above code only modifies existing locks in case of merging or
+        * replacing. If new lock(s) need to be inserted all modifications are
+        * done below this, so it's safe yet to bail out.
         */
        error = -ENOLCK; /* "no luck" */
        if (right && left == right && !new_fl2)
@@ -974,7 +1076,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                locks_wake_up_blocks(left);
        }
  out:
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        /*
         * Free any unused locks.
         */
@@ -1049,14 +1151,14 @@ int locks_mandatory_locked(struct inode *inode)
        /*
         * Search the lock list for this inode for any POSIX locks.
         */
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (!IS_POSIX(fl))
                        continue;
                if (fl->fl_owner != owner)
                        break;
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        return fl ? -EAGAIN : 0;
 }
 
@@ -1199,7 +1301,7 @@ int __break_lease(struct inode *inode, unsigned int mode)
        if (IS_ERR(new_fl))
                return PTR_ERR(new_fl);
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
 
        time_out_leases(inode);
 
@@ -1249,11 +1351,11 @@ restart:
                        break_time++;
        }
        locks_insert_block(flock, new_fl);
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        error = wait_event_interruptible_timeout(new_fl->fl_wait,
                                                !new_fl->fl_next, break_time);
-       lock_flocks();
-       __locks_delete_block(new_fl);
+       spin_lock(&inode->i_lock);
+       locks_delete_block(new_fl);
        if (error >= 0) {
                if (error == 0)
                        time_out_leases(inode);
@@ -1270,7 +1372,7 @@ restart:
        }
 
 out:
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        locks_free_lock(new_fl);
        return error;
 }
@@ -1323,9 +1425,10 @@ EXPORT_SYMBOL(lease_get_mtime);
 int fcntl_getlease(struct file *filp)
 {
        struct file_lock *fl;
+       struct inode *inode = file_inode(filp);
        int type = F_UNLCK;
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        time_out_leases(file_inode(filp));
        for (fl = file_inode(filp)->i_flock; fl && IS_LEASE(fl);
                        fl = fl->fl_next) {
@@ -1334,11 +1437,11 @@ int fcntl_getlease(struct file *filp)
                        break;
                }
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        return type;
 }
 
-int generic_add_lease(struct file *filp, long arg, struct file_lock **flp)
+static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp)
 {
        struct file_lock *fl, **before, **my_before = NULL, *lease;
        struct dentry *dentry = filp->f_path.dentry;
@@ -1403,7 +1506,7 @@ out:
        return error;
 }
 
-int generic_delete_lease(struct file *filp, struct file_lock **flp)
+static int generic_delete_lease(struct file *filp, struct file_lock **flp)
 {
        struct file_lock *fl, **before;
        struct dentry *dentry = filp->f_path.dentry;
@@ -1428,7 +1531,7 @@ int generic_delete_lease(struct file *filp, struct file_lock **flp)
  *     The (input) flp->fl_lmops->lm_break function is required
  *     by break_lease().
  *
- *     Called with file_lock_lock held.
+ *     Called with inode->i_lock held.
  */
 int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
 {
@@ -1497,11 +1600,12 @@ static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
 
 int vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
 {
+       struct inode *inode = file_inode(filp);
        int error;
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        error = __vfs_setlease(filp, arg, lease);
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 
        return error;
 }
@@ -1519,6 +1623,7 @@ static int do_fcntl_delete_lease(struct file *filp)
 static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
 {
        struct file_lock *fl, *ret;
+       struct inode *inode = file_inode(filp);
        struct fasync_struct *new;
        int error;
 
@@ -1532,10 +1637,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
                return -ENOMEM;
        }
        ret = fl;
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        error = __vfs_setlease(filp, arg, &ret);
        if (error) {
-               unlock_flocks();
+               spin_unlock(&inode->i_lock);
                locks_free_lock(fl);
                goto out_free_fasync;
        }
@@ -1552,7 +1657,7 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
                new = NULL;
 
        error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 
 out_free_fasync:
        if (new)
@@ -2076,7 +2181,7 @@ void locks_remove_flock(struct file *filp)
                        fl.fl_ops->fl_release_private(&fl);
        }
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        before = &inode->i_flock;
 
        while ((fl = *before) != NULL) {
@@ -2094,30 +2199,28 @@ void locks_remove_flock(struct file *filp)
                }
                before = &fl->fl_next;
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 }
 
 /**
  *     posix_unblock_lock - stop waiting for a file lock
- *      @filp:   how the file was opened
  *     @waiter: the lock which was waiting
  *
  *     lockd needs to block waiting for locks.
  */
 int
-posix_unblock_lock(struct file *filp, struct file_lock *waiter)
+posix_unblock_lock(struct file_lock *waiter)
 {
        int status = 0;
 
-       lock_flocks();
+       spin_lock(&blocked_lock_lock);
        if (waiter->fl_next)
                __locks_delete_block(waiter);
        else
                status = -ENOENT;
-       unlock_flocks();
+       spin_unlock(&blocked_lock_lock);
        return status;
 }
-
 EXPORT_SYMBOL(posix_unblock_lock);
 
 /**
@@ -2215,7 +2318,7 @@ static int locks_show(struct seq_file *f, void *v)
 {
        struct file_lock *fl, *bfl;
 
-       fl = list_entry(v, struct file_lock, fl_link);
+       fl = hlist_entry(v, struct file_lock, fl_link);
 
        lock_get_status(f, fl, *((loff_t *)f->private), "");
 
@@ -2229,21 +2332,23 @@ static void *locks_start(struct seq_file *f, loff_t *pos)
 {
        loff_t *p = f->private;
 
-       lock_flocks();
+       spin_lock(&file_lock_lock);
+       spin_lock(&blocked_lock_lock);
        *p = (*pos + 1);
-       return seq_list_start(&file_lock_list, *pos);
+       return seq_hlist_start(&file_lock_list, *pos);
 }
 
 static void *locks_next(struct seq_file *f, void *v, loff_t *pos)
 {
        loff_t *p = f->private;
        ++*p;
-       return seq_list_next(v, &file_lock_list, pos);
+       return seq_hlist_next(v, &file_lock_list, pos);
 }
 
 static void locks_stop(struct seq_file *f, void *v)
 {
-       unlock_flocks();
+       spin_unlock(&blocked_lock_lock);
+       spin_unlock(&file_lock_lock);
 }
 
 static const struct seq_operations locks_seq_operations = {
@@ -2290,7 +2395,8 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len)
 {
        struct file_lock *fl;
        int result = 1;
-       lock_flocks();
+
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (IS_POSIX(fl)) {
                        if (fl->fl_type == F_RDLCK)
@@ -2307,7 +2413,7 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len)
                result = 0;
                break;
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        return result;
 }
 
@@ -2330,7 +2436,8 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
 {
        struct file_lock *fl;
        int result = 1;
-       lock_flocks();
+
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (IS_POSIX(fl)) {
                        if ((fl->fl_end < start) || (fl->fl_start > (start + len)))
@@ -2345,7 +2452,7 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
                result = 0;
                break;
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        return result;
 }
 
index 08c442902fcdbf9ec5a9039621f8b8900ea6bf0e..dfaf6fa9b7b52a28bcb00ce3c4cd3df817158814 100644 (file)
@@ -93,7 +93,7 @@ static int minix_readdir(struct file *file, struct dir_context *ctx)
        unsigned offset;
        unsigned long n;
 
-       ctx->pos = pos = (pos + chunk_size-1) & ~(chunk_size-1);
+       ctx->pos = pos = ALIGN(pos, chunk_size);
        if (pos >= inode->i_size)
                return 0;
 
index 0db73d9dd66845d289f6f1a58e1960ecc1ee3e74..cd950e2331b6c3164376e1b2205b3563f5703525 100644 (file)
@@ -54,6 +54,18 @@ static int minix_mknod(struct inode * dir, struct dentry *dentry, umode_t mode,
        return error;
 }
 
+static int minix_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       int error;
+       struct inode *inode = minix_new_inode(dir, mode, &error);
+       if (inode) {
+               minix_set_inode(inode, 0);
+               mark_inode_dirty(inode);
+               d_tmpfile(dentry, inode);
+       }
+       return error;
+}
+
 static int minix_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                bool excl)
 {
@@ -254,4 +266,5 @@ const struct inode_operations minix_dir_inode_operations = {
        .mknod          = minix_mknod,
        .rename         = minix_rename,
        .getattr        = minix_getattr,
+       .tmpfile        = minix_tmpfile,
 };
index 9ed9361223c08f30ebbcca48e165588adeb31378..b2beee7a733fe3f862945f39042e04937f821741 100644 (file)
@@ -1352,7 +1352,7 @@ static int lookup_fast(struct nameidata *nd,
         */
        if (nd->flags & LOOKUP_RCU) {
                unsigned seq;
-               dentry = __d_lookup_rcu(parent, &nd->last, &seq, nd->inode);
+               dentry = __d_lookup_rcu(parent, &nd->last, &seq);
                if (!dentry)
                        goto unlazy;
 
@@ -1787,8 +1787,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                        struct dentry *parent = nd->path.dentry;
                        nd->flags &= ~LOOKUP_JUMPED;
                        if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
-                               err = parent->d_op->d_hash(parent, nd->inode,
-                                                          &this);
+                               err = parent->d_op->d_hash(parent, &this);
                                if (err < 0)
                                        break;
                        }
@@ -2121,7 +2120,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
         * to use its own hash..
         */
        if (base->d_flags & DCACHE_OP_HASH) {
-               int err = base->d_op->d_hash(base, base->d_inode, &this);
+               int err = base->d_op->d_hash(base, &this);
                if (err < 0)
                        return ERR_PTR(err);
        }
@@ -2690,28 +2689,10 @@ static int do_last(struct nameidata *nd, struct path *path,
        nd->flags &= ~LOOKUP_PARENT;
        nd->flags |= op->intent;
 
-       switch (nd->last_type) {
-       case LAST_DOTDOT:
-       case LAST_DOT:
+       if (nd->last_type != LAST_NORM) {
                error = handle_dots(nd, nd->last_type);
                if (error)
                        return error;
-               /* fallthrough */
-       case LAST_ROOT:
-               error = complete_walk(nd);
-               if (error)
-                       return error;
-               audit_inode(name, nd->path.dentry, 0);
-               if (open_flag & O_CREAT) {
-                       error = -EISDIR;
-                       goto out;
-               }
-               goto finish_open;
-       case LAST_BIND:
-               error = complete_walk(nd);
-               if (error)
-                       return error;
-               audit_inode(name, dir, 0);
                goto finish_open;
        }
 
@@ -2841,19 +2822,19 @@ finish_lookup:
        }
        nd->inode = inode;
        /* Why this, you ask?  _Now_ we might have grown LOOKUP_JUMPED... */
+finish_open:
        error = complete_walk(nd);
        if (error) {
                path_put(&save_parent);
                return error;
        }
+       audit_inode(name, nd->path.dentry, 0);
        error = -EISDIR;
        if ((open_flag & O_CREAT) && S_ISDIR(nd->inode->i_mode))
                goto out;
        error = -ENOTDIR;
        if ((nd->flags & LOOKUP_DIRECTORY) && !can_lookup(nd->inode))
                goto out;
-       audit_inode(name, nd->path.dentry, 0);
-finish_open:
        if (!S_ISREG(nd->inode->i_mode))
                will_truncate = false;
 
@@ -2920,6 +2901,67 @@ stale_open:
        goto retry_lookup;
 }
 
+static int do_tmpfile(int dfd, struct filename *pathname,
+               struct nameidata *nd, int flags,
+               const struct open_flags *op,
+               struct file *file, int *opened)
+{
+       static const struct qstr name = QSTR_INIT("/", 1);
+       struct dentry *dentry, *child;
+       struct inode *dir;
+       int error = path_lookupat(dfd, pathname->name,
+                                 flags | LOOKUP_DIRECTORY, nd);
+       if (unlikely(error))
+               return error;
+       error = mnt_want_write(nd->path.mnt);
+       if (unlikely(error))
+               goto out;
+       /* we want directory to be writable */
+       error = inode_permission(nd->inode, MAY_WRITE | MAY_EXEC);
+       if (error)
+               goto out2;
+       dentry = nd->path.dentry;
+       dir = dentry->d_inode;
+       if (!dir->i_op->tmpfile) {
+               error = -EOPNOTSUPP;
+               goto out2;
+       }
+       child = d_alloc(dentry, &name);
+       if (unlikely(!child)) {
+               error = -ENOMEM;
+               goto out2;
+       }
+       nd->flags &= ~LOOKUP_DIRECTORY;
+       nd->flags |= op->intent;
+       dput(nd->path.dentry);
+       nd->path.dentry = child;
+       error = dir->i_op->tmpfile(dir, nd->path.dentry, op->mode);
+       if (error)
+               goto out2;
+       audit_inode(pathname, nd->path.dentry, 0);
+       error = may_open(&nd->path, op->acc_mode, op->open_flag);
+       if (error)
+               goto out2;
+       file->f_path.mnt = nd->path.mnt;
+       error = finish_open(file, nd->path.dentry, NULL, opened);
+       if (error)
+               goto out2;
+       error = open_check_o_direct(file);
+       if (error) {
+               fput(file);
+       } else if (!(op->open_flag & O_EXCL)) {
+               struct inode *inode = file_inode(file);
+               spin_lock(&inode->i_lock);
+               inode->i_state |= I_LINKABLE;
+               spin_unlock(&inode->i_lock);
+       }
+out2:
+       mnt_drop_write(nd->path.mnt);
+out:
+       path_put(&nd->path);
+       return error;
+}
+
 static struct file *path_openat(int dfd, struct filename *pathname,
                struct nameidata *nd, const struct open_flags *op, int flags)
 {
@@ -2935,6 +2977,11 @@ static struct file *path_openat(int dfd, struct filename *pathname,
 
        file->f_flags = op->open_flag;
 
+       if (unlikely(file->f_flags & O_TMPFILE)) {
+               error = do_tmpfile(dfd, pathname, nd, flags, op, file, &opened);
+               goto out;
+       }
+
        error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, &base);
        if (unlikely(error))
                goto out;
@@ -2987,9 +3034,10 @@ out:
 }
 
 struct file *do_filp_open(int dfd, struct filename *pathname,
-               const struct open_flags *op, int flags)
+               const struct open_flags *op)
 {
        struct nameidata nd;
+       int flags = op->lookup_flags;
        struct file *filp;
 
        filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
@@ -3001,17 +3049,16 @@ struct file *do_filp_open(int dfd, struct filename *pathname,
 }
 
 struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
-               const char *name, const struct open_flags *op, int flags)
+               const char *name, const struct open_flags *op)
 {
        struct nameidata nd;
        struct file *file;
        struct filename filename = { .name = name };
+       int flags = op->lookup_flags | LOOKUP_ROOT;
 
        nd.root.mnt = mnt;
        nd.root.dentry = dentry;
 
-       flags |= LOOKUP_ROOT;
-
        if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN)
                return ERR_PTR(-ELOOP);
 
@@ -3586,12 +3633,18 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
 
        mutex_lock(&inode->i_mutex);
        /* Make sure we don't allow creating hardlink to an unlinked file */
-       if (inode->i_nlink == 0)
+       if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE))
                error =  -ENOENT;
        else if (max_links && inode->i_nlink >= max_links)
                error = -EMLINK;
        else
                error = dir->i_op->link(old_dentry, dir, new_dentry);
+
+       if (!error && (inode->i_state & I_LINKABLE)) {
+               spin_lock(&inode->i_lock);
+               inode->i_state &= ~I_LINKABLE;
+               spin_unlock(&inode->i_lock);
+       }
        mutex_unlock(&inode->i_mutex);
        if (!error)
                fsnotify_link(dir, inode, new_dentry);
index 0e7f00298213f3249b34f8564609c762d2e765ed..3be047474bfc355731c08e2a6c27b40e73ce9e8b 100644 (file)
@@ -73,10 +73,8 @@ const struct inode_operations ncp_dir_inode_operations =
  * Dentry operations routines
  */
 static int ncp_lookup_validate(struct dentry *, unsigned int);
-static int ncp_hash_dentry(const struct dentry *, const struct inode *,
-               struct qstr *);
-static int ncp_compare_dentry(const struct dentry *, const struct inode *,
-               const struct dentry *, const struct inode *,
+static int ncp_hash_dentry(const struct dentry *, struct qstr *);
+static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
                unsigned int, const char *, const struct qstr *);
 static int ncp_delete_dentry(const struct dentry *);
 
@@ -119,11 +117,19 @@ static inline int ncp_case_sensitive(const struct inode *i)
 /*
  * Note: leave the hash unchanged if the directory
  * is case-sensitive.
+ *
+ * Accessing the parent inode can be racy under RCU pathwalking.
+ * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
+ * the callers will handle races.
  */
 static int 
-ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *this)
+ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
 {
+       struct inode *inode = ACCESS_ONCE(dentry->d_inode);
+
+       if (!inode)
+               return 0;
+
        if (!ncp_case_sensitive(inode)) {
                struct super_block *sb = dentry->d_sb;
                struct nls_table *t;
@@ -140,14 +146,24 @@ ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode,
        return 0;
 }
 
+/*
+ * Accessing the parent inode can be racy under RCU pathwalking.
+ * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
+ * the callers will handle races.
+ */
 static int
-ncp_compare_dentry(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
+       struct inode *pinode;
+
        if (len != name->len)
                return 1;
 
+       pinode = ACCESS_ONCE(parent->d_inode);
+       if (!pinode)
+               return 1;
+
        if (ncp_case_sensitive(pinode))
                return strncmp(str, name->name, len);
 
@@ -659,8 +675,6 @@ end_advance:
        if (!valid)
                ctl.valid = 0;
        if (!ctl.filled && (ctl.fpos == ctx->pos)) {
-               if (!ino)
-                       ino = find_inode_number(dentry, &qname);
                if (!ino)
                        ino = iunique(dir->i_sb, 2);
                ctl.filled = !dir_emit(ctx, qname.name, qname.len,
@@ -1123,17 +1137,6 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
                old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
                new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
 
-       if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode)) {
-               /*
-                * fail with EBUSY if there are still references to this
-                * directory.
-                */
-               dentry_unhash(new_dentry);
-               error = -EBUSY;
-               if (!d_unhashed(new_dentry))
-                       goto out;
-       }
-
        ncp_age_dentry(server, old_dentry);
        ncp_age_dentry(server, new_dentry);
 
index 26910c8154da1be65c0318eb088d5d69d3e08baf..0765ad12c3827cf9822dacc1875cb64a957c9864 100644 (file)
@@ -891,6 +891,10 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
        if (!server)    /* How this could happen? */
                goto out;
 
+       result = -EPERM;
+       if (IS_DEADDIR(dentry->d_inode))
+               goto out;
+
        /* ageing the dentry to force validation */
        ncp_age_dentry(server, dentry);
 
index 57db3244f4d967dd5479dbf3ab883c6d28cc2cbd..7ec4814e298d4d957fd4bfa17cb59de20e429ba9 100644 (file)
@@ -73,20 +73,20 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
        if (inode->i_flock == NULL)
                goto out;
 
-       /* Protect inode->i_flock using the file locks lock */
-       lock_flocks();
+       /* Protect inode->i_flock using the i_lock */
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
                        continue;
                if (nfs_file_open_context(fl->fl_file) != ctx)
                        continue;
-               unlock_flocks();
+               spin_unlock(&inode->i_lock);
                status = nfs4_lock_delegation_recall(fl, state, stateid);
                if (status < 0)
                        goto out;
-               lock_flocks();
+               spin_lock(&inode->i_lock);
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 out:
        return status;
 }
index 1fab140764c42756867f064a81b61903b8858a91..ff10b4aa534c0d855408ac5ec0dbb2a8c7cf92ba 100644 (file)
@@ -1373,13 +1373,13 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
        /* Guard against delegation returns and new lock/unlock calls */
        down_write(&nfsi->rwsem);
        /* Protect inode->i_flock using the BKL */
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
                        continue;
                if (nfs_file_open_context(fl->fl_file)->state != state)
                        continue;
-               unlock_flocks();
+               spin_unlock(&inode->i_lock);
                status = ops->recover_lock(state, fl);
                switch (status) {
                        case 0:
@@ -1406,9 +1406,9 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
                                /* kill_proc(fl->fl_pid, SIGLOST, 1); */
                                status = 0;
                }
-               lock_flocks();
+               spin_lock(&inode->i_lock);
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 out:
        up_write(&nfsi->rwsem);
        return status;
index 316ec843dec238b027ebf94629c1d56955b60731..f17051838b41aeda88075ac9f81f72f3a1559ce9 100644 (file)
@@ -2645,13 +2645,13 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
 
        list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
 
-       /* only place dl_time is set. protected by lock_flocks*/
+       /* Only place dl_time is set; protected by i_lock: */
        dp->dl_time = get_seconds();
 
        nfsd4_cb_recall(dp);
 }
 
-/* Called from break_lease() with lock_flocks() held. */
+/* Called from break_lease() with i_lock held. */
 static void nfsd_break_deleg_cb(struct file_lock *fl)
 {
        struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
@@ -4520,7 +4520,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner)
        struct inode *inode = filp->fi_inode;
        int status = 0;
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
                if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
                        status = 1;
@@ -4528,7 +4528,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner)
                }
        }
 out:
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        return status;
 }
 
index 6c80083a984fc192ebc73bad2a2edc86b4c25e11..1ea52f7c031fbd2aed6247ec445d10103ec973ad 100644 (file)
@@ -399,9 +399,6 @@ static int fanotify_release(struct inode *ignored, struct file *file)
        wake_up(&group->fanotify_data.access_waitq);
 #endif
 
-       if (file->f_flags & FASYNC)
-               fsnotify_fasync(-1, file, 0);
-
        /* matches the fanotify_init->fsnotify_alloc_group */
        fsnotify_destroy_group(group);
 
index 8a38714f1d92ec98b197e28e1a06adcce6e6b582..41000f223ca42bb855a57f1cc27f08a28ecccba9 100644 (file)
@@ -2646,17 +2646,7 @@ static loff_t ocfs2_file_llseek(struct file *file, loff_t offset, int whence)
                goto out;
        }
 
-       if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
-               ret = -EINVAL;
-       if (!ret && offset > inode->i_sb->s_maxbytes)
-               ret = -EINVAL;
-       if (ret)
-               goto out;
-
-       if (offset != file->f_pos) {
-               file->f_pos = offset;
-               file->f_version = 0;
-       }
+       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out:
        mutex_unlock(&inode->i_mutex);
index 8c741002f947908d26788ad83c91f28bc44c8295..fca72c4d3f17ac13758ac5315e413d749bf7667b 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -840,11 +840,15 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
        if (flags & __O_SYNC)
                flags |= O_DSYNC;
 
-       /*
-        * If we have O_PATH in the open flag. Then we
-        * cannot have anything other than the below set of flags
-        */
-       if (flags & O_PATH) {
+       if (flags & O_TMPFILE) {
+               if (!(flags & O_CREAT))
+                       return -EINVAL;
+               acc_mode = MAY_OPEN | ACC_MODE(flags);
+       } else if (flags & O_PATH) {
+               /*
+                * If we have O_PATH in the open flag. Then we
+                * cannot have anything other than the below set of flags
+                */
                flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH;
                acc_mode = 0;
        } else {
@@ -876,7 +880,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
                lookup_flags |= LOOKUP_DIRECTORY;
        if (!(flags & O_NOFOLLOW))
                lookup_flags |= LOOKUP_FOLLOW;
-       return lookup_flags;
+       op->lookup_flags = lookup_flags;
+       return 0;
 }
 
 /**
@@ -893,8 +898,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
 struct file *file_open_name(struct filename *name, int flags, umode_t mode)
 {
        struct open_flags op;
-       int lookup = build_open_flags(flags, mode, &op);
-       return do_filp_open(AT_FDCWD, name, &op, lookup);
+       int err = build_open_flags(flags, mode, &op);
+       return err ? ERR_PTR(err) : do_filp_open(AT_FDCWD, name, &op);
 }
 
 /**
@@ -919,37 +924,43 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
                            const char *filename, int flags)
 {
        struct open_flags op;
-       int lookup = build_open_flags(flags, 0, &op);
+       int err = build_open_flags(flags, 0, &op);
+       if (err)
+               return ERR_PTR(err);
        if (flags & O_CREAT)
                return ERR_PTR(-EINVAL);
        if (!filename && (flags & O_DIRECTORY))
                if (!dentry->d_inode->i_op->lookup)
                        return ERR_PTR(-ENOTDIR);
-       return do_file_open_root(dentry, mnt, filename, &op, lookup);
+       return do_file_open_root(dentry, mnt, filename, &op);
 }
 EXPORT_SYMBOL(file_open_root);
 
 long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
 {
        struct open_flags op;
-       int lookup = build_open_flags(flags, mode, &op);
-       struct filename *tmp = getname(filename);
-       int fd = PTR_ERR(tmp);
-
-       if (!IS_ERR(tmp)) {
-               fd = get_unused_fd_flags(flags);
-               if (fd >= 0) {
-                       struct file *f = do_filp_open(dfd, tmp, &op, lookup);
-                       if (IS_ERR(f)) {
-                               put_unused_fd(fd);
-                               fd = PTR_ERR(f);
-                       } else {
-                               fsnotify_open(f);
-                               fd_install(fd, f);
-                       }
+       int fd = build_open_flags(flags, mode, &op);
+       struct filename *tmp;
+
+       if (fd)
+               return fd;
+
+       tmp = getname(filename);
+       if (IS_ERR(tmp))
+               return PTR_ERR(tmp);
+
+       fd = get_unused_fd_flags(flags);
+       if (fd >= 0) {
+               struct file *f = do_filp_open(dfd, tmp, &op);
+               if (IS_ERR(f)) {
+                       put_unused_fd(fd);
+                       fd = PTR_ERR(f);
+               } else {
+                       fsnotify_open(f);
+                       fd_install(fd, f);
                }
-               putname(tmp);
        }
+       putname(tmp);
        return fd;
 }
 
index 0016350ad95e13a646978f8d3f19fb1afa145424..1485e38daaa38100278f56e710a8233338693fd5 100644 (file)
@@ -1686,41 +1686,29 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx,
        instantiate_t instantiate, struct task_struct *task, const void *ptr)
 {
        struct dentry *child, *dir = file->f_path.dentry;
+       struct qstr qname = QSTR_INIT(name, len);
        struct inode *inode;
-       struct qstr qname;
-       ino_t ino = 0;
-       unsigned type = DT_UNKNOWN;
+       unsigned type;
+       ino_t ino;
 
-       qname.name = name;
-       qname.len  = len;
-       qname.hash = full_name_hash(name, len);
-
-       child = d_lookup(dir, &qname);
+       child = d_hash_and_lookup(dir, &qname);
        if (!child) {
-               struct dentry *new;
-               new = d_alloc(dir, &qname);
-               if (new) {
-                       child = instantiate(dir->d_inode, new, task, ptr);
-                       if (child)
-                               dput(new);
-                       else
-                               child = new;
+               child = d_alloc(dir, &qname);
+               if (!child)
+                       goto end_instantiate;
+               if (instantiate(dir->d_inode, child, task, ptr) < 0) {
+                       dput(child);
+                       goto end_instantiate;
                }
        }
-       if (!child || IS_ERR(child) || !child->d_inode)
-               goto end_instantiate;
        inode = child->d_inode;
-       if (inode) {
-               ino = inode->i_ino;
-               type = inode->i_mode >> 12;
-       }
+       ino = inode->i_ino;
+       type = inode->i_mode >> 12;
        dput(child);
-end_instantiate:
-       if (!ino)
-               ino = find_inode_number(dir, &qname);
-       if (!ino)
-               ino = 1;
        return dir_emit(ctx, name, len, ino, type);
+
+end_instantiate:
+       return dir_emit(ctx, name, len, 1, DT_UNKNOWN);
 }
 
 #ifdef CONFIG_CHECKPOINT_RESTORE
@@ -1846,7 +1834,7 @@ struct map_files_info {
        unsigned char   name[4*sizeof(long)+2]; /* max: %lx-%lx\0 */
 };
 
-static struct dentry *
+static int
 proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
                           struct task_struct *task, const void *ptr)
 {
@@ -1856,7 +1844,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
 
        inode = proc_pid_make_inode(dir->i_sb, task);
        if (!inode)
-               return ERR_PTR(-ENOENT);
+               return -ENOENT;
 
        ei = PROC_I(inode);
        ei->op.proc_get_link = proc_map_files_get_link;
@@ -1873,7 +1861,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
        d_set_d_op(dentry, &tid_map_files_dentry_operations);
        d_add(dentry, inode);
 
-       return NULL;
+       return 0;
 }
 
 static struct dentry *proc_map_files_lookup(struct inode *dir,
@@ -1882,23 +1870,23 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
        unsigned long vm_start, vm_end;
        struct vm_area_struct *vma;
        struct task_struct *task;
-       struct dentry *result;
+       int result;
        struct mm_struct *mm;
 
-       result = ERR_PTR(-EPERM);
+       result = -EPERM;
        if (!capable(CAP_SYS_ADMIN))
                goto out;
 
-       result = ERR_PTR(-ENOENT);
+       result = -ENOENT;
        task = get_proc_task(dir);
        if (!task)
                goto out;
 
-       result = ERR_PTR(-EACCES);
+       result = -EACCES;
        if (!ptrace_may_access(task, PTRACE_MODE_READ))
                goto out_put_task;
 
-       result = ERR_PTR(-ENOENT);
+       result = -ENOENT;
        if (dname_to_vma_addr(dentry, &vm_start, &vm_end))
                goto out_put_task;
 
@@ -1921,7 +1909,7 @@ out_no_vma:
 out_put_task:
        put_task_struct(task);
 out:
-       return result;
+       return ERR_PTR(result);
 }
 
 static const struct inode_operations proc_map_files_inode_operations = {
@@ -2135,13 +2123,12 @@ static const struct file_operations proc_timers_operations = {
 };
 #endif /* CONFIG_CHECKPOINT_RESTORE */
 
-static struct dentry *proc_pident_instantiate(struct inode *dir,
+static int proc_pident_instantiate(struct inode *dir,
        struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
        const struct pid_entry *p = ptr;
        struct inode *inode;
        struct proc_inode *ei;
-       struct dentry *error = ERR_PTR(-ENOENT);
 
        inode = proc_pid_make_inode(dir->i_sb, task);
        if (!inode)
@@ -2160,9 +2147,9 @@ static struct dentry *proc_pident_instantiate(struct inode *dir,
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (pid_revalidate(dentry, 0))
-               error = NULL;
+               return 0;
 out:
-       return error;
+       return -ENOENT;
 }
 
 static struct dentry *proc_pident_lookup(struct inode *dir, 
@@ -2170,11 +2157,11 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
                                         const struct pid_entry *ents,
                                         unsigned int nents)
 {
-       struct dentry *error;
+       int error;
        struct task_struct *task = get_proc_task(dir);
        const struct pid_entry *p, *last;
 
-       error = ERR_PTR(-ENOENT);
+       error = -ENOENT;
 
        if (!task)
                goto out_no_task;
@@ -2197,7 +2184,7 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
 out:
        put_task_struct(task);
 out_no_task:
-       return error;
+       return ERR_PTR(error);
 }
 
 static int proc_pident_readdir(struct file *file, struct dir_context *ctx,
@@ -2780,11 +2767,10 @@ void proc_flush_task(struct task_struct *task)
        }
 }
 
-static struct dentry *proc_pid_instantiate(struct inode *dir,
-                                          struct dentry * dentry,
-                                          struct task_struct *task, const void *ptr)
+static int proc_pid_instantiate(struct inode *dir,
+                                  struct dentry * dentry,
+                                  struct task_struct *task, const void *ptr)
 {
-       struct dentry *error = ERR_PTR(-ENOENT);
        struct inode *inode;
 
        inode = proc_pid_make_inode(dir->i_sb, task);
@@ -2804,14 +2790,14 @@ static struct dentry *proc_pid_instantiate(struct inode *dir,
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (pid_revalidate(dentry, 0))
-               error = NULL;
+               return 0;
 out:
-       return error;
+       return -ENOENT;
 }
 
 struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
 {
-       struct dentry *result = NULL;
+       int result = 0;
        struct task_struct *task;
        unsigned tgid;
        struct pid_namespace *ns;
@@ -2832,7 +2818,7 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsign
        result = proc_pid_instantiate(dir, dentry, task, NULL);
        put_task_struct(task);
 out:
-       return result;
+       return ERR_PTR(result);
 }
 
 /*
@@ -2884,21 +2870,21 @@ retry:
 int proc_pid_readdir(struct file *file, struct dir_context *ctx)
 {
        struct tgid_iter iter;
-       struct pid_namespace *ns;
+       struct pid_namespace *ns = file->f_dentry->d_sb->s_fs_info;
        loff_t pos = ctx->pos;
 
        if (pos >= PID_MAX_LIMIT + TGID_OFFSET)
                return 0;
 
        if (pos == TGID_OFFSET - 1) {
-               if (!proc_fill_cache(file, ctx, "self", 4, NULL, NULL, NULL))
+               struct inode *inode = ns->proc_self->d_inode;
+               if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK))
                        return 0;
                iter.tgid = 0;
        } else {
                iter.tgid = pos - TGID_OFFSET;
        }
        iter.task = NULL;
-       ns = file->f_dentry->d_sb->s_fs_info;
        for (iter = next_tgid(ns, iter);
             iter.task;
             iter.tgid += 1, iter = next_tgid(ns, iter)) {
@@ -3027,10 +3013,9 @@ static const struct inode_operations proc_tid_base_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-static struct dentry *proc_task_instantiate(struct inode *dir,
+static int proc_task_instantiate(struct inode *dir,
        struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
-       struct dentry *error = ERR_PTR(-ENOENT);
        struct inode *inode;
        inode = proc_pid_make_inode(dir->i_sb, task);
 
@@ -3049,14 +3034,14 @@ static struct dentry *proc_task_instantiate(struct inode *dir,
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (pid_revalidate(dentry, 0))
-               error = NULL;
+               return 0;
 out:
-       return error;
+       return -ENOENT;
 }
 
 static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
 {
-       struct dentry *result = ERR_PTR(-ENOENT);
+       int result = -ENOENT;
        struct task_struct *task;
        struct task_struct *leader = get_proc_task(dir);
        unsigned tid;
@@ -3086,7 +3071,7 @@ out_drop_task:
 out:
        put_task_struct(leader);
 out_no_task:
-       return result;
+       return ERR_PTR(result);
 }
 
 /*
index 1441f143c43b6d187f5d6f2b181118148d2501e5..75f2890abbd8ddcc8a674b1c42397cc1456fd33e 100644 (file)
@@ -167,11 +167,10 @@ static int proc_fd_link(struct dentry *dentry, struct path *path)
        return ret;
 }
 
-static struct dentry *
+static int
 proc_fd_instantiate(struct inode *dir, struct dentry *dentry,
                    struct task_struct *task, const void *ptr)
 {
-       struct dentry *error = ERR_PTR(-ENOENT);
        unsigned fd = (unsigned long)ptr;
        struct proc_inode *ei;
        struct inode *inode;
@@ -194,9 +193,9 @@ proc_fd_instantiate(struct inode *dir, struct dentry *dentry,
 
        /* Close the race of the process dying before we return the dentry */
        if (tid_fd_revalidate(dentry, 0))
-               error = NULL;
+               return 0;
  out:
-       return error;
+       return -ENOENT;
 }
 
 static struct dentry *proc_lookupfd_common(struct inode *dir,
@@ -204,7 +203,7 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
                                           instantiate_t instantiate)
 {
        struct task_struct *task = get_proc_task(dir);
-       struct dentry *result = ERR_PTR(-ENOENT);
+       int result = -ENOENT;
        unsigned fd = name_to_int(dentry);
 
        if (!task)
@@ -216,7 +215,7 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
 out:
        put_task_struct(task);
 out_no_task:
-       return result;
+       return ERR_PTR(result);
 }
 
 static int proc_readfd_common(struct file *file, struct dir_context *ctx,
@@ -300,11 +299,10 @@ const struct inode_operations proc_fd_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-static struct dentry *
+static int
 proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry,
                        struct task_struct *task, const void *ptr)
 {
-       struct dentry *error = ERR_PTR(-ENOENT);
        unsigned fd = (unsigned long)ptr;
        struct proc_inode *ei;
        struct inode *inode;
@@ -324,9 +322,9 @@ proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry,
 
        /* Close the race of the process dying before we return the dentry */
        if (tid_fd_revalidate(dentry, 0))
-               error = NULL;
+               return 0;
  out:
-       return error;
+       return -ENOENT;
 }
 
 static struct dentry *
index 4eae2e149f31c05bb2d802c05f64bf91afdd4d29..651d09a11dde360a3ebabc26cc206aefb3b0515c 100644 (file)
@@ -170,7 +170,7 @@ extern struct dentry *proc_pid_lookup(struct inode *, struct dentry *, unsigned
 extern loff_t mem_lseek(struct file *, loff_t, int);
 
 /* Lookups */
-typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
+typedef int instantiate_t(struct inode *, struct dentry *,
                                     struct task_struct *, const void *);
 extern bool proc_fill_cache(struct file *, struct dir_context *, const char *, int,
                           instantiate_t, struct task_struct *, const void *);
index f6abbbbfad8a765d115013ae65b07632b7e15258..49a7fff2e83a9906f39a685ddad0e98211dd155f 100644 (file)
@@ -187,13 +187,12 @@ static const struct inode_operations proc_ns_link_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-static struct dentry *proc_ns_instantiate(struct inode *dir,
+static int proc_ns_instantiate(struct inode *dir,
        struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
        const struct proc_ns_operations *ns_ops = ptr;
        struct inode *inode;
        struct proc_inode *ei;
-       struct dentry *error = ERR_PTR(-ENOENT);
 
        inode = proc_pid_make_inode(dir->i_sb, task);
        if (!inode)
@@ -208,9 +207,9 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (pid_revalidate(dentry, 0))
-               error = NULL;
+               return 0;
 out:
-       return error;
+       return -ENOENT;
 }
 
 static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx)
@@ -248,12 +247,12 @@ const struct file_operations proc_ns_dir_operations = {
 static struct dentry *proc_ns_dir_lookup(struct inode *dir,
                                struct dentry *dentry, unsigned int flags)
 {
-       struct dentry *error;
+       int error;
        struct task_struct *task = get_proc_task(dir);
        const struct proc_ns_operations **entry, **last;
        unsigned int len = dentry->d_name.len;
 
-       error = ERR_PTR(-ENOENT);
+       error = -ENOENT;
 
        if (!task)
                goto out_no_task;
@@ -272,7 +271,7 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir,
 out:
        put_task_struct(task);
 out_no_task:
-       return error;
+       return ERR_PTR(error);
 }
 
 const struct inode_operations proc_ns_dir_inode_operations = {
index f3a570e7c2575a723b5ac4061c1dd7aca1cb80c8..71290463a1d3fa87a5132e21615792fe7fbaf9f4 100644 (file)
@@ -796,15 +796,16 @@ static int sysctl_is_seen(struct ctl_table_header *p)
        return res;
 }
 
-static int proc_sys_compare(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int proc_sys_compare(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        struct ctl_table_header *head;
+       struct inode *inode;
+
        /* Although proc doesn't have negative dentries, rcu-walk means
         * that inode here can be NULL */
        /* AV: can it, indeed? */
+       inode = ACCESS_ONCE(dentry->d_inode);
        if (!inode)
                return 1;
        if (name->len != len)
index 2cefa417be349b0016ffa8606635db9e85751015..122a3846d9e14270a26952e92b25971257ebd82b 100644 (file)
@@ -41,8 +41,19 @@ static inline int unsigned_offsets(struct file *file)
        return file->f_mode & FMODE_UNSIGNED_OFFSET;
 }
 
-static loff_t lseek_execute(struct file *file, struct inode *inode,
-               loff_t offset, loff_t maxsize)
+/**
+ * vfs_setpos - update the file offset for lseek
+ * @file:      file structure in question
+ * @offset:    file offset to seek to
+ * @maxsize:   maximum file size
+ *
+ * This is a low-level filesystem helper for updating the file offset to
+ * the value specified by @offset if the given offset is valid and it is
+ * not equal to the current file offset.
+ *
+ * Return the specified offset on success and -EINVAL on invalid offset.
+ */
+loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize)
 {
        if (offset < 0 && !unsigned_offsets(file))
                return -EINVAL;
@@ -55,6 +66,7 @@ static loff_t lseek_execute(struct file *file, struct inode *inode,
        }
        return offset;
 }
+EXPORT_SYMBOL(vfs_setpos);
 
 /**
  * generic_file_llseek_size - generic llseek implementation for regular files
@@ -76,8 +88,6 @@ loff_t
 generic_file_llseek_size(struct file *file, loff_t offset, int whence,
                loff_t maxsize, loff_t eof)
 {
-       struct inode *inode = file->f_mapping->host;
-
        switch (whence) {
        case SEEK_END:
                offset += eof;
@@ -97,8 +107,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence,
                 * like SEEK_SET.
                 */
                spin_lock(&file->f_lock);
-               offset = lseek_execute(file, inode, file->f_pos + offset,
-                                      maxsize);
+               offset = vfs_setpos(file, file->f_pos + offset, maxsize);
                spin_unlock(&file->f_lock);
                return offset;
        case SEEK_DATA:
@@ -120,7 +129,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence,
                break;
        }
 
-       return lseek_execute(file, inode, offset, maxsize);
+       return vfs_setpos(file, offset, maxsize);
 }
 EXPORT_SYMBOL(generic_file_llseek_size);
 
@@ -144,6 +153,26 @@ loff_t generic_file_llseek(struct file *file, loff_t offset, int whence)
 }
 EXPORT_SYMBOL(generic_file_llseek);
 
+/**
+ * fixed_size_llseek - llseek implementation for fixed-sized devices
+ * @file:      file structure to seek on
+ * @offset:    file offset to seek to
+ * @whence:    type of seek
+ * @size:      size of the file
+ *
+ */
+loff_t fixed_size_llseek(struct file *file, loff_t offset, int whence, loff_t size)
+{
+       switch (whence) {
+       case SEEK_SET: case SEEK_CUR: case SEEK_END:
+               return generic_file_llseek_size(file, offset, whence,
+                                               size, size);
+       default:
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL(fixed_size_llseek);
+
 /**
  * noop_llseek - No Operation Performed llseek implementation
  * @file:      file structure to seek on
@@ -296,7 +325,7 @@ out_putf:
  * them to something that fits in "int" so that others
  * won't have to do range checks all the time.
  */
-int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
+int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count)
 {
        struct inode *inode;
        loff_t pos;
@@ -477,7 +506,8 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
        if (f.file) {
                loff_t pos = file_pos_read(f.file);
                ret = vfs_read(f.file, buf, count, &pos);
-               file_pos_write(f.file, pos);
+               if (ret >= 0)
+                       file_pos_write(f.file, pos);
                fdput(f);
        }
        return ret;
@@ -492,7 +522,8 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
        if (f.file) {
                loff_t pos = file_pos_read(f.file);
                ret = vfs_write(f.file, buf, count, &pos);
-               file_pos_write(f.file, pos);
+               if (ret >= 0)
+                       file_pos_write(f.file, pos);
                fdput(f);
        }
 
@@ -780,7 +811,8 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
        if (f.file) {
                loff_t pos = file_pos_read(f.file);
                ret = vfs_readv(f.file, vec, vlen, &pos);
-               file_pos_write(f.file, pos);
+               if (ret >= 0)
+                       file_pos_write(f.file, pos);
                fdput(f);
        }
 
@@ -799,7 +831,8 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
        if (f.file) {
                loff_t pos = file_pos_read(f.file);
                ret = vfs_writev(f.file, vec, vlen, &pos);
-               file_pos_write(f.file, pos);
+               if (ret >= 0)
+                       file_pos_write(f.file, pos);
                fdput(f);
        }
 
@@ -959,7 +992,8 @@ COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd,
                return -EBADF;
        pos = f.file->f_pos;
        ret = compat_readv(f.file, vec, vlen, &pos);
-       f.file->f_pos = pos;
+       if (ret >= 0)
+               f.file->f_pos = pos;
        fdput(f);
        return ret;
 }
@@ -1025,7 +1059,8 @@ COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd,
                return -EBADF;
        pos = f.file->f_pos;
        ret = compat_writev(f.file, vec, vlen, &pos);
-       f.file->f_pos = pos;
+       if (ret >= 0)
+               f.file->f_pos = pos;
        fdput(f);
        return ret;
 }
@@ -1129,7 +1164,9 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
        if (in.file->f_flags & O_NONBLOCK)
                fl = SPLICE_F_NONBLOCK;
 #endif
+       file_start_write(out.file);
        retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl);
+       file_end_write(out.file);
 
        if (retval > 0) {
                add_rchar(current, retval);
index d37431dd60a1009f224d4c1bdc65b4fff505d2db..3b7ee656f3aaeacd719955b2bba80fd5d8d43b0a 100644 (file)
@@ -1098,27 +1098,13 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
 {
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
                                loff_t *, size_t, unsigned int);
-       int ret;
-
-       if (unlikely(!(out->f_mode & FMODE_WRITE)))
-               return -EBADF;
-
-       if (unlikely(out->f_flags & O_APPEND))
-               return -EINVAL;
-
-       ret = rw_verify_area(WRITE, out, ppos, len);
-       if (unlikely(ret < 0))
-               return ret;
 
        if (out->f_op && out->f_op->splice_write)
                splice_write = out->f_op->splice_write;
        else
                splice_write = default_file_splice_write;
 
-       file_start_write(out);
-       ret = splice_write(pipe, out, ppos, len, flags);
-       file_end_write(out);
-       return ret;
+       return splice_write(pipe, out, ppos, len, flags);
 }
 
 /*
@@ -1307,6 +1293,16 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
        };
        long ret;
 
+       if (unlikely(!(out->f_mode & FMODE_WRITE)))
+               return -EBADF;
+
+       if (unlikely(out->f_flags & O_APPEND))
+               return -EINVAL;
+
+       ret = rw_verify_area(WRITE, out, opos, len);
+       if (unlikely(ret < 0))
+               return ret;
+
        ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
        if (ret > 0)
                *ppos = sd.pos;
@@ -1362,7 +1358,19 @@ static long do_splice(struct file *in, loff_t __user *off_in,
                        offset = out->f_pos;
                }
 
+               if (unlikely(!(out->f_mode & FMODE_WRITE)))
+                       return -EBADF;
+
+               if (unlikely(out->f_flags & O_APPEND))
+                       return -EINVAL;
+
+               ret = rw_verify_area(WRITE, out, &offset, len);
+               if (unlikely(ret < 0))
+                       return ret;
+
+               file_start_write(out);
                ret = do_splice_from(ipipe, out, &offset, len, flags);
+               file_end_write(out);
 
                if (!off_out)
                        out->f_pos = offset;
index 1c0d5f264767df5ebc7bf0dc77a0267b097a4052..731b2bbcaab37f7e8d4da84dcc9e9600d3b4e969 100644 (file)
@@ -27,8 +27,7 @@ static int add_nondir(struct dentry *dentry, struct inode *inode)
        return err;
 }
 
-static int sysv_hash(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+static int sysv_hash(const struct dentry *dentry, struct qstr *qstr)
 {
        /* Truncate the name in place, avoids having to define a compare
           function. */
index 102c072c6bbfed3d76541b2c3766d89c9272d2ca..5f6fc17d6bc5c0694fa357b739a290e608da9588 100644 (file)
@@ -594,6 +594,29 @@ static int udf_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        return 0;
 }
 
+static int udf_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       struct inode *inode;
+       struct udf_inode_info *iinfo;
+       int err;
+
+       inode = udf_new_inode(dir, mode, &err);
+       if (!inode)
+               return err;
+
+       iinfo = UDF_I(inode);
+       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+               inode->i_data.a_ops = &udf_adinicb_aops;
+       else
+               inode->i_data.a_ops = &udf_aops;
+       inode->i_op = &udf_file_inode_operations;
+       inode->i_fop = &udf_file_operations;
+       mark_inode_dirty(inode);
+
+       d_tmpfile(dentry, inode);
+       return 0;
+}
+
 static int udf_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
                     dev_t rdev)
 {
@@ -1311,6 +1334,7 @@ const struct inode_operations udf_dir_inode_operations = {
        .rmdir                          = udf_rmdir,
        .mknod                          = udf_mknod,
        .rename                         = udf_rename,
+       .tmpfile                        = udf_tmpfile,
 };
 const struct inode_operations udf_symlink_inode_operations = {
        .readlink       = generic_readlink,
index 0ad2b95fca12fbd215b9eb63f84b2bd7c21b6609..de3dc98f4e8f76067c1e7d0ee4631a8638d87988 100644 (file)
@@ -1268,8 +1268,7 @@ xfs_seek_data(
        }
 
 out:
-       if (offset != file->f_pos)
-               file->f_pos = offset;
+       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out_unlock:
        xfs_iunlock_map_shared(ip, lock);
@@ -1377,8 +1376,7 @@ out:
         * situation in particular.
         */
        offset = min_t(loff_t, offset, isize);
-       if (offset != file->f_pos)
-               file->f_pos = offset;
+       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out_unlock:
        xfs_iunlock_map_shared(ip, lock);
index 1a6bb81f0fe5a13d93c799cfbcd4062d0e288c28..f42dbe1454793870dba2d4afd456f51bc2c8b2a5 100644 (file)
@@ -146,10 +146,8 @@ enum dentry_d_lock_class
 struct dentry_operations {
        int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_weak_revalidate)(struct dentry *, unsigned int);
-       int (*d_hash)(const struct dentry *, const struct inode *,
-                       struct qstr *);
-       int (*d_compare)(const struct dentry *, const struct inode *,
-                       const struct dentry *, const struct inode *,
+       int (*d_hash)(const struct dentry *, struct qstr *);
+       int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(const struct dentry *);
        void (*d_release)(struct dentry *);
@@ -246,6 +244,8 @@ extern struct dentry * d_make_root(struct inode *);
 /* <clickety>-<click> the ramfs-type tree */
 extern void d_genocide(struct dentry *);
 
+extern void d_tmpfile(struct dentry *, struct inode *);
+
 extern struct dentry *d_find_alias(struct inode *);
 extern void d_prune_aliases(struct inode *);
 
@@ -300,8 +300,7 @@ extern struct dentry *d_lookup(const struct dentry *, const struct qstr *);
 extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *);
 extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *);
 extern struct dentry *__d_lookup_rcu(const struct dentry *parent,
-                               const struct qstr *name,
-                               unsigned *seq, struct inode *inode);
+                               const struct qstr *name, unsigned *seq);
 
 /**
  * __d_rcu_to_refcount - take a refcount on dentry if sequence check is ok
index f8a5240541b77e17df8bf17fa4c10399cdb7fbd2..2b82c80414900fc22d152b6ad9eb71d8d790767a 100644 (file)
@@ -908,6 +908,7 @@ struct file_lock_operations {
 
 struct lock_manager_operations {
        int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
+       unsigned long (*lm_owner_key)(struct file_lock *);
        void (*lm_notify)(struct file_lock *);  /* unblock callback */
        int (*lm_grant)(struct file_lock *, struct file_lock *, int);
        void (*lm_break)(struct file_lock *);
@@ -926,9 +927,27 @@ int locks_in_grace(struct net *);
 /* that will die - we need it for nfs_lock_info */
 #include <linux/nfs_fs_i.h>
 
+/*
+ * struct file_lock represents a generic "file lock". It's used to represent
+ * POSIX byte range locks, BSD (flock) locks, and leases. It's important to
+ * note that the same struct is used to represent both a request for a lock and
+ * the lock itself, but the same object is never used for both.
+ *
+ * FIXME: should we create a separate "struct lock_request" to help distinguish
+ * these two uses?
+ *
+ * The i_flock list is ordered by:
+ *
+ * 1) lock type -- FL_LEASEs first, then FL_FLOCK, and finally FL_POSIX
+ * 2) lock owner
+ * 3) lock range start
+ * 4) lock range end
+ *
+ * Obviously, the last two criteria only matter for POSIX locks.
+ */
 struct file_lock {
        struct file_lock *fl_next;      /* singly linked list for this inode  */
-       struct list_head fl_link;       /* doubly linked list of all locks */
+       struct hlist_node fl_link;      /* node in global lists */
        struct list_head fl_block;      /* circular list of blocked processes */
        fl_owner_t fl_owner;
        unsigned int fl_flags;
@@ -994,7 +1013,7 @@ extern void locks_release_private(struct file_lock *);
 extern void posix_test_lock(struct file *, struct file_lock *);
 extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
 extern int posix_lock_file_wait(struct file *, struct file_lock *);
-extern int posix_unblock_lock(struct file *, struct file_lock *);
+extern int posix_unblock_lock(struct file_lock *);
 extern int vfs_test_lock(struct file *, struct file_lock *);
 extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
 extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
@@ -1006,9 +1025,6 @@ extern int vfs_setlease(struct file *, long, struct file_lock **);
 extern int lease_modify(struct file_lock **, int);
 extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
 extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
-extern void locks_delete_block(struct file_lock *waiter);
-extern void lock_flocks(void);
-extern void unlock_flocks(void);
 #else /* !CONFIG_FILE_LOCKING */
 static inline int fcntl_getlk(struct file *file, struct flock __user *user)
 {
@@ -1084,8 +1100,7 @@ static inline int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
        return -ENOLCK;
 }
 
-static inline int posix_unblock_lock(struct file *filp,
-                                    struct file_lock *waiter)
+static inline int posix_unblock_lock(struct file_lock *waiter)
 {
        return -ENOENT;
 }
@@ -1150,19 +1165,6 @@ static inline int lock_may_write(struct inode *inode, loff_t start,
 {
        return 1;
 }
-
-static inline void locks_delete_block(struct file_lock *waiter)
-{
-}
-
-static inline void lock_flocks(void)
-{
-}
-
-static inline void unlock_flocks(void)
-{
-}
-
 #endif /* !CONFIG_FILE_LOCKING */
 
 
@@ -1580,6 +1582,7 @@ struct inode_operations {
        int (*atomic_open)(struct inode *, struct dentry *,
                           struct file *, unsigned open_flag,
                           umode_t create_mode, int *opened);
+       int (*tmpfile) (struct inode *, struct dentry *, umode_t);
 } ____cacheline_aligned;
 
 ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
@@ -1743,6 +1746,7 @@ struct super_operations {
 #define I_REFERENCED           (1 << 8)
 #define __I_DIO_WAKEUP         9
 #define I_DIO_WAKEUP           (1 << I_DIO_WAKEUP)
+#define I_LINKABLE             (1 << 10)
 
 #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
 
@@ -1896,7 +1900,6 @@ extern int current_umask(void);
 extern struct kobject *fs_kobj;
 
 #define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
-extern int rw_verify_area(int, struct file *, loff_t *, size_t);
 
 #define FLOCK_VERIFY_READ  1
 #define FLOCK_VERIFY_WRITE 2
@@ -2309,7 +2312,6 @@ extern struct file * open_exec(const char *);
 /* fs/dcache.c -- generic fs support functions */
 extern int is_subdir(struct dentry *, struct dentry *);
 extern int path_is_under(struct path *, struct path *);
-extern ino_t find_inode_number(struct dentry *, struct qstr *);
 
 #include <linux/err.h>
 
@@ -2424,9 +2426,12 @@ extern void
 file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
 extern loff_t noop_llseek(struct file *file, loff_t offset, int whence);
 extern loff_t no_llseek(struct file *file, loff_t offset, int whence);
+extern loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize);
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int whence);
 extern loff_t generic_file_llseek_size(struct file *file, loff_t offset,
                int whence, loff_t maxsize, loff_t eof);
+extern loff_t fixed_size_llseek(struct file *file, loff_t offset,
+               int whence, loff_t size);
 extern int generic_file_open(struct inode * inode, struct file * filp);
 extern int nonseekable_open(struct inode * inode, struct file * filp);
 
index a78680a92dba3a8a2ad88fca6ef5416e2504312b..1c804b057fb1095dd00038cdd55580d08e773407 100644 (file)
@@ -38,7 +38,7 @@ static inline int fsnotify_parent(struct path *path, struct dentry *dentry, __u3
 static inline int fsnotify_perm(struct file *file, int mask)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = path->dentry->d_inode;
+       struct inode *inode = file_inode(file);
        __u32 fsnotify_mask = 0;
        int ret;
 
@@ -192,7 +192,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
 static inline void fsnotify_access(struct file *file)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = path->dentry->d_inode;
+       struct inode *inode = file_inode(file);
        __u32 mask = FS_ACCESS;
 
        if (S_ISDIR(inode->i_mode))
@@ -210,7 +210,7 @@ static inline void fsnotify_access(struct file *file)
 static inline void fsnotify_modify(struct file *file)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = path->dentry->d_inode;
+       struct inode *inode = file_inode(file);
        __u32 mask = FS_MODIFY;
 
        if (S_ISDIR(inode->i_mode))
@@ -228,7 +228,7 @@ static inline void fsnotify_modify(struct file *file)
 static inline void fsnotify_open(struct file *file)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = path->dentry->d_inode;
+       struct inode *inode = file_inode(file);
        __u32 mask = FS_OPEN;
 
        if (S_ISDIR(inode->i_mode))
index a48937d4a5ea5715fafe813baf4f586a0b747355..06632beaa6d515d80fc2a62c5ddca455c964e0a3 100644 (file)
 #define O_PATH         010000000
 #endif
 
+#ifndef O_TMPFILE
+#define O_TMPFILE      020000000
+#endif
+
 #ifndef O_NDELAY
 #define O_NDELAY       O_NONBLOCK
 #endif
index 5e6a8422658b832921196ca4908e7cc6148eb84a..118dfa4952f4dc565fd284c0df6b0d2bd19f4452 100644 (file)
@@ -1798,10 +1798,7 @@ static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence)
                }
        }
 
-       if (offset >= 0 && offset != file->f_pos) {
-               file->f_pos = offset;
-               file->f_version = 0;
-       }
+       offset = vfs_setpos(file, offset, MAX_LFS_FILESIZE);
        mutex_unlock(&inode->i_mutex);
        return offset;
 }
@@ -1965,6 +1962,37 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
        return error;
 }
 
+static int
+shmem_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       struct inode *inode;
+       int error = -ENOSPC;
+
+       inode = shmem_get_inode(dir->i_sb, dir, mode, 0, VM_NORESERVE);
+       if (inode) {
+               error = security_inode_init_security(inode, dir,
+                                                    NULL,
+                                                    shmem_initxattrs, NULL);
+               if (error) {
+                       if (error != -EOPNOTSUPP) {
+                               iput(inode);
+                               return error;
+                       }
+               }
+#ifdef CONFIG_TMPFS_POSIX_ACL
+               error = generic_acl_init(inode, dir);
+               if (error) {
+                       iput(inode);
+                       return error;
+               }
+#else
+               error = 0;
+#endif
+               d_tmpfile(dentry, inode);
+       }
+       return error;
+}
+
 static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        int error;
@@ -2723,6 +2751,7 @@ static const struct inode_operations shmem_dir_inode_operations = {
        .rmdir          = shmem_rmdir,
        .mknod          = shmem_mknod,
        .rename         = shmem_rename,
+       .tmpfile        = shmem_tmpfile,
 #endif
 #ifdef CONFIG_TMPFS_XATTR
        .setxattr       = shmem_setxattr,
index 29b4ba93ab3cb795fb8dd307f6e248bfcc3a1495..b05ace4c5f124886f165e2f091713397dbe38df4 100644 (file)
@@ -1330,7 +1330,7 @@ static int wait_for_gss_proxy(struct net *net, struct file *file)
 static ssize_t write_gssp(struct file *file, const char __user *buf,
                         size_t count, loff_t *ppos)
 {
-       struct net *net = PDE_DATA(file->f_path.dentry->d_inode);
+       struct net *net = PDE_DATA(file_inode(file));
        char tbuf[20];
        unsigned long i;
        int res;
@@ -1358,7 +1358,7 @@ static ssize_t write_gssp(struct file *file, const char __user *buf,
 static ssize_t read_gssp(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
-       struct net *net = PDE_DATA(file->f_path.dentry->d_inode);
+       struct net *net = PDE_DATA(file_inode(file));
        unsigned long p = *ppos;
        char tbuf[10];
        size_t len;
index 6c491a63128efe7327e33e34b266a64dfc6e6385..e9508d5bbfcff7ee087d069697c6088da7da0210 100644 (file)
@@ -57,7 +57,7 @@ __setup("ima_hash=", hash_setup);
 static void ima_rdwr_violation_check(struct file *file)
 {
        struct dentry *dentry = file->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file_inode(file);
        fmode_t mode = file->f_mode;
        int must_measure;
        bool send_tomtou = false, send_writers = false;
index 5c6f2cd2d095ee8b2a4e828123c00f7966639b6a..db1fca990a2468a4ac292f50daba582df4dc113e 100644 (file)
@@ -1547,6 +1547,18 @@ static inline int path_has_perm(const struct cred *cred,
        return inode_has_perm(cred, inode, av, &ad, 0);
 }
 
+/* Same as path_has_perm, but uses the inode from the file struct. */
+static inline int file_path_has_perm(const struct cred *cred,
+                                    struct file *file,
+                                    u32 av)
+{
+       struct common_audit_data ad;
+
+       ad.type = LSM_AUDIT_DATA_PATH;
+       ad.u.path = file->f_path;
+       return inode_has_perm(cred, file_inode(file), av, &ad, 0);
+}
+
 /* Check whether a task can use an open file descriptor to
    access an inode in a given way.  Check access to the
    descriptor itself, and then use dentry_has_perm to
@@ -2141,14 +2153,14 @@ static inline void flush_unauthorized_files(const struct cred *cred,
                        struct tty_file_private *file_priv;
 
                        /* Revalidate access to controlling tty.
-                          Use path_has_perm on the tty path directly rather
-                          than using file_has_perm, as this particular open
-                          file may belong to another process and we are only
-                          interested in the inode-based check here. */
+                          Use file_path_has_perm on the tty path directly
+                          rather than using file_has_perm, as this particular
+                          open file may belong to another process and we are
+                          only interested in the inode-based check here. */
                        file_priv = list_first_entry(&tty->tty_files,
                                                struct tty_file_private, list);
                        file = file_priv->file;
-                       if (path_has_perm(cred, &file->f_path, FILE__READ | FILE__WRITE))
+                       if (file_path_has_perm(cred, file, FILE__READ | FILE__WRITE))
                                drop_tty = 1;
                }
                spin_unlock(&tty_files_lock);
@@ -3259,7 +3271,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred)
         * new inode label or new policy.
         * This check is not redundant - do not remove.
         */
-       return path_has_perm(cred, &file->f_path, open_file_to_av(file));
+       return file_path_has_perm(cred, file, open_file_to_av(file));
 }
 
 /* task security operations */
index f92818155958d2a166d3a90f1f2ed2670e9217d2..a68d4c6d702c80cd461def1c84c4a91a254b21a4 100644 (file)
@@ -1589,29 +1589,16 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
 }
 
 
-/* WARNING: Don't forget to fput back the file */
-static struct file *snd_pcm_file_fd(int fd, int *fput_needed)
+static bool is_pcm_file(struct file *file)
 {
-       struct file *file;
-       struct inode *inode;
+       struct inode *inode = file_inode(file);
        unsigned int minor;
 
-       file = fget_light(fd, fput_needed);
-       if (!file)
-               return NULL;
-       inode = file_inode(file);
-       if (!S_ISCHR(inode->i_mode) ||
-           imajor(inode) != snd_major) {
-               fput_light(file, *fput_needed);
-               return NULL;
-       }
+       if (!S_ISCHR(inode->i_mode) || imajor(inode) != snd_major)
+               return false;
        minor = iminor(inode);
-       if (!snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) &&
-           !snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE)) {
-               fput_light(file, *fput_needed);
-               return NULL;
-       }
-       return file;
+       return snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) ||
+               snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE);
 }
 
 /*
@@ -1620,16 +1607,18 @@ static struct file *snd_pcm_file_fd(int fd, int *fput_needed)
 static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
 {
        int res = 0;
-       struct file *file;
        struct snd_pcm_file *pcm_file;
        struct snd_pcm_substream *substream1;
        struct snd_pcm_group *group;
-       int fput_needed;
+       struct fd f = fdget(fd);
 
-       file = snd_pcm_file_fd(fd, &fput_needed);
-       if (!file)
+       if (!f.file)
                return -EBADFD;
-       pcm_file = file->private_data;
+       if (!is_pcm_file(f.file)) {
+               res = -EBADFD;
+               goto _badf;
+       }
+       pcm_file = f.file->private_data;
        substream1 = pcm_file->substream;
        group = kmalloc(sizeof(*group), GFP_KERNEL);
        if (!group) {
@@ -1663,8 +1652,9 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
        up_write(&snd_pcm_link_rwsem);
  _nolock:
        snd_card_unref(substream1->pcm->card);
-       fput_light(file, fput_needed);
        kfree(group);
+ _badf:
+       fdput(f);
        return res;
 }