diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 130 |
1 files changed, 68 insertions, 62 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index cbefe1f1f9fe..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; |
@@ -1065,6 +1065,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) | |||
1065 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | 1065 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) |
1066 | { | 1066 | { |
1067 | struct cifsFileInfo *open_file; | 1067 | struct cifsFileInfo *open_file; |
1068 | bool any_available = false; | ||
1068 | int rc; | 1069 | int rc; |
1069 | 1070 | ||
1070 | /* Having a null inode here (because mapping->host was set to zero by | 1071 | /* Having a null inode here (because mapping->host was set to zero by |
@@ -1080,8 +1081,10 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | |||
1080 | read_lock(&GlobalSMBSeslock); | 1081 | read_lock(&GlobalSMBSeslock); |
1081 | refind_writable: | 1082 | refind_writable: |
1082 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 1083 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
1083 | if (open_file->closePend) | 1084 | if (open_file->closePend || |
1085 | (!any_available && open_file->pid != current->tgid)) | ||
1084 | continue; | 1086 | continue; |
1087 | |||
1085 | if (open_file->pfile && | 1088 | if (open_file->pfile && |
1086 | ((open_file->pfile->f_flags & O_RDWR) || | 1089 | ((open_file->pfile->f_flags & O_RDWR) || |
1087 | (open_file->pfile->f_flags & O_WRONLY))) { | 1090 | (open_file->pfile->f_flags & O_WRONLY))) { |
@@ -1131,6 +1134,11 @@ refind_writable: | |||
1131 | of the loop here. */ | 1134 | of the loop here. */ |
1132 | } | 1135 | } |
1133 | } | 1136 | } |
1137 | /* couldn't find useable FH with same pid, try any available */ | ||
1138 | if (!any_available) { | ||
1139 | any_available = true; | ||
1140 | goto refind_writable; | ||
1141 | } | ||
1134 | read_unlock(&GlobalSMBSeslock); | 1142 | read_unlock(&GlobalSMBSeslock); |
1135 | return NULL; | 1143 | return NULL; |
1136 | } | 1144 | } |
@@ -1447,49 +1455,52 @@ static int cifs_writepage(struct page *page, struct writeback_control *wbc) | |||
1447 | return rc; | 1455 | return rc; |
1448 | } | 1456 | } |
1449 | 1457 | ||
1450 | static int cifs_commit_write(struct file *file, struct page *page, | 1458 | static int cifs_write_end(struct file *file, struct address_space *mapping, |
1451 | unsigned offset, unsigned to) | 1459 | loff_t pos, unsigned len, unsigned copied, |
1460 | struct page *page, void *fsdata) | ||
1452 | { | 1461 | { |
1453 | int xid; | 1462 | int rc; |
1454 | int rc = 0; | 1463 | struct inode *inode = mapping->host; |
1455 | struct inode *inode = page->mapping->host; | ||
1456 | loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | ||
1457 | char *page_data; | ||
1458 | 1464 | ||
1459 | xid = GetXid(); | 1465 | cFYI(1, ("write_end for page %p from pos %lld with %d bytes", |
1460 | cFYI(1, ("commit write for page %p up to position %lld for %d", | 1466 | page, pos, copied)); |
1461 | page, position, to)); | 1467 | |
1462 | spin_lock(&inode->i_lock); | 1468 | if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE) |
1463 | if (position > inode->i_size) | 1469 | SetPageUptodate(page); |
1464 | i_size_write(inode, position); | ||
1465 | 1470 | ||
1466 | spin_unlock(&inode->i_lock); | ||
1467 | if (!PageUptodate(page)) { | 1471 | if (!PageUptodate(page)) { |
1468 | position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; | 1472 | char *page_data; |
1469 | /* can not rely on (or let) writepage write this data */ | 1473 | unsigned offset = pos & (PAGE_CACHE_SIZE - 1); |
1470 | if (to < offset) { | 1474 | int xid; |
1471 | cFYI(1, ("Illegal offsets, can not copy from %d to %d", | 1475 | |
1472 | offset, to)); | 1476 | xid = GetXid(); |
1473 | FreeXid(xid); | ||
1474 | return rc; | ||
1475 | } | ||
1476 | /* this is probably better than directly calling | 1477 | /* this is probably better than directly calling |
1477 | partialpage_write since in this function the file handle is | 1478 | partialpage_write since in this function the file handle is |
1478 | known which we might as well leverage */ | 1479 | known which we might as well leverage */ |
1479 | /* BB check if anything else missing out of ppw | 1480 | /* BB check if anything else missing out of ppw |
1480 | such as updating last write time */ | 1481 | such as updating last write time */ |
1481 | page_data = kmap(page); | 1482 | page_data = kmap(page); |
1482 | rc = cifs_write(file, page_data + offset, to-offset, | 1483 | rc = cifs_write(file, page_data + offset, copied, &pos); |
1483 | &position); | 1484 | /* if (rc < 0) should we set writebehind rc? */ |
1484 | if (rc > 0) | ||
1485 | rc = 0; | ||
1486 | /* else if (rc < 0) should we set writebehind rc? */ | ||
1487 | kunmap(page); | 1485 | kunmap(page); |
1486 | |||
1487 | FreeXid(xid); | ||
1488 | } else { | 1488 | } else { |
1489 | rc = copied; | ||
1490 | pos += copied; | ||
1489 | set_page_dirty(page); | 1491 | set_page_dirty(page); |
1490 | } | 1492 | } |
1491 | 1493 | ||
1492 | 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 | |||
1493 | return rc; | 1504 | return rc; |
1494 | } | 1505 | } |
1495 | 1506 | ||
@@ -2035,49 +2046,44 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file) | |||
2035 | return true; | 2046 | return true; |
2036 | } | 2047 | } |
2037 | 2048 | ||
2038 | static int cifs_prepare_write(struct file *file, struct page *page, | 2049 | static int cifs_write_begin(struct file *file, struct address_space *mapping, |
2039 | unsigned from, unsigned to) | 2050 | loff_t pos, unsigned len, unsigned flags, |
2051 | struct page **pagep, void **fsdata) | ||
2040 | { | 2052 | { |
2041 | int rc = 0; | 2053 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
2042 | loff_t i_size; | 2054 | loff_t offset = pos & (PAGE_CACHE_SIZE - 1); |
2043 | loff_t offset; | ||
2044 | 2055 | ||
2045 | cFYI(1, ("prepare write for page %p from %d to %d", page, from, to)); | 2056 | cFYI(1, ("write_begin from %lld len %d", (long long)pos, len)); |
2046 | if (PageUptodate(page)) | 2057 | |
2058 | *pagep = __grab_cache_page(mapping, index); | ||
2059 | if (!*pagep) | ||
2060 | return -ENOMEM; | ||
2061 | |||
2062 | if (PageUptodate(*pagep)) | ||
2047 | return 0; | 2063 | return 0; |
2048 | 2064 | ||
2049 | /* 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, |
2050 | no need to read from the server */ | 2066 | no need to read from the server */ |
2051 | if ((to == PAGE_CACHE_SIZE) && (from == 0)) { | 2067 | if (len == PAGE_CACHE_SIZE && flags & AOP_FLAG_UNINTERRUPTIBLE) |
2052 | SetPageUptodate(page); | ||
2053 | return 0; | 2068 | return 0; |
2054 | } | ||
2055 | 2069 | ||
2056 | offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | 2070 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) { |
2057 | i_size = i_size_read(page->mapping->host); | 2071 | int rc; |
2058 | 2072 | ||
2059 | if ((offset >= i_size) || | ||
2060 | ((from == 0) && (offset + to) >= i_size)) { | ||
2061 | /* | ||
2062 | * We don't need to read data beyond the end of the file. | ||
2063 | * zero it, and set the page uptodate | ||
2064 | */ | ||
2065 | simple_prepare_write(file, page, from, to); | ||
2066 | SetPageUptodate(page); | ||
2067 | } else if ((file->f_flags & O_ACCMODE) != O_WRONLY) { | ||
2068 | /* might as well read a page, it is fast enough */ | 2073 | /* might as well read a page, it is fast enough */ |
2069 | 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 */ | ||
2070 | } else { | 2080 | } else { |
2071 | /* we could try using another file handle if there is one - | 2081 | /* we could try using another file handle if there is one - |
2072 | 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 |
2073 | racing with this read? In any case | 2083 | racing with this read? In any case |
2074 | this will be written out by commit_write so is fine */ | 2084 | this will be written out by write_end so is fine */ |
2075 | } | 2085 | } |
2076 | 2086 | ||
2077 | /* we do not need to pass errors back | ||
2078 | e.g. if we do not have read access to the file | ||
2079 | because cifs_commit_write will do the right thing. -- shaggy */ | ||
2080 | |||
2081 | return 0; | 2087 | return 0; |
2082 | } | 2088 | } |
2083 | 2089 | ||
@@ -2086,8 +2092,8 @@ const struct address_space_operations cifs_addr_ops = { | |||
2086 | .readpages = cifs_readpages, | 2092 | .readpages = cifs_readpages, |
2087 | .writepage = cifs_writepage, | 2093 | .writepage = cifs_writepage, |
2088 | .writepages = cifs_writepages, | 2094 | .writepages = cifs_writepages, |
2089 | .prepare_write = cifs_prepare_write, | 2095 | .write_begin = cifs_write_begin, |
2090 | .commit_write = cifs_commit_write, | 2096 | .write_end = cifs_write_end, |
2091 | .set_page_dirty = __set_page_dirty_nobuffers, | 2097 | .set_page_dirty = __set_page_dirty_nobuffers, |
2092 | /* .sync_page = cifs_sync_page, */ | 2098 | /* .sync_page = cifs_sync_page, */ |
2093 | /* .direct_IO = */ | 2099 | /* .direct_IO = */ |
@@ -2102,8 +2108,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { | |||
2102 | .readpage = cifs_readpage, | 2108 | .readpage = cifs_readpage, |
2103 | .writepage = cifs_writepage, | 2109 | .writepage = cifs_writepage, |
2104 | .writepages = cifs_writepages, | 2110 | .writepages = cifs_writepages, |
2105 | .prepare_write = cifs_prepare_write, | 2111 | .write_begin = cifs_write_begin, |
2106 | .commit_write = cifs_commit_write, | 2112 | .write_end = cifs_write_end, |
2107 | .set_page_dirty = __set_page_dirty_nobuffers, | 2113 | .set_page_dirty = __set_page_dirty_nobuffers, |
2108 | /* .sync_page = cifs_sync_page, */ | 2114 | /* .sync_page = cifs_sync_page, */ |
2109 | /* .direct_IO = */ | 2115 | /* .direct_IO = */ |