Skip to content

Commit

Permalink
quota: move code from sync_quota_sb into vfs_quota_sync
Browse files Browse the repository at this point in the history
Currenly sync_quota_sb does a lot of sync and truncate action that only
applies to "VFS" style quotas and is actively harmful for the sync
performance in XFS.  Move it into vfs_quota_sync and add a wait parameter
to ->quota_sync to tell if we need it or not.

My audit of the GFS2 code says it's also not needed given the way GFS2
implements quotas, but I'd be happy if this can get a detailed review.

Signed-off-by: Christoph Hellwig <[email protected]>
Signed-off-by: Jan Kara <[email protected]>
  • Loading branch information
Christoph Hellwig authored and jankara committed Mar 4, 2010
1 parent 8c4e4ac commit 5fb324a
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 71 deletions.
9 changes: 7 additions & 2 deletions fs/gfs2/quota.c
Original file line number Diff line number Diff line change
Expand Up @@ -1083,7 +1083,7 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
}
}

int gfs2_quota_sync(struct super_block *sb, int type)
int gfs2_quota_sync(struct super_block *sb, int type, int wait)
{
struct gfs2_sbd *sdp = sb->s_fs_info;
struct gfs2_quota_data **qda;
Expand Down Expand Up @@ -1127,6 +1127,11 @@ int gfs2_quota_sync(struct super_block *sb, int type)
return error;
}

static int gfs2_quota_sync_timeo(struct super_block *sb, int type)
{
return gfs2_quota_sync(sb, type, 0);
}

int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id)
{
struct gfs2_quota_data *qd;
Expand Down Expand Up @@ -1382,7 +1387,7 @@ int gfs2_quotad(void *data)
&tune->gt_statfs_quantum);

/* Update quota file */
quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t,
quotad_check_timeo(sdp, "sync", gfs2_quota_sync_timeo, t,
&quotad_timeo, &tune->gt_quota_quantum);

/* Check for & recover partially truncated inodes */
Expand Down
2 changes: 1 addition & 1 deletion fs/gfs2/quota.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extern int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid);
extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
u32 uid, u32 gid);

extern int gfs2_quota_sync(struct super_block *sb, int type);
extern int gfs2_quota_sync(struct super_block *sb, int type, int wait);
extern int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id);

extern int gfs2_quota_init(struct gfs2_sbd *sdp);
Expand Down
2 changes: 1 addition & 1 deletion fs/gfs2/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
int error;

flush_workqueue(gfs2_delete_workqueue);
gfs2_quota_sync(sdp->sd_vfs, 0);
gfs2_quota_sync(sdp->sd_vfs, 0, 1);
gfs2_statfs_sync(sdp->sd_vfs, 0);

error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE,
Expand Down
2 changes: 1 addition & 1 deletion fs/gfs2/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf,
if (simple_strtol(buf, NULL, 0) != 1)
return -EINVAL;

gfs2_quota_sync(sdp->sd_vfs, 0);
gfs2_quota_sync(sdp->sd_vfs, 0, 1);
return len;
}

Expand Down
29 changes: 28 additions & 1 deletion fs/quota/dquot.c
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ int dquot_scan_active(struct super_block *sb,
}
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;
Expand Down Expand Up @@ -615,6 +615,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);
Expand Down
46 changes: 5 additions & 41 deletions fs/quota/quota.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,44 +48,6 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
return security_quotactl(cmd, type, id, sb);
}

#ifdef CONFIG_QUOTA
void sync_quota_sb(struct super_block *sb, int type)
{
int cnt;

if (!sb->s_qcop || !sb->s_qcop->quota_sync)
return;

sb->s_qcop->quota_sync(sb, type);

if (sb_dqopt(sb)->flags & DQUOT_QUOTA_SYS_FILE)
return;
/* 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);
}
#endif

static int quota_sync_all(int type)
{
struct super_block *sb;
Expand All @@ -101,6 +63,9 @@ static int quota_sync_all(int type)
spin_lock(&sb_lock);
restart:
list_for_each_entry(sb, &super_blocks, s_list) {
if (!sb->s_qcop || !sb->s_qcop->quota_sync)
continue;

/* This test just improves performance so it needn't be
* reliable... */
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
Expand All @@ -119,7 +84,7 @@ static int quota_sync_all(int type)
spin_unlock(&sb_lock);
down_read(&sb->s_umount);
if (sb->s_root)
sync_quota_sb(sb, type);
sb->s_qcop->quota_sync(sb, type, 1);
up_read(&sb->s_umount);
spin_lock(&sb_lock);
if (__put_super_and_need_restart(sb))
Expand Down Expand Up @@ -306,8 +271,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
case Q_SYNC:
if (!sb->s_qcop->quota_sync)
return -ENOSYS;
sync_quota_sb(sb, type);
return 0;
return sb->s_qcop->quota_sync(sb, type, 1);
case Q_XQUOTAON:
case Q_XQUOTAOFF:
case Q_XQUOTARM:
Expand Down
14 changes: 7 additions & 7 deletions fs/sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ static int __sync_filesystem(struct super_block *sb, int wait)
if (!sb->s_bdi)
return 0;

/* Avoid doing twice syncing and cache pruning for quota sync */
if (!wait) {
writeout_quota_sb(sb, -1);
writeback_inodes_sb(sb);
} else {
sync_quota_sb(sb, -1);
if (sb->s_qcop && sb->s_qcop->quota_sync)
sb->s_qcop->quota_sync(sb, -1, wait);

if (wait)
sync_inodes_sb(sb);
}
else
writeback_inodes_sb(sb);

if (sb->s_op->sync_fs)
sb->s_op->sync_fs(sb, wait);
return __sync_blockdev(sb->s_bdev, wait);
Expand Down
2 changes: 1 addition & 1 deletion include/linux/quota.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ struct dquot_operations {
struct quotactl_ops {
int (*quota_on)(struct super_block *, int, int, char *, int);
int (*quota_off)(struct super_block *, int, int);
int (*quota_sync)(struct super_block *, int);
int (*quota_sync)(struct super_block *, int, int);
int (*get_info)(struct super_block *, int, struct if_dqinfo *);
int (*set_info)(struct super_block *, int, struct if_dqinfo *);
int (*get_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *);
Expand Down
17 changes: 1 addition & 16 deletions include/linux/quotaops.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@ static inline struct quota_info *sb_dqopt(struct super_block *sb)
/*
* declaration of quota_function calls in kernel.
*/
void sync_quota_sb(struct super_block *sb, int type);
static inline void writeout_quota_sb(struct super_block *sb, int type)
{
if (sb->s_qcop && sb->s_qcop->quota_sync)
sb->s_qcop->quota_sync(sb, type);
}

void inode_add_rsv_space(struct inode *inode, qsize_t number);
void inode_claim_rsv_space(struct inode *inode, qsize_t number);
void inode_sub_rsv_space(struct inode *inode, qsize_t number);
Expand Down Expand Up @@ -67,7 +60,7 @@ int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
int format_id, int type);
int vfs_quota_off(struct super_block *sb, int type, int remount);
int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags);
int vfs_quota_sync(struct super_block *sb, int type);
int vfs_quota_sync(struct super_block *sb, int type, int wait);
int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di);
Expand Down Expand Up @@ -340,14 +333,6 @@ static inline void vfs_dq_free_inode(struct inode *inode)
{
}

static inline void sync_quota_sb(struct super_block *sb, int type)
{
}

static inline void writeout_quota_sb(struct super_block *sb, int type)
{
}

static inline int vfs_dq_off(struct super_block *sb, int remount)
{
return 0;
Expand Down

0 comments on commit 5fb324a

Please sign in to comment.