Commit 736e690e authored by Jan Kara's avatar Jan Kara Committed by Linus Torvalds

[PATCH] [11/13] quota-11-sync

Implemented proper syncing of dquots - ie. also global information
about quota files are synced. We find info to sync by walking through
all superblocks...
parent 0c532315
......@@ -368,12 +368,13 @@ static void invalidate_dquots(struct super_block *sb, int type)
}
}
int sync_dquots(struct super_block *sb, int type)
static int vfs_quota_sync(struct super_block *sb, int type)
{
struct list_head *head;
struct dquot *dquot;
struct quota_info *dqopt = sb_dqopt(sb);
int cnt;
lock_kernel();
restart:
list_for_each(head, &inuse_list) {
dquot = list_entry(head, struct dquot, dq_inuse);
......@@ -396,12 +397,64 @@ int sync_dquots(struct super_block *sb, int type)
dqput(dquot);
goto restart;
}
/* FIXME: Here we should also sync all file info */
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt))
dqopt->info[cnt].dqi_flags &= ~DQF_ANY_DQUOT_DIRTY;
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt]))
dqopt->ops[cnt]->write_file_info(sb, cnt);
dqstats.syncs++;
unlock_kernel();
return 0;
}
static struct super_block *get_super_to_sync(int type)
{
struct list_head *head;
int cnt, dirty;
restart:
spin_lock(&sb_lock);
list_for_each(head, &super_blocks) {
struct super_block *sb = list_entry(head, struct super_block, s_list);
for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++)
if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt)
&& sb_dqopt(sb)->info[cnt].dqi_flags & DQF_ANY_DQUOT_DIRTY)
dirty = 1;
if (!dirty)
continue;
sb->s_count++;
spin_unlock(&sb_lock);
down_read(&sb->s_umount);
if (!sb->s_root) {
drop_super(sb);
goto restart;
}
return sb;
}
spin_unlock(&sb_lock);
return NULL;
}
void sync_dquots(struct super_block *sb, int type)
{
if (sb) {
lock_kernel();
if (sb->s_qcop->quota_sync)
sb->s_qcop->quota_sync(sb, type);
unlock_kernel();
}
else {
while ((sb = get_super_to_sync(type))) {
lock_kernel();
if (sb->s_qcop->quota_sync)
sb->s_qcop->quota_sync(sb, type);
unlock_kernel();
drop_super(sb);
}
}
}
/* Free unused dquots from cache */
static void prune_dqcache(int count)
{
......@@ -1212,7 +1265,7 @@ int vfs_quota_off(struct super_block *sb, int type)
/* Note: these are blocking operations */
remove_dquot_ref(sb, cnt);
invalidate_dquots(sb, cnt);
if (info_dirty(&dqopt->info[cnt]))
if (info_dirty(&dqopt->info[cnt]))
dqopt->ops[cnt]->write_file_info(sb, cnt);
if (dqopt->ops[cnt]->free_file_info)
dqopt->ops[cnt]->free_file_info(sb, cnt);
......@@ -1291,11 +1344,6 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
return error;
}
int vfs_quota_sync(struct super_block *sb, int type)
{
return sync_dquots(sb, type);
}
/* Generic routine for getting common part of quota structure */
static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di)
{
......
......@@ -617,18 +617,6 @@ struct nameidata {
struct vfsmount *old_mnt;
};
#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */
#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */
struct quota_info {
unsigned int flags; /* Flags for diskquotas on this device */
struct semaphore dqio_sem; /* lock device while I/O in progress */
struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */
struct file *files[MAXQUOTAS]; /* fp's to quotafiles */
struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */
struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */
};
/*
* Umount options
*/
......
......@@ -170,6 +170,7 @@ struct mem_dqinfo {
#define DQF_MASK 0xffff /* Mask for format specific flags */
#define DQF_INFO_DIRTY 0x10000 /* Is info dirty? */
#define DQF_ANY_DQUOT_DIRTY 0x20000 /* Is any dquot dirty? */
extern inline void mark_info_dirty(struct mem_dqinfo *info)
{
......@@ -178,6 +179,9 @@ extern inline void mark_info_dirty(struct mem_dqinfo *info)
#define info_dirty(info) ((info)->dqi_flags & DQF_INFO_DIRTY)
#define info_any_dirty(info) ((info)->dqi_flags & DQF_INFO_DIRTY ||\
(info)->dqi_flags & DQF_ANY_DQUOT_DIRTY)
#define sb_dqopt(sb) (&(sb)->s_dquot)
extern int nr_dquots, nr_free_dquots;
......@@ -224,13 +228,6 @@ struct dquot {
struct mem_dqblk dq_dqb; /* Diskquota usage */
};
extern inline void mark_dquot_dirty(struct dquot *dquot)
{
dquot->dq_flags |= DQ_MOD;
}
#define dquot_dirty(dquot) ((dquot)->dq_flags & DQ_MOD)
#define NODQUOT (struct dquot *)NULL
#define QUOTA_OK 0
......@@ -279,6 +276,26 @@ struct quota_format_type {
struct quota_format_type *qf_next;
};
#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */
#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */
struct quota_info {
unsigned int flags; /* Flags for diskquotas on this device */
struct semaphore dqio_sem; /* lock device while I/O in progress */
struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */
struct file *files[MAXQUOTAS]; /* fp's to quotafiles */
struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */
struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */
};
/* Inline would be better but we need to dereference super_block which is not defined yet */
#define mark_dquot_dirty(dquot) do {\
dquot->dq_flags |= DQ_MOD;\
sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_flags |= DQF_ANY_DQUOT_DIRTY;\
} while (0)
#define dquot_dirty(dquot) ((dquot)->dq_flags & DQ_MOD)
static inline int is_enabled(struct quota_info *dqopt, int type)
{
switch (type) {
......
......@@ -20,7 +20,7 @@
/*
* declaration of quota_function calls in kernel.
*/
extern int sync_dquots(kdev_t dev, int type);
extern void sync_dquots(struct super_block *sb, int type);
extern void dquot_initialize(struct inode *inode, int type);
extern void dquot_drop(struct inode *inode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment