From: Timothy Shimmin <tes@sgi.com>
To: Roger Willcocks <roger@filmlight.ltd.uk>
Cc: xfs@oss.sgi.com
Subject: Re: bug: truncate to zero + setuid
Date: Tue, 30 Oct 2007 15:06:06 +1100 [thread overview]
Message-ID: <4726ADAE.9070206@sgi.com> (raw)
In-Reply-To: <47262CD0.5010708@filmlight.ltd.uk>
Roger Willcocks wrote:
> Tim Shimmin wrote:
>> Hi Roger,
>>
>> Roger Willcocks wrote:
>>> The nfsv3 setattr call permits a simultaneous truncate + setuid/gid
>>> operation. Normally XFS handles this fine, but if the file's being
>>> truncated to zero, and the file's already empty, XFS simply ignores
>>> the setuid/gid part, returning 'success'.
>>>
>>> The error's in xfs_vnodeops.c/xfs_setattr below the comment 'Short
>>> circuit the truncate case for zero length files', which bypasses all
>>> other changes.
>>>
>>> The simplest fix is to test whether this is the only change that's
>>> happening, otherwise you get tangled in transactions.
>>>
>>> if (mask & XFS_AT_SIZE) {
>>> /* Short circuit the truncate case for zero length
>>> files */
>>> - if ((vap->va_size == 0) &&
>>> + if (((mask & ~XFS_AT_SIZE) == 0) && (vap->va_size ==
>>> 0) &&
>>> (ip->i_d.di_size == 0) && (ip->i_d.di_nextents ==
>>> 0)) {
>>>
>>>
>>> --
>>> Roger
>>>
>>
>> Yeah, I see your problem.
>> It is interesting to know how much of multiple actions (different
>> bits of mask) are supported.
>> XFS_AT_UPDTIMES doesn't support anything else and will return quickly.
>> As far as code which goes via error_return, it looks like the
>> only non-error case is the short-circuit one mentioned above -
>> truncating to zero an already zeroed file.
>>
>> I see your fix will get what we want although, it will mean that we
>> will go thru the truncating path when we don't need to.
>> It would be nice if we could act like the XFS_AT_SIZE was never set
>> on the call in the case that other bits are set.
>> Though when we first test the AT_SIZE, we don't have the inode locked.
>> And I presume in that case we don't necessarily need to send a
>> DMAPI truncate event?
>> So I wonder if before the 1st AT_SIZE test that we have now,
>> in the AT_SIZE case and with other bits set,
>> we could lock the inode and test
>> for the zero truncate of zero-len file and if so then remove the
>> AT_SIZE bit
>> and then go on to the other testing as if AT_SIZE was never set.
>> Hmmm, may be that just complicates things too much.
>>
> Yes I looked at simply unsetting the XFS_AT_SIZE bit (you'd also need to
> set
> timeflags appropriately) but the problem is the bit's used to check when
> to create
> a transaction - either up front as XFS_TRANS_SETATTR_NOT_SIZE, or
> later on, after the inode's been locked and unlocked again, as
> XFS_TRANS_SETATTR_SIZE. So if you unset the bit (and there's still more
> to do) you need to build a not_size transaction, at which point you
> might as well
> rewrite the whole routine...
>
> --
> Roger
So this was done by Steve L. for AIM performance...
----------------------------
revision 1.446
date: 2000/06/09 02:59:45; author: lord; state: Exp; lines: +11 -0
modid: 2.4.0-test1-xfs:slinx:55891a
Merge of 2.3.99pre2-xfs:slinx:55891a by ananth.
Short circuit the case where we truncate a zero length
file down to zero length so that we do not do a transaction.
This close to doubles create/close AIM run performance.
----------------------------
> p_rdiff -r1.445,1.446 xfs_vnodeops.c
746a747,757
> /* Short circuit the truncate case for zero length files */
> if ((vap->va_size == 0) &&
> (ip->i_d.di_size == 0) && (ip->i_d.di_nextents == 0)) {
> xfs_iunlock(ip, XFS_ILOCK_EXCL);
> lock_flags &= ~XFS_ILOCK_EXCL;
> if (mask & AT_CTIME)
> xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
> code = 0;
> goto error_return;
> }
>
----------------------------
revision 1.506
date: 2001/06/26 22:07:29; author: lord; state: Exp; lines: +1 -1
modid: 2.4.x-xfs:slinx:97694a
Set the mtime on a zero length file when a create is being done on
top of it.
----------------------------
> p_rdiff -r1.505,1.506 xfs_vnodeops.c
526c526
< xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
---
> xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
I presume it was done where it was done so that the inode was locked and we
were under the XFS_AT_SIZE predicate.
I was just thinking of something like...
but I'm probably missing something.
Index: 2.6.x-xfs/fs/xfs/xfs_vnodeops.c
===================================================================
--- 2.6.x-xfs.orig/fs/xfs/xfs_vnodeops.c 2007-10-12 16:06:15.000000000 +1000
+++ 2.6.x-xfs/fs/xfs/xfs_vnodeops.c 2007-10-30 14:59:46.418837757 +1100
@@ -304,6 +304,24 @@
}
/*
+ * Short circuit the truncate case for zero length files.
+ * If more mask bits are set, then just remove the SIZE one
+ * and keep going.
+ */
+ if (mask & XFS_AT_SIZE) {
+ xfs_ilock(ip, XFS_ILOCK_SHARED);
+ if ((vap->va_size == 0) && (ip->i_size == 0) && (ip->i_d.di_nextents == 0)) {
+ if (mask & ~XFS_AT_SIZE) {
+ mask &= ~XFS_AT_SIZE;
+ } else {
+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
+ return 0;
+ }
+ }
+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
+ }
+
+ /*
* For the other attributes, we acquire the inode lock and
* first do an error checking pass.
*/
@@ -451,17 +469,6 @@
* Truncate file. Must have write permission and not be a directory.
*/
if (mask & XFS_AT_SIZE) {
- /* Short circuit the truncate case for zero length files */
- if ((vap->va_size == 0) &&
- (ip->i_size == 0) && (ip->i_d.di_nextents == 0)) {
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- lock_flags &= ~XFS_ILOCK_EXCL;
- if (mask & XFS_AT_CTIME)
- xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
- code = 0;
- goto error_return;
- }
-
if (VN_ISDIR(vp)) {
code = XFS_ERROR(EISDIR);
goto error_return;
next prev parent reply other threads:[~2007-10-30 4:06 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-10-28 14:36 bug: truncate to zero + setuid Roger Willcocks
2007-10-29 0:54 ` Tim Shimmin
2007-10-29 18:56 ` Roger Willcocks
2007-10-30 4:06 ` Timothy Shimmin [this message]
2007-10-30 17:28 ` Roger Willcocks
2007-11-02 1:11 ` Timothy Shimmin
2007-11-04 11:59 ` Roger Willcocks
2007-11-08 3:13 ` Timothy Shimmin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4726ADAE.9070206@sgi.com \
--to=tes@sgi.com \
--cc=roger@filmlight.ltd.uk \
--cc=xfs@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox