Hi,
  for some time I was seeing that I'm getting parts of files
overwritten by zeroes - last line overwritten with zeroes
in /etc/mtab, damaged just downloaded *.deb file and so on.
After some searching I found following code, which executes
on write() request.
  It looks to me like that if 
    block_end <= zerofrom || block_start >= zeroto
no-one marks buffer dirty... And because of default value
of 'zeroto' is zero, it is sometime trigerred.
  Because of this is important filesystem/buffer code and 
I'm not too familiar with it, there is no patch attached.
But quick fix looks like moving 'else' branch (marked
with /******/ by me in code below) into both code paths,
not only into full-write path.
  I'll do it and I'll see, it cannot be worse, I think.
  If I run testprogram, 'cat asd' then prints 'asdfghjk'.
If I do 'cat /600MBfile >/dev/null' after that, 'od -c' 
says
0000000   a   s   d   f  \0  \0  \0  \0
0000010
and it is wrong, isn't it?
  [I'm using IDE, if it matters, but I do not think...]
                                   Thanks for your time,
                                        Petr Vandrovec
                                        [EMAIL PROTECTED]

int block_write_range(struct dentry *dentry, struct page *page,
                unsigned zerofrom, unsigned from, unsigned to,
                const char * buf)
{
        struct inode *inode = dentry->d_inode;
        unsigned zeroto = 0, block_start, block_end;
        unsigned long block;
[snip]
                if (buffer_new(bh)) {
                        zeroto = block_end;
                        if (block_start < zerofrom)
                                zerofrom = block_start;
                        continue;
                }
[snip]
        while(wait_bh > wait) {
                wait_on_buffer(*--wait_bh);
                err = -EIO;
                if (!buffer_uptodate(*wait_bh))
                        goto out;
        }
[snip]
        for(bh = head, block_start = 0;
            bh != head || !block_start;
            block_start=block_end, bh = bh->b_this_page) {
                block_end = block_start + blocksize;
                if (block_end <= zerofrom || block_start >= zeroto) {
                        if (!buffer_uptodate(bh))
                                partial = 1;
                } else { /******/
                        set_bit(BH_Uptodate, &bh->b_state);
                        if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
                                __mark_dirty(bh, 0);
                                need_balance_dirty = 1;
                        }
                }
        }
[snip]
        if (!partial)
                SetPageUptodate(page);
        kunmap(page);
        return 0;


/* test program */
#include <unistd.h>
#include <fcntl.h>

int main(void) {
        int fd = open("asd", O_RDWR|O_TRUNC|O_CREAT, 0600);

        write(fd, "asdf", 4);
        sync();
        write(fd, "ghjk", 4);
        close(fd);
        return 0;
}

Reply via email to