Re: [RFC] quota: 64-bit limits with vfs, updated

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

 



Hello, Andreas

On Sunday 16 March 2008 01:47:26 Andreas Dilger wrote:
> 
> Is this ever used on values that are read from the disk?  If yes, then
> having it BUG() because there is corruption on the disk is bad.

This is used on revision variable that is either 0 or 1, which is
determined by the special function. As this special function cannot
return any other values, having rev!=0&&rev!=1 just means we got
a memory corruption.

> This is no good - if there is an error from ->quota_read() then the kernel
> will BUG() here.  You need proper (non fatal) error handling when you are
> first loading the quota information into memory.

My point is that something very very nasty have happened if we succeed on first
version check and fail right after that. In principle, we dont even need this
second check as we have done the check at this point. But using
results from previous check would need some interface changes(sigh).

I'll change the BUG_ON to returning error, but my point is if it happens, then
user is not expecting any sane error handling or it just won't help him. :)

> 
> This could be inline.
> 

I agree.

> 
> While this produces nice looking code, it isn't very efficient to run.
> It has 8 checks for "rev" per call, and it would have an additional
> 8 checks for "sizeof" except those are constant and optimized away
> by the compiler.  If you can convince me that the compiler will also
> optimize the 8 checks for "rev" into a single branch then it can
> stay, otherwise you should split it into 2 large sections based on
> "rev" and then decode r0 and r1 structures separately.
> 

I'll check the code produced by gcc.

> > @@ -301,17 +371,18 @@ static uint find_free_dqentry(struct dqu
> > +	/* Block will be full? */
> > +	if (le16_to_cpu(dh->dqdh_entries)+1 >= dqstrinblk)
> >  		if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
> >  			printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
> >  			goto out_buf;
> >  		}
> 
> Can you please clean this up a bit while here:
> 
> 	/* Block will be full? */
> 	if (le16_to_cpu(dh->dqdh_entries) + 1 >= dqstrinblk &&
> 	    (*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
> 		printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove "
> 				"block (%u) from entry free list.\n", blk);
> 		goto out_buf;
> 	}

While this makes sense to me, this change would be prohibited by
checkpatch.pl because of adding (*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)
assignment in condition. Indeed, we can move further with the change, but
code refactoring/cleaning is not the purpose of my patch. :)

> 
> > +	for (i = 0; i < dqstrinblk && memcmp(&emptydquot,
> > +			ddquot+i, dqblksz); i++);
> 
> This is also quite easy to be confused, please write it as:
> 
> 	for (i = 0; i < dqstrinblk && memcmp(&emptydquot,ddquot+i,dqblksz); i++)
> 		/* empty loop to count used dquot structs in block */;

You killed two spaces to fit the line in 80 chars. IIRC, checkpatch.pl requires that 
args should be separated with spaces.

> 
> In fact, it would be even better to just increment "ddquot" in the loop to
> avoid having to re-do the offset each time:
> 
> 	for (i = 0; i < dqstrinblk && memcmp(&emptydquot, ddquot, dqblksz);
> 	     i++, ddquot++)
> 		/* empty loop to count used dquot structs in block */;
> 
> > -	dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
> > +	dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+
> > +			sizeof(struct v2_disk_dqdbheader)+i*dqblksz;
> 
> With the above change to ddquot you can then use it directly here:
> 
> 	dquot->dq_off = (blk << V2_DQBLKSIZE_BITS) +
> 			((char *)ddquot - (char *)buf);

I agree.

