On Thu 13-05-10 14:30:10, Jiaying Zhang wrote: > > This patch changes quota_tree.c:write_blk() to detect error caused by partial write > to quota file and add a macro to limit control printed quota error messages so we > won't fill up dmesg with a corrupted quota file. > > Signed-off-by: Jiaying Zhang <jiayingz@xxxxxxxxxx> The patch looks fine. Merged. Honza > > diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c > index f81f4bc..46387ec 100644 > --- a/fs/quota/quota_tree.c > +++ b/fs/quota/quota_tree.c > @@ -60,9 +60,17 @@ static ssize_t read_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf) > static ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf) > { > struct super_block *sb = info->dqi_sb; > + ssize_t ret; > > - return sb->s_op->quota_write(sb, info->dqi_type, buf, > + ret = sb->s_op->quota_write(sb, info->dqi_type, buf, > info->dqi_usable_bs, blk << info->dqi_blocksize_bits); > + if (ret != info->dqi_usable_bs) { > + q_warn(KERN_WARNING "VFS: dquota write failed on " > + "dev %s\n", sb->s_id); > + if (ret >= 0) > + ret = -EIO; > + } > + return ret; > } > > /* Remove empty block from list and return it */ > @@ -152,7 +160,7 @@ static int remove_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, > dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); > /* No matter whether write succeeds block is out of list */ > if (write_blk(info, blk, buf) < 0) > - printk(KERN_ERR > + q_warn(KERN_ERR > "VFS: Can't write block (%u) with free entries.\n", > blk); > return 0; > @@ -244,7 +252,7 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info, > if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) { > *err = remove_free_dqentry(info, buf, blk); > if (*err < 0) { > - printk(KERN_ERR "VFS: find_free_dqentry(): Can't " > + q_warn(KERN_ERR "VFS: find_free_dqentry(): Can't " > "remove block (%u) from entry free list.\n", > blk); > goto out_buf; > @@ -268,7 +276,7 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info, > #endif > *err = write_blk(info, blk, buf); > if (*err < 0) { > - printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota " > + q_warn(KERN_ERR "VFS: find_free_dqentry(): Can't write quota " > "data block %u.\n", blk); > goto out_buf; > } > @@ -303,7 +311,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, > } else { > ret = read_blk(info, *treeblk, buf); > if (ret < 0) { > - printk(KERN_ERR "VFS: Can't read tree quota block " > + q_warn(KERN_ERR "VFS: Can't read tree quota block " > "%u.\n", *treeblk); > goto out_buf; > } > @@ -365,7 +373,7 @@ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) > if (!dquot->dq_off) { > ret = dq_insert_tree(info, dquot); > if (ret < 0) { > - printk(KERN_ERR "VFS: Error %zd occurred while " > + q_warn(KERN_ERR "VFS: Error %zd occurred while " > "creating quota.\n", ret); > kfree(ddquot); > return ret; > @@ -377,7 +385,7 @@ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) > ret = sb->s_op->quota_write(sb, type, ddquot, info->dqi_entry_size, > dquot->dq_off); > if (ret != info->dqi_entry_size) { > - printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", > + q_warn(KERN_WARNING "VFS: dquota write failed on dev %s\n", > sb->s_id); > if (ret >= 0) > ret = -ENOSPC; > @@ -402,14 +410,14 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, > if (!buf) > return -ENOMEM; > if (dquot->dq_off >> info->dqi_blocksize_bits != blk) { > - printk(KERN_ERR "VFS: Quota structure has offset to other " > + q_warn(KERN_ERR "VFS: Quota structure has offset to other " > "block (%u) than it should (%u).\n", blk, > (uint)(dquot->dq_off >> info->dqi_blocksize_bits)); > goto out_buf; > } > ret = read_blk(info, blk, buf); > if (ret < 0) { > - printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk); > + q_warn(KERN_ERR "VFS: Can't read quota data block %u\n", blk); > goto out_buf; > } > dh = (struct qt_disk_dqdbheader *)buf; > @@ -419,7 +427,7 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, > if (ret >= 0) > ret = put_free_dqblk(info, buf, blk); > if (ret < 0) { > - printk(KERN_ERR "VFS: Can't move quota data block (%u) " > + q_warn(KERN_ERR "VFS: Can't move quota data block (%u) " > "to free list.\n", blk); > goto out_buf; > } > @@ -432,14 +440,14 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, > /* Insert will write block itself */ > ret = insert_free_dqentry(info, buf, blk); > if (ret < 0) { > - printk(KERN_ERR "VFS: Can't insert quota data " > + q_warn(KERN_ERR "VFS: Can't insert quota data " > "block (%u) to free entry list.\n", blk); > goto out_buf; > } > } else { > ret = write_blk(info, blk, buf); > if (ret < 0) { > - printk(KERN_ERR "VFS: Can't write quota data " > + q_warn(KERN_ERR "VFS: Can't write quota data " > "block %u\n", blk); > goto out_buf; > } > @@ -464,7 +472,7 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, > return -ENOMEM; > ret = read_blk(info, *blk, buf); > if (ret < 0) { > - printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk); > + q_warn(KERN_ERR "VFS: Can't read quota data block %u\n", *blk); > goto out_buf; > } > newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); > @@ -488,7 +496,7 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, > } else { > ret = write_blk(info, *blk, buf); > if (ret < 0) > - printk(KERN_ERR "VFS: Can't write quota tree " > + q_warn(KERN_ERR "VFS: Can't write quota tree " > "block %u.\n", *blk); > } > } > @@ -521,7 +529,7 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info, > return -ENOMEM; > ret = read_blk(info, blk, buf); > if (ret < 0) { > - printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); > + q_warn(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); > goto out_buf; > } > ddquot = buf + sizeof(struct qt_disk_dqdbheader); > @@ -531,7 +539,7 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info, > ddquot += info->dqi_entry_size; > } > if (i == qtree_dqstr_in_blk(info)) { > - printk(KERN_ERR "VFS: Quota for id %u referenced " > + q_warn(KERN_ERR "VFS: Quota for id %u referenced " > "but not present.\n", dquot->dq_id); > ret = -EIO; > goto out_buf; > @@ -556,7 +564,7 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info, > return -ENOMEM; > ret = read_blk(info, blk, buf); > if (ret < 0) { > - printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); > + q_warn(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); > goto out_buf; > } > ret = 0; > @@ -599,7 +607,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) > offset = find_dqentry(info, dquot); > if (offset <= 0) { /* Entry not present? */ > if (offset < 0) > - printk(KERN_ERR "VFS: Can't read quota " > + q_warn(KERN_ERR "VFS: Can't read quota " > "structure for id %u.\n", dquot->dq_id); > dquot->dq_off = 0; > set_bit(DQ_FAKE_B, &dquot->dq_flags); > @@ -617,7 +625,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) > if (ret != info->dqi_entry_size) { > if (ret >= 0) > ret = -EIO; > - printk(KERN_ERR "VFS: Error while reading quota " > + q_warn(KERN_ERR "VFS: Error while reading quota " > "structure for id %u.\n", dquot->dq_id); > set_bit(DQ_FAKE_B, &dquot->dq_flags); > memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); > diff --git a/fs/quota/quota_tree.h b/fs/quota/quota_tree.h > index a1ab8db..ccc3e71 100644 > --- a/fs/quota/quota_tree.h > +++ b/fs/quota/quota_tree.h > @@ -22,4 +22,10 @@ struct qt_disk_dqdbheader { > > #define QT_TREEOFF 1 /* Offset of tree in file in blocks */ > > +#define q_warn(fmt, args...) \ > +do { \ > + if (printk_ratelimit()) \ > + printk(fmt, ## args); \ > +} while(0) > + > #endif /* _LINUX_QUOTAIO_TREE_H */ > diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c > index e3da02f..135206a 100644 > --- a/fs/quota/quota_v2.c > +++ b/fs/quota/quota_v2.c > @@ -63,7 +63,7 @@ static int v2_read_header(struct super_block *sb, int type, > size = sb->s_op->quota_read(sb, type, (char *)dqhead, > sizeof(struct v2_disk_dqheader), 0); > if (size != sizeof(struct v2_disk_dqheader)) { > - printk(KERN_WARNING "quota_v2: Failed header read:" > + q_warn(KERN_WARNING "quota_v2: Failed header read:" > " expected=%zd got=%zd\n", > sizeof(struct v2_disk_dqheader), size); > return 0; > @@ -106,7 +106,7 @@ static int v2_read_file_info(struct super_block *sb, int type) > size = sb->s_op->quota_read(sb, type, (char *)&dinfo, > sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); > if (size != sizeof(struct v2_disk_dqinfo)) { > - printk(KERN_WARNING "quota_v2: Can't read info structure on device %s.\n", > + q_warn(KERN_WARNING "quota_v2: Can't read info structure on device %s.\n", > sb->s_id); > return -1; > } > @@ -167,7 +167,7 @@ static int v2_write_file_info(struct super_block *sb, int type) > size = sb->s_op->quota_write(sb, type, (char *)&dinfo, > sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); > if (size != sizeof(struct v2_disk_dqinfo)) { > - printk(KERN_WARNING "Can't write info structure on device %s.\n", > + q_warn(KERN_WARNING "Can't write info structure on device %s.\n", > sb->s_id); > return -1; > } -- Jan Kara <jack@xxxxxxx> SUSE Labs, CR -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html