Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 21 Mar 2016 19:22:37 +0000 (12:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 21 Mar 2016 19:22:37 +0000 (12:22 -0700)
Pull UDF and quota updates from Jan Kara:
 "This contains a rewrite of UDF handling of filename encoding to fix
  remaining overflow issues from Andrew Gabbasov and quota changes to
  support new Q_[X]GETNEXTQUOTA quotactl for VFS quota formats"

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  quota: Fix possible GPF due to uninitialised pointers
  ext4: Make Q_GETNEXTQUOTA work for quota in hidden inodes
  quota: Forbid Q_GETQUOTA and Q_GETNEXTQUOTA for frozen filesystem
  quota: Fix possible races during quota loading
  ocfs2: Implement get_next_id()
  quota_v2: Implement get_next_id() for V2 quota format
  quota: Add support for ->get_nextdqblk() for VFS quota
  udf: Merge linux specific translation into CS0 conversion function
  udf: Remove struct ustr as non-needed intermediate storage
  udf: Use separate buffer for copying split names
  udf: Adjust UDF_NAME_LEN to better reflect actual restrictions
  udf: Join functions for UTF8 and NLS conversions
  udf: Parameterize output length in udf_put_filename
  quota: Allow Q_GETQUOTA for frozen filesystem
  quota: Fixup comments about return value of Q_[X]GETNEXTQUOTA

1  2 
fs/ext4/super.c
fs/quota/dquot.c

diff --combined fs/ext4/super.c
index 99996e9a8f575ea0a8f271cccbedb7ac92c9ba8c,2ed6596feadfcd307d680f0c04fe22c2a8f460e8..5392975158963118f7eeba2dcf8d560ec485e53d
@@@ -55,6 -55,7 +55,6 @@@
  
  static struct ext4_lazy_init *ext4_li_info;
  static struct mutex ext4_li_mtx;
 -static int ext4_mballoc_ready;
  static struct ratelimit_state ext4_mount_msg_ratelimit;
  
  static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
@@@ -843,6 -844,7 +843,6 @@@ static void ext4_put_super(struct super
        ext4_release_system_zone(sb);
        ext4_mb_release(sb);
        ext4_ext_release(sb);
 -      ext4_xattr_put_super(sb);
  
        if (!(sb->s_flags & MS_RDONLY)) {
                ext4_clear_feature_journal_needs_recovery(sb);
@@@ -942,6 -944,7 +942,6 @@@ static struct inode *ext4_alloc_inode(s
        spin_lock_init(&ei->i_completed_io_lock);
        ei->i_sync_tid = 0;
        ei->i_datasync_tid = 0;
 -      atomic_set(&ei->i_ioend_count, 0);
        atomic_set(&ei->i_unwritten, 0);
        INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work);
  #ifdef CONFIG_EXT4_FS_ENCRYPTION
@@@ -1129,6 -1132,7 +1129,7 @@@ static const struct dquot_operations ex
        .alloc_dquot    = dquot_alloc,
        .destroy_dquot  = dquot_destroy,
        .get_projid     = ext4_get_projid,
+       .get_next_id    = dquot_get_next_id,
  };
  
  static const struct quotactl_ops ext4_qctl_operations = {
        .get_state      = dquot_get_state,
        .set_info       = dquot_set_dqinfo,
        .get_dqblk      = dquot_get_dqblk,
-       .set_dqblk      = dquot_set_dqblk
+       .set_dqblk      = dquot_set_dqblk,
+       .get_nextdqblk  = dquot_get_next_dqblk,
  };
  #endif
  
@@@ -1422,9 -1427,9 +1424,9 @@@ static const struct mount_opts 
        {Opt_err_ro, EXT4_MOUNT_ERRORS_RO, MOPT_SET | MOPT_CLEAR_ERR},
        {Opt_err_cont, EXT4_MOUNT_ERRORS_CONT, MOPT_SET | MOPT_CLEAR_ERR},
        {Opt_data_err_abort, EXT4_MOUNT_DATA_ERR_ABORT,
 -       MOPT_NO_EXT2 | MOPT_SET},
 +       MOPT_NO_EXT2},
        {Opt_data_err_ignore, EXT4_MOUNT_DATA_ERR_ABORT,
 -       MOPT_NO_EXT2 | MOPT_CLEAR},
 +       MOPT_NO_EXT2},
        {Opt_barrier, EXT4_MOUNT_BARRIER, MOPT_SET},
        {Opt_nobarrier, EXT4_MOUNT_BARRIER, MOPT_CLEAR},
        {Opt_noauto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_SET},
@@@ -1702,10 -1707,6 +1704,10 @@@ static int handle_mount_opt(struct supe
                ext4_msg(sb, KERN_INFO, "dax option not supported");
                return -1;
  #endif
 +      } else if (token == Opt_data_err_abort) {
 +              sbi->s_mount_opt |= m->mount_opt;
 +      } else if (token == Opt_data_err_ignore) {
 +              sbi->s_mount_opt &= ~m->mount_opt;
        } else {
                if (!args->from)
                        arg = 1;
@@@ -1915,8 -1916,6 +1917,8 @@@ static int _ext4_show_options(struct se
                SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult);
        if (nodefs || sbi->s_max_dir_size_kb)
                SEQ_OPTS_PRINT("max_dir_size_kb=%u", sbi->s_max_dir_size_kb);
 +      if (test_opt(sb, DATA_ERR_ABORT))
 +              SEQ_OPTS_PUTS("data_err=abort");
  
        ext4_show_quota_options(seq, sb);
        return 0;
@@@ -3799,10 -3798,12 +3801,10 @@@ static int ext4_fill_super(struct super
        sbi->s_journal->j_commit_callback = ext4_journal_commit_callback;
  
  no_journal:
 -      if (ext4_mballoc_ready) {
 -              sbi->s_mb_cache = ext4_xattr_create_cache(sb->s_id);
 -              if (!sbi->s_mb_cache) {
 -                      ext4_msg(sb, KERN_ERR, "Failed to create an mb_cache");
 -                      goto failed_mount_wq;
 -              }
 +      sbi->s_mb_cache = ext4_xattr_create_cache();
 +      if (!sbi->s_mb_cache) {
 +              ext4_msg(sb, KERN_ERR, "Failed to create an mb_cache");
 +              goto failed_mount_wq;
        }
  
        if ((DUMMY_ENCRYPTION_ENABLED(sbi) || ext4_has_feature_encrypt(sb)) &&
@@@ -4028,10 -4029,6 +4030,10 @@@ failed_mount4
        if (EXT4_SB(sb)->rsv_conversion_wq)
                destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq);
  failed_mount_wq:
 +      if (sbi->s_mb_cache) {
 +              ext4_xattr_destroy_cache(sbi->s_mb_cache);
 +              sbi->s_mb_cache = NULL;
 +      }
        if (sbi->s_journal) {
                jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
@@@ -5326,6 -5323,7 +5328,6 @@@ MODULE_ALIAS_FS("ext4")
  
  /* Shared across all ext4 file systems */
  wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
 -struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
  
  static int __init ext4_init_fs(void)
  {
        /* Build-time check for flags consistency */
        ext4_check_flag_values();
  
 -      for (i = 0; i < EXT4_WQ_HASH_SZ; i++) {
 -              mutex_init(&ext4__aio_mutex[i]);
 +      for (i = 0; i < EXT4_WQ_HASH_SZ; i++)
                init_waitqueue_head(&ext4__ioend_wq[i]);
 -      }
  
        err = ext4_init_es();
        if (err)
        err = ext4_init_mballoc();
        if (err)
                goto out2;
 -      else
 -              ext4_mballoc_ready = 1;
        err = init_inodecache();
        if (err)
                goto out1;
@@@ -5375,6 -5377,7 +5377,6 @@@ out
        unregister_as_ext3();
        destroy_inodecache();
  out1:
 -      ext4_mballoc_ready = 0;
        ext4_exit_mballoc();
  out2:
        ext4_exit_sysfs();
diff --combined fs/quota/dquot.c
index 04ca0cc6d065478351e63a13f22d3b90ecb6b96e,dcec1edf579fef6791c7fb630724227b804476bd..ba827daea5a0b2a7883327a18a83a43315c9bd2a
@@@ -411,6 -411,8 +411,8 @@@ int dquot_acquire(struct dquot *dquot
                ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot);
        if (ret < 0)
                goto out_iolock;
+       /* Make sure flags update is visible after dquot has been filled */
+       smp_mb__before_atomic();
        set_bit(DQ_READ_B, &dquot->dq_flags);
        /* Instantiate dquot if needed */
        if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) {
                        goto out_iolock;
                }
        }
+       /*
+        * Make sure flags update is visible after on-disk struct has been
+        * allocated. Paired with smp_rmb() in dqget().
+        */
+       smp_mb__before_atomic();
        set_bit(DQ_ACTIVE_B, &dquot->dq_flags);
  out_iolock:
        mutex_unlock(&dqopt->dqio_mutex);
@@@ -887,6 -894,11 +894,11 @@@ we_slept
                        goto out;
                }
        }
+       /*
+        * Make sure following reads see filled structure - paired with
+        * smp_mb__before_atomic() in dquot_acquire().
+        */
+       smp_rmb();
  #ifdef CONFIG_QUOTA_DEBUG
        BUG_ON(!dquot->dq_sb);  /* Has somebody invalidated entry under us? */
  #endif
@@@ -1398,7 -1410,7 +1410,7 @@@ static int dquot_active(const struct in
  static int __dquot_initialize(struct inode *inode, int type)
  {
        int cnt, init_needed = 0;
-       struct dquot **dquots, *got[MAXQUOTAS];
+       struct dquot **dquots, *got[MAXQUOTAS] = {};
        struct super_block *sb = inode->i_sb;
        qsize_t rsv;
        int ret = 0;
                int rc;
                struct dquot *dquot;
  
-               got[cnt] = NULL;
                if (type != -1 && cnt != type)
                        continue;
                /*
@@@ -2031,6 -2042,21 +2042,21 @@@ int dquot_commit_info(struct super_bloc
  }
  EXPORT_SYMBOL(dquot_commit_info);
  
+ int dquot_get_next_id(struct super_block *sb, struct kqid *qid)
+ {
+       struct quota_info *dqopt = sb_dqopt(sb);
+       int err;
+       if (!dqopt->ops[qid->type]->get_next_id)
+               return -ENOSYS;
+       mutex_lock(&dqopt->dqio_mutex);
+       err = dqopt->ops[qid->type]->get_next_id(sb, qid);
+       mutex_unlock(&dqopt->dqio_mutex);
+       return err;
+ }
+ EXPORT_SYMBOL(dquot_get_next_id);
  /*
   * Definitions of diskquota operations.
   */
@@@ -2042,6 -2068,7 +2068,7 @@@ const struct dquot_operations dquot_ope
        .write_info     = dquot_commit_info,
        .alloc_dquot    = dquot_alloc,
        .destroy_dquot  = dquot_destroy,
+       .get_next_id    = dquot_get_next_id,
  };
  EXPORT_SYMBOL(dquot_operations);
  
@@@ -2430,7 -2457,9 +2457,7 @@@ int dquot_quota_on_mount(struct super_b
        struct dentry *dentry;
        int error;
  
 -      inode_lock(d_inode(sb->s_root));
 -      dentry = lookup_one_len(qf_name, sb->s_root, strlen(qf_name));
 -      inode_unlock(d_inode(sb->s_root));
 +      dentry = lookup_one_len_unlocked(qf_name, sb->s_root, strlen(qf_name));
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
  
@@@ -2563,6 -2592,27 +2590,27 @@@ int dquot_get_dqblk(struct super_block 
  }
  EXPORT_SYMBOL(dquot_get_dqblk);
  
+ int dquot_get_next_dqblk(struct super_block *sb, struct kqid *qid,
+                        struct qc_dqblk *di)
+ {
+       struct dquot *dquot;
+       int err;
+       if (!sb->dq_op->get_next_id)
+               return -ENOSYS;
+       err = sb->dq_op->get_next_id(sb, qid);
+       if (err < 0)
+               return err;
+       dquot = dqget(sb, *qid);
+       if (IS_ERR(dquot))
+               return PTR_ERR(dquot);
+       do_get_dqblk(dquot, di);
+       dqput(dquot);
+       return 0;
+ }
+ EXPORT_SYMBOL(dquot_get_next_dqblk);
  #define VFS_QC_MASK \
        (QC_SPACE | QC_SPC_SOFT | QC_SPC_HARD | \
         QC_INO_COUNT | QC_INO_SOFT | QC_INO_HARD | \
@@@ -2763,6 -2813,7 +2811,7 @@@ const struct quotactl_ops dquot_quotact
        .get_state      = dquot_get_state,
        .set_info       = dquot_set_dqinfo,
        .get_dqblk      = dquot_get_dqblk,
+       .get_nextdqblk  = dquot_get_next_dqblk,
        .set_dqblk      = dquot_set_dqblk
  };
  EXPORT_SYMBOL(dquot_quotactl_ops);
@@@ -2774,6 -2825,7 +2823,7 @@@ const struct quotactl_ops dquot_quotact
        .get_state      = dquot_get_state,
        .set_info       = dquot_set_dqinfo,
        .get_dqblk      = dquot_get_dqblk,
+       .get_nextdqblk  = dquot_get_next_dqblk,
        .set_dqblk      = dquot_set_dqblk
  };
  EXPORT_SYMBOL(dquot_quotactl_sysfile_ops);