Re: VFS write operations (Michael Welch)
site_archiver@lists.apple.com Delivered-To: darwin-kernel@lists.apple.com Hi Mike, On 13/09/2006, at 5:03 AM, Michael Welch <mwelch@adobe.com> wrote: So on HFS+: - - - - - - - - <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> - - - - - - - - - - - - - - - - <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.> - - - - - - - - Sam _______________________________________________ Do not post admin requests to the list. They will be ignored. Darwin-kernel mailing list (Darwin-kernel@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/darwin-kernel/site_archiver%40lists.a...
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. ti:~ sjv: echo foo > file.txt ti:~ sjv: open !$ open file.txt ti:~ sjv: ktrace -p `ps auxww | grep [T]extEdit | awk '{print $2;}'` 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 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. This email sent to site_archiver@lists.apple.com
participants (1)
-
Sam Vaughan