cifs_stats_bytes_written(pTcon, total_written);
/* since the write may have blocked check these pointers again */
- if (file->f_path.dentry) {
- if (file->f_path.dentry->d_inode) {
- struct inode *inode = file->f_path.dentry->d_inode;
- inode->i_ctime = inode->i_mtime =
- current_fs_time(inode->i_sb);
- if (total_written > 0) {
- if (*poffset > file->f_path.dentry->d_inode->i_size)
- i_size_write(file->f_path.dentry->d_inode,
+ if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
+ struct inode *inode = file->f_path.dentry->d_inode;
+/* Do not update local mtime - server will set its actual value on write
+ * inode->i_ctime = inode->i_mtime =
+ * current_fs_time(inode->i_sb);*/
+ if (total_written > 0) {
+ spin_lock(&inode->i_lock);
+ if (*poffset > file->f_path.dentry->d_inode->i_size)
+ i_size_write(file->f_path.dentry->d_inode,
*poffset);
- }
- mark_inode_dirty_sync(file->f_path.dentry->d_inode);
+ spin_unlock(&inode->i_lock);
}
+ mark_inode_dirty_sync(file->f_path.dentry->d_inode);
}
FreeXid(xid);
return total_written;
cifs_stats_bytes_written(pTcon, total_written);
/* since the write may have blocked check these pointers again */
- if (file->f_path.dentry) {
- if (file->f_path.dentry->d_inode) {
- file->f_path.dentry->d_inode->i_ctime =
- file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;
- if (total_written > 0) {
- if (*poffset > file->f_path.dentry->d_inode->i_size)
- i_size_write(file->f_path.dentry->d_inode,
- *poffset);
- }
- mark_inode_dirty_sync(file->f_path.dentry->d_inode);
+ if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
+/*BB We could make this contingent on superblock ATIME flag too */
+/* file->f_path.dentry->d_inode->i_ctime =
+ file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
+ if (total_written > 0) {
+ spin_lock(&file->f_path.dentry->d_inode->i_lock);
+ if (*poffset > file->f_path.dentry->d_inode->i_size)
+ i_size_write(file->f_path.dentry->d_inode,
+ *poffset);
+ spin_unlock(&file->f_path.dentry->d_inode->i_lock);
}
+ mark_inode_dirty_sync(file->f_path.dentry->d_inode);
}
FreeXid(xid);
return total_written;
pgoff_t end;
pgoff_t index;
int range_whole = 0;
- struct kvec iov[32];
+ struct kvec * iov;
int len;
int n_iov = 0;
pgoff_t next;
if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
if(cifs_sb->tcon->ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
- if(!experimEnabled)
+ if(!experimEnabled)
return generic_writepages(mapping, wbc);
+ iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
+ if(iov == NULL)
+ return generic_writepages(mapping, wbc);
+
+
/*
* BB: Is this meaningful for a non-block-device file system?
* If it is, we should test it again after we do I/O
*/
if (wbc->nonblocking && bdi_write_congested(bdi)) {
wbc->encountered_congestion = 1;
+ kfree(iov);
return 0;
}
wait_on_page_writeback(page);
if (PageWriteback(page) ||
- !test_clear_page_dirty(page)) {
+ !clear_page_dirty_for_io(page)) {
unlock_page(page);
break;
}
+ /*
+ * This actually clears the dirty bit in the radix tree.
+ * See cifs_writepage() for more commentary.
+ */
+ set_page_writeback(page);
+
if (page_offset(page) >= mapping->host->i_size) {
done = 1;
unlock_page(page);
+ end_page_writeback(page);
break;
}
SetPageError(page);
kunmap(page);
unlock_page(page);
+ end_page_writeback(page);
page_cache_release(page);
}
if ((wbc->nr_to_write -= n_iov) <= 0)
mapping->writeback_index = index;
FreeXid(xid);
-
+ kfree(iov);
return rc;
}
if (!PageUptodate(page)) {
cFYI(1, ("ppw - page not up to date"));
}
-
+
+ /*
+ * Set the "writeback" flag, and clear "dirty" in the radix tree.
+ *
+ * A writepage() implementation always needs to do either this,
+ * or re-dirty the page with "redirty_page_for_writepage()" in
+ * the case of a failure.
+ *
+ * Just unlocking the page will cause the radix tree tag-bits
+ * to fail to update with the state of the page correctly.
+ */
+ set_page_writeback(page);
rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
unlock_page(page);
- page_cache_release(page);
+ end_page_writeback(page);
+ page_cache_release(page);
FreeXid(xid);
return rc;
}
xid = GetXid();
cFYI(1, ("commit write for page %p up to position %lld for %d",
page, position, to));
+ spin_lock(&inode->i_lock);
if (position > inode->i_size) {
i_size_write(inode, position);
/* if (file->private_data == NULL) {
cFYI(1, (" SetEOF (commit write) rc = %d", rc));
} */
}
+ spin_unlock(&inode->i_lock);
if (!PageUptodate(page)) {
position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
/* can not rely on (or let) writepage write this data */
refreshing the inode only on increases in the file size
but this is tricky to do without racing with writebehind
page caching in the current Linux kernel design */
-int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
+int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
{
struct cifsFileInfo *open_file = NULL;
return 1;
}
+ if(i_size_read(&cifsInode->vfs_inode) < end_of_file)
+ return 1;
+
return 0;
} else
return 1;
unsigned from, unsigned to)
{
int rc = 0;
- loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
+ loff_t i_size;
+ loff_t offset;
+
cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
- if (!PageUptodate(page)) {
- /* if (to - from != PAGE_CACHE_SIZE) {
- void *kaddr = kmap_atomic(page, KM_USER0);
+ if (PageUptodate(page))
+ return 0;
+
+ /* If we are writing a full page it will be up to date,
+ no need to read from the server */
+ if ((to == PAGE_CACHE_SIZE) && (from == 0)) {
+ SetPageUptodate(page);
+ return 0;
+ }
+
+ offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
+ i_size = i_size_read(page->mapping->host);
+
+ if ((offset >= i_size) ||
+ ((from == 0) && (offset + to) >= i_size)) {
+ /*
+ * We don't need to read data beyond the end of the file.
+ * zero it, and set the page uptodate
+ */
+ void *kaddr = kmap_atomic(page, KM_USER0);
+
+ if (from)
memset(kaddr, 0, from);
+ if (to < PAGE_CACHE_SIZE)
memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
- } */
- /* If we are writing a full page it will be up to date,
- no need to read from the server */
- if ((to == PAGE_CACHE_SIZE) && (from == 0))
- SetPageUptodate(page);
-
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+ SetPageUptodate(page);
+ } else if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
/* might as well read a page, it is fast enough */
- if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
- rc = cifs_readpage_worker(file, page, &offset);
- } else {
- /* should we try using another file handle if there is one -
- how would we lock it to prevent close of that handle
- racing with this read?
- In any case this will be written out by commit_write */
- }
+ rc = cifs_readpage_worker(file, page, &offset);
+ } else {
+ /* we could try using another file handle if there is one -
+ but how would we lock it to prevent close of that handle
+ racing with this read? In any case
+ this will be written out by commit_write so is fine */
}
- /* BB should we pass any errors back?
- e.g. if we do not have read access to the file */
+ /* we do not need to pass errors back
+ e.g. if we do not have read access to the file
+ because cifs_commit_write will do the right thing. -- shaggy */
+
return 0;
}