Loading fs/cifs/cifsproto.h +1 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int is_valid_oplock_break(struct smb_hdr *smb); extern int is_size_safe_to_change(struct cifsInodeInfo *); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, Loading fs/cifs/file.c +35 −77 Original line number Diff line number Diff line Loading @@ -904,6 +904,25 @@ static ssize_t cifs_write(struct file *file, const char *write_data, return total_written; } static struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) { struct cifsFileInfo *open_file; read_lock(&GlobalSMBSeslock); list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { if (open_file->closePend) continue; if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { read_unlock(&GlobalSMBSeslock); return open_file; } } read_unlock(&GlobalSMBSeslock); return NULL; } static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) { struct address_space *mapping = page->mapping; Loading @@ -914,10 +933,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; struct inode *inode; struct cifsInodeInfo *cifsInode; struct cifsFileInfo *open_file = NULL; struct list_head *tmp; struct list_head *tmp1; struct cifsFileInfo *open_file; if (!mapping || !mapping->host) return -EFAULT; Loading Loading @@ -945,49 +961,19 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) if (mapping->host->i_size - offset < (loff_t)to) to = (unsigned)(mapping->host->i_size - offset); cifsInode = CIFS_I(mapping->host); read_lock(&GlobalSMBSeslock); /* BB we should start at the end */ list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, flist); if (open_file->closePend) continue; /* We check if file is open for writing first */ if ((open_file->pfile) && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { read_unlock(&GlobalSMBSeslock); bytes_written = cifs_write(open_file->pfile, write_data, to-from, &offset); read_lock(&GlobalSMBSeslock); open_file = find_writable_file(CIFS_I(mapping->host)); if (open_file) { bytes_written = cifs_write(open_file->pfile, write_data, to-from, &offset); /* Does mm or vfs already set times? */ inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); if ((bytes_written > 0) && (offset)) { rc = 0; } else if (bytes_written < 0) { if (rc == -EBADF) { /* have seen a case in which kernel seemed to have closed/freed a file even with writes active so we might as well see if there are other file structs to try for the same inode before giving up */ continue; } else if (rc != -EBADF) rc = bytes_written; } break; /* now that we found a valid file handle and tried to write to it we are done, no sense continuing to loop looking for another */ } if (tmp->next == NULL) { cFYI(1, ("File instance %p removed", tmp)); break; } } read_unlock(&GlobalSMBSeslock); if (open_file == NULL) { } else { cFYI(1, ("No writeable filehandles for inode")); rc = -EIO; } Loading Loading @@ -1604,40 +1590,12 @@ static int cifs_readpage(struct file *file, struct page *page) page caching in the current Linux kernel design */ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) { struct list_head *tmp; struct list_head *tmp1; struct cifsFileInfo *open_file = NULL; int rc = TRUE; if (cifsInode == NULL) return rc; read_lock(&GlobalSMBSeslock); list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, flist); if (open_file == NULL) break; if (open_file->closePend) continue; /* We check if file is open for writing, BB we could supplement this with a check to see if file size changes have been flushed to server - ie inode metadata dirty */ if ((open_file->pfile) && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { rc = FALSE; break; } if (tmp->next == NULL) { cFYI(1, ("File instance %p removed", tmp)); break; } } read_unlock(&GlobalSMBSeslock); return rc; if (cifsInode && find_writable_file(cifsInode)) return 0; else return 1; } static int cifs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { Loading fs/cifs/inode.c +14 −42 Original line number Diff line number Diff line Loading @@ -995,7 +995,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) filemap_fdatawait(direntry->d_inode->i_mapping); if (attrs->ia_valid & ATTR_SIZE) { read_lock(&GlobalSMBSeslock); /* To avoid spurious oplock breaks from server, in the case of inodes that we already have open, avoid doing path based setting of file size if we can do it by handle. Loading @@ -1003,49 +1002,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) when the local oplock break takes longer to flush writebehind data than the SMB timeout for the SetPathInfo request would allow */ list_for_each(tmp, &cifsInode->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, flist); /* We check if file is open for writing first */ if ((open_file->pfile) && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { if (open_file->invalidHandle == FALSE) { /* we found a valid, writeable network file handle to use to try to set the file size */ open_file = find_writable_file(cifsInode); if (open_file) { __u16 nfid = open_file->netfid; __u32 npid = open_file->pid; read_unlock(&GlobalSMBSeslock); found = TRUE; rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, npid, FALSE); cFYI(1, ("SetFileSize by handle " "(setattrs) rc = %d", rc)); /* Do not need reopen and retry on EAGAIN since we will retry by pathname below */ /* now that we found one valid file handle no sense continuing to loop trying others, so break here */ rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, npid, FALSE); cFYI(1,("SetFSize for attrs rc = %d", rc)); if(rc == -EINVAL) { int bytes_written; rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size, &bytes_written, NULL, NULL, 1 /* 45 sec */); cFYI(1,("wrt seteof rc %d",rc)); nfid, 0, attrs->ia_size, &bytes_written, NULL, NULL, 1 /* 45 seconds */); cFYI(1,("Wrt seteof rc %d", rc)); } break; } } } if (found == FALSE) read_unlock(&GlobalSMBSeslock); if (rc != 0) { /* Set file size by pathname rather than by handle either because no valid, writeable file handle for Loading Loading
fs/cifs/cifsproto.h +1 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int is_valid_oplock_break(struct smb_hdr *smb); extern int is_size_safe_to_change(struct cifsInodeInfo *); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, Loading
fs/cifs/file.c +35 −77 Original line number Diff line number Diff line Loading @@ -904,6 +904,25 @@ static ssize_t cifs_write(struct file *file, const char *write_data, return total_written; } static struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) { struct cifsFileInfo *open_file; read_lock(&GlobalSMBSeslock); list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { if (open_file->closePend) continue; if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { read_unlock(&GlobalSMBSeslock); return open_file; } } read_unlock(&GlobalSMBSeslock); return NULL; } static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) { struct address_space *mapping = page->mapping; Loading @@ -914,10 +933,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; struct inode *inode; struct cifsInodeInfo *cifsInode; struct cifsFileInfo *open_file = NULL; struct list_head *tmp; struct list_head *tmp1; struct cifsFileInfo *open_file; if (!mapping || !mapping->host) return -EFAULT; Loading Loading @@ -945,49 +961,19 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) if (mapping->host->i_size - offset < (loff_t)to) to = (unsigned)(mapping->host->i_size - offset); cifsInode = CIFS_I(mapping->host); read_lock(&GlobalSMBSeslock); /* BB we should start at the end */ list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, flist); if (open_file->closePend) continue; /* We check if file is open for writing first */ if ((open_file->pfile) && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { read_unlock(&GlobalSMBSeslock); bytes_written = cifs_write(open_file->pfile, write_data, to-from, &offset); read_lock(&GlobalSMBSeslock); open_file = find_writable_file(CIFS_I(mapping->host)); if (open_file) { bytes_written = cifs_write(open_file->pfile, write_data, to-from, &offset); /* Does mm or vfs already set times? */ inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); if ((bytes_written > 0) && (offset)) { rc = 0; } else if (bytes_written < 0) { if (rc == -EBADF) { /* have seen a case in which kernel seemed to have closed/freed a file even with writes active so we might as well see if there are other file structs to try for the same inode before giving up */ continue; } else if (rc != -EBADF) rc = bytes_written; } break; /* now that we found a valid file handle and tried to write to it we are done, no sense continuing to loop looking for another */ } if (tmp->next == NULL) { cFYI(1, ("File instance %p removed", tmp)); break; } } read_unlock(&GlobalSMBSeslock); if (open_file == NULL) { } else { cFYI(1, ("No writeable filehandles for inode")); rc = -EIO; } Loading Loading @@ -1604,40 +1590,12 @@ static int cifs_readpage(struct file *file, struct page *page) page caching in the current Linux kernel design */ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) { struct list_head *tmp; struct list_head *tmp1; struct cifsFileInfo *open_file = NULL; int rc = TRUE; if (cifsInode == NULL) return rc; read_lock(&GlobalSMBSeslock); list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, flist); if (open_file == NULL) break; if (open_file->closePend) continue; /* We check if file is open for writing, BB we could supplement this with a check to see if file size changes have been flushed to server - ie inode metadata dirty */ if ((open_file->pfile) && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { rc = FALSE; break; } if (tmp->next == NULL) { cFYI(1, ("File instance %p removed", tmp)); break; } } read_unlock(&GlobalSMBSeslock); return rc; if (cifsInode && find_writable_file(cifsInode)) return 0; else return 1; } static int cifs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { Loading
fs/cifs/inode.c +14 −42 Original line number Diff line number Diff line Loading @@ -995,7 +995,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) filemap_fdatawait(direntry->d_inode->i_mapping); if (attrs->ia_valid & ATTR_SIZE) { read_lock(&GlobalSMBSeslock); /* To avoid spurious oplock breaks from server, in the case of inodes that we already have open, avoid doing path based setting of file size if we can do it by handle. Loading @@ -1003,49 +1002,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) when the local oplock break takes longer to flush writebehind data than the SMB timeout for the SetPathInfo request would allow */ list_for_each(tmp, &cifsInode->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, flist); /* We check if file is open for writing first */ if ((open_file->pfile) && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { if (open_file->invalidHandle == FALSE) { /* we found a valid, writeable network file handle to use to try to set the file size */ open_file = find_writable_file(cifsInode); if (open_file) { __u16 nfid = open_file->netfid; __u32 npid = open_file->pid; read_unlock(&GlobalSMBSeslock); found = TRUE; rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, npid, FALSE); cFYI(1, ("SetFileSize by handle " "(setattrs) rc = %d", rc)); /* Do not need reopen and retry on EAGAIN since we will retry by pathname below */ /* now that we found one valid file handle no sense continuing to loop trying others, so break here */ rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, npid, FALSE); cFYI(1,("SetFSize for attrs rc = %d", rc)); if(rc == -EINVAL) { int bytes_written; rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size, &bytes_written, NULL, NULL, 1 /* 45 sec */); cFYI(1,("wrt seteof rc %d",rc)); nfid, 0, attrs->ia_size, &bytes_written, NULL, NULL, 1 /* 45 seconds */); cFYI(1,("Wrt seteof rc %d", rc)); } break; } } } if (found == FALSE) read_unlock(&GlobalSMBSeslock); if (rc != 0) { /* Set file size by pathname rather than by handle either because no valid, writeable file handle for Loading