RE: VFS write operations (Michael Welch)
RE: VFS write operations (Michael Welch)
- Subject: RE: VFS write operations (Michael Welch)
- From: "Michael Welch" <email@hidden>
- Date: Tue, 12 Sep 2006 19:42:59 -0700
- Thread-topic: VFS write operations (Michael Welch)
Thanks, Sam. I will give ktrace a whirl and see if anything else pops
up. In the mean time, I should mention:
1) I have not implemented VNOP_EXCHANGE. In VFS_GETATTR I set it as a
valid but not supported capability. "I'm aware of ExchangeData, but I
don't do that..."
2) I have implemented VNOP_RENAME, and it seems to work fine from both
the command line ($mv file1 file2) and through the Finder.
In my TextEdit scenario, I don't even see a rename attempted. I see it
create a new file, write the contents there (successfully), read the
file's attributes, and then delete it and bail. Maybe ktrace will
reveal some additional steps going on in there that I don't see
otherwise.
Does that additional info make things better or worse?
- Mike
> -----Original Message-----
> From: Sam Vaughan [mailto:email@hidden]
> Sent: Tuesday, September 12, 2006 7:06 PM
> To: Michael Welch
> Cc: email@hidden
> Subject: Re: VFS write operations (Michael Welch)
>
> Hi Mike,
>
> On 13/09/2006, at 5:03 AM, Michael Welch <email@hidden> wrote:
>
> > From the terminal, I can read (e.g. $cat filename), write
> $echo "foo"
> > > filename), and append ($echo "foo" >> filename). All seems well.
>
> Good, this means that your VNOP_READ and VNOP_WRITE code is
> working.
> Saving from TextEdit will need more than that though...
>
> > Then I try to write from a simple app like TextEdit... here's where
> > the fun begins. I open a file in TextEdit (it can read just fine),
> > make some changes, and hit save. From what I can decipher,
> TextEdit
> > performs the following steps (with the corresponding VNOP's going
> > through my
> > VFS):
> >
> > 1) Open the existing file, read a whole slew of attributes
> > (permissions, file size, timestamps, etc.), and then close the file.
> > 2) Repeat (1) for the parent dir, it's parent, etc. up to
> the root of
> > the file system.
> > 3) Create a temporary file, open it, and write the data.
> > 4) Read some attributes on the temp file (only uid, gid, flags,
> > fileid, and fsid) and close it.
> > 5) Delete the temp file.
> > 6) Report that the file could not be saved (duh - you just deleted
> > it!).
> >
> > My best (only) guess is that it's unhappy with the
> attributes it sees
> > - but what I return in those attributes are the same values
> specified
> > during file creation time (except size, which is updated at write
> > time).
> > Stepping through I've verified that the temp file is created in the
> > same directory as my cache file and the data is in fact
> written to it
> > after step 3. The attributes look right.
> >
> > So writing a file from TextEdit fails. However - if the
> file size is
> > zero, the save succeeds (that is, if the new size is zero,
> regardless
> > of what the old size was). Instead of (4) and (5), it does
> what you'd
> > pretty much expect - delete the original file and rename
> the temp file
> > back into place.
>
> TextEdit is trying to do a safe save. i.e. write to a
> different file and swap that file with the original file in a
> file-system-atomic way. It'll try to use exchangedata(2)
> first, and if that fails, it'll use two rename(2) operations.
>
> Have you implemented VNOP_EXCHANGE? If so then that's
> probably where you should be looking. Otherwise I'd say the
> issue will be in your VNOP_RENAME. The ktrace(1) tool is
> going to be your best bet to narrow down your problem.
>
> I'd recommend walking through the ktrace output from
> successful TextEdit saves and comparing them to the ktrace
> output from a save to your file system. You might want to
> repeat this on a UFS formatted disk image to see the generic
> file system behaviour when things like VolFS and exchangedata
> aren't involved.
>
> So on HFS+:
>
> - - - - - - - -
>
> ti:~ sjv: echo foo > file.txt
> ti:~ sjv: open !$
> open file.txt
> ti:~ sjv: ktrace -p `ps auxww | grep [T]extEdit | awk
> '{print $2;}'`
>
> <modify and save the file in TextEdit>
>
> ti:~ sjv: ktrace -C
> ti:~ sjv: kdump
>
>
> <snip uid, DNLC, stat, attr and access stuff>
>
> -- check availability of temp file name A ".15066-179801665-1.txt":
>
> 15066 TextEdit CALL lstat(0xbfffd4c0,0xbfffd930)
> 15066 TextEdit NAMI "/Users/sjv/.15066-179801665-1.txt"
> 15066 TextEdit RET lstat -1 errno 2 No such file or directory
>
> <snip umask stuff>
>
> 15066 TextEdit CALL stat(0xbfffdda0,0xbfffd500)
> 15066 TextEdit NAMI "/Users/sjv/.15066-179801665-1.txt"
> 15066 TextEdit RET stat -1 errno 2 No such file or directory
>
> -- write data to temp file B ".dat3ada.001":
>
> 15066 TextEdit CALL open(0xbfffd560,0xa02,0x180)
> 15066 TextEdit NAMI "/Users/sjv/.dat3ada.001"
> 15066 TextEdit RET open 12/0xc
> 15066 TextEdit CALL write(0xc,0x3837f0,0x5)
> 15066 TextEdit GIO fd 12 wrote 5 bytes
> "food
> "
> 15066 TextEdit RET write 5
> 15066 TextEdit CALL fsync(0xc)
> 15066 TextEdit RET fsync 0
> 15066 TextEdit CALL close(0xc)
> 15066 TextEdit RET close 0
>
> -- rename B to A and chmod
>
> 15066 TextEdit CALL rename(0xbfffd560,0xbfffdda0)
> 15066 TextEdit NAMI "/Users/sjv/.dat3ada.001"
> 15066 TextEdit NAMI "/Users/sjv/.15066-179801665-1.txt"
> 15066 TextEdit RET rename 0
> 15066 TextEdit CALL chmod(0xbfffdda0,0x1a4)
> 15066 TextEdit NAMI "/Users/sjv/.15066-179801665-1.txt"
> 15066 TextEdit RET chmod 0
>
> -- check for tilde file in case exchangedata isn't supported
>
> 15066 TextEdit CALL lstat(0xbfffd530,0xbfffd9a0)
> 15066 TextEdit NAMI "/Users/sjv/file~.txt"
> 15066 TextEdit RET lstat -1 errno 2 No such file or directory
>
> -- exchangedata from A to original file
>
> 15066 TextEdit CALL exchangedata(0xbfffda10,0xbfffde20,0)
> 15066 TextEdit NAMI "/Users/sjv/.15066-179801665-1.txt"
> 15066 TextEdit NAMI "/Users/sjv/file.txt"
> 15066 TextEdit RET exchangedata 0
>
> <snip stat stuff>
>
> -- unlink temp file A
>
> 15066 TextEdit CALL unlink(0xbfffd3b0)
> 15066 TextEdit NAMI "/Users/sjv/.15066-179801665-1.txt"
> 15066 TextEdit RET unlink 0
>
> <snip other foo>
>
> - - - - - - - -
>
>
> And on UFS, it's largely the same process with the addition
> of some extra operations on Apple Double files, e.g.
> "._file.txt". There's also a lot more stat/attr activity,
> something that clustered file systems hate to see due to the
> metadata traffic it entails. (Radar
> #3634554)
>
>
> - - - - - - - -
>
> ti:~ sjv: hdiutil create -fs UFS -size 10m -volname ufs
> ufs.dmg > /dev/null
> ti:~ sjv: hdiutil attach ufs.dmg
> /dev/disk4 Apple_partition_scheme
> /dev/disk4s1 Apple_partition_map
> /dev/disk4s2 Apple_UFS
> /Volumes/
> ufs
> ti:~ sjv: echo foo > /Volumes/ufs/file.txt
> ti:~ sjv: open !$
> open /Volumes/ufs/file.txt
> ti:~ sjv: ktrace -p `ps auxww | grep [T]extEdit | awk
> '{print $2;}'`
> ti:~ sjv: ktrace -C
> ti:~ sjv: kdump
>
>
> <snip uid, DNLC, stat, attr and access stuff>
>
> <snip similar stuff to HFS+ above>
>
> -- exchangedata fails because UFS doesn't support it:
>
> 15177 TextEdit CALL exchangedata(0xbfffda10,0xbfffde20,0)
> 15177 TextEdit NAMI "/Volumes/ufs/.15177-179803682-1.txt"
> 15177 TextEdit NAMI "/Volumes/ufs/file.txt"
> 15177 TextEdit RET exchangedata -1 errno 45 Operation not supported
>
> <snip more stat/uid foo>
>
> -- rename old files to tilde files
>
> 15177 TextEdit CALL rename(0xbfffc170,0xbfffc570)
> 15177 TextEdit NAMI "/Volumes/ufs/file.txt"
> 15177 TextEdit NAMI "/Volumes/ufs/file~.txt"
> 15177 TextEdit NAMI "._file.txt"
> 15177 TextEdit NAMI "._file~.txt"
> 15177 TextEdit RET rename 0
>
> <snip uid foo>
>
> -- check that the original directory entry is now available
>
> 15177 TextEdit CALL lstat(0xbfffcc50,0xbfffd0c0)
> 15177 TextEdit NAMI "/Volumes/ufs/file.txt"
> 15177 TextEdit RET lstat -1 errno 2 No such file or directory
>
> <snip more stat/uid/attr foo>
>
> -- better check again because we've been tooling around with stats
>
> 15177 TextEdit CALL lstat(0xbfffcc50,0xbfffd0c0)
> 15177 TextEdit NAMI "/Volumes/ufs/file.txt"
> 15177 TextEdit RET lstat -1 errno 2 No such file or directory
>
> <snip uid foo>
>
> -- rename our temporary file to the original file
>
> 15177 TextEdit CALL rename(0xbfffc170,0xbfffc570)
> 15177 TextEdit NAMI "/Volumes/ufs/.15177-179803682-1.txt"
> 15177 TextEdit NAMI "/Volumes/ufs/file.txt"
> 15177 TextEdit NAMI "._.15177-179803682-1.txt"
> 15177 TextEdit NAMI "._file.txt"
> 15177 TextEdit RET rename 0
>
> <unlink, tidy up etc.>
>
> - - - - - - - -
>
>
> So as you can see, TextEdit or the layers of File Manager
> code beneath it know how to save a file to a file system that
> supports exchangedata(2), as well as how to back up a file
> and use rename to atomically save a file on a file system
> that doesn't. The difference in the two approaches is that
> in the latter case there's a window of time where a lookup on
> the file will return ENOENT.
>
> Only your ktrace from the file system you're working on will
> tell you what's going wrong, but by comparing it to the HFS+
> and UFS traces you should be able to pinpoint the operation
> that causes the save operation to your file system to be aborted.
>
> Sam
>
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden