Re: [PATCH, RFC] detect partial write error to quota file in write_blk() and add printk_ratelimit for quota error messages

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux