Merge branch 'cross-rename' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 4 Apr 2014 21:03:05 +0000 (14:03 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 4 Apr 2014 21:03:05 +0000 (14:03 -0700)
Pull renameat2 system call from Miklos Szeredi:
 "This adds a new syscall, renameat2(), which is the same as renameat()
  but with a flags argument.

  The purpose of extending rename is to add cross-rename, a symmetric
  variant of rename, which exchanges the two files.  This allows
  interesting things, which were not possible before, for example
  atomically replacing a directory tree with a symlink, etc...  This
  also allows overlayfs and friends to operate on whiteouts atomically.

  Andy Lutomirski also suggested a "noreplace" flag, which disables the
  overwriting behavior of rename.

  These two flags, RENAME_EXCHANGE and RENAME_NOREPLACE are only
  implemented for ext4 as an example and for testing"

* 'cross-rename' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ext4: add cross rename support
  ext4: rename: split out helper functions
  ext4: rename: move EMLINK check up
  ext4: rename: create ext4_renament structure for local vars
  vfs: add cross-rename
  vfs: lock_two_nondirectories: allow directory args
  security: add flags to rename hooks
  vfs: add RENAME_NOREPLACE flag
  vfs: add renameat2 syscall
  vfs: rename: use common code for dir and non-dir
  vfs: rename: move d_move() up
  vfs: add d_is_dir()

1  2 
drivers/staging/lustre/lustre/lvfs/lvfs_linux.c
fs/inode.c
include/linux/fs.h

@@@ -55,7 -55,7 +55,7 @@@
  
  struct lprocfs_stats *obd_memory = NULL;
  EXPORT_SYMBOL(obd_memory);
 -/* refine later and change to seqlock or simlar from libcfs */
 +/* refine later and change to seqlock or similar from libcfs */
  
  /* Debugging check only needed during development */
  #ifdef OBD_CTXT_DEBUG
@@@ -223,7 -223,7 +223,7 @@@ int lustre_rename(struct dentry *dir, s
                GOTO(put_old, err = PTR_ERR(dchild_new));
  
        err = ll_vfs_rename(dir->d_inode, dchild_old, mnt,
-                           dir->d_inode, dchild_new, mnt, NULL);
+                           dir->d_inode, dchild_new, mnt);
  
        dput(dchild_new);
  put_old:
diff --combined fs/inode.c
@@@ -503,7 -503,6 +503,7 @@@ void clear_inode(struct inode *inode
         */
        spin_lock_irq(&inode->i_data.tree_lock);
        BUG_ON(inode->i_data.nrpages);
 +      BUG_ON(inode->i_data.nrshadows);
        spin_unlock_irq(&inode->i_data.tree_lock);
        BUG_ON(!list_empty(&inode->i_data.private_list));
        BUG_ON(!(inode->i_state & I_FREEING));
@@@ -549,7 -548,8 +549,7 @@@ static void evict(struct inode *inode
        if (op->evict_inode) {
                op->evict_inode(inode);
        } else {
 -              if (inode->i_data.nrpages)
 -                      truncate_inode_pages(&inode->i_data, 0);
 +              truncate_inode_pages_final(&inode->i_data);
                clear_inode(inode);
        }
        if (S_ISBLK(inode->i_mode) && inode->i_bdev)
@@@ -944,24 -944,22 +944,22 @@@ EXPORT_SYMBOL(unlock_new_inode)
  
  /**
   * lock_two_nondirectories - take two i_mutexes on non-directory objects
+  *
+  * Lock any non-NULL argument that is not a directory.
+  * Zero, one or two objects may be locked by this function.
+  *
   * @inode1: first inode to lock
   * @inode2: second inode to lock
   */
  void lock_two_nondirectories(struct inode *inode1, struct inode *inode2)
  {
-       WARN_ON_ONCE(S_ISDIR(inode1->i_mode));
-       if (inode1 == inode2 || !inode2) {
-               mutex_lock(&inode1->i_mutex);
-               return;
-       }
-       WARN_ON_ONCE(S_ISDIR(inode2->i_mode));
-       if (inode1 < inode2) {
+       if (inode1 > inode2)
+               swap(inode1, inode2);
+       if (inode1 && !S_ISDIR(inode1->i_mode))
                mutex_lock(&inode1->i_mutex);
+       if (inode2 && !S_ISDIR(inode2->i_mode) && inode2 != inode1)
                mutex_lock_nested(&inode2->i_mutex, I_MUTEX_NONDIR2);
-       } else {
-               mutex_lock(&inode2->i_mutex);
-               mutex_lock_nested(&inode1->i_mutex, I_MUTEX_NONDIR2);
-       }
  }
  EXPORT_SYMBOL(lock_two_nondirectories);
  
   */
  void unlock_two_nondirectories(struct inode *inode1, struct inode *inode2)
  {
-       mutex_unlock(&inode1->i_mutex);
-       if (inode2 && inode2 != inode1)
+       if (inode1 && !S_ISDIR(inode1->i_mode))
+               mutex_unlock(&inode1->i_mutex);
+       if (inode2 && !S_ISDIR(inode2->i_mode) && inode2 != inode1)
                mutex_unlock(&inode2->i_mutex);
  }
  EXPORT_SYMBOL(unlock_two_nondirectories);
diff --combined include/linux/fs.h
@@@ -419,7 -419,6 +419,7 @@@ struct address_space 
        struct mutex            i_mmap_mutex;   /* protect tree, count, list */
        /* Protected by tree_lock together with the radix tree */
        unsigned long           nrpages;        /* number of total pages */
 +      unsigned long           nrshadows;      /* number of shadow entries */
        pgoff_t                 writeback_index;/* writeback starts here */
        const struct address_space_operations *a_ops;   /* methods */
        unsigned long           flags;          /* error bits/gfp mask */
@@@ -590,9 -589,6 +590,9 @@@ struct inode 
        atomic_t                i_count;
        atomic_t                i_dio_count;
        atomic_t                i_writecount;
 +#ifdef CONFIG_IMA
 +      atomic_t                i_readcount; /* struct files open RO */
 +#endif
        const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */
        struct file_lock        *i_flock;
        struct address_space    i_data;
        struct hlist_head       i_fsnotify_marks;
  #endif
  
 -#ifdef CONFIG_IMA
 -      atomic_t                i_readcount; /* struct files open RO */
 -#endif
        void                    *i_private; /* fs or device private pointer */
  };
  
@@@ -1461,7 -1460,7 +1461,7 @@@ extern int vfs_symlink(struct inode *, 
  extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct inode **);
  extern int vfs_rmdir(struct inode *, struct dentry *);
  extern int vfs_unlink(struct inode *, struct dentry *, struct inode **);
- extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **);
+ extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int);
  
  /*
   * VFS dentry helper functions.
@@@ -1572,6 -1571,8 +1572,8 @@@ struct inode_operations 
        int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
        int (*rename) (struct inode *, struct dentry *,
                        struct inode *, struct dentry *);
+       int (*rename2) (struct inode *, struct dentry *,
+                       struct inode *, struct dentry *, unsigned int);
        int (*setattr) (struct dentry *, struct iattr *);
        int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
        int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);