diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 316 |
1 files changed, 167 insertions, 149 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 94d5b49049d..894b1f7b299 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -2,8 +2,8 @@ * fs/cifs/file.c * * vfs operations that deal with files - * - * Copyright (C) International Business Machines Corp., 2002,2003 + * + * Copyright (C) International Business Machines Corp., 2002,2007 * Author(s): Steve French (sfrench@us.ibm.com) * Jeremy Allison (jra@samba.org) * @@ -45,7 +45,7 @@ static inline struct cifsFileInfo *cifs_init_private( { memset(private_data, 0, sizeof(struct cifsFileInfo)); private_data->netfid = netfid; - private_data->pid = current->tgid; + private_data->pid = current->tgid; init_MUTEX(&private_data->fh_sem); mutex_init(&private_data->lock_mutex); INIT_LIST_HEAD(&private_data->llist); @@ -57,7 +57,7 @@ static inline struct cifsFileInfo *cifs_init_private( does not tell us which handle the write is for so there can be a close (overlapping with write) of the filehandle that cifs_writepages chose to use */ - atomic_set(&private_data->wrtPending,0); + atomic_set(&private_data->wrtPending, 0); return private_data; } @@ -105,7 +105,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, in the list so we do not have to walk the list to search for one in prepare_write */ if ((file->f_flags & O_ACCMODE) == O_WRONLY) { - list_add_tail(&pCifsFile->flist, + list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList); } else { list_add(&pCifsFile->flist, @@ -138,7 +138,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, } client_can_cache: - if (pTcon->ses->capabilities & CAP_UNIX) + if (pTcon->unix_ext) rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode, full_path, inode->i_sb, xid); else @@ -189,7 +189,7 @@ int cifs_open(struct inode *inode, struct file *file) /* needed for writepage */ pCifsFile->pfile = file; - + file->private_data = pCifsFile; break; } @@ -212,15 +212,15 @@ int cifs_open(struct inode *inode, struct file *file) return -ENOMEM; } - cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", + cFYI(1, ("inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags, full_path)); desiredAccess = cifs_convert_flags(file->f_flags); /********************************************************************* * open flag mapping table: - * + * * POSIX Flag CIFS Disposition - * ---------- ---------------- + * ---------- ---------------- * O_CREAT FILE_OPEN_IF * O_CREAT | O_EXCL FILE_CREATE * O_CREAT | O_TRUNC FILE_OVERWRITE_IF @@ -228,12 +228,12 @@ int cifs_open(struct inode *inode, struct file *file) * none of the above FILE_OPEN * * Note that there is not a direct match between disposition - * FILE_SUPERSEDE (ie create whether or not file exists although + * FILE_SUPERSEDE (ie create whether or not file exists although * O_CREAT | O_TRUNC is similar but truncates the existing * file rather than creating a new file as FILE_SUPERSEDE does * (which uses the attributes / metadata passed in on open call) *? - *? O_SYNC is a reasonable match to CIFS writethrough flag + *? O_SYNC is a reasonable match to CIFS writethrough flag *? and the read write flags match reasonably. O_LARGEFILE *? is irrelevant because largefile support is always used *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, @@ -253,8 +253,8 @@ int cifs_open(struct inode *inode, struct file *file) and calling get_inode_info with returned buf (at least helps non-Unix server case) */ - /* BB we can not do this if this is the second open of a file - and the first handle has writebehind data, we might be + /* BB we can not do this if this is the second open of a file + and the first handle has writebehind data, we might be able to simply do a filemap_fdatawrite/filemap_fdatawait first */ buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); if (!buf) { @@ -263,7 +263,7 @@ int cifs_open(struct inode *inode, struct file *file) } if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) - rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -300,15 +300,15 @@ int cifs_open(struct inode *inode, struct file *file) write_unlock(&GlobalSMBSeslock); } - if (oplock & CIFS_CREATE_ACTION) { + if (oplock & CIFS_CREATE_ACTION) { /* time to set mode which we can not set earlier due to problems creating new read-only files */ - if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { + if (pTcon->unix_ext) { CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, (__u64)-1, (__u64)-1, 0 /* dev */, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else { /* BB implement via Windows security descriptors eg @@ -345,7 +345,7 @@ static int cifs_reopen_file(struct file *file, int can_flush) struct cifsTconInfo *pTcon; struct cifsFileInfo *pCifsFile; struct cifsInodeInfo *pCifsInode; - struct inode * inode; + struct inode *inode; char *full_path = NULL; int desiredAccess; int disposition = FILE_OPEN; @@ -372,13 +372,13 @@ static int cifs_reopen_file(struct file *file, int can_flush) } inode = file->f_path.dentry->d_inode; - if(inode == NULL) { + if (inode == NULL) { cERROR(1, ("inode not valid")); dump_stack(); rc = -EBADF; goto reopen_error_exit; } - + cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; @@ -396,7 +396,7 @@ reopen_error_exit: } cFYI(1, ("inode = 0x%p file flags 0x%x for %s", - inode, file->f_flags,full_path)); + inode, file->f_flags, full_path)); desiredAccess = cifs_convert_flags(file->f_flags); if (oplockEnabled) @@ -405,14 +405,14 @@ reopen_error_exit: oplock = FALSE; /* Can not refresh inode by passing in file_info buf to be returned - by SMBOpen and then calling get_inode_info with returned buf - since file might have write behind data that needs to be flushed + by SMBOpen and then calling get_inode_info with returned buf + since file might have write behind data that needs to be flushed and server version of file size can be stale. If we knew for sure that inode was not dirty locally we could do this */ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, NULL, - cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { up(&pCifsFile->fh_sem); @@ -430,7 +430,7 @@ reopen_error_exit: go to server to get inode info */ pCifsInode->clientCanCacheAll = FALSE; pCifsInode->clientCanCacheRead = FALSE; - if (pTcon->ses->capabilities & CAP_UNIX) + if (pTcon->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, xid); else @@ -486,23 +486,24 @@ int cifs_close(struct inode *inode, struct file *file) already closed */ if (pTcon->tidStatus != CifsNeedReconnect) { int timeout = 2; - while((atomic_read(&pSMBFile->wrtPending) != 0) + while ((atomic_read(&pSMBFile->wrtPending) != 0) && (timeout < 1000) ) { /* Give write a better chance to get to server ahead of the close. We do not want to add a wait_q here as it would increase the memory utilization as the struct would be in each open file, - but this should give enough time to + but this should give enough time to clear the socket */ #ifdef CONFIG_CIFS_DEBUG2 - cFYI(1,("close delay, write pending")); + cFYI(1, ("close delay, write pending")); #endif /* DEBUG2 */ msleep(timeout); timeout *= 4; } - if(atomic_read(&pSMBFile->wrtPending)) - cERROR(1,("close with pending writes")); + if (atomic_read(&pSMBFile->wrtPending)) + cERROR(1, + ("close with pending writes")); rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid); } @@ -534,7 +535,7 @@ int cifs_close(struct inode *inode, struct file *file) CIFS_I(inode)->clientCanCacheRead = FALSE; CIFS_I(inode)->clientCanCacheAll = FALSE; } - if ((rc ==0) && CIFS_I(inode)->write_behind_rc) + if ((rc == 0) && CIFS_I(inode)->write_behind_rc) rc = CIFS_I(inode)->write_behind_rc; FreeXid(xid); return rc; @@ -554,7 +555,8 @@ int cifs_closedir(struct inode *inode, struct file *file) if (pCFileStruct) { struct cifsTconInfo *pTcon; - struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); + struct cifs_sb_info *cifs_sb = + CIFS_SB(file->f_path.dentry->d_sb); pTcon = cifs_sb->tcon; @@ -572,7 +574,7 @@ int cifs_closedir(struct inode *inode, struct file *file) if (ptmp) { cFYI(1, ("closedir free smb buf in srch struct")); pCFileStruct->srch_inf.ntwrk_buf_start = NULL; - if(pCFileStruct->srch_inf.smallBuf) + if (pCFileStruct->srch_inf.smallBuf) cifs_small_buf_release(ptmp); else cifs_buf_release(ptmp); @@ -594,7 +596,8 @@ int cifs_closedir(struct inode *inode, struct file *file) static int store_file_lock(struct cifsFileInfo *fid, __u64 len, __u64 offset, __u8 lockType) { - struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); + struct cifsLockInfo *li = + kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); if (li == NULL) return -ENOMEM; li->offset = offset; @@ -625,8 +628,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) cFYI(1, ("Lock parm: 0x%x flockflags: " "0x%x flocktype: 0x%x start: %lld end: %lld", - cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start, - pfLock->fl_end)); + cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start, + pfLock->fl_end)); if (pfLock->fl_flags & FL_POSIX) cFYI(1, ("Posix")); @@ -641,7 +644,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) "not implemented yet")); if (pfLock->fl_flags & FL_LEASE) cFYI(1, ("Lease on file - not implemented yet")); - if (pfLock->fl_flags & + if (pfLock->fl_flags & (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE))) cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags)); @@ -683,9 +686,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) account for negative length which we can not accept over the wire */ if (IS_GETLK(cmd)) { - if(posix_locking) { + if (posix_locking) { int posix_lock_type; - if(lockType & LOCKING_ANDX_SHARED_LOCK) + if (lockType & LOCKING_ANDX_SHARED_LOCK) posix_lock_type = CIFS_RDLCK; else posix_lock_type = CIFS_WRLCK; @@ -700,7 +703,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, 0, 1, lockType, 0 /* wait flag */ ); if (rc == 0) { - rc = CIFSSMBLock(xid, pTcon, netfid, length, + rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, 1 /* numUnlock */ , 0 /* numLock */ , lockType, 0 /* wait flag */ ); @@ -729,22 +732,24 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) if (posix_locking) { int posix_lock_type; - if(lockType & LOCKING_ANDX_SHARED_LOCK) + if (lockType & LOCKING_ANDX_SHARED_LOCK) posix_lock_type = CIFS_RDLCK; else posix_lock_type = CIFS_WRLCK; - - if(numUnlock == 1) + + if (numUnlock == 1) posix_lock_type = CIFS_UNLCK; rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */, length, pfLock, posix_lock_type, wait_flag); } else { - struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data; + struct cifsFileInfo *fid = + (struct cifsFileInfo *)file->private_data; if (numLock) { - rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, + rc = CIFSSMBLock(xid, pTcon, netfid, length, + pfLock->fl_start, 0, numLock, lockType, wait_flag); if (rc == 0) { @@ -763,7 +768,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) list_for_each_entry_safe(li, tmp, &fid->llist, llist) { if (pfLock->fl_start <= li->offset && length >= li->length) { - stored_rc = CIFSSMBLock(xid, pTcon, netfid, + stored_rc = CIFSSMBLock(xid, pTcon, + netfid, li->length, li->offset, 1, 0, li->type, FALSE); if (stored_rc) @@ -805,7 +811,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, if (file->private_data == NULL) return -EBADF; open_file = (struct cifsFileInfo *) file->private_data; - + xid = GetXid(); if (*poffset > file->f_path.dentry->d_inode->i_size) @@ -824,7 +830,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, and blocked, and the file has been freed on us while we blocked so return what we managed to write */ return total_written; - } + } if (open_file->closePend) { FreeXid(xid); if (total_written) @@ -867,8 +873,8 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, /* since the write may have blocked check these pointers again */ 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 = +/* 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); @@ -877,7 +883,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, *poffset); spin_unlock(&inode->i_lock); } - mark_inode_dirty_sync(file->f_path.dentry->d_inode); + mark_inode_dirty_sync(file->f_path.dentry->d_inode); } FreeXid(xid); return total_written; @@ -898,13 +904,13 @@ static ssize_t cifs_write(struct file *file, const char *write_data, pTcon = cifs_sb->tcon; - cFYI(1,("write %zd bytes to offset %lld of %s", write_size, + cFYI(1, ("write %zd bytes to offset %lld of %s", write_size, *poffset, file->f_path.dentry->d_name.name)); if (file->private_data == NULL) return -EBADF; open_file = (struct cifsFileInfo *)file->private_data; - + xid = GetXid(); if (*poffset > file->f_path.dentry->d_inode->i_size) @@ -921,10 +927,10 @@ static ssize_t cifs_write(struct file *file, const char *write_data, FreeXid(xid); /* if we have gotten here we have written some data and blocked, and the file has been freed on us - while we blocked so return what we managed to + while we blocked so return what we managed to write */ return total_written; - } + } if (open_file->closePend) { FreeXid(xid); if (total_written) @@ -935,14 +941,14 @@ static ssize_t cifs_write(struct file *file, const char *write_data, if (open_file->invalidHandle) { /* we could deadlock if we called filemap_fdatawait from here so tell - reopen_file not to flush data to + reopen_file not to flush data to server now */ rc = cifs_reopen_file(file, FALSE); if (rc != 0) break; } - if(experimEnabled || (pTcon->ses->server && - ((pTcon->ses->server->secMode & + if (experimEnabled || (pTcon->ses->server && + ((pTcon->ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0))) { struct kvec iov[2]; @@ -976,7 +982,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, } } else *poffset += bytes_written; - long_op = FALSE; /* subsequent writes fast - + long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */ } @@ -1009,8 +1015,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) the VFS or MM) should not happen but we had reports of on oops (due to it being zero) during stress testcases so we need to check for it */ - if(cifs_inode == NULL) { - cERROR(1,("Null inode passed to cifs_writeable_file")); + if (cifs_inode == NULL) { + cERROR(1, ("Null inode passed to cifs_writeable_file")); dump_stack(); return NULL; } @@ -1024,13 +1030,14 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) (open_file->pfile->f_flags & O_WRONLY))) { atomic_inc(&open_file->wrtPending); read_unlock(&GlobalSMBSeslock); - if((open_file->invalidHandle) && + if ((open_file->invalidHandle) && (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) { rc = cifs_reopen_file(open_file->pfile, FALSE); /* if it fails, try another handle - might be */ /* dangerous to hold up writepages with retry */ - if(rc) { - cFYI(1,("failed on reopen file in wp")); + if (rc) { + cFYI(1, + ("failed on reopen file in wp")); read_lock(&GlobalSMBSeslock); /* can not use this handle, no write pending on this one after all */ @@ -1082,7 +1089,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) /* check to make sure that we are not extending the file */ if (mapping->host->i_size - offset < (loff_t)to) - to = (unsigned)(mapping->host->i_size - offset); + to = (unsigned)(mapping->host->i_size - offset); open_file = find_writable_file(CIFS_I(mapping->host)); if (open_file) { @@ -1116,8 +1123,8 @@ static int cifs_writepages(struct address_space *mapping, int done = 0; pgoff_t end; pgoff_t index; - int range_whole = 0; - struct kvec * iov; + int range_whole = 0; + struct kvec *iov; int len; int n_iov = 0; pgoff_t next; @@ -1131,7 +1138,7 @@ static int cifs_writepages(struct address_space *mapping, int xid; cifs_sb = CIFS_SB(mapping->host->i_sb); - + /* * If wsize is smaller that the page cache size, default to writing * one page at a time via cifs_writepage @@ -1139,14 +1146,14 @@ static int cifs_writepages(struct address_space *mapping, if (cifs_sb->wsize < PAGE_CACHE_SIZE) return generic_writepages(mapping, wbc); - 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 ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) + if (cifs_sb->tcon->ses->server->secMode & + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + if (!experimEnabled) return generic_writepages(mapping, wbc); iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL); - if(iov == NULL) + if (iov == NULL) return generic_writepages(mapping, wbc); @@ -1279,7 +1286,7 @@ retry: 1); atomic_dec(&open_file->wrtPending); if (rc || bytes_written < bytes_to_write) { - cERROR(1,("Write2 ret %d, written = %d", + cERROR(1, ("Write2 ret %d, wrote %d", rc, bytes_written)); /* BB what if continued retry is requested via mount flags? */ @@ -1295,8 +1302,8 @@ retry: success rc but too little data written? */ /* BB investigate retry logic on temporary server crash cases and how recovery works - when page marked as error */ - if(rc) + when page marked as error */ + if (rc) SetPageError(page); kunmap(page); unlock_page(page); @@ -1326,7 +1333,7 @@ retry: return rc; } -static int cifs_writepage(struct page* page, struct writeback_control *wbc) +static int cifs_writepage(struct page *page, struct writeback_control *wbc) { int rc = -EFAULT; int xid; @@ -1334,7 +1341,7 @@ static int cifs_writepage(struct page* page, struct writeback_control *wbc) xid = GetXid(); /* BB add check for wbc flags */ page_cache_get(page); - if (!PageUptodate(page)) { + if (!PageUptodate(page)) { cFYI(1, ("ppw - page not up to date")); } @@ -1348,7 +1355,7 @@ static int cifs_writepage(struct page* page, struct writeback_control *wbc) * 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); + set_page_writeback(page); rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE); SetPageUptodate(page); /* BB add check for error and Clearuptodate? */ unlock_page(page); @@ -1368,7 +1375,7 @@ static int cifs_commit_write(struct file *file, struct page *page, char *page_data; xid = GetXid(); - cFYI(1, ("commit write for page %p up to position %lld for %d", + 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) { @@ -1396,7 +1403,7 @@ static int cifs_commit_write(struct file *file, struct page *page, rc = 0; /* else if (rc < 0) should we set writebehind rc? */ kunmap(page); - } else { + } else { set_page_dirty(page); } @@ -1412,9 +1419,9 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) xid = GetXid(); - cFYI(1, ("Sync file - name: %s datasync: 0x%x", + cFYI(1, ("Sync file - name: %s datasync: 0x%x", dentry->d_name.name, datasync)); - + rc = filemap_fdatawrite(inode->i_mapping); if (rc == 0) CIFS_I(inode)->write_behind_rc = 0; @@ -1438,7 +1445,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) if (!inode) return; */ -/* fill in rpages then +/* fill in rpages then result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */ /* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index)); @@ -1456,7 +1463,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) */ int cifs_flush(struct file *file, fl_owner_t id) { - struct inode * inode = file->f_path.dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; int rc = 0; /* Rather than do the steps manually: @@ -1471,8 +1478,8 @@ int cifs_flush(struct file *file, fl_owner_t id) rc = filemap_fdatawrite(inode->i_mapping); if (!rc) /* reset wb rc if we were able to write out dirty pages */ CIFS_I(inode)->write_behind_rc = 0; - - cFYI(1, ("Flush inode %p file %p rc %d",inode,file,rc)); + + cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc)); return rc; } @@ -1508,13 +1515,13 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, for (total_read = 0, current_offset = read_data; read_size > total_read; total_read += bytes_read, current_offset += bytes_read) { - current_read_size = min_t(const int, read_size - total_read, + current_read_size = min_t(const int, read_size - total_read, cifs_sb->rsize); rc = -EAGAIN; smb_read_data = NULL; while (rc == -EAGAIN) { int buf_type = CIFS_NO_BUFFER; - if ((open_file->invalidHandle) && + if ((open_file->invalidHandle) && (!open_file->closePend)) { rc = cifs_reopen_file(file, TRUE); if (rc != 0) @@ -1535,9 +1542,9 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, rc = -EFAULT; } - if(buf_type == CIFS_SMALL_BUFFER) + if (buf_type == CIFS_SMALL_BUFFER) cifs_small_buf_release(smb_read_data); - else if(buf_type == CIFS_LARGE_BUFFER) + else if (buf_type == CIFS_LARGE_BUFFER) cifs_buf_release(smb_read_data); smb_read_data = NULL; } @@ -1586,21 +1593,21 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, if ((file->f_flags & O_ACCMODE) == O_WRONLY) cFYI(1, ("attempting read on write only file instance")); - for (total_read = 0, current_offset = read_data; + for (total_read = 0, current_offset = read_data; read_size > total_read; total_read += bytes_read, current_offset += bytes_read) { current_read_size = min_t(const int, read_size - total_read, cifs_sb->rsize); /* For windows me and 9x we do not want to request more than it negotiated since it will refuse the read then */ - if((pTcon->ses) && + if ((pTcon->ses) && !(pTcon->ses->capabilities & CAP_LARGE_FILES)) { current_read_size = min_t(const int, current_read_size, pTcon->ses->server->maxBuf - 128); } rc = -EAGAIN; while (rc == -EAGAIN) { - if ((open_file->invalidHandle) && + if ((open_file->invalidHandle) && (!open_file->closePend)) { rc = cifs_reopen_file(file, TRUE); if (rc != 0) @@ -1646,7 +1653,7 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) } -static void cifs_copy_cache_pages(struct address_space *mapping, +static void cifs_copy_cache_pages(struct address_space *mapping, struct list_head *pages, int bytes_read, char *data, struct pagevec *plru_pvec) { @@ -1669,12 +1676,12 @@ static void cifs_copy_cache_pages(struct address_space *mapping, continue; } - target = kmap_atomic(page,KM_USER0); + target = kmap_atomic(page, KM_USER0); if (PAGE_CACHE_SIZE > bytes_read) { memcpy(target, data, bytes_read); /* zero the tail end of this partial page */ - memset(target + bytes_read, 0, + memset(target + bytes_read, 0, PAGE_CACHE_SIZE - bytes_read); bytes_read = 0; } else { @@ -1703,7 +1710,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int bytes_read = 0; - unsigned int read_size,i; + unsigned int read_size, i; char *smb_read_data = NULL; struct smb_com_read_rsp *pSMBr; struct pagevec lru_pvec; @@ -1720,7 +1727,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, pTcon = cifs_sb->tcon; pagevec_init(&lru_pvec, 0); - +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("rpages: num pages %d", num_pages)); +#endif for (i = 0; i < num_pages; ) { unsigned contig_pages; struct page *tmp_page; @@ -1734,14 +1743,14 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, /* count adjacent pages that we will read into */ contig_pages = 0; - expected_index = + expected_index = list_entry(page_list->prev, struct page, lru)->index; - list_for_each_entry_reverse(tmp_page,page_list,lru) { + list_for_each_entry_reverse(tmp_page, page_list, lru) { if (tmp_page->index == expected_index) { contig_pages++; expected_index++; } else - break; + break; } if (contig_pages + i > num_pages) contig_pages = num_pages - i; @@ -1753,10 +1762,13 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, /* Read size needs to be in multiples of one page */ read_size = min_t(const unsigned int, read_size, cifs_sb->rsize & PAGE_CACHE_MASK); - +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("rpages: read size 0x%x contiguous pages %d", + read_size, contig_pages)); +#endif rc = -EAGAIN; while (rc == -EAGAIN) { - if ((open_file->invalidHandle) && + if ((open_file->invalidHandle) && (!open_file->closePend)) { rc = cifs_reopen_file(file, TRUE); if (rc != 0) @@ -1769,11 +1781,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, &bytes_read, &smb_read_data, &buf_type); /* BB more RC checks ? */ - if (rc== -EAGAIN) { + if (rc == -EAGAIN) { if (smb_read_data) { - if(buf_type == CIFS_SMALL_BUFFER) + if (buf_type == CIFS_SMALL_BUFFER) cifs_small_buf_release(smb_read_data); - else if(buf_type == CIFS_LARGE_BUFFER) + else if (buf_type == CIFS_LARGE_BUFFER) cifs_buf_release(smb_read_data); smb_read_data = NULL; } @@ -1794,10 +1806,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { i++; /* account for partial page */ - /* server copy of file can have smaller size + /* server copy of file can have smaller size than client */ - /* BB do we need to verify this common case ? - this case is ok - if we are at server EOF + /* BB do we need to verify this common case ? + this case is ok - if we are at server EOF we will hit it on next read */ /* break; */ @@ -1806,14 +1818,14 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, cFYI(1, ("No bytes read (%d) at offset %lld . " "Cleaning remaining pages from readahead list", bytes_read, offset)); - /* BB turn off caching and do new lookup on + /* BB turn off caching and do new lookup on file size at server? */ break; } if (smb_read_data) { - if(buf_type == CIFS_SMALL_BUFFER) + if (buf_type == CIFS_SMALL_BUFFER) cifs_small_buf_release(smb_read_data); - else if(buf_type == CIFS_LARGE_BUFFER) + else if (buf_type == CIFS_LARGE_BUFFER) cifs_buf_release(smb_read_data); smb_read_data = NULL; } @@ -1824,12 +1836,12 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, /* need to free smb_read_data buf before exit */ if (smb_read_data) { - if(buf_type == CIFS_SMALL_BUFFER) + if (buf_type == CIFS_SMALL_BUFFER) cifs_small_buf_release(smb_read_data); - else if(buf_type == CIFS_LARGE_BUFFER) + else if (buf_type == CIFS_LARGE_BUFFER) cifs_buf_release(smb_read_data); smb_read_data = NULL; - } + } FreeXid(xid); return rc; @@ -1844,26 +1856,26 @@ static int cifs_readpage_worker(struct file *file, struct page *page, page_cache_get(page); read_data = kmap(page); /* for reads over a certain size could initiate async read ahead */ - + rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset); - + if (rc < 0) goto io_error; else - cFYI(1, ("Bytes read %d",rc)); - + cFYI(1, ("Bytes read %d", rc)); + file->f_path.dentry->d_inode->i_atime = current_fs_time(file->f_path.dentry->d_inode->i_sb); - + if (PAGE_CACHE_SIZE > rc) memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc); flush_dcache_page(page); SetPageUptodate(page); rc = 0; - + io_error: - kunmap(page); + kunmap(page); page_cache_release(page); return rc; } @@ -1881,7 +1893,7 @@ static int cifs_readpage(struct file *file, struct page *page) return -EBADF; } - cFYI(1, ("readpage %p at offset %d 0x%x\n", + cFYI(1, ("readpage %p at offset %d 0x%x\n", page, (int)offset, (int)offset)); rc = cifs_readpage_worker(file, page, &offset); @@ -1892,35 +1904,48 @@ static int cifs_readpage(struct file *file, struct page *page) return rc; } +static int is_inode_writable(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 1; + } + } + read_unlock(&GlobalSMBSeslock); + return 0; +} + /* We do not want to update the file size from server for inodes open for write - to avoid races with writepage extending the file - in the future we could consider allowing - refreshing the inode only on increases in the file size + 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, __u64 end_of_file) { - struct cifsFileInfo *open_file = NULL; + if (!cifsInode) + return 1; - if (cifsInode) - open_file = find_writable_file(cifsInode); - - if(open_file) { + if (is_inode_writable(cifsInode)) { + /* This inode is open for write at least once */ struct cifs_sb_info *cifs_sb; - /* there is not actually a write pending so let - this handle go free and allow it to - be closable if needed */ - atomic_dec(&open_file->wrtPending); - cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb); if ( cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO ) { - /* since no page cache to corrupt on directio + /* since no page cache to corrupt on directio we can change size safely */ return 1; } - if(i_size_read(&cifsInode->vfs_inode) < end_of_file) + if (i_size_read(&cifsInode->vfs_inode) < end_of_file) return 1; return 0; @@ -1935,7 +1960,7 @@ static int cifs_prepare_write(struct file *file, struct page *page, loff_t i_size; loff_t offset; - cFYI(1, ("prepare write for page %p from %d to %d",page,from,to)); + cFYI(1, ("prepare write for page %p from %d to %d", page, from, to)); if (PageUptodate(page)) return 0; @@ -1955,14 +1980,7 @@ static int cifs_prepare_write(struct file *file, struct page *page, * 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); + simple_prepare_write(file, page, from, to); SetPageUptodate(page); } else if ((file->f_flags & O_ACCMODE) != O_WRONLY) { /* might as well read a page, it is fast enough */ @@ -1974,8 +1992,8 @@ static int cifs_prepare_write(struct file *file, struct page *page, this will be written out by commit_write so is fine */ } - /* we do not need to pass 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; |