Last Comment Bug 750207 - pop3 on linux checks quota incorrectly, resulting in wrong "Insufficient disk space" messages
: pop3 on linux checks quota incorrectly, resulting in wrong "Insufficient disk...
Product: Core Graveyard
Classification: Graveyard
Component: File Handling (show other bugs)
: Trunk
: All Linux
: -- normal (vote)
: mozilla15
Assigned To: Michael Tokarev
Depends on:
  Show dependency treegraph
Reported: 2012-04-30 03:48 PDT by Michael Tokarev
Modified: 2016-06-22 12:16 PDT (History)
4 users (show)
ryanvm: in‑testsuite-
See Also:
QA Whiteboard:
Iteration: ---
Points: ---

proposed code patch that fixes this ussue (1.92 KB, patch)
2012-04-30 03:48 PDT, Michael Tokarev
stransky: review-
Details | Diff | Splinter Review
another version of the proposed fix (2.65 KB, patch)
2012-05-10 03:45 PDT, Michael Tokarev
stransky: review-
Details | Diff | Splinter Review
v3 patch (2.67 KB, patch)
2012-05-10 06:16 PDT, Michael Tokarev
stransky: review+
benjamin: review+
Details | Diff | Splinter Review
a patch for check-in (1.26 KB, patch)
2012-05-23 04:52 PDT, Martin Stránský
no flags Details | Diff | Splinter Review

Description User image Michael Tokarev 2012-04-30 03:48:59 PDT
Created attachment 619518 [details] [diff] [review]
proposed code patch that fixes this ussue

User Agent: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:10.0.3) Gecko/20100101 Firefox/10.0.3 Iceweasel/10.0.3
Build ID: 20120330191503

Steps to reproduce:

On linux, enabled filesystem quota mechanism for the filesystem where the thunderbird profile resides (/home) but did not actually set any quota limits of the account in question.  Also created a POP3 account in thunderbird.

Actual results:

When TB tries to fetch mail over POP3, it displays the following message:

 There is not enough disk space to download new messages. Try deleting old mail, emptying the Trash folder, and compacting your mail folders, and then try again.

and does not download any messages from the mailbox.

Expected results:

It should download the messages and stop displaying false and misleading message.

The problem is that in nsLocalFileUnix.cpp:nsLocalFile::GetDiskSpaceAvailable(), there's a call to quotactl() which succeds if quota is enabled for the filesystem in question.  But if no quota is set for the user, corresponding limit will be 0, and the amount of bytes in the remote mailbox gets compared with this 0 and TB decides since there's zero available bytes, the messages can't be stored.

But limit == 0 actually means there's no limit at all.

There's a few more problems with the current code.

quotactl() return a structure with one field (dqb_valid) being a bitmask indicating which other fields (actual limits) are valid.  It is an error to access, say, qb_bhardlimit without checking dqb_valid&QIF_BLIMITS first.  It works just because current - at least linux - kernel code always sets this flag, but it does not have to.

This bug is a very old bug, introduced somewhere in 3.x version or even before, and is present up till current version.

Original discussion on mozillazine forum:
Comment 1 User image Magnus Melin 2012-05-02 12:54:54 PDT
Are you willing to create a patch to fix that?
Comment 2 User image Michael Tokarev 2012-05-02 13:12:50 PDT
I'm sorry but.. what?  I attached the patch fixing the bug to my bugreport...
Comment 3 User image Magnus Melin 2012-05-02 21:54:57 PDT
Duh! Sorry about that. Please ask to review your patch.
Comment 4 User image Benjamin Smedberg [:bsmedberg] 2012-05-07 10:09:51 PDT
Comment on attachment 619518 [details] [diff] [review]
proposed code patch that fixes this ussue

stransky, can you check this? MichaelT, I suppose there really isn't a way to write an automated (xpcshell) test for this functionality?
Comment 5 User image Michael Tokarev 2012-05-09 11:25:25 PDT
It is indeed difficult to write a test for this, since dealing with quotas usually requires root privileges (or else it defeats the purpose), and quota should be enabled by appropriate filesystem mount options and initial current quota collection run.  This case (quotas enabled but not set for a given user) may be checked in an automated script, and a script can either run (if the condition is met) or skipped (with the appropriate message saying that in order to run this script, you have to enable but not set quotas), but I highly doubt lots of environments will do that in order to run this test, so the whole thing wont be very useful.  Just IMHO anyway.
Comment 6 User image Martin Stránský 2012-05-10 01:57:15 PDT
Comment on attachment 619518 [details] [diff] [review]
proposed code patch that fixes this ussue

According to quota implementation in samba (which looks robust enough) the quota is not set when both dqb_bsoftlimit and dqb_bhardlimit are zero. (see for instance, the quotas.c file).

The QIF_BLIMITS check is not necessary (according to the man page all flags are set by kernel) but it may not hurt us. But I don't see the check anywhere it in the samba quota implementation.

So please add the dqb_bsoftlimit and dqb_bhardlimit zero check at least.
Comment 7 User image Michael Tokarev 2012-05-10 02:21:05 PDT
This is, well, not right understanding.

Either or both or none of softlimit and hardlimit can be set to 0 or set to something other than 0.  Setting hard limit to 0 but soft limit to non-0 means that softlimit will become hard after a grace period.  Setting soft limit to 0 but hard to non-0 means there's no soft limit, ony hard limit.

Samba tries to check both soft and hard limit.  In particular, it declares that user does not have any space if he exceeded soft limit _only_.  But softlimit is just that - soft, it is okay to exceed soft limit temporarily (up to a grace period in time and up to actual hard limit in size).  But note that samba here actually returns available disk space, not tries to undestand if the user has enough disk space to store some file -- which might be right thing to do.  Samba will actually try to write data or create files if client asked it to do so, and will return whatever actual _kernel_ error it will hit, if any.  The disk space is just informational thing for the user here, nothing more.

Mozilla on the other hand checks if the user has enough space to store mailbox data.  Initially it has been decided that only hard quota is interesting, and I understand why: dealing with soft quotas and grace periods is sort of insane, since the logic is not really trivial and the kernel may implement it slightly differently anyway.  And I can easily imagine users complaining when mozilla refuses to d/load messages saying about not enough disk space when the user exceeded only soft quota.

So I think checking for hard limit only (or not checking at all) is the way to do it in Mozilla.


Comment 8 User image Martin Stránský 2012-05-10 02:40:02 PDT
Yes, you're right about the soft quota. My concern is just how to detect that the quota is not set, because dqb_bhardlimit = 0 can mean that there isn't any available block, right? Or do you mean that dqb_bhardlimit can't be set to 0 unless the quota is unset? And if so, is there any documentation about it?
Comment 9 User image Michael Tokarev 2012-05-10 02:42:41 PDT
Each {soft,hard}{block,inode} limit is independent of all other.  If one is 0 it means this one is not set, and it does not mean anything at all about others.  That's what I mean about the "not right understanding", and this is what I described in the second paragraph above (in comment 7)
Comment 10 User image Martin Stránský 2012-05-10 02:52:10 PDT
Okay. But please provide an answer to my question why do you think the the dqb_bhardlimit != 0 check is enough when samba uses the dqb_bhardlimit != 0 && dqb_bsoftlimit != 0 check. Which makes sense to me, because if bsoftlimit is zero it can't became hardlimit after the grace period, right?)
Comment 11 User image Michael Tokarev 2012-05-10 03:03:45 PDT
Here's the samba code (simplified a bit):

   if ((D.softlimit && D.curblocks >= D.softlimit) ||
       (D.hardlimit && D.curblocks >= D.hardlimit)) {
                *dfree = 0;
                *dsize = D.curblocks;
   } else if (D.softlimit==0 && D.hardlimit==0) {
   } else {
                if (D.softlimit == 0)
                       D.softlimit = D.hardlimit;
                *dfree = D.softlimit - D.curblocks;
                *dsize = D.softlimit;

Translation: if either hard or soft limit is set and exceeded, we set disk free space to 0.  Else, if neither soft nor hard limit is set, we pretend we don't know what the disk free space is.  Else, which means at least one of the limits is set and neither is exceeded, we choose whatever is set and use it as the disk size.

It does not ensure that both is set, it merely uses whatever is set.

And as I already said in comment 7, it is perfectly legal to have softlimit != 0 and hardlimit = 0, there's nothing wrong with that.  It means that the user in question may use any available disk space but up to a grace period in time, after which he will have to free space to be able to write again.
Comment 12 User image Martin Stránský 2012-05-10 03:17:00 PDT
I see. It looks like the whole implementation of the quota in mozilla is broken, because we use:

PRInt64 QuotaSpaceAvailable = PRInt64(fs_buf.f_bsize * dq.dqb_bhardlimit);

which actually should be:

PRInt64 QuotaSpaceAvailable = PRInt64(fs_buf.f_bsize * (dq.dqb_bhardlimit - dq.dqb_curspace));

and then it makes sense the dqb_bhardlimit zero check.
Comment 13 User image Michael Tokarev 2012-05-10 03:25:09 PDT
It looks like you're right, I overlooked this place apparently.

But it shouldn't do it this way, since both curspace and hardlimit are unsigned, and limit might be less than curspace.  So it should actually be:

 PRInt64 QuotaSpaceAvailable =  dq.dqb_bhardlimit > dq.dqb_curspace ? PRInt64(fs_buf.f_bsize * (dq.dqb_bhardlimit - dq.dqb_curspace)) : 0;

(or something in that theme).

But dq.dqb_bhardlimit != 0 check should be in the if statement anyway.
Comment 14 User image Martin Stránský 2012-05-10 03:32:36 PDT
Yeah, please update your patch with those fixes.
Comment 15 User image Michael Tokarev 2012-05-10 03:45:33 PDT
Created attachment 622677 [details] [diff] [review]
another version of the proposed fix

I'm attaching a new version of the patch, which also corrects the other issue (taking into account already used blocks).  But this time it is not even compile-tested, since right now I don't a machine where I can try to compile it.
Comment 16 User image Michael Tokarev 2012-05-10 03:46:18 PDT
btw, can we set status of this bug already, to something more appropriate than "unconfirmed" ? :)
Comment 17 User image Martin Stránský 2012-05-10 06:01:53 PDT
Comment on attachment 622677 [details] [diff] [review]
another version of the proposed fix

Looks okay, Thanks! Just some indentation nits:

+       && dq.dqb_bhardlimit) {

Please place the bracket on a newline. 

+        PRInt64 QuotaSpaceAvailable =
+            dq.dqb_bhardlimit < dq.dqb_curspace ? 0
+            : PRInt64(fs_buf.f_bsize * (dq.dqb_curspace - dq.dqb_bhardlimit));

Something like:

PRInt64 QuotaSpaceAvailable = 0;
if (dq.dqb_curspace > dq.dqb_bhardlimit)
    QuotaSpaceAvailable = PRInt64(fs_buf.f_bsize * (dq.dqb_curspace - dq.dqb_bhardlimit));

would look better here. r+ with those changes.
Comment 18 User image Michael Tokarev 2012-05-10 06:16:41 PDT
Created attachment 622703 [details] [diff] [review]
v3 patch

Fixed the identation as suggested.  Also fixed the inversed substraction (hardlimit - curspace is right, curspace - hardlimit is wrong).
Comment 19 User image Martin Stránský 2012-05-10 06:18:31 PDT
Comment on attachment 622677 [details] [diff] [review]
another version of the proposed fix

Uhh, The patch is still wrong. Because dqb_curspace means "used blocks" and when quota is on, it's not bigger than dqb_bhardlimit (at least we don't care when it is).

So it has to be:

if (dq.dqb_bhardlimit > dq.dqb_curspace)
    QuotaSpaceAvailable = PRInt64(fs_buf.f_bsize * (dq.dqb_bhardlimit - dq.dqb_curspace));

Sorry for the confusion here.
Comment 20 User image Michael Tokarev 2012-05-10 06:20:23 PDT
Heh. I was faster and found it before you :)
Comment 21 User image Martin Stránský 2012-05-10 06:59:42 PDT
Comment on attachment 622703 [details] [diff] [review]
v3 patch

Yes, looks okay now.
Comment 22 User image Martin Stránský 2012-05-10 07:02:01 PDT
Comment on attachment 622703 [details] [diff] [review]
v3 patch

Benjamin, can you confirm it?
Comment 23 User image Benjamin Smedberg [:bsmedberg] 2012-05-11 08:47:40 PDT
Comment on attachment 622703 [details] [diff] [review]
v3 patch

Please take a look at the normal style of commit messages in mozilla-central and make this commit message match, in particular: list the bug number and basic patch description in the first line along with the marking "r=stransky/bsmedberg". The full change description on subsequent lines as you have it is fine.
Comment 24 User image Michael Tokarev 2012-05-11 09:05:27 PDT
do you want another attachment from me?  Come on guys, I just wanted to fix a bug but no matter how I asked no one knew.  So I found the problem, and provided a patch in a hope it will be easier this way -- for a code/project I had _never_ looked before.  To me the problem is solved, I just changed my quota setup to match the buggy mozilla behavour.  Next time (if I'll ever have a next time) I'll try to not do anything besides just submitting a bugreport.  Or wont even do that - after finding where the problem is and working around it locally.
Comment 25 User image Benjamin Smedberg [:bsmedberg] 2012-05-11 09:10:48 PDT
Michael, I want to thank you for the report and the patch. I figured that you were happy providing followup patches, since you presumably already have them in a convenient form. If you'd like somebody else to finish this off, please just let us know! Typically all you'd have to do from here is provide a patch in the form that the "checkin-needed" volunteers can push it directly to our tree and we're done.
Comment 26 User image Martin Stránský 2012-05-23 04:52:57 PDT
Created attachment 626394 [details] [diff] [review]
a patch for check-in
Comment 27 User image Ryan VanderMeulen [:RyanVM] 2012-05-23 18:04:00 PDT
Comment 28 User image Ed Morley [:emorley] 2012-05-24 09:26:28 PDT

Note You need to log in before you can comment on or make changes to this bug.