quota: move code from sync_quota_sb into vfs_quota_sync
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 <hch@lst.de> Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
Родитель
8c4e4acd66
Коммит
5fb324ad24
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
"ad_timeo, &tune->gt_quota_quantum);
|
||||
|
||||
/* Check for & recover partially truncated inodes */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -570,7 +570,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;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
@ -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++) {
|
||||
|
@ -119,7 +84,7 @@ restart:
|
|||
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))
|
||||
|
@ -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:
|
||||
|
|
14
fs/sync.c
14
fs/sync.c
|
@ -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);
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче