Merge branch 'reiserfs/kill-bkl' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 2 Jan 2010 19:17:05 +0000 (11:17 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 2 Jan 2010 19:17:05 +0000 (11:17 -0800)
* 'reiserfs/kill-bkl' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/random-tracing:
  reiserfs: Safely acquire i_mutex from xattr_rmdir
  reiserfs: Safely acquire i_mutex from reiserfs_for_each_xattr
  reiserfs: Fix journal mutex <-> inode mutex lock inversion
  reiserfs: Fix unwanted recursive reiserfs lock in reiserfs_unlink()
  reiserfs: Relax lock before open xattr dir in reiserfs_xattr_set_handle()
  reiserfs: Relax reiserfs lock while freeing the journal
  reiserfs: Fix reiserfs lock <-> i_mutex dependency inversion on xattr
  reiserfs: Warn on lock relax if taken recursively
  reiserfs: Fix reiserfs lock <-> i_xattr_sem dependency inversion
  reiserfs: Fix remaining in-reclaim-fs <-> reclaim-fs-on locking inversion
  reiserfs: Fix reiserfs lock <-> inode mutex dependency inversion
  reiserfs: Fix reiserfs lock and journal lock inversion dependency
  reiserfs: Fix possible recursive lock

1  2 
fs/reiserfs/inode.c
fs/reiserfs/xattr.c
include/linux/reiserfs_fs.h

diff --combined fs/reiserfs/inode.c
@@@ -31,11 -31,12 +31,12 @@@ void reiserfs_delete_inode(struct inod
            JOURNAL_PER_BALANCE_CNT * 2 +
            2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb);
        struct reiserfs_transaction_handle th;
+       int depth;
        int err;
  
        truncate_inode_pages(&inode->i_data, 0);
  
-       reiserfs_write_lock(inode->i_sb);
+       depth = reiserfs_write_lock_once(inode->i_sb);
  
        /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */
        if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) {  /* also handles bad_inode case */
@@@ -74,7 -75,7 +75,7 @@@
        out:
        clear_inode(inode);     /* note this must go after the journal_end to prevent deadlock */
        inode->i_blocks = 0;
-       reiserfs_write_unlock(inode->i_sb);
+       reiserfs_write_unlock_once(inode->i_sb, depth);
  }
  
  static void _make_cpu_key(struct cpu_key *key, int version, __u32 dirid,
@@@ -2538,12 -2539,6 +2539,12 @@@ static int reiserfs_writepage(struct pa
        return reiserfs_write_full_page(page, wbc);
  }
  
 +static void reiserfs_truncate_failed_write(struct inode *inode)
 +{
 +      truncate_inode_pages(inode->i_mapping, inode->i_size);
 +      reiserfs_truncate_file(inode, 0);
 +}
 +
  static int reiserfs_write_begin(struct file *file,
                                struct address_space *mapping,
                                loff_t pos, unsigned len, unsigned flags,
        if (ret) {
                unlock_page(page);
                page_cache_release(page);
 +              /* Truncate allocated blocks */
 +              reiserfs_truncate_failed_write(inode);
        }
        return ret;
  }
@@@ -2709,7 -2702,9 +2710,7 @@@ static int reiserfs_write_end(struct fi
         ** transaction tracking stuff when the size changes.  So, we have
         ** to do the i_size updates here.
         */
 -      pos += copied;
 -
 -      if (pos > inode->i_size) {
 +      if (pos + copied > inode->i_size) {
                struct reiserfs_transaction_handle myth;
                lock_depth = reiserfs_write_lock_once(inode->i_sb);
                locked = true;
                        goto journal_error;
  
                reiserfs_update_inode_transaction(inode);
 -              inode->i_size = pos;
 +              inode->i_size = pos + copied;
                /*
                 * this will just nest into our transaction.  It's important
                 * to use mark_inode_dirty so the inode gets pushed around on the
                reiserfs_write_unlock_once(inode->i_sb, lock_depth);
        unlock_page(page);
        page_cache_release(page);
 +
 +      if (pos + len > inode->i_size)
 +              reiserfs_truncate_failed_write(inode);
 +
        return ret == 0 ? copied : ret;
  
        journal_error:
diff --combined fs/reiserfs/xattr.c
@@@ -48,7 -48,6 +48,7 @@@
  #include <net/checksum.h>
  #include <linux/stat.h>
  #include <linux/quotaops.h>
 +#include <linux/security.h>
  
  #define PRIVROOT_NAME ".reiserfs_priv"
  #define XAROOT_NAME   "xattrs"
@@@ -83,7 -82,8 +83,8 @@@ static int xattr_unlink(struct inode *d
        BUG_ON(!mutex_is_locked(&dir->i_mutex));
        vfs_dq_init(dir);
  
-       mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
+       reiserfs_mutex_lock_nested_safe(&dentry->d_inode->i_mutex,
+                                       I_MUTEX_CHILD, dir->i_sb);
        error = dir->i_op->unlink(dir, dentry);
        mutex_unlock(&dentry->d_inode->i_mutex);
  
@@@ -98,7 -98,8 +99,8 @@@ static int xattr_rmdir(struct inode *di
        BUG_ON(!mutex_is_locked(&dir->i_mutex));
        vfs_dq_init(dir);
  
-       mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
+       reiserfs_mutex_lock_nested_safe(&dentry->d_inode->i_mutex,
+                                       I_MUTEX_CHILD, dir->i_sb);
        dentry_unhash(dentry);
        error = dir->i_op->rmdir(dir, dentry);
        if (!error)
@@@ -235,16 -236,22 +237,22 @@@ static int reiserfs_for_each_xattr(stru
        if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
                return 0;
  
+       reiserfs_write_unlock(inode->i_sb);
        dir = open_xa_dir(inode, XATTR_REPLACE);
        if (IS_ERR(dir)) {
                err = PTR_ERR(dir);
+               reiserfs_write_lock(inode->i_sb);
                goto out;
        } else if (!dir->d_inode) {
                err = 0;
+               reiserfs_write_lock(inode->i_sb);
                goto out_dir;
        }
  
        mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);
+       reiserfs_write_lock(inode->i_sb);
        buf.xadir = dir;
        err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos);
        while ((err == 0 || err == -ENOSPC) && buf.count) {
                err = journal_begin(&th, inode->i_sb, blocks);
                if (!err) {
                        int jerror;
-                       mutex_lock_nested(&dir->d_parent->d_inode->i_mutex,
-                                         I_MUTEX_XATTR);
+                       reiserfs_mutex_lock_nested_safe(
+                                         &dir->d_parent->d_inode->i_mutex,
+                                         I_MUTEX_XATTR, inode->i_sb);
                        err = action(dir, data);
                        jerror = journal_end(&th, inode->i_sb, blocks);
                        mutex_unlock(&dir->d_parent->d_inode->i_mutex);
@@@ -480,11 -488,16 +489,16 @@@ reiserfs_xattr_set_handle(struct reiser
        if (!buffer)
                return lookup_and_delete_xattr(inode, name);
  
+       reiserfs_write_unlock(inode->i_sb);
        dentry = xattr_lookup(inode, name, flags);
-       if (IS_ERR(dentry))
+       if (IS_ERR(dentry)) {
+               reiserfs_write_lock(inode->i_sb);
                return PTR_ERR(dentry);
+       }
+       down_read(&REISERFS_I(inode)->i_xattr_sem);
  
-       down_write(&REISERFS_I(inode)->i_xattr_sem);
+       reiserfs_write_lock(inode->i_sb);
  
        xahash = xattr_hash(buffer, buffer_size);
        while (buffer_pos < buffer_size || buffer_pos == 0) {
@@@ -727,14 -740,15 +741,14 @@@ ssize_
  reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer,
                  size_t size)
  {
 -      struct inode *inode = dentry->d_inode;
        struct xattr_handler *handler;
  
 -      handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name);
 +      handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
  
 -      if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1)
 +      if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
  
 -      return handler->get(inode, name, buffer, size);
 +      return handler->get(dentry, name, buffer, size, handler->flags);
  }
  
  /*
@@@ -746,14 -760,15 +760,14 @@@ in
  reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
                  size_t size, int flags)
  {
 -      struct inode *inode = dentry->d_inode;
        struct xattr_handler *handler;
  
 -      handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name);
 +      handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
  
 -      if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1)
 +      if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
  
 -      return handler->set(inode, name, value, size, flags);
 +      return handler->set(dentry, name, value, size, flags, handler->flags);
  }
  
  /*
   */
  int reiserfs_removexattr(struct dentry *dentry, const char *name)
  {
 -      struct inode *inode = dentry->d_inode;
        struct xattr_handler *handler;
 -      handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name);
 +      handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
  
 -      if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1)
 +      if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
  
 -      return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
 +      return handler->set(dentry, name, NULL, 0, XATTR_REPLACE, handler->flags);
  }
  
  struct listxattr_buf {
        size_t size;
        size_t pos;
        char *buf;
 -      struct inode *inode;
 +      struct dentry *dentry;
  };
  
  static int listxattr_filler(void *buf, const char *name, int namelen,
        if (name[0] != '.' ||
            (namelen != 1 && (name[1] != '.' || namelen != 2))) {
                struct xattr_handler *handler;
 -              handler = find_xattr_handler_prefix(b->inode->i_sb->s_xattr,
 +              handler = find_xattr_handler_prefix(b->dentry->d_sb->s_xattr,
                                                    name);
                if (!handler)   /* Unsupported xattr name */
                        return 0;
                if (b->buf) {
 -                      size = handler->list(b->inode, b->buf + b->pos,
 -                                       b->size, name, namelen);
 +                      size = handler->list(b->dentry, b->buf + b->pos,
 +                                       b->size, name, namelen,
 +                                       handler->flags);
                        if (size > b->size)
                                return -ERANGE;
                } else {
 -                      size = handler->list(b->inode, NULL, 0, name, namelen);
 +                      size = handler->list(b->dentry, NULL, 0, name,
 +                                           namelen, handler->flags);
                }
  
                b->pos += size;
@@@ -820,7 -834,7 +834,7 @@@ ssize_t reiserfs_listxattr(struct dentr
        int err = 0;
        loff_t pos = 0;
        struct listxattr_buf buf = {
 -              .inode = dentry->d_inode,
 +              .dentry = dentry,
                .buf = buffer,
                .size = buffer ? size : 0,
        };
@@@ -62,6 -62,12 +62,12 @@@ void reiserfs_write_unlock(struct super
  int reiserfs_write_lock_once(struct super_block *s);
  void reiserfs_write_unlock_once(struct super_block *s, int lock_depth);
  
+ #ifdef CONFIG_REISERFS_CHECK
+ void reiserfs_lock_check_recursive(struct super_block *s);
+ #else
+ static inline void reiserfs_lock_check_recursive(struct super_block *s) { }
+ #endif
  /*
   * Several mutexes depend on the write lock.
   * However sometimes we want to relax the write lock while we hold
  static inline void reiserfs_mutex_lock_safe(struct mutex *m,
                               struct super_block *s)
  {
+       reiserfs_lock_check_recursive(s);
        reiserfs_write_unlock(s);
        mutex_lock(m);
        reiserfs_write_lock(s);
  }
  
+ static inline void
+ reiserfs_mutex_lock_nested_safe(struct mutex *m, unsigned int subclass,
+                              struct super_block *s)
+ {
+       reiserfs_lock_check_recursive(s);
+       reiserfs_write_unlock(s);
+       mutex_lock_nested(m, subclass);
+       reiserfs_write_lock(s);
+ }
+ static inline void
+ reiserfs_down_read_safe(struct rw_semaphore *sem, struct super_block *s)
+ {
+       reiserfs_lock_check_recursive(s);
+       reiserfs_write_unlock(s);
+       down_read(sem);
+       reiserfs_write_lock(s);
+ }
  /*
   * When we schedule, we usually want to also release the write lock,
   * according to the previous bkl based locking scheme of reiserfs.
@@@ -2051,12 -2077,25 +2077,12 @@@ void set_de_name_and_namelen(struct rei
  int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
                        struct treepath *path, struct reiserfs_dir_entry *de);
  struct dentry *reiserfs_get_parent(struct dentry *);
 -/* procfs.c */
 -
 -#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
 -#define REISERFS_PROC_INFO
 -#else
 -#undef REISERFS_PROC_INFO
 -#endif
  
 +#ifdef CONFIG_REISERFS_PROC_INFO
  int reiserfs_proc_info_init(struct super_block *sb);
  int reiserfs_proc_info_done(struct super_block *sb);
 -struct proc_dir_entry *reiserfs_proc_register_global(char *name,
 -                                                   read_proc_t * func);
 -void reiserfs_proc_unregister_global(const char *name);
  int reiserfs_proc_info_global_init(void);
  int reiserfs_proc_info_global_done(void);
 -int reiserfs_global_version_in_proc(char *buffer, char **start, off_t offset,
 -                                  int count, int *eof, void *data);
 -
 -#if defined( REISERFS_PROC_INFO )
  
  #define PROC_EXP( e )   e
  
      PROC_INFO_ADD( sb, free_at[ ( level ) ], B_FREE_SPACE( bh ) );    \
      PROC_INFO_ADD( sb, items_at[ ( level ) ], B_NR_ITEMS( bh ) )
  #else
 +static inline int reiserfs_proc_info_init(struct super_block *sb)
 +{
 +      return 0;
 +}
 +
 +static inline int reiserfs_proc_info_done(struct super_block *sb)
 +{
 +      return 0;
 +}
 +
 +static inline int reiserfs_proc_info_global_init(void)
 +{
 +      return 0;
 +}
 +
 +static inline int reiserfs_proc_info_global_done(void)
 +{
 +      return 0;
 +}
 +
  #define PROC_EXP( e )
  #define VOID_V ( ( void ) 0 )
  #define PROC_INFO_MAX( sb, field, value ) VOID_V