|
@@ -100,9 +100,13 @@
|
|
|
*
|
|
|
* Any operation working on dquots via inode pointers must hold dqptr_sem. If
|
|
|
* operation is just reading pointers from inode (or not using them at all) the
|
|
|
- * read lock is enough. If pointers are altered function must hold write lock
|
|
|
- * (these locking rules also apply for S_NOQUOTA flag in the inode - note that
|
|
|
- * for altering the flag i_mutex is also needed).
|
|
|
+ * read lock is enough. If pointers are altered function must hold write lock.
|
|
|
+ * Special care needs to be taken about S_NOQUOTA inode flag (marking that
|
|
|
+ * inode is a quota file). Functions adding pointers from inode to dquots have
|
|
|
+ * to check this flag under dqptr_sem and then (if S_NOQUOTA is not set) they
|
|
|
+ * have to do all pointer modifications before dropping dqptr_sem. This makes
|
|
|
+ * sure they cannot race with quotaon which first sets S_NOQUOTA flag and
|
|
|
+ * then drops all pointers to dquots from an inode.
|
|
|
*
|
|
|
* Each dquot has its dq_lock mutex. Locked dquots might not be referenced
|
|
|
* from inodes (dquot_alloc_space() and such don't check the dq_lock).
|
|
@@ -225,6 +229,9 @@ static struct hlist_head *dquot_hash;
|
|
|
struct dqstats dqstats;
|
|
|
EXPORT_SYMBOL(dqstats);
|
|
|
|
|
|
+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)
|
|
|
{
|
|
@@ -564,7 +571,7 @@ out:
|
|
|
}
|
|
|
EXPORT_SYMBOL(dquot_scan_active);
|
|
|
|
|
|
-int vfs_quota_sync(struct super_block *sb, int type)
|
|
|
+int vfs_quota_sync(struct super_block *sb, int type, int wait)
|
|
|
{
|
|
|
struct list_head *dirty;
|
|
|
struct dquot *dquot;
|
|
@@ -609,6 +616,33 @@ int vfs_quota_sync(struct super_block *sb, int type)
|
|
|
spin_unlock(&dq_list_lock);
|
|
|
mutex_unlock(&dqopt->dqonoff_mutex);
|
|
|
|
|
|
+ if (!wait || (sb_dqopt(sb)->flags & DQUOT_QUOTA_SYS_FILE))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* This is not very clever (and fast) but currently I don't know about
|
|
|
+ * any other simple way of getting quota data to disk and we must get
|
|
|
+ * them there for userspace to be visible... */
|
|
|
+ if (sb->s_op->sync_fs)
|
|
|
+ sb->s_op->sync_fs(sb, 1);
|
|
|
+ sync_blockdev(sb->s_bdev);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Now when everything is written we can discard the pagecache so
|
|
|
+ * that userspace sees the changes.
|
|
|
+ */
|
|
|
+ mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
|
|
|
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
+ if (type != -1 && cnt != type)
|
|
|
+ continue;
|
|
|
+ if (!sb_has_quota_active(sb, cnt))
|
|
|
+ continue;
|
|
|
+ mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex,
|
|
|
+ I_MUTEX_QUOTA);
|
|
|
+ truncate_inode_pages(&sb_dqopt(sb)->files[cnt]->i_data, 0);
|
|
|
+ mutex_unlock(&sb_dqopt(sb)->files[cnt]->i_mutex);
|
|
|
+ }
|
|
|
+ mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL(vfs_quota_sync);
|
|
@@ -840,11 +874,14 @@ static int dqinit_needed(struct inode *inode, int type)
|
|
|
static void add_dquot_ref(struct super_block *sb, int type)
|
|
|
{
|
|
|
struct inode *inode, *old_inode = NULL;
|
|
|
+ int reserved = 0;
|
|
|
|
|
|
spin_lock(&inode_lock);
|
|
|
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
|
|
|
if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
|
|
|
continue;
|
|
|
+ if (unlikely(inode_get_rsv_space(inode) > 0))
|
|
|
+ reserved = 1;
|
|
|
if (!atomic_read(&inode->i_writecount))
|
|
|
continue;
|
|
|
if (!dqinit_needed(inode, type))
|
|
@@ -854,7 +891,7 @@ static void add_dquot_ref(struct super_block *sb, int type)
|
|
|
spin_unlock(&inode_lock);
|
|
|
|
|
|
iput(old_inode);
|
|
|
- sb->dq_op->initialize(inode, type);
|
|
|
+ __dquot_initialize(inode, type);
|
|
|
/* We hold a reference to 'inode' so it couldn't have been
|
|
|
* removed from s_inodes list while we dropped the inode_lock.
|
|
|
* We cannot iput the inode now as we can be holding the last
|
|
@@ -865,6 +902,12 @@ static void add_dquot_ref(struct super_block *sb, int type)
|
|
|
}
|
|
|
spin_unlock(&inode_lock);
|
|
|
iput(old_inode);
|
|
|
+
|
|
|
+ if (reserved) {
|
|
|
+ printk(KERN_WARNING "VFS (%s): Writes happened before quota"
|
|
|
+ " was turned on thus quota information is probably "
|
|
|
+ "inconsistent. Please run quotacheck(8).\n", sb->s_id);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -978,10 +1021,12 @@ static inline void dquot_resv_space(struct dquot *dquot, qsize_t number)
|
|
|
/*
|
|
|
* Claim reserved quota space
|
|
|
*/
|
|
|
-static void dquot_claim_reserved_space(struct dquot *dquot,
|
|
|
- qsize_t number)
|
|
|
+static void dquot_claim_reserved_space(struct dquot *dquot, qsize_t number)
|
|
|
{
|
|
|
- WARN_ON(dquot->dq_dqb.dqb_rsvspace < number);
|
|
|
+ if (dquot->dq_dqb.dqb_rsvspace < number) {
|
|
|
+ WARN_ON_ONCE(1);
|
|
|
+ number = dquot->dq_dqb.dqb_rsvspace;
|
|
|
+ }
|
|
|
dquot->dq_dqb.dqb_curspace += number;
|
|
|
dquot->dq_dqb.dqb_rsvspace -= number;
|
|
|
}
|
|
@@ -989,7 +1034,12 @@ static void dquot_claim_reserved_space(struct dquot *dquot,
|
|
|
static inline
|
|
|
void dquot_free_reserved_space(struct dquot *dquot, qsize_t number)
|
|
|
{
|
|
|
- dquot->dq_dqb.dqb_rsvspace -= number;
|
|
|
+ if (dquot->dq_dqb.dqb_rsvspace >= number)
|
|
|
+ dquot->dq_dqb.dqb_rsvspace -= number;
|
|
|
+ else {
|
|
|
+ WARN_ON_ONCE(1);
|
|
|
+ dquot->dq_dqb.dqb_rsvspace = 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
|
|
@@ -1131,13 +1181,13 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
|
|
|
*warntype = QUOTA_NL_NOWARN;
|
|
|
if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
|
|
|
test_bit(DQ_FAKE_B, &dquot->dq_flags))
|
|
|
- return QUOTA_OK;
|
|
|
+ return 0;
|
|
|
|
|
|
if (dquot->dq_dqb.dqb_ihardlimit &&
|
|
|
newinodes > dquot->dq_dqb.dqb_ihardlimit &&
|
|
|
!ignore_hardlimit(dquot)) {
|
|
|
*warntype = QUOTA_NL_IHARDWARN;
|
|
|
- return NO_QUOTA;
|
|
|
+ return -EDQUOT;
|
|
|
}
|
|
|
|
|
|
if (dquot->dq_dqb.dqb_isoftlimit &&
|
|
@@ -1146,7 +1196,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
|
|
|
get_seconds() >= dquot->dq_dqb.dqb_itime &&
|
|
|
!ignore_hardlimit(dquot)) {
|
|
|
*warntype = QUOTA_NL_ISOFTLONGWARN;
|
|
|
- return NO_QUOTA;
|
|
|
+ return -EDQUOT;
|
|
|
}
|
|
|
|
|
|
if (dquot->dq_dqb.dqb_isoftlimit &&
|
|
@@ -1157,7 +1207,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
|
|
|
sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
|
|
|
}
|
|
|
|
|
|
- return QUOTA_OK;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/* needs dq_data_lock */
|
|
@@ -1169,7 +1219,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
|
|
|
*warntype = QUOTA_NL_NOWARN;
|
|
|
if (!sb_has_quota_limits_enabled(sb, dquot->dq_type) ||
|
|
|
test_bit(DQ_FAKE_B, &dquot->dq_flags))
|
|
|
- return QUOTA_OK;
|
|
|
+ return 0;
|
|
|
|
|
|
tspace = dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace
|
|
|
+ space;
|
|
@@ -1179,7 +1229,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
|
|
|
!ignore_hardlimit(dquot)) {
|
|
|
if (!prealloc)
|
|
|
*warntype = QUOTA_NL_BHARDWARN;
|
|
|
- return NO_QUOTA;
|
|
|
+ return -EDQUOT;
|
|
|
}
|
|
|
|
|
|
if (dquot->dq_dqb.dqb_bsoftlimit &&
|
|
@@ -1189,7 +1239,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
|
|
|
!ignore_hardlimit(dquot)) {
|
|
|
if (!prealloc)
|
|
|
*warntype = QUOTA_NL_BSOFTLONGWARN;
|
|
|
- return NO_QUOTA;
|
|
|
+ return -EDQUOT;
|
|
|
}
|
|
|
|
|
|
if (dquot->dq_dqb.dqb_bsoftlimit &&
|
|
@@ -1205,10 +1255,10 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
|
|
|
* We don't allow preallocation to exceed softlimit so exceeding will
|
|
|
* be always printed
|
|
|
*/
|
|
|
- return NO_QUOTA;
|
|
|
+ return -EDQUOT;
|
|
|
}
|
|
|
|
|
|
- return QUOTA_OK;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static int info_idq_free(struct dquot *dquot, qsize_t inodes)
|
|
@@ -1242,25 +1292,32 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space)
|
|
|
return QUOTA_NL_BHARDBELOW;
|
|
|
return QUOTA_NL_NOWARN;
|
|
|
}
|
|
|
+
|
|
|
/*
|
|
|
- * Initialize quota pointers in inode
|
|
|
- * We do things in a bit complicated way but by that we avoid calling
|
|
|
- * dqget() and thus filesystem callbacks under dqptr_sem.
|
|
|
+ * Initialize quota pointers in inode
|
|
|
+ *
|
|
|
+ * We do things in a bit complicated way but by that we avoid calling
|
|
|
+ * dqget() and thus filesystem callbacks under dqptr_sem.
|
|
|
+ *
|
|
|
+ * It is better to call this function outside of any transaction as it
|
|
|
+ * might need a lot of space in journal for dquot structure allocation.
|
|
|
*/
|
|
|
-int dquot_initialize(struct inode *inode, int type)
|
|
|
+static void __dquot_initialize(struct inode *inode, int type)
|
|
|
{
|
|
|
unsigned int id = 0;
|
|
|
- int cnt, ret = 0;
|
|
|
- struct dquot *got[MAXQUOTAS] = { NULL, NULL };
|
|
|
+ int cnt;
|
|
|
+ struct dquot *got[MAXQUOTAS];
|
|
|
struct super_block *sb = inode->i_sb;
|
|
|
+ qsize_t rsv;
|
|
|
|
|
|
/* First test before acquiring mutex - solves deadlocks when we
|
|
|
* re-enter the quota code and are already holding the mutex */
|
|
|
- if (IS_NOQUOTA(inode))
|
|
|
- return 0;
|
|
|
+ if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
|
|
|
+ return;
|
|
|
|
|
|
/* First get references to structures we might need. */
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
+ got[cnt] = NULL;
|
|
|
if (type != -1 && cnt != type)
|
|
|
continue;
|
|
|
switch (cnt) {
|
|
@@ -1275,7 +1332,6 @@ int dquot_initialize(struct inode *inode, int type)
|
|
|
}
|
|
|
|
|
|
down_write(&sb_dqopt(sb)->dqptr_sem);
|
|
|
- /* Having dqptr_sem we know NOQUOTA flags can't be altered... */
|
|
|
if (IS_NOQUOTA(inode))
|
|
|
goto out_err;
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
@@ -1287,20 +1343,31 @@ int dquot_initialize(struct inode *inode, int type)
|
|
|
if (!inode->i_dquot[cnt]) {
|
|
|
inode->i_dquot[cnt] = got[cnt];
|
|
|
got[cnt] = NULL;
|
|
|
+ /*
|
|
|
+ * Make quota reservation system happy if someone
|
|
|
+ * did a write before quota was turned on
|
|
|
+ */
|
|
|
+ rsv = inode_get_rsv_space(inode);
|
|
|
+ if (unlikely(rsv))
|
|
|
+ dquot_resv_space(inode->i_dquot[cnt], rsv);
|
|
|
}
|
|
|
}
|
|
|
out_err:
|
|
|
up_write(&sb_dqopt(sb)->dqptr_sem);
|
|
|
/* Drop unused references */
|
|
|
dqput_all(got);
|
|
|
- return ret;
|
|
|
+}
|
|
|
+
|
|
|
+void dquot_initialize(struct inode *inode)
|
|
|
+{
|
|
|
+ __dquot_initialize(inode, -1);
|
|
|
}
|
|
|
EXPORT_SYMBOL(dquot_initialize);
|
|
|
|
|
|
/*
|
|
|
* Release all quotas referenced by inode
|
|
|
*/
|
|
|
-int dquot_drop(struct inode *inode)
|
|
|
+static void __dquot_drop(struct inode *inode)
|
|
|
{
|
|
|
int cnt;
|
|
|
struct dquot *put[MAXQUOTAS];
|
|
@@ -1312,32 +1379,31 @@ int dquot_drop(struct inode *inode)
|
|
|
}
|
|
|
up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
dqput_all(put);
|
|
|
- return 0;
|
|
|
}
|
|
|
-EXPORT_SYMBOL(dquot_drop);
|
|
|
|
|
|
-/* Wrapper to remove references to quota structures from inode */
|
|
|
-void vfs_dq_drop(struct inode *inode)
|
|
|
-{
|
|
|
- /* Here we can get arbitrary inode from clear_inode() so we have
|
|
|
- * to be careful. OTOH we don't need locking as quota operations
|
|
|
- * are allowed to change only at mount time */
|
|
|
- if (!IS_NOQUOTA(inode) && inode->i_sb && inode->i_sb->dq_op
|
|
|
- && inode->i_sb->dq_op->drop) {
|
|
|
- int cnt;
|
|
|
- /* Test before calling to rule out calls from proc and such
|
|
|
- * where we are not allowed to block. Note that this is
|
|
|
- * actually reliable test even without the lock - the caller
|
|
|
- * must assure that nobody can come after the DQUOT_DROP and
|
|
|
- * add quota pointers back anyway */
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
- if (inode->i_dquot[cnt])
|
|
|
- break;
|
|
|
- if (cnt < MAXQUOTAS)
|
|
|
- inode->i_sb->dq_op->drop(inode);
|
|
|
- }
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(vfs_dq_drop);
|
|
|
+void dquot_drop(struct inode *inode)
|
|
|
+{
|
|
|
+ int cnt;
|
|
|
+
|
|
|
+ if (IS_NOQUOTA(inode))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Test before calling to rule out calls from proc and such
|
|
|
+ * where we are not allowed to block. Note that this is
|
|
|
+ * actually reliable test even without the lock - the caller
|
|
|
+ * must assure that nobody can come after the DQUOT_DROP and
|
|
|
+ * add quota pointers back anyway.
|
|
|
+ */
|
|
|
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
+ if (inode->i_dquot[cnt])
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cnt < MAXQUOTAS)
|
|
|
+ __dquot_drop(inode);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(dquot_drop);
|
|
|
|
|
|
/*
|
|
|
* inode_reserved_space is managed internally by quota, and protected by
|
|
@@ -1351,28 +1417,30 @@ static qsize_t *inode_reserved_space(struct inode * inode)
|
|
|
return inode->i_sb->dq_op->get_reserved_space(inode);
|
|
|
}
|
|
|
|
|
|
-static void inode_add_rsv_space(struct inode *inode, qsize_t number)
|
|
|
+void inode_add_rsv_space(struct inode *inode, qsize_t number)
|
|
|
{
|
|
|
spin_lock(&inode->i_lock);
|
|
|
*inode_reserved_space(inode) += number;
|
|
|
spin_unlock(&inode->i_lock);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(inode_add_rsv_space);
|
|
|
|
|
|
-
|
|
|
-static void inode_claim_rsv_space(struct inode *inode, qsize_t number)
|
|
|
+void inode_claim_rsv_space(struct inode *inode, qsize_t number)
|
|
|
{
|
|
|
spin_lock(&inode->i_lock);
|
|
|
*inode_reserved_space(inode) -= number;
|
|
|
__inode_add_bytes(inode, number);
|
|
|
spin_unlock(&inode->i_lock);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(inode_claim_rsv_space);
|
|
|
|
|
|
-static void inode_sub_rsv_space(struct inode *inode, qsize_t number)
|
|
|
+void inode_sub_rsv_space(struct inode *inode, qsize_t number)
|
|
|
{
|
|
|
spin_lock(&inode->i_lock);
|
|
|
*inode_reserved_space(inode) -= number;
|
|
|
spin_unlock(&inode->i_lock);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(inode_sub_rsv_space);
|
|
|
|
|
|
static qsize_t inode_get_rsv_space(struct inode *inode)
|
|
|
{
|
|
@@ -1404,38 +1472,34 @@ static void inode_decr_space(struct inode *inode, qsize_t number, int reserve)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Following four functions update i_blocks+i_bytes fields and
|
|
|
- * quota information (together with appropriate checks)
|
|
|
- * NOTE: We absolutely rely on the fact that caller dirties
|
|
|
- * the inode (usually macros in quotaops.h care about this) and
|
|
|
- * holds a handle for the current transaction so that dquot write and
|
|
|
- * inode write go into the same transaction.
|
|
|
+ * This functions updates i_blocks+i_bytes fields and quota information
|
|
|
+ * (together with appropriate checks).
|
|
|
+ *
|
|
|
+ * NOTE: We absolutely rely on the fact that caller dirties the inode
|
|
|
+ * (usually helpers in quotaops.h care about this) and holds a handle for
|
|
|
+ * the current transaction so that dquot write and inode write go into the
|
|
|
+ * same transaction.
|
|
|
*/
|
|
|
|
|
|
/*
|
|
|
* This operation can block, but only after everything is updated
|
|
|
*/
|
|
|
int __dquot_alloc_space(struct inode *inode, qsize_t number,
|
|
|
- int warn, int reserve)
|
|
|
+ int warn, int reserve)
|
|
|
{
|
|
|
- int cnt, ret = QUOTA_OK;
|
|
|
+ int cnt, ret = 0;
|
|
|
char warntype[MAXQUOTAS];
|
|
|
|
|
|
/*
|
|
|
* First test before acquiring mutex - solves deadlocks when we
|
|
|
* re-enter the quota code and are already holding the mutex
|
|
|
*/
|
|
|
- if (IS_NOQUOTA(inode)) {
|
|
|
+ if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
|
|
|
inode_incr_space(inode, number, reserve);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- if (IS_NOQUOTA(inode)) {
|
|
|
- inode_incr_space(inode, number, reserve);
|
|
|
- goto out_unlock;
|
|
|
- }
|
|
|
-
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
warntype[cnt] = QUOTA_NL_NOWARN;
|
|
|
|
|
@@ -1443,9 +1507,9 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number,
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
if (!inode->i_dquot[cnt])
|
|
|
continue;
|
|
|
- if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt)
|
|
|
- == NO_QUOTA) {
|
|
|
- ret = NO_QUOTA;
|
|
|
+ ret = check_bdq(inode->i_dquot[cnt], number, !warn,
|
|
|
+ warntype+cnt);
|
|
|
+ if (ret) {
|
|
|
spin_unlock(&dq_data_lock);
|
|
|
goto out_flush_warn;
|
|
|
}
|
|
@@ -1466,61 +1530,45 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number,
|
|
|
mark_all_dquot_dirty(inode->i_dquot);
|
|
|
out_flush_warn:
|
|
|
flush_warnings(inode->i_dquot, warntype);
|
|
|
-out_unlock:
|
|
|
up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
out:
|
|
|
return ret;
|
|
|
}
|
|
|
-
|
|
|
-int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
|
|
|
-{
|
|
|
- return __dquot_alloc_space(inode, number, warn, 0);
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(dquot_alloc_space);
|
|
|
-
|
|
|
-int dquot_reserve_space(struct inode *inode, qsize_t number, int warn)
|
|
|
-{
|
|
|
- return __dquot_alloc_space(inode, number, warn, 1);
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(dquot_reserve_space);
|
|
|
+EXPORT_SYMBOL(__dquot_alloc_space);
|
|
|
|
|
|
/*
|
|
|
* This operation can block, but only after everything is updated
|
|
|
*/
|
|
|
-int dquot_alloc_inode(const struct inode *inode, qsize_t number)
|
|
|
+int dquot_alloc_inode(const struct inode *inode)
|
|
|
{
|
|
|
- int cnt, ret = NO_QUOTA;
|
|
|
+ int cnt, ret = 0;
|
|
|
char warntype[MAXQUOTAS];
|
|
|
|
|
|
/* First test before acquiring mutex - solves deadlocks when we
|
|
|
* re-enter the quota code and are already holding the mutex */
|
|
|
- if (IS_NOQUOTA(inode))
|
|
|
- return QUOTA_OK;
|
|
|
+ if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
|
|
|
+ return 0;
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
warntype[cnt] = QUOTA_NL_NOWARN;
|
|
|
down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- if (IS_NOQUOTA(inode)) {
|
|
|
- up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- return QUOTA_OK;
|
|
|
- }
|
|
|
spin_lock(&dq_data_lock);
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
if (!inode->i_dquot[cnt])
|
|
|
continue;
|
|
|
- if (check_idq(inode->i_dquot[cnt], number, warntype+cnt)
|
|
|
- == NO_QUOTA)
|
|
|
+ ret = check_idq(inode->i_dquot[cnt], 1, warntype + cnt);
|
|
|
+ if (ret)
|
|
|
goto warn_put_all;
|
|
|
}
|
|
|
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
if (!inode->i_dquot[cnt])
|
|
|
continue;
|
|
|
- dquot_incr_inodes(inode->i_dquot[cnt], number);
|
|
|
+ dquot_incr_inodes(inode->i_dquot[cnt], 1);
|
|
|
}
|
|
|
- ret = QUOTA_OK;
|
|
|
+
|
|
|
warn_put_all:
|
|
|
spin_unlock(&dq_data_lock);
|
|
|
- if (ret == QUOTA_OK)
|
|
|
+ if (ret == 0)
|
|
|
mark_all_dquot_dirty(inode->i_dquot);
|
|
|
flush_warnings(inode->i_dquot, warntype);
|
|
|
up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
@@ -1528,23 +1576,19 @@ warn_put_all:
|
|
|
}
|
|
|
EXPORT_SYMBOL(dquot_alloc_inode);
|
|
|
|
|
|
-int dquot_claim_space(struct inode *inode, qsize_t number)
|
|
|
+/*
|
|
|
+ * Convert in-memory reserved quotas to real consumed quotas
|
|
|
+ */
|
|
|
+int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
|
|
|
{
|
|
|
int cnt;
|
|
|
- int ret = QUOTA_OK;
|
|
|
|
|
|
- if (IS_NOQUOTA(inode)) {
|
|
|
+ if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
|
|
|
inode_claim_rsv_space(inode, number);
|
|
|
- goto out;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- if (IS_NOQUOTA(inode)) {
|
|
|
- up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- inode_claim_rsv_space(inode, number);
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
spin_lock(&dq_data_lock);
|
|
|
/* Claim reserved quotas to allocated quotas */
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
@@ -1557,33 +1601,26 @@ int dquot_claim_space(struct inode *inode, qsize_t number)
|
|
|
spin_unlock(&dq_data_lock);
|
|
|
mark_all_dquot_dirty(inode->i_dquot);
|
|
|
up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
-out:
|
|
|
- return ret;
|
|
|
+ return 0;
|
|
|
}
|
|
|
-EXPORT_SYMBOL(dquot_claim_space);
|
|
|
+EXPORT_SYMBOL(dquot_claim_space_nodirty);
|
|
|
|
|
|
/*
|
|
|
* This operation can block, but only after everything is updated
|
|
|
*/
|
|
|
-int __dquot_free_space(struct inode *inode, qsize_t number, int reserve)
|
|
|
+void __dquot_free_space(struct inode *inode, qsize_t number, int reserve)
|
|
|
{
|
|
|
unsigned int cnt;
|
|
|
char warntype[MAXQUOTAS];
|
|
|
|
|
|
/* First test before acquiring mutex - solves deadlocks when we
|
|
|
* re-enter the quota code and are already holding the mutex */
|
|
|
- if (IS_NOQUOTA(inode)) {
|
|
|
-out_sub:
|
|
|
+ if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
|
|
|
inode_decr_space(inode, number, reserve);
|
|
|
- return QUOTA_OK;
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- /* Now recheck reliably when holding dqptr_sem */
|
|
|
- if (IS_NOQUOTA(inode)) {
|
|
|
- up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- goto out_sub;
|
|
|
- }
|
|
|
spin_lock(&dq_data_lock);
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
if (!inode->i_dquot[cnt])
|
|
@@ -1603,56 +1640,34 @@ out_sub:
|
|
|
out_unlock:
|
|
|
flush_warnings(inode->i_dquot, warntype);
|
|
|
up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- return QUOTA_OK;
|
|
|
-}
|
|
|
-
|
|
|
-int dquot_free_space(struct inode *inode, qsize_t number)
|
|
|
-{
|
|
|
- return __dquot_free_space(inode, number, 0);
|
|
|
}
|
|
|
-EXPORT_SYMBOL(dquot_free_space);
|
|
|
-
|
|
|
-/*
|
|
|
- * Release reserved quota space
|
|
|
- */
|
|
|
-void dquot_release_reserved_space(struct inode *inode, qsize_t number)
|
|
|
-{
|
|
|
- __dquot_free_space(inode, number, 1);
|
|
|
-
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(dquot_release_reserved_space);
|
|
|
+EXPORT_SYMBOL(__dquot_free_space);
|
|
|
|
|
|
/*
|
|
|
* This operation can block, but only after everything is updated
|
|
|
*/
|
|
|
-int dquot_free_inode(const struct inode *inode, qsize_t number)
|
|
|
+void dquot_free_inode(const struct inode *inode)
|
|
|
{
|
|
|
unsigned int cnt;
|
|
|
char warntype[MAXQUOTAS];
|
|
|
|
|
|
/* First test before acquiring mutex - solves deadlocks when we
|
|
|
* re-enter the quota code and are already holding the mutex */
|
|
|
- if (IS_NOQUOTA(inode))
|
|
|
- return QUOTA_OK;
|
|
|
+ if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
|
|
|
+ return;
|
|
|
|
|
|
down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- /* Now recheck reliably when holding dqptr_sem */
|
|
|
- if (IS_NOQUOTA(inode)) {
|
|
|
- up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- return QUOTA_OK;
|
|
|
- }
|
|
|
spin_lock(&dq_data_lock);
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
if (!inode->i_dquot[cnt])
|
|
|
continue;
|
|
|
- warntype[cnt] = info_idq_free(inode->i_dquot[cnt], number);
|
|
|
- dquot_decr_inodes(inode->i_dquot[cnt], number);
|
|
|
+ warntype[cnt] = info_idq_free(inode->i_dquot[cnt], 1);
|
|
|
+ dquot_decr_inodes(inode->i_dquot[cnt], 1);
|
|
|
}
|
|
|
spin_unlock(&dq_data_lock);
|
|
|
mark_all_dquot_dirty(inode->i_dquot);
|
|
|
flush_warnings(inode->i_dquot, warntype);
|
|
|
up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- return QUOTA_OK;
|
|
|
}
|
|
|
EXPORT_SYMBOL(dquot_free_inode);
|
|
|
|
|
@@ -1662,37 +1677,31 @@ EXPORT_SYMBOL(dquot_free_inode);
|
|
|
* This operation can block, but only after everything is updated
|
|
|
* A transaction must be started when entering this function.
|
|
|
*/
|
|
|
-int dquot_transfer(struct inode *inode, struct iattr *iattr)
|
|
|
+static int __dquot_transfer(struct inode *inode, qid_t *chid, unsigned long mask)
|
|
|
{
|
|
|
qsize_t space, cur_space;
|
|
|
qsize_t rsv_space = 0;
|
|
|
struct dquot *transfer_from[MAXQUOTAS];
|
|
|
struct dquot *transfer_to[MAXQUOTAS];
|
|
|
- int cnt, ret = QUOTA_OK;
|
|
|
- int chuid = iattr->ia_valid & ATTR_UID && inode->i_uid != iattr->ia_uid,
|
|
|
- chgid = iattr->ia_valid & ATTR_GID && inode->i_gid != iattr->ia_gid;
|
|
|
+ int cnt, ret = 0;
|
|
|
char warntype_to[MAXQUOTAS];
|
|
|
char warntype_from_inodes[MAXQUOTAS], warntype_from_space[MAXQUOTAS];
|
|
|
|
|
|
/* First test before acquiring mutex - solves deadlocks when we
|
|
|
* re-enter the quota code and are already holding the mutex */
|
|
|
if (IS_NOQUOTA(inode))
|
|
|
- return QUOTA_OK;
|
|
|
+ return 0;
|
|
|
/* Initialize the arrays */
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
transfer_from[cnt] = NULL;
|
|
|
transfer_to[cnt] = NULL;
|
|
|
warntype_to[cnt] = QUOTA_NL_NOWARN;
|
|
|
}
|
|
|
- if (chuid)
|
|
|
- transfer_to[USRQUOTA] = dqget(inode->i_sb, iattr->ia_uid,
|
|
|
- USRQUOTA);
|
|
|
- if (chgid)
|
|
|
- transfer_to[GRPQUOTA] = dqget(inode->i_sb, iattr->ia_gid,
|
|
|
- GRPQUOTA);
|
|
|
-
|
|
|
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
+ if (mask & (1 << cnt))
|
|
|
+ transfer_to[cnt] = dqget(inode->i_sb, chid[cnt], cnt);
|
|
|
+ }
|
|
|
down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- /* Now recheck reliably when holding dqptr_sem */
|
|
|
if (IS_NOQUOTA(inode)) { /* File without quota accounting? */
|
|
|
up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
goto put_all;
|
|
@@ -1706,9 +1715,11 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
|
|
|
if (!transfer_to[cnt])
|
|
|
continue;
|
|
|
transfer_from[cnt] = inode->i_dquot[cnt];
|
|
|
- if (check_idq(transfer_to[cnt], 1, warntype_to + cnt) ==
|
|
|
- NO_QUOTA || check_bdq(transfer_to[cnt], space, 0,
|
|
|
- warntype_to + cnt) == NO_QUOTA)
|
|
|
+ ret = check_idq(transfer_to[cnt], 1, warntype_to + cnt);
|
|
|
+ if (ret)
|
|
|
+ goto over_quota;
|
|
|
+ ret = check_bdq(transfer_to[cnt], space, 0, warntype_to + cnt);
|
|
|
+ if (ret)
|
|
|
goto over_quota;
|
|
|
}
|
|
|
|
|
@@ -1762,22 +1773,32 @@ over_quota:
|
|
|
/* Clear dquot pointers we don't want to dqput() */
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
transfer_from[cnt] = NULL;
|
|
|
- ret = NO_QUOTA;
|
|
|
goto warn_put_all;
|
|
|
}
|
|
|
-EXPORT_SYMBOL(dquot_transfer);
|
|
|
|
|
|
-/* Wrapper for transferring ownership of an inode */
|
|
|
-int vfs_dq_transfer(struct inode *inode, struct iattr *iattr)
|
|
|
+/* Wrapper for transferring ownership of an inode for uid/gid only
|
|
|
+ * Called from FSXXX_setattr()
|
|
|
+ */
|
|
|
+int dquot_transfer(struct inode *inode, struct iattr *iattr)
|
|
|
{
|
|
|
+ qid_t chid[MAXQUOTAS];
|
|
|
+ unsigned long mask = 0;
|
|
|
+
|
|
|
+ if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) {
|
|
|
+ mask |= 1 << USRQUOTA;
|
|
|
+ chid[USRQUOTA] = iattr->ia_uid;
|
|
|
+ }
|
|
|
+ if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) {
|
|
|
+ mask |= 1 << GRPQUOTA;
|
|
|
+ chid[GRPQUOTA] = iattr->ia_gid;
|
|
|
+ }
|
|
|
if (sb_any_quota_active(inode->i_sb) && !IS_NOQUOTA(inode)) {
|
|
|
- vfs_dq_init(inode);
|
|
|
- if (inode->i_sb->dq_op->transfer(inode, iattr) == NO_QUOTA)
|
|
|
- return 1;
|
|
|
+ dquot_initialize(inode);
|
|
|
+ return __dquot_transfer(inode, chid, mask);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
-EXPORT_SYMBOL(vfs_dq_transfer);
|
|
|
+EXPORT_SYMBOL(dquot_transfer);
|
|
|
|
|
|
/*
|
|
|
* Write info of quota file to disk
|
|
@@ -1798,13 +1819,6 @@ EXPORT_SYMBOL(dquot_commit_info);
|
|
|
* Definitions of diskquota operations.
|
|
|
*/
|
|
|
const struct dquot_operations dquot_operations = {
|
|
|
- .initialize = dquot_initialize,
|
|
|
- .drop = dquot_drop,
|
|
|
- .alloc_space = dquot_alloc_space,
|
|
|
- .alloc_inode = dquot_alloc_inode,
|
|
|
- .free_space = dquot_free_space,
|
|
|
- .free_inode = dquot_free_inode,
|
|
|
- .transfer = dquot_transfer,
|
|
|
.write_dquot = dquot_commit,
|
|
|
.acquire_dquot = dquot_acquire,
|
|
|
.release_dquot = dquot_release,
|
|
@@ -1814,6 +1828,20 @@ const struct dquot_operations dquot_operations = {
|
|
|
.destroy_dquot = dquot_destroy,
|
|
|
};
|
|
|
|
|
|
+/*
|
|
|
+ * Generic helper for ->open on filesystems supporting disk quotas.
|
|
|
+ */
|
|
|
+int dquot_file_open(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ int error;
|
|
|
+
|
|
|
+ error = generic_file_open(inode, file);
|
|
|
+ if (!error && (file->f_mode & FMODE_WRITE))
|
|
|
+ dquot_initialize(inode);
|
|
|
+ return error;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(dquot_file_open);
|
|
|
+
|
|
|
/*
|
|
|
* Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
|
|
|
*/
|
|
@@ -1993,11 +2021,13 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
|
|
|
}
|
|
|
|
|
|
if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
|
|
|
- /* As we bypass the pagecache we must now flush the inode so
|
|
|
- * that we see all the changes from userspace... */
|
|
|
- write_inode_now(inode, 1);
|
|
|
- /* And now flush the block cache so that kernel sees the
|
|
|
- * changes */
|
|
|
+ /* As we bypass the pagecache we must now flush all the
|
|
|
+ * dirty data and invalidate caches so that kernel sees
|
|
|
+ * changes from userspace. It is not enough to just flush
|
|
|
+ * the quota file since if blocksize < pagesize, invalidation
|
|
|
+ * of the cache could fail because of other unrelated dirty
|
|
|
+ * data */
|
|
|
+ sync_filesystem(sb);
|
|
|
invalidate_bdev(sb->s_bdev);
|
|
|
}
|
|
|
mutex_lock(&dqopt->dqonoff_mutex);
|
|
@@ -2010,14 +2040,16 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
|
|
|
/* We don't want quota and atime on quota files (deadlocks
|
|
|
* possible) Also nobody should write to the file - we use
|
|
|
* special IO operations which ignore the immutable bit. */
|
|
|
- down_write(&dqopt->dqptr_sem);
|
|
|
mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
|
|
|
oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE |
|
|
|
S_NOQUOTA);
|
|
|
inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE;
|
|
|
mutex_unlock(&inode->i_mutex);
|
|
|
- up_write(&dqopt->dqptr_sem);
|
|
|
- sb->dq_op->drop(inode);
|
|
|
+ /*
|
|
|
+ * When S_NOQUOTA is set, remove dquot references as no more
|
|
|
+ * references can be added
|
|
|
+ */
|
|
|
+ __dquot_drop(inode);
|
|
|
}
|
|
|
|
|
|
error = -EIO;
|
|
@@ -2053,14 +2085,12 @@ out_file_init:
|
|
|
iput(inode);
|
|
|
out_lock:
|
|
|
if (oldflags != -1) {
|
|
|
- down_write(&dqopt->dqptr_sem);
|
|
|
mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
|
|
|
/* Set the flags back (in the case of accidental quotaon()
|
|
|
* on a wrong file we don't want to mess up the flags) */
|
|
|
inode->i_flags &= ~(S_NOATIME | S_NOQUOTA | S_IMMUTABLE);
|
|
|
inode->i_flags |= oldflags;
|
|
|
mutex_unlock(&inode->i_mutex);
|
|
|
- up_write(&dqopt->dqptr_sem);
|
|
|
}
|
|
|
mutex_unlock(&dqopt->dqonoff_mutex);
|
|
|
out_fmt:
|