{"push_id":1277584823,"size":1,"distinct_size":1,"ref":"refs/heads/6.0.1","head":"a3989a22b2ebfbe507e708225653efe4d54cf8f8","before":"64c15a287767a28306ce210d2dbdbb30b7e5699e","commits":[{"sha":"a3989a22b2ebfbe507e708225653efe4d54cf8f8","author":{"name":"Maxim Patlasov","email":"722ffad1b17189e74038d593447ca47ab369fef6@parallels.com"},"message":"fuse: hotfix truncate_pagecache() issue\n\ncommit 06a7c3c2781409af95000c60a5df743fd4e2f8b4 upstream.\n\nThe way how fuse calls truncate_pagecache() from fuse_change_attributes()\nis completely wrong. Because, w/o i_mutex held, we never sure whether\n'oldsize' and 'attr->size' are valid by the time of execution of\ntruncate_pagecache(inode, oldsize, attr->size). In fact, as soon as we\nreleased fc->lock in the middle of fuse_change_attributes(), we completely\nloose control of actions which may happen with given inode until we reach\ntruncate_pagecache. The list of potentially dangerous actions includes\nmmap-ed reads and writes, ftruncate(2) and write(2) extending file size.\n\nThe typical outcome of doing truncate_pagecache() with outdated arguments\nis data corruption from user point of view. This is (in some sense)\nacceptable in cases when the issue is triggered by a change of the file on\nthe server (i.e. externally wrt fuse operation), but it is absolutely\nintolerable in scenarios when a single fuse client modifies a file without\nany external intervention. A real life case I discovered by fsx-linux\nlooked like this:\n\n1. Shrinking ftruncate(2) comes to fuse_do_setattr(). The latter sends\nFUSE_SETATTR to the server synchronously, but before getting fc->lock ...\n2. fuse_dentry_revalidate() is asynchronously called. It sends FUSE_LOOKUP\nto the server synchronously, then calls fuse_change_attributes(). The\nlatter updates i_size, releases fc->lock, but before comparing oldsize vs\nattr->size..\n3. fuse_do_setattr() from the first step proceeds by acquiring fc->lock and\nupdating attributes and i_size, but now oldsize is equal to\noutarg.attr.size because i_size has just been updated (step 2). Hence,\nfuse_do_setattr() returns w/o calling truncate_pagecache().\n4. As soon as ftruncate(2) completes, the user extends file size by\nwrite(2) making a hole in the middle of file, then reads data from the hole\neither by read(2) or mmap-ed read. The user expects to get zero data from\nthe hole, but gets stale data because truncate_pagecache() is not executed\nyet.\n\nThe scenario above illustrates one side of the problem: not truncating the\npage cache even though we should. Another side corresponds to truncating\npage cache too late, when the state of inode changed significantly.\nTheoretically, the following is possible:\n\n1. As in the previous scenario fuse_dentry_revalidate() discovered that\ni_size changed (due to our own fuse_do_setattr()) and is going to call\ntruncate_pagecache() for some 'new_size' it believes valid right now. But\nby the time that particular truncate_pagecache() is called ...\n2. fuse_do_setattr() returns (either having called truncate_pagecache() or\nnot -- it doesn't matter).\n3. The file is extended either by write(2) or ftruncate(2) or fallocate(2).\n4. mmap-ed write makes a page in the extended region dirty.\n\nThe result will be the lost of data user wrote on the fourth step.\n\nThe patch is a hotfix resolving the issue in a simplistic way: let's skip\ndangerous i_size update and truncate_pagecache if an operation changing\nfile size is in progress. This simplistic approach looks correct for the\ncases w/o external changes. And to handle them properly, more sophisticated\nand intrusive techniques (e.g. NFS-like one) would be required. I'd like to\npostpone it until the issue is well discussed on the mailing list(s).\n\nChanged in v2:\n - improved patch description to cover both sides of the issue.\n\nSigned-off-by: Maxim Patlasov <mpatlasov@parallels.com>\nSigned-off-by: Miklos Szeredi <mszeredi@suse.cz>\n[bwh: Backported to 3.2: add the fuse_inode::state field which we didn't have]\nSigned-off-by: Ben Hutchings <ben@decadent.org.uk>\nCc: Rui Xiang <rui.xiang@huawei.com>\nSigned-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>","distinct":true,"url":"https://api.github.com/repos/dblockopp/G3_CooCoo_Kernel/commits/a3989a22b2ebfbe507e708225653efe4d54cf8f8"}]}
{"actor":{"display_login":"dblockopp"}}