aboutsummaryrefslogtreecommitdiffstats
path: root/fs/quota/dquot.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/quota/dquot.c')
-rw-r--r--fs/quota/dquot.c144
1 files changed, 82 insertions, 62 deletions
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 10cbe841cb7..05ae3c97f7a 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -78,7 +78,7 @@
#include <linux/quotaops.h>
#include "../internal.h" /* ugh */
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
/*
* There are three quota SMP locks. dq_list_lock protects all lists with quotas
@@ -253,8 +253,10 @@ static qsize_t inode_get_rsv_space(struct inode *inode);
static void __dquot_initialize(struct inode *inode, int type);
static inline unsigned int
-hashfn(const struct super_block *sb, unsigned int id, int type)
+hashfn(const struct super_block *sb, struct kqid qid)
{
+ unsigned int id = from_kqid(&init_user_ns, qid);
+ int type = qid.type;
unsigned long tmp;
tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type);
@@ -267,7 +269,7 @@ hashfn(const struct super_block *sb, unsigned int id, int type)
static inline void insert_dquot_hash(struct dquot *dquot)
{
struct hlist_head *head;
- head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type);
+ head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id);
hlist_add_head(&dquot->dq_hash, head);
}
@@ -277,15 +279,14 @@ static inline void remove_dquot_hash(struct dquot *dquot)
}
static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb,
- unsigned int id, int type)
+ struct kqid qid)
{
struct hlist_node *node;
struct dquot *dquot;
hlist_for_each (node, dquot_hash+hashent) {
dquot = hlist_entry(node, struct dquot, dq_hash);
- if (dquot->dq_sb == sb && dquot->dq_id == id &&
- dquot->dq_type == type)
+ if (dquot->dq_sb == sb && qid_eq(dquot->dq_id, qid))
return dquot;
}
return NULL;
@@ -351,7 +352,7 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)
spin_lock(&dq_list_lock);
if (!test_and_set_bit(DQ_MOD_B, &dquot->dq_flags)) {
list_add(&dquot->dq_dirty, &sb_dqopt(dquot->dq_sb)->
- info[dquot->dq_type].dqi_dirty_list);
+ info[dquot->dq_id.type].dqi_dirty_list);
ret = 0;
}
spin_unlock(&dq_list_lock);
@@ -410,17 +411,17 @@ int dquot_acquire(struct dquot *dquot)
mutex_lock(&dquot->dq_lock);
mutex_lock(&dqopt->dqio_mutex);
if (!test_bit(DQ_READ_B, &dquot->dq_flags))
- ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot);
+ ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot);
if (ret < 0)
goto out_iolock;
set_bit(DQ_READ_B, &dquot->dq_flags);
/* Instantiate dquot if needed */
if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) {
- ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+ ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot);
/* Write the info if needed */
- if (info_dirty(&dqopt->info[dquot->dq_type])) {
- ret2 = dqopt->ops[dquot->dq_type]->write_file_info(
- dquot->dq_sb, dquot->dq_type);
+ if (info_dirty(&dqopt->info[dquot->dq_id.type])) {
+ ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info(
+ dquot->dq_sb, dquot->dq_id.type);
}
if (ret < 0)
goto out_iolock;
@@ -455,7 +456,7 @@ int dquot_commit(struct dquot *dquot)
/* Inactive dquot can be only if there was error during read/init
* => we have better not writing it */
if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
- ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+ ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot);
else
ret = -EIO;
out_sem:
@@ -477,12 +478,12 @@ int dquot_release(struct dquot *dquot)
if (atomic_read(&dquot->dq_count) > 1)
goto out_dqlock;
mutex_lock(&dqopt->dqio_mutex);
- if (dqopt->ops[dquot->dq_type]->release_dqblk) {
- ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot);
+ if (dqopt->ops[dquot->dq_id.type]->release_dqblk) {
+ ret = dqopt->ops[dquot->dq_id.type]->release_dqblk(dquot);
/* Write the info */
- if (info_dirty(&dqopt->info[dquot->dq_type])) {
- ret2 = dqopt->ops[dquot->dq_type]->write_file_info(
- dquot->dq_sb, dquot->dq_type);
+ if (info_dirty(&dqopt->info[dquot->dq_id.type])) {
+ ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info(
+ dquot->dq_sb, dquot->dq_id.type);
}
if (ret >= 0)
ret = ret2;
@@ -521,7 +522,7 @@ restart:
list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
if (dquot->dq_sb != sb)
continue;
- if (dquot->dq_type != type)
+ if (dquot->dq_id.type != type)
continue;
/* Wait for dquot users */
if (atomic_read(&dquot->dq_count)) {
@@ -595,12 +596,14 @@ out:
}
EXPORT_SYMBOL(dquot_scan_active);
-int dquot_quota_sync(struct super_block *sb, int type, int wait)
+/* Write all dquot structures to quota files */
+int dquot_writeback_dquots(struct super_block *sb, int type)
{
struct list_head *dirty;
struct dquot *dquot;
struct quota_info *dqopt = sb_dqopt(sb);
int cnt;
+ int err, ret = 0;
mutex_lock(&dqopt->dqonoff_mutex);
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -624,7 +627,9 @@ int dquot_quota_sync(struct super_block *sb, int type, int wait)
atomic_inc(&dquot->dq_count);
spin_unlock(&dq_list_lock);
dqstats_inc(DQST_LOOKUPS);
- sb->dq_op->write_dquot(dquot);
+ err = sb->dq_op->write_dquot(dquot);
+ if (!ret && err)
+ err = ret;
dqput(dquot);
spin_lock(&dq_list_lock);
}
@@ -638,7 +643,21 @@ int dquot_quota_sync(struct super_block *sb, int type, int wait)
dqstats_inc(DQST_SYNCS);
mutex_unlock(&dqopt->dqonoff_mutex);
- if (!wait || (dqopt->flags & DQUOT_QUOTA_SYS_FILE))
+ return ret;
+}
+EXPORT_SYMBOL(dquot_writeback_dquots);
+
+/* Write all dquot structures to disk and make them visible from userspace */
+int dquot_quota_sync(struct super_block *sb, int type)
+{
+ struct quota_info *dqopt = sb_dqopt(sb);
+ int cnt;
+ int ret;
+
+ ret = dquot_writeback_dquots(sb, type);
+ if (ret)
+ return ret;
+ if (dqopt->flags & DQUOT_QUOTA_SYS_FILE)
return 0;
/* This is not very clever (and fast) but currently I don't know about
@@ -723,7 +742,8 @@ void dqput(struct dquot *dquot)
#ifdef CONFIG_QUOTA_DEBUG
if (!atomic_read(&dquot->dq_count)) {
quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
- quotatypes[dquot->dq_type], dquot->dq_id);
+ quotatypes[dquot->dq_id.type],
+ from_kqid(&init_user_ns, dquot->dq_id));
BUG();
}
#endif
@@ -734,7 +754,7 @@ we_slept:
/* We have more than one user... nothing to do */
atomic_dec(&dquot->dq_count);
/* Releasing dquot during quotaoff phase? */
- if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_type) &&
+ if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_id.type) &&
atomic_read(&dquot->dq_count) == 1)
wake_up(&dquot->dq_wait_unused);
spin_unlock(&dq_list_lock);
@@ -797,7 +817,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
INIT_LIST_HEAD(&dquot->dq_dirty);
init_waitqueue_head(&dquot->dq_wait_unused);
dquot->dq_sb = sb;
- dquot->dq_type = type;
+ dquot->dq_id = make_kqid_invalid(type);
atomic_set(&dquot->dq_count, 1);
return dquot;
@@ -811,35 +831,35 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
* a) checking for quota flags under dq_list_lock and
* b) getting a reference to dquot before we release dq_list_lock
*/
-struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
+struct dquot *dqget(struct super_block *sb, struct kqid qid)
{
- unsigned int hashent = hashfn(sb, id, type);
+ unsigned int hashent = hashfn(sb, qid);
struct dquot *dquot = NULL, *empty = NULL;
- if (!sb_has_quota_active(sb, type))
+ if (!sb_has_quota_active(sb, qid.type))
return NULL;
we_slept:
spin_lock(&dq_list_lock);
spin_lock(&dq_state_lock);
- if (!sb_has_quota_active(sb, type)) {
+ if (!sb_has_quota_active(sb, qid.type)) {
spin_unlock(&dq_state_lock);
spin_unlock(&dq_list_lock);
goto out;
}
spin_unlock(&dq_state_lock);
- dquot = find_dquot(hashent, sb, id, type);
+ dquot = find_dquot(hashent, sb, qid);
if (!dquot) {
if (!empty) {
spin_unlock(&dq_list_lock);
- empty = get_empty_dquot(sb, type);
+ empty = get_empty_dquot(sb, qid.type);
if (!empty)
schedule(); /* Try to wait for a moment... */
goto we_slept;
}
dquot = empty;
empty = NULL;
- dquot->dq_id = id;
+ dquot->dq_id = qid;
/* all dquots go on the inuse_list */
put_inuse(dquot);
/* hash it first so it can be found */
@@ -1111,8 +1131,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
struct dquot_warn {
struct super_block *w_sb;
- qid_t w_dq_id;
- short w_dq_type;
+ struct kqid w_dq_id;
short w_type;
};
@@ -1136,11 +1155,13 @@ static int need_print_warning(struct dquot_warn *warn)
if (!flag_print_warnings)
return 0;
- switch (warn->w_dq_type) {
+ switch (warn->w_dq_id.type) {
case USRQUOTA:
- return current_fsuid() == warn->w_dq_id;
+ return uid_eq(current_fsuid(), warn->w_dq_id.uid);
case GRPQUOTA:
- return in_group_p(warn->w_dq_id);
+ return in_group_p(warn->w_dq_id.gid);
+ case PRJQUOTA: /* Never taken... Just make gcc happy */
+ return 0;
}
return 0;
}
@@ -1166,7 +1187,7 @@ static void print_warning(struct dquot_warn *warn)
tty_write_message(tty, ": warning, ");
else
tty_write_message(tty, ": write failed, ");
- tty_write_message(tty, quotatypes[warn->w_dq_type]);
+ tty_write_message(tty, quotatypes[warn->w_dq_id.type]);
switch (warntype) {
case QUOTA_NL_IHARDWARN:
msg = " file limit reached.\r\n";
@@ -1200,7 +1221,6 @@ static void prepare_warning(struct dquot_warn *warn, struct dquot *dquot,
warn->w_type = warntype;
warn->w_sb = dquot->dq_sb;
warn->w_dq_id = dquot->dq_id;
- warn->w_dq_type = dquot->dq_type;
}
/*
@@ -1218,14 +1238,14 @@ static void flush_warnings(struct dquot_warn *warn)
#ifdef CONFIG_PRINT_QUOTA_WARNING
print_warning(&warn[i]);
#endif
- quota_send_warning(warn[i].w_dq_type, warn[i].w_dq_id,
+ quota_send_warning(warn[i].w_dq_id,
warn[i].w_sb->s_dev, warn[i].w_type);
}
}
static int ignore_hardlimit(struct dquot *dquot)
{
- struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+ struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type];
return capable(CAP_SYS_RESOURCE) &&
(info->dqi_format->qf_fmt_id != QFMT_VFS_OLD ||
@@ -1238,7 +1258,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
{
qsize_t newinodes = dquot->dq_dqb.dqb_curinodes + inodes;
- if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
+ if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_id.type) ||
test_bit(DQ_FAKE_B, &dquot->dq_flags))
return 0;
@@ -1263,7 +1283,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
dquot->dq_dqb.dqb_itime == 0) {
prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN);
dquot->dq_dqb.dqb_itime = get_seconds() +
- sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+ sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type].dqi_igrace;
}
return 0;
@@ -1276,7 +1296,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
qsize_t tspace;
struct super_block *sb = dquot->dq_sb;
- if (!sb_has_quota_limits_enabled(sb, dquot->dq_type) ||
+ if (!sb_has_quota_limits_enabled(sb, dquot->dq_id.type) ||
test_bit(DQ_FAKE_B, &dquot->dq_flags))
return 0;
@@ -1307,7 +1327,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
if (!prealloc) {
prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN);
dquot->dq_dqb.dqb_btime = get_seconds() +
- sb_dqopt(sb)->info[dquot->dq_type].dqi_bgrace;
+ sb_dqopt(sb)->info[dquot->dq_id.type].dqi_bgrace;
}
else
/*
@@ -1326,7 +1346,7 @@ static int info_idq_free(struct dquot *dquot, qsize_t inodes)
if (test_bit(DQ_FAKE_B, &dquot->dq_flags) ||
dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit ||
- !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type))
+ !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_id.type))
return QUOTA_NL_NOWARN;
newinodes = dquot->dq_dqb.dqb_curinodes - inodes;
@@ -1372,7 +1392,6 @@ static int dquot_active(const struct inode *inode)
*/
static void __dquot_initialize(struct inode *inode, int type)
{
- unsigned int id = 0;
int cnt;
struct dquot *got[MAXQUOTAS];
struct super_block *sb = inode->i_sb;
@@ -1385,18 +1404,19 @@ static void __dquot_initialize(struct inode *inode, int type)
/* First get references to structures we might need. */
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+ struct kqid qid;
got[cnt] = NULL;
if (type != -1 && cnt != type)
continue;
switch (cnt) {
case USRQUOTA:
- id = inode->i_uid;
+ qid = make_kqid_uid(inode->i_uid);
break;
case GRPQUOTA:
- id = inode->i_gid;
+ qid = make_kqid_gid(inode->i_gid);
break;
}
- got[cnt] = dqget(sb, id, cnt);
+ got[cnt] = dqget(sb, qid);
}
down_write(&sb_dqopt(sb)->dqptr_sem);
@@ -1571,10 +1591,10 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
goto out;
}
- down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
warn[cnt].w_type = QUOTA_NL_NOWARN;
+ down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
spin_lock(&dq_data_lock);
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (!dquots[cnt])
@@ -1879,10 +1899,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
if (!dquot_active(inode))
return 0;
- if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
- transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA);
- if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)
- transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA);
+ if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
+ transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(iattr->ia_uid));
+ if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
+ transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(iattr->ia_gid));
ret = __dquot_transfer(inode, transfer_to);
dqput_all(transfer_to);
@@ -2342,9 +2362,9 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
memset(di, 0, sizeof(*di));
di->d_version = FS_DQUOT_VERSION;
- di->d_flags = dquot->dq_type == USRQUOTA ?
+ di->d_flags = dquot->dq_id.type == USRQUOTA ?
FS_USER_QUOTA : FS_GROUP_QUOTA;
- di->d_id = dquot->dq_id;
+ di->d_id = from_kqid_munged(current_user_ns(), dquot->dq_id);
spin_lock(&dq_data_lock);
di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
@@ -2358,12 +2378,12 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
spin_unlock(&dq_data_lock);
}
-int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
struct fs_disk_quota *di)
{
struct dquot *dquot;
- dquot = dqget(sb, id, type);
+ dquot = dqget(sb, qid);
if (!dquot)
return -ESRCH;
do_get_dqblk(dquot, di);
@@ -2383,7 +2403,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
{
struct mem_dqblk *dm = &dquot->dq_dqb;
int check_blim = 0, check_ilim = 0;
- struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+ struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type];
if (di->d_fieldmask & ~VFS_FS_DQ_MASK)
return -EINVAL;
@@ -2470,13 +2490,13 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
return 0;
}
-int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, struct kqid qid,
struct fs_disk_quota *di)
{
struct dquot *dquot;
int rc;
- dquot = dqget(sb, id, type);
+ dquot = dqget(sb, qid);
if (!dquot) {
rc = -ESRCH;
goto out;