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) ...@@ -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 list_head *head;
struct dquot *dquot; struct dquot *dquot;
struct quota_info *dqopt = sb_dqopt(sb);
int cnt;
lock_kernel();
restart: restart:
list_for_each(head, &inuse_list) { list_for_each(head, &inuse_list) {
dquot = list_entry(head, struct dquot, dq_inuse); dquot = list_entry(head, struct dquot, dq_inuse);
...@@ -396,12 +397,64 @@ int sync_dquots(struct super_block *sb, int type) ...@@ -396,12 +397,64 @@ int sync_dquots(struct super_block *sb, int type)
dqput(dquot); dqput(dquot);
goto restart; 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++; dqstats.syncs++;
unlock_kernel();
return 0; 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 */ /* Free unused dquots from cache */
static void prune_dqcache(int count) static void prune_dqcache(int count)
{ {
...@@ -1291,11 +1344,6 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) ...@@ -1291,11 +1344,6 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
return error; 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 */ /* Generic routine for getting common part of quota structure */
static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di) static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di)
{ {
......
...@@ -617,18 +617,6 @@ struct nameidata { ...@@ -617,18 +617,6 @@ struct nameidata {
struct vfsmount *old_mnt; 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 * Umount options
*/ */
......
...@@ -170,6 +170,7 @@ struct mem_dqinfo { ...@@ -170,6 +170,7 @@ struct mem_dqinfo {
#define DQF_MASK 0xffff /* Mask for format specific flags */ #define DQF_MASK 0xffff /* Mask for format specific flags */
#define DQF_INFO_DIRTY 0x10000 /* Is info dirty? */ #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) extern inline void mark_info_dirty(struct mem_dqinfo *info)
{ {
...@@ -178,6 +179,9 @@ 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_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) #define sb_dqopt(sb) (&(sb)->s_dquot)
extern int nr_dquots, nr_free_dquots; extern int nr_dquots, nr_free_dquots;
...@@ -224,13 +228,6 @@ struct dquot { ...@@ -224,13 +228,6 @@ struct dquot {
struct mem_dqblk dq_dqb; /* Diskquota usage */ 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 NODQUOT (struct dquot *)NULL
#define QUOTA_OK 0 #define QUOTA_OK 0
...@@ -279,6 +276,26 @@ struct quota_format_type { ...@@ -279,6 +276,26 @@ struct quota_format_type {
struct quota_format_type *qf_next; 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) static inline int is_enabled(struct quota_info *dqopt, int type)
{ {
switch (type) { switch (type) {
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
/* /*
* declaration of quota_function calls in kernel. * 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_initialize(struct inode *inode, int type);
extern void dquot_drop(struct inode *inode); 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