diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 120 |
1 files changed, 59 insertions, 61 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index d39e852a28a9..c4a8a0605125 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -107,7 +107,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, | |||
107 | 107 | ||
108 | /* want handles we can use to read with first | 108 | /* want handles we can use to read with first |
109 | in the list so we do not have to walk the | 109 | in the list so we do not have to walk the |
110 | list to search for one in prepare_write */ | 110 | list to search for one in write_begin */ |
111 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | 111 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { |
112 | list_add_tail(&pCifsFile->flist, | 112 | list_add_tail(&pCifsFile->flist, |
113 | &pCifsInode->openFileList); | 113 | &pCifsInode->openFileList); |
@@ -915,7 +915,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
915 | } | 915 | } |
916 | 916 | ||
917 | static ssize_t cifs_write(struct file *file, const char *write_data, | 917 | static ssize_t cifs_write(struct file *file, const char *write_data, |
918 | size_t write_size, loff_t *poffset) | 918 | size_t write_size, loff_t *poffset) |
919 | { | 919 | { |
920 | int rc = 0; | 920 | int rc = 0; |
921 | unsigned int bytes_written = 0; | 921 | unsigned int bytes_written = 0; |
@@ -1455,49 +1455,52 @@ static int cifs_writepage(struct page *page, struct writeback_control *wbc) | |||
1455 | return rc; | 1455 | return rc; |
1456 | } | 1456 | } |
1457 | 1457 | ||
1458 | static int cifs_commit_write(struct file *file, struct page *page, | 1458 | static int cifs_write_end(struct file *file, struct address_space *mapping, |
1459 | unsigned offset, unsigned to) | 1459 | loff_t pos, unsigned len, unsigned copied, |
1460 | struct page *page, void *fsdata) | ||
1460 | { | 1461 | { |
1461 | int xid; | 1462 | int rc; |
1462 | int rc = 0; | 1463 | struct inode *inode = mapping->host; |
1463 | struct inode *inode = page->mapping->host; | ||
1464 | loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | ||
1465 | char *page_data; | ||
1466 | 1464 | ||
1467 | xid = GetXid(); | 1465 | cFYI(1, ("write_end for page %p from pos %lld with %d bytes", |
1468 | cFYI(1, ("commit write for page %p up to position %lld for %d", | 1466 | page, pos, copied)); |
1469 | page, position, to)); | 1467 | |
1470 | spin_lock(&inode->i_lock); | 1468 | if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE) |
1471 | if (position > inode->i_size) | 1469 | SetPageUptodate(page); |
1472 | i_size_write(inode, position); | ||
1473 | 1470 | ||
1474 | spin_unlock(&inode->i_lock); | ||
1475 | if (!PageUptodate(page)) { | 1471 | if (!PageUptodate(page)) { |
1476 | position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; | 1472 | char *page_data; |
1477 | /* can not rely on (or let) writepage write this data */ | 1473 | unsigned offset = pos & (PAGE_CACHE_SIZE - 1); |
1478 | if (to < offset) { | 1474 | int xid; |
1479 | cFYI(1, ("Illegal offsets, can not copy from %d to %d", | 1475 | |
1480 | offset, to)); | 1476 | xid = GetXid(); |
1481 | FreeXid(xid); | ||
1482 | return rc; | ||
1483 | } | ||
1484 | /* this is probably better than directly calling | 1477 | /* this is probably better than directly calling |
1485 | partialpage_write since in this function the file handle is | 1478 | partialpage_write since in this function the file handle is |
1486 | known which we might as well leverage */ | 1479 | known which we might as well leverage */ |
1487 | /* BB check if anything else missing out of ppw | 1480 | /* BB check if anything else missing out of ppw |
1488 | such as updating last write time */ | 1481 | such as updating last write time */ |
1489 | page_data = kmap(page); | 1482 | page_data = kmap(page); |
1490 | rc = cifs_write(file, page_data + offset, to-offset, | 1483 | rc = cifs_write(file, page_data + offset, copied, &pos); |
1491 | &position); | 1484 | /* if (rc < 0) should we set writebehind rc? */ |
1492 | if (rc > 0) | ||
1493 | rc = 0; | ||
1494 | /* else if (rc < 0) should we set writebehind rc? */ | ||
1495 | kunmap(page); | 1485 | kunmap(page); |
1486 | |||
1487 | FreeXid(xid); | ||
1496 | } else { | 1488 | } else { |
1489 | rc = copied; | ||
1490 | pos += copied; | ||
1497 | set_page_dirty(page); | 1491 | set_page_dirty(page); |
1498 | } | 1492 | } |
1499 | 1493 | ||
1500 | FreeXid(xid); | 1494 | if (rc > 0) { |
1495 | spin_lock(&inode->i_lock); | ||
1496 | if (pos > inode->i_size) | ||
1497 | i_size_write(inode, pos); | ||
1498 | spin_unlock(&inode->i_lock); | ||
1499 | } | ||
1500 | |||
1501 | unlock_page(page); | ||
1502 | page_cache_release(page); | ||
1503 | |||
1501 | return rc; | 1504 | return rc; |
1502 | } | 1505 | } |
1503 | 1506 | ||
@@ -2043,49 +2046,44 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file) | |||
2043 | return true; | 2046 | return true; |
2044 | } | 2047 | } |
2045 | 2048 | ||
2046 | static int cifs_prepare_write(struct file *file, struct page *page, | 2049 | static int cifs_write_begin(struct file *file, struct address_space *mapping, |
2047 | unsigned from, unsigned to) | 2050 | loff_t pos, unsigned len, unsigned flags, |
2051 | struct page **pagep, void **fsdata) | ||
2048 | { | 2052 | { |
2049 | int rc = 0; | 2053 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
2050 | loff_t i_size; | 2054 | loff_t offset = pos & (PAGE_CACHE_SIZE - 1); |
2051 | loff_t offset; | 2055 | |
2056 | cFYI(1, ("write_begin from %lld len %d", (long long)pos, len)); | ||
2057 | |||
2058 | *pagep = __grab_cache_page(mapping, index); | ||
2059 | if (!*pagep) | ||
2060 | return -ENOMEM; | ||
2052 | 2061 | ||
2053 | cFYI(1, ("prepare write for page %p from %d to %d", page, from, to)); | 2062 | if (PageUptodate(*pagep)) |
2054 | if (PageUptodate(page)) | ||
2055 | return 0; | 2063 | return 0; |
2056 | 2064 | ||
2057 | /* If we are writing a full page it will be up to date, | 2065 | /* If we are writing a full page it will be up to date, |
2058 | no need to read from the server */ | 2066 | no need to read from the server */ |
2059 | if ((to == PAGE_CACHE_SIZE) && (from == 0)) { | 2067 | if (len == PAGE_CACHE_SIZE && flags & AOP_FLAG_UNINTERRUPTIBLE) |
2060 | SetPageUptodate(page); | ||
2061 | return 0; | 2068 | return 0; |
2062 | } | ||
2063 | 2069 | ||
2064 | offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | 2070 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) { |
2065 | i_size = i_size_read(page->mapping->host); | 2071 | int rc; |
2066 | 2072 | ||
2067 | if ((offset >= i_size) || | ||
2068 | ((from == 0) && (offset + to) >= i_size)) { | ||
2069 | /* | ||
2070 | * We don't need to read data beyond the end of the file. | ||
2071 | * zero it, and set the page uptodate | ||
2072 | */ | ||
2073 | simple_prepare_write(file, page, from, to); | ||
2074 | SetPageUptodate(page); | ||
2075 | } else if ((file->f_flags & O_ACCMODE) != O_WRONLY) { | ||
2076 | /* might as well read a page, it is fast enough */ | 2073 | /* might as well read a page, it is fast enough */ |
2077 | rc = cifs_readpage_worker(file, page, &offset); | 2074 | rc = cifs_readpage_worker(file, *pagep, &offset); |
2075 | |||
2076 | /* we do not need to pass errors back | ||
2077 | e.g. if we do not have read access to the file | ||
2078 | because cifs_write_end will attempt synchronous writes | ||
2079 | -- shaggy */ | ||
2078 | } else { | 2080 | } else { |
2079 | /* we could try using another file handle if there is one - | 2081 | /* we could try using another file handle if there is one - |
2080 | but how would we lock it to prevent close of that handle | 2082 | but how would we lock it to prevent close of that handle |
2081 | racing with this read? In any case | 2083 | racing with this read? In any case |
2082 | this will be written out by commit_write so is fine */ | 2084 | this will be written out by write_end so is fine */ |
2083 | } | 2085 | } |
2084 | 2086 | ||
2085 | /* we do not need to pass errors back | ||
2086 | e.g. if we do not have read access to the file | ||
2087 | because cifs_commit_write will do the right thing. -- shaggy */ | ||
2088 | |||
2089 | return 0; | 2087 | return 0; |
2090 | } | 2088 | } |
2091 | 2089 | ||
@@ -2094,8 +2092,8 @@ const struct address_space_operations cifs_addr_ops = { | |||
2094 | .readpages = cifs_readpages, | 2092 | .readpages = cifs_readpages, |
2095 | .writepage = cifs_writepage, | 2093 | .writepage = cifs_writepage, |
2096 | .writepages = cifs_writepages, | 2094 | .writepages = cifs_writepages, |
2097 | .prepare_write = cifs_prepare_write, | 2095 | .write_begin = cifs_write_begin, |
2098 | .commit_write = cifs_commit_write, | 2096 | .write_end = cifs_write_end, |
2099 | .set_page_dirty = __set_page_dirty_nobuffers, | 2097 | .set_page_dirty = __set_page_dirty_nobuffers, |
2100 | /* .sync_page = cifs_sync_page, */ | 2098 | /* .sync_page = cifs_sync_page, */ |
2101 | /* .direct_IO = */ | 2099 | /* .direct_IO = */ |
@@ -2110,8 +2108,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { | |||
2110 | .readpage = cifs_readpage, | 2108 | .readpage = cifs_readpage, |
2111 | .writepage = cifs_writepage, | 2109 | .writepage = cifs_writepage, |
2112 | .writepages = cifs_writepages, | 2110 | .writepages = cifs_writepages, |
2113 | .prepare_write = cifs_prepare_write, | 2111 | .write_begin = cifs_write_begin, |
2114 | .commit_write = cifs_commit_write, | 2112 | .write_end = cifs_write_end, |
2115 | .set_page_dirty = __set_page_dirty_nobuffers, | 2113 | .set_page_dirty = __set_page_dirty_nobuffers, |
2116 | /* .sync_page = cifs_sync_page, */ | 2114 | /* .sync_page = cifs_sync_page, */ |
2117 | /* .direct_IO = */ | 2115 | /* .direct_IO = */ |