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 = */ |
