Commit e69c0c55 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Quota fix 3 - quota file corruption

From: Jan Kara <jack@ucw.cz>

This patch fixes possible quota files corruption which could happen when root
did not have any inodes&space allocated.

Originally this could not happen as structure would not be written to disk in
that case but with journalled quota we need to write even all-zero structure. 
The fix is not very nice but change of the format on disk is probably worse (I
made a mistake with not including the usage-bitmaps into format :().
parent cfeff004
...@@ -1205,8 +1205,11 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) ...@@ -1205,8 +1205,11 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
if (transfer_to[cnt] == NODQUOT) if (transfer_to[cnt] == NODQUOT)
continue; continue;
dquot_decr_inodes(transfer_from[cnt], 1); /* Due to IO error we might not have transfer_from[] structure */
dquot_decr_space(transfer_from[cnt], space); if (transfer_from[cnt]) {
dquot_decr_inodes(transfer_from[cnt], 1);
dquot_decr_space(transfer_from[cnt], space);
}
dquot_incr_inodes(transfer_to[cnt], 1); dquot_incr_inodes(transfer_to[cnt], 1);
dquot_incr_space(transfer_to[cnt], space); dquot_incr_space(transfer_to[cnt], space);
......
...@@ -420,7 +420,7 @@ static int v2_write_dquot(struct dquot *dquot) ...@@ -420,7 +420,7 @@ static int v2_write_dquot(struct dquot *dquot)
mm_segment_t fs; mm_segment_t fs;
loff_t offset; loff_t offset;
ssize_t ret; ssize_t ret;
struct v2_disk_dqblk ddquot; struct v2_disk_dqblk ddquot, empty;
/* dq_off is guarded by dqio_sem */ /* dq_off is guarded by dqio_sem */
if (!dquot->dq_off) if (!dquot->dq_off)
...@@ -432,6 +432,12 @@ static int v2_write_dquot(struct dquot *dquot) ...@@ -432,6 +432,12 @@ static int v2_write_dquot(struct dquot *dquot)
offset = dquot->dq_off; offset = dquot->dq_off;
spin_lock(&dq_data_lock); spin_lock(&dq_data_lock);
mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id); mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
/* Argh... We may need to write structure full of zeroes but that would be
* treated as an empty place by the rest of the code. Format change would
* be definitely cleaner but the problems probably are not worth it */
memset(&empty, 0, sizeof(struct v2_disk_dqblk));
if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
ddquot.dqb_itime = cpu_to_le64(1);
spin_unlock(&dq_data_lock); spin_unlock(&dq_data_lock);
fs = get_fs(); fs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
...@@ -622,7 +628,7 @@ static int v2_read_dquot(struct dquot *dquot) ...@@ -622,7 +628,7 @@ static int v2_read_dquot(struct dquot *dquot)
struct file *filp; struct file *filp;
mm_segment_t fs; mm_segment_t fs;
loff_t offset; loff_t offset;
struct v2_disk_dqblk ddquot; struct v2_disk_dqblk ddquot, empty;
int ret = 0; int ret = 0;
filp = sb_dqopt(dquot->dq_sb)->files[type]; filp = sb_dqopt(dquot->dq_sb)->files[type];
...@@ -652,8 +658,14 @@ static int v2_read_dquot(struct dquot *dquot) ...@@ -652,8 +658,14 @@ static int v2_read_dquot(struct dquot *dquot)
printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id); printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id);
memset(&ddquot, 0, sizeof(struct v2_disk_dqblk)); memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
} }
else else {
ret = 0; ret = 0;
/* We need to escape back all-zero structure */
memset(&empty, 0, sizeof(struct v2_disk_dqblk));
empty.dqb_itime = cpu_to_le64(1);
if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
ddquot.dqb_itime = 0;
}
set_fs(fs); set_fs(fs);
disk2memdqb(&dquot->dq_dqb, &ddquot); disk2memdqb(&dquot->dq_dqb, &ddquot);
if (!dquot->dq_dqb.dqb_bhardlimit && if (!dquot->dq_dqb.dqb_bhardlimit &&
......
...@@ -59,7 +59,7 @@ struct v2_disk_dqinfo { ...@@ -59,7 +59,7 @@ struct v2_disk_dqinfo {
/* /*
* Structure of header of block with quota structures. It is padded to 16 bytes so * Structure of header of block with quota structures. It is padded to 16 bytes so
* there will be space for exactly 18 quota-entries in a block * there will be space for exactly 21 quota-entries in a block
*/ */
struct v2_disk_dqdbheader { struct v2_disk_dqdbheader {
__u32 dqdh_next_free; /* Number of next block with free entry */ __u32 dqdh_next_free; /* Number of next block with free entry */
......
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