Commit 77d91317 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 53d2e697 ab73ef46
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -1129,6 +1129,7 @@ static const struct dquot_operations ext4_quota_operations = {
	.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 = {
@@ -1138,7 +1139,8 @@ 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

+2 −0
Original line number Diff line number Diff line
@@ -2035,6 +2035,8 @@ DEFINE_OCFS2_UINT_INT_EVENT(ocfs2_release_dquot);

DEFINE_OCFS2_UINT_INT_EVENT(ocfs2_acquire_dquot);

DEFINE_OCFS2_UINT_INT_EVENT(ocfs2_get_next_id);

DEFINE_OCFS2_UINT_INT_EVENT(ocfs2_mark_dquot_dirty);

/* End of trace events for fs/ocfs2/quota_global.c. */
+25 −0
Original line number Diff line number Diff line
@@ -860,6 +860,30 @@ out:
	return status;
}

static int ocfs2_get_next_id(struct super_block *sb, struct kqid *qid)
{
	int type = qid->type;
	struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
	int status = 0;

	trace_ocfs2_get_next_id(from_kqid(&init_user_ns, *qid), type);
	status = ocfs2_lock_global_qf(info, 0);
	if (status < 0)
		goto out;
	status = ocfs2_qinfo_lock(info, 0);
	if (status < 0)
		goto out_global;
	status = qtree_get_next_id(&info->dqi_gi, qid);
	ocfs2_qinfo_unlock(info, 0);
out_global:
	ocfs2_unlock_global_qf(info, 0);
out:
	/* Avoid logging ENOENT since it just means there isn't next ID */
	if (status && status != -ENOENT)
		mlog_errno(status);
	return status;
}

static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
{
	unsigned long mask = (1 << (DQ_LASTSET_B + QIF_ILIMITS_B)) |
@@ -968,4 +992,5 @@ const struct dquot_operations ocfs2_quota_operations = {
	.write_info	= ocfs2_write_info,
	.alloc_dquot	= ocfs2_alloc_dquot,
	.destroy_dquot	= ocfs2_destroy_dquot,
	.get_next_id	= ocfs2_get_next_id,
};
+52 −2
Original line number Diff line number Diff line
@@ -411,6 +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) {
@@ -427,6 +429,11 @@ int dquot_acquire(struct dquot *dquot)
			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 @@ 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 @@ static int dquot_active(const struct inode *inode)
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;
@@ -1415,7 +1427,6 @@ static int __dquot_initialize(struct inode *inode, int type)
		int rc;
		struct dquot *dquot;

		got[cnt] = NULL;
		if (type != -1 && cnt != type)
			continue;
		/*
@@ -2031,6 +2042,21 @@ int dquot_commit_info(struct super_block *sb, int type)
}
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 @@ const struct dquot_operations dquot_operations = {
	.write_info	= dquot_commit_info,
	.alloc_dquot	= dquot_alloc,
	.destroy_dquot	= dquot_destroy,
	.get_next_id	= dquot_get_next_id,
};
EXPORT_SYMBOL(dquot_operations);

@@ -2563,6 +2590,27 @@ int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
}
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 +2811,7 @@ const struct quotactl_ops dquot_quotactl_ops = {
	.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 +2823,7 @@ const struct quotactl_ops dquot_quotactl_sysfile_ops = {
	.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);
+7 −3
Original line number Diff line number Diff line
@@ -224,7 +224,7 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id,

/*
 * Return quota for next active quota >= this id, if any exists,
 * otherwise return -ESRCH via ->get_nextdqblk
 * otherwise return -ENOENT via ->get_nextdqblk
 */
static int quota_getnextquota(struct super_block *sb, int type, qid_t id,
			  void __user *addr)
@@ -655,7 +655,7 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id,

/*
 * Return quota for next active quota >= this id, if any exists,
 * otherwise return -ESRCH via ->get_nextdqblk.
 * otherwise return -ENOENT via ->get_nextdqblk.
 */
static int quota_getnextxquota(struct super_block *sb, int type, qid_t id,
			    void __user *addr)
@@ -765,10 +765,14 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
/* Return 1 if 'cmd' will block on frozen filesystem */
static int quotactl_cmd_write(int cmd)
{
	/*
	 * We cannot allow Q_GETQUOTA and Q_GETNEXTQUOTA without write access
	 * as dquot_acquire() may allocate space for new structure and OCFS2
	 * needs to increment on-disk use count.
	 */
	switch (cmd) {
	case Q_GETFMT:
	case Q_GETINFO:
	case Q_GETNEXTQUOTA:
	case Q_SYNC:
	case Q_XGETQSTAT:
	case Q_XGETQSTATV:
Loading