2010/12/14 Jeff Layton <jlayton@xxxxxxxxxx>: > On Tue, 14 Dec 2010 14:10:58 +0300 > Pavel Shilovsky <piastryyy@xxxxxxxxx> wrote: > >> If we don't have Exclusive oplock we write a data to the server through >> cifs_write. Also set invalidate_mapping flag on the inode if we wrote >> something to the server. >> >> Signed-off-by: Pavel Shilovsky <piastryyy@xxxxxxxxx> >> --- >> fs/cifs/cifsfs.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++--- >> fs/cifs/cifsproto.h | 3 ++ >> fs/cifs/file.c | 5 +-- >> 3 files changed, 75 insertions(+), 7 deletions(-) >> >> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c >> index a218afe..5df0503 100644 >> --- a/fs/cifs/cifsfs.c >> +++ b/fs/cifs/cifsfs.c >> @@ -572,15 +572,81 @@ cifs_do_mount(struct file_system_type *fs_type, >> return dget(sb->s_root); >> } >> >> +static ssize_t cifs_strict_write(struct kiocb *iocb, const struct iovec *iov, >> + unsigned long nr_segs, loff_t pos) >> +{ >> + struct inode *inode; >> + struct cifs_sb_info *cifs_sb; >> + ssize_t written = 0; >> + unsigned long i, len = 0; >> + char *buf, *offset; >> + >> + inode = iocb->ki_filp->f_path.dentry->d_inode; >> + >> + if (CIFS_I(inode)->clientCanCacheAll) >> + return generic_file_aio_write(iocb, iov, nr_segs, pos); >> + >> + cifs_sb = CIFS_SB(iocb->ki_filp->f_path.dentry->d_sb); >> + >> + /* >> + * In strict cache mode we need to write the data to the server exactly >> + * from the pos to pos+len-1 rather than flush all affected pages >> + * because it may cause a error with mandatory locks on these pages but >> + * not on the region from pos to ppos+len-1. >> + */ >> + >> + for (i = 0; i < nr_segs; i++) >> + len += iov[i].iov_len; >> + >> + /* >> + * BB - optimize the way when signing is disabled. We can drop this >> + * extra memory-to-memory copying and use iovec buffers for constructing >> + * write request. >> + */ >> + >> + buf = kmalloc(len, GFP_KERNEL); >> + > > Actually...I thought about another problem here. Suppose an application > does a 100M write. This may fail in that case. It varies by the slab > allocator in use, but there are limits to how large you can kmalloc. > This is especially going to be a problem on 32-bit arches where > GFP_KERNEL memory is more limited. > > There are a couple of different solutions, but I think the best one > would be to stitch together individual pages. Walk the iov array first > and figure out how many pages you're going to need, and kmalloc an iov > array that size. Then start allocating pages (preferably using > GFP_HIGHMEM and kmapping them) and then copy the data to them. Stop > when you get to the wsize limit, and issue a CIFSSMBWrite2 call. When > it returns, pick up where you left off and do it again. May be I should allocate buffer of min(wsize, write_len) size, fill it with a data to write on cycle and issue a cifs_write with this buffer. 1) get write data len into 'len' 2) buf = kmalloc(min(wsize, len), GFP_KERNEL) 3) last_ind = 0, last_len = iov[0].iov_len 4) while (len > 0){ cur_len = min(len, last_len) memcpy(buf, iov[last_ind].iov_base + iov[last_ind].iov_len - last_len, cur_len) len -= cur_len last_len -= cur_len if (last_len == 0) { last_ind++ last_len = iov[last_ind].iov_len } cifs_write(buf) } So - it is like the way I do in read part (cifs_fill_iov). Thoughts? > >> + for (i = 0, offset = buf; i < nr_segs; i++) { >> + if (copy_from_user(offset, iov[i].iov_base, iov[i].iov_len)) { >> + kfree(buf); >> + return -EFAULT; >> + } >> + >> + offset += iov[i].iov_len; >> + } >> + >> + written = cifs_write((struct cifsFileInfo *)iocb->ki_filp->private_data, >> + buf, len, &pos); >> + if (written < 0) { >> + kfree(buf); >> + return written; >> + } >> + >> + iocb->ki_pos = pos; >> + >> + if (written > 0) >> + CIFS_I(inode)->invalid_mapping = true; >> + >> + kfree(buf); >> + return written; >> +} >> + >> static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, >> unsigned long nr_segs, loff_t pos) >> { >> struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; >> ssize_t written; >> + int rc; >> >> written = generic_file_aio_write(iocb, iov, nr_segs, pos); >> - if (!CIFS_I(inode)->clientCanCacheAll) >> - filemap_fdatawrite(inode->i_mapping); >> + >> + if (CIFS_I(inode)->clientCanCacheAll) >> + return written; >> + >> + rc = filemap_fdatawrite(inode->i_mapping); >> + if (rc) >> + cFYI(1, "cifs_file_aio_write: %d rc on %p inode", rc, inode); >> + >> return written; >> } >> >> @@ -714,7 +780,7 @@ const struct file_operations cifs_file_strict_ops = { >> .read = do_sync_read, >> .write = do_sync_write, >> .aio_read = generic_file_aio_read, >> - .aio_write = cifs_file_aio_write, >> + .aio_write = cifs_strict_write, >> .open = cifs_open, >> .release = cifs_close, >> .lock = cifs_lock, >> @@ -770,7 +836,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = { >> .read = do_sync_read, >> .write = do_sync_write, >> .aio_read = generic_file_aio_read, >> - .aio_write = cifs_file_aio_write, >> + .aio_write = cifs_strict_write, >> .open = cifs_open, >> .release = cifs_close, >> .fsync = cifs_strict_fsync, >> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h >> index e6d1481..3a337a9 100644 >> --- a/fs/cifs/cifsproto.h >> +++ b/fs/cifs/cifsproto.h >> @@ -79,6 +79,9 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); >> extern bool is_valid_oplock_break(struct smb_hdr *smb, >> struct TCP_Server_Info *); >> extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); >> +extern ssize_t cifs_write(struct cifsFileInfo *open_file, >> + const char *write_data, size_t write_size, >> + loff_t *poffset); >> extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); >> extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); >> extern unsigned int smbCalcSize(struct smb_hdr *ptr); >> diff --git a/fs/cifs/file.c b/fs/cifs/file.c >> index dd1e59a..2c848ef 100644 >> --- a/fs/cifs/file.c >> +++ b/fs/cifs/file.c >> @@ -1026,9 +1026,8 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, >> return total_written; >> } >> >> -static ssize_t cifs_write(struct cifsFileInfo *open_file, >> - const char *write_data, size_t write_size, >> - loff_t *poffset) >> +ssize_t cifs_write(struct cifsFileInfo *open_file, const char *write_data, >> + size_t write_size, loff_t *poffset) >> { >> int rc = 0; >> unsigned int bytes_written = 0; > > > -- > Jeff Layton <jlayton@xxxxxxxxxx> > -- Best regards, Pavel Shilovsky. -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html