> 
> > @@ -395,7 +467,9 @@ static int v2_write_dquot(struct dquot *
> >  {
> >  	int type = dquot->dq_type;
> 
> type is only used twice in this function, please remove it from the stack.
> 
> > @@ -538,27 +613,29 @@ static loff_t find_block_dqentry(struct
> > +	union v2_disk_dqblk *ddquot = GETENTRIES(buf);
> > +	int type = dquot->dq_type;
> 
> type only used twice in this function, please remove from stack.
> 
> > +	uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.dqi_revision;
> > +	uint dqblksz = v2_dqblksz(rev), dqstrinblk = v2_dqstrinblk(rev);
> >  
> >  	if (dquot->dq_id)
> > -		for (i = 0; i < V2_DQSTRINBLK &&
> > -		     le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
> > +		for (i = 0; i < dqstrinblk &&
> > +		     DQF_GET(ddquot+i, rev, dqb_id) != dquot->dq_id; i++);
> >  	else {	/* ID 0 as a bit more complicated searching... */
> 
> Spaces around " + ", and please add a { } around this block because second
> part has { } already.
> 
> > +		for (i = 0; i < dqstrinblk; i++)
> > +			if (!DQF_GET(ddquot+i, rev, dqb_id) &&
> > +			    memcmp(&emptydquot, ddquot+i, dqblksz))
> >  				break;
> >  	}
> 
> Spaces around " + " here also.  Actually, please run the patch through
> "checkpatch.pl" to find any similar issues.
> 
> > @@ -608,7 +685,7 @@ static int v2_read_dquot(struct dquot *d
> >  {
> >  	int type = dquot->dq_type;
> >  	loff_t offset;
> > -	struct v2_disk_dqblk ddquot, empty;
> > +	union v2_disk_dqblk ddquot;
> 
> Please remove type from stack.
> 

These comments refer mostly to enhancements to the original code. While I agree with most of them,
I see no reason, why they should be a part of this very patch. As for checkpatch.pl, I did run
it before emailing the patch and it did not find absent spaces around "+" to be an issue:

panda:/usr/src/linux-2.6.24.3 # md5sum /usr/src/quota.patch
e306aaf884b11709d9e744dfa5e89672  /usr/src/quota.patch
panda:/usr/src/linux-2.6.24.3 # scripts/checkpatch.pl /usr/src/quota.patch
ERROR: Missing Signed-off-by: line(s)

total: 1 errors, 0 warnings, 460 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.


> > @@ -629,25 +706,25 @@ static int v2_read_dquot(struct dquot *d
> > +		uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.
> > +			   dqi_revision, dqblksz = v2_dqblksz(rev);
> 
> Use another line with "uint dqblksz = v2_dqblksz(rev);" here.
> 

I agree.

> >  struct mem_dqblk {
> > -	__u32 dqb_bhardlimit;	/* absolute limit on disk blks alloc */
> > -	__u32 dqb_bsoftlimit;	/* preferred limit on disk blks */
> > +	qsize_t dqb_bhardlimit;	/* absolute limit on disk blks alloc */
> > +	qsize_t dqb_bsoftlimit;	/* preferred limit on disk blks */
> >  	qsize_t dqb_curspace;	/* current used space */
> > -	__u32 dqb_ihardlimit;	/* absolute limit on allocated inodes */
> > -	__u32 dqb_isoftlimit;	/* preferred inode limit */
> > -	__u32 dqb_curinodes;	/* current # allocated inodes */
> > +	qsize_t dqb_ihardlimit;	/* absolute limit on allocated inodes */
> > +	qsize_t dqb_isoftlimit;	/* preferred inode limit */
> > +	qsize_t dqb_curinodes;	/* current # allocated inodes */
> >  	time_t dqb_btime;	/* time limit for excessive disk use */
> >  	time_t dqb_itime;	/* time limit for excessive inode use */
> >  };
> 
> Is there a reason to use "qsize_t" instead of just using __u64 directly?
> 

Well, I'm not sure if there's a special meaning for qsize_t. I have only followed
the dqb_curspace convention, which is of qsize_t type. While I see no
special usage for qsize_t (well, it looks more nice than __u64 :), I at the same time 
see no problems using qsize_t. Maybe Jan will tell us more about qsize_t.

> > +++ linux-2.6.24.3/include/linux/quotaio_v2.h	2008-03-13 22:01:48.000000000 +0300
> > @@ -16,28 +16,51 @@
> > @@ -59,7 +82,7 @@ struct v2_disk_dqinfo {
> >  
> >  /*
> >   *  Structure of header of block with quota structures. It is padded to 16 bytes so
> > - *  there will be space for exactly 21 quota-entries in a block
> > + *  there will be space for exactly 21 (r0) or 14 (r1) quota-entries in a block
> >   */
> 
> Hmm, when this comment says "block" does it mean "1024-byte block" or
> filesystem block?  For 1024-byte block it is true that both 48-byte (r0) and
> 72-byte (r1) records fit evenly, but for 4096-byte blocks 72-byte records
> do not fit evenly.  Is that a problem?

Quota file is internally divided into 1024 byte blocks (see V2_DQBLKSIZE constant) each
consisting of a block header (which is used for free space management) and a fixed number 
of quota entries. This is not related in any way to fs blocks. quota format module
interacts with underlying storage only through quota_read/quota_write interface.

I'm going to update the patch with respect to your comments.
Btw, I lost "static" before disk2memdqblk, I'm going to update this one too.

Thanks and cheers.
Andrew.
--
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