Commit 6b12c1b37e5556af073c1ebfa04c1f9df3a2beaf
Committed by
Miklos Szeredi
1 parent
482fce55d2
fuse: Implement write_begin/write_end callbacks
The .write_begin and .write_end are requiered to use generic routines (generic_file_aio_write --> ... --> generic_perform_write) for buffered writes. Signed-off-by: Maxim Patlasov <MPatlasov@parallels.com> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Showing 1 changed file with 73 additions and 0 deletions Side-by-side Diff
fs/fuse/file.c
... | ... | @@ -1952,6 +1952,77 @@ |
1952 | 1952 | return err; |
1953 | 1953 | } |
1954 | 1954 | |
1955 | +/* | |
1956 | + * It's worthy to make sure that space is reserved on disk for the write, | |
1957 | + * but how to implement it without killing performance need more thinking. | |
1958 | + */ | |
1959 | +static int fuse_write_begin(struct file *file, struct address_space *mapping, | |
1960 | + loff_t pos, unsigned len, unsigned flags, | |
1961 | + struct page **pagep, void **fsdata) | |
1962 | +{ | |
1963 | + pgoff_t index = pos >> PAGE_CACHE_SHIFT; | |
1964 | + struct fuse_conn *fc = get_fuse_conn(file->f_dentry->d_inode); | |
1965 | + struct page *page; | |
1966 | + loff_t fsize; | |
1967 | + int err = -ENOMEM; | |
1968 | + | |
1969 | + WARN_ON(!fc->writeback_cache); | |
1970 | + | |
1971 | + page = grab_cache_page_write_begin(mapping, index, flags); | |
1972 | + if (!page) | |
1973 | + goto error; | |
1974 | + | |
1975 | + fuse_wait_on_page_writeback(mapping->host, page->index); | |
1976 | + | |
1977 | + if (PageUptodate(page) || len == PAGE_CACHE_SIZE) | |
1978 | + goto success; | |
1979 | + /* | |
1980 | + * Check if the start this page comes after the end of file, in which | |
1981 | + * case the readpage can be optimized away. | |
1982 | + */ | |
1983 | + fsize = i_size_read(mapping->host); | |
1984 | + if (fsize <= (pos & PAGE_CACHE_MASK)) { | |
1985 | + size_t off = pos & ~PAGE_CACHE_MASK; | |
1986 | + if (off) | |
1987 | + zero_user_segment(page, 0, off); | |
1988 | + goto success; | |
1989 | + } | |
1990 | + err = fuse_do_readpage(file, page); | |
1991 | + if (err) | |
1992 | + goto cleanup; | |
1993 | +success: | |
1994 | + *pagep = page; | |
1995 | + return 0; | |
1996 | + | |
1997 | +cleanup: | |
1998 | + unlock_page(page); | |
1999 | + page_cache_release(page); | |
2000 | +error: | |
2001 | + return err; | |
2002 | +} | |
2003 | + | |
2004 | +static int fuse_write_end(struct file *file, struct address_space *mapping, | |
2005 | + loff_t pos, unsigned len, unsigned copied, | |
2006 | + struct page *page, void *fsdata) | |
2007 | +{ | |
2008 | + struct inode *inode = page->mapping->host; | |
2009 | + | |
2010 | + if (!PageUptodate(page)) { | |
2011 | + /* Zero any unwritten bytes at the end of the page */ | |
2012 | + size_t endoff = (pos + copied) & ~PAGE_CACHE_MASK; | |
2013 | + if (endoff) | |
2014 | + zero_user_segment(page, endoff, PAGE_CACHE_SIZE); | |
2015 | + SetPageUptodate(page); | |
2016 | + } | |
2017 | + | |
2018 | + fuse_write_update_size(inode, pos + copied); | |
2019 | + set_page_dirty(page); | |
2020 | + unlock_page(page); | |
2021 | + page_cache_release(page); | |
2022 | + | |
2023 | + return copied; | |
2024 | +} | |
2025 | + | |
1955 | 2026 | static int fuse_launder_page(struct page *page) |
1956 | 2027 | { |
1957 | 2028 | int err = 0; |
... | ... | @@ -2979,6 +3050,8 @@ |
2979 | 3050 | .set_page_dirty = __set_page_dirty_nobuffers, |
2980 | 3051 | .bmap = fuse_bmap, |
2981 | 3052 | .direct_IO = fuse_direct_IO, |
3053 | + .write_begin = fuse_write_begin, | |
3054 | + .write_end = fuse_write_end, | |
2982 | 3055 | }; |
2983 | 3056 | |
2984 | 3057 | void fuse_init_file_inode(struct inode *inode) |