Actually update the fixed up compile failures.
[safe/jmp/linux-2.6] / fs / cifs / file.c
index da4f5e1..2436ed8 100644 (file)
@@ -5,6 +5,7 @@
  * 
  *   Copyright (C) International Business Machines  Corp., 2002,2003
  *   Author(s): Steve French (sfrench@us.ibm.com)
+ *              Jeremy Allison (jra@samba.org)
  *
  *   This library is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published
@@ -24,7 +25,6 @@
 #include <linux/backing-dev.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
-#include <linux/mpage.h>
 #include <linux/pagemap.h>
 #include <linux/pagevec.h>
 #include <linux/smp_lock.h>
@@ -47,6 +47,8 @@ static inline struct cifsFileInfo *cifs_init_private(
        private_data->netfid = netfid;
        private_data->pid = current->tgid;      
        init_MUTEX(&private_data->fh_sem);
+       init_MUTEX(&private_data->lock_sem);
+       INIT_LIST_HEAD(&private_data->llist);
        private_data->pfile = file; /* needed for writepage */
        private_data->pInode = inode;
        private_data->invalidHandle = FALSE;
@@ -84,6 +86,8 @@ static inline int cifs_get_disposition(unsigned int flags)
                return FILE_OVERWRITE_IF;
        else if ((flags & O_CREAT) == O_CREAT)
                return FILE_OPEN_IF;
+       else if ((flags & O_TRUNC) == O_TRUNC)
+               return FILE_OVERWRITE;
        else
                return FILE_OPEN;
 }
@@ -108,7 +112,6 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
                         &pCifsInode->openFileList);
        }
        write_unlock(&GlobalSMBSeslock);
-       write_unlock(&file->f_owner.lock);
        if (pCifsInode->clientCanCacheRead) {
                /* we have the inode open somewhere else
                   no need to discard cache data */
@@ -127,8 +130,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
                if (file->f_dentry->d_inode->i_mapping) {
                /* BB no need to lock inode until after invalidate
                   since namei code should already have it locked? */
-                       filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
-                       filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
+                       filemap_write_and_wait(file->f_dentry->d_inode->i_mapping);
                }
                cFYI(1, ("invalidating remote inode since open detected it "
                         "changed"));
@@ -200,13 +202,11 @@ int cifs_open(struct inode *inode, struct file *file)
                } else {
                        if (file->f_flags & O_EXCL)
                                cERROR(1, ("could not find file instance for "
-                                          "new file %p ", file));
+                                          "new file %p", file));
                }
        }
 
-       down(&inode->i_sb->s_vfs_rename_sem);
        full_path = build_path_from_dentry(file->f_dentry);
-       up(&inode->i_sb->s_vfs_rename_sem);
        if (full_path == NULL) {
                FreeXid(xid);
                return -ENOMEM;
@@ -261,10 +261,15 @@ int cifs_open(struct inode *inode, struct file *file)
                rc = -ENOMEM;
                goto out;
        }
-       rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
-                        CREATE_NOT_DIR, &netfid, &oplock, buf,
+
+       if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
+               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);
+       else
+               rc = -EIO; /* no NT SMB support fall into legacy open below */
+
        if (rc == -EIO) {
                /* Old server, try legacy style OpenX */
                rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
@@ -273,7 +278,7 @@ int cifs_open(struct inode *inode, struct file *file)
                                & CIFS_MOUNT_MAP_SPECIAL_CHR);
        }
        if (rc) {
-               cFYI(1, ("cifs_open returned 0x%x ", rc));
+               cFYI(1, ("cifs_open returned 0x%x", rc));
                goto out;
        }
        file->private_data =
@@ -283,7 +288,6 @@ int cifs_open(struct inode *inode, struct file *file)
                goto out;
        }
        pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
-       write_lock(&file->f_owner.lock);
        write_lock(&GlobalSMBSeslock);
        list_add(&pCifsFile->tlist, &pTcon->openFileList);
 
@@ -294,7 +298,6 @@ int cifs_open(struct inode *inode, struct file *file)
                                            &oplock, buf, full_path, xid);
        } else {
                write_unlock(&GlobalSMBSeslock);
-               write_unlock(&file->f_owner.lock);
        }
 
        if (oplock & CIFS_CREATE_ACTION) {           
@@ -323,7 +326,7 @@ out:
        return rc;
 }
 
-/* Try to reaquire byte range locks that were released when session */
+/* Try to reacquire byte range locks that were released when session */
 /* to server was lost */
 static int cifs_relock_file(struct cifsFileInfo *cifsFile)
 {
@@ -410,8 +413,8 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc) {
                up(&pCifsFile->fh_sem);
-               cFYI(1, ("cifs_open returned 0x%x ", rc));
-               cFYI(1, ("oplock: %d ", oplock));
+               cFYI(1, ("cifs_open returned 0x%x", rc));
+               cFYI(1, ("oplock: %d", oplock));
        } else {
                pCifsFile->netfid = netfid;
                pCifsFile->invalidHandle = FALSE;
@@ -419,8 +422,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
                pCifsInode = CIFS_I(inode);
                if (pCifsInode) {
                        if (can_flush) {
-                               filemap_fdatawrite(inode->i_mapping);
-                               filemap_fdatawait(inode->i_mapping);
+                               filemap_write_and_wait(inode->i_mapping);
                        /* temporarily disable caching while we
                           go to server to get inode info */
                                pCifsInode->clientCanCacheAll = FALSE;
@@ -473,8 +475,9 @@ int cifs_close(struct inode *inode, struct file *file)
        cifs_sb = CIFS_SB(inode->i_sb);
        pTcon = cifs_sb->tcon;
        if (pSMBFile) {
+               struct cifsLockInfo *li, *tmp;
+
                pSMBFile->closePend = TRUE;
-               write_lock(&file->f_owner.lock);
                if (pTcon) {
                        /* no sense reconnecting to close a file that is
                           already closed */
@@ -489,21 +492,32 @@ int cifs_close(struct inode *inode, struct file *file)
                                        the struct would be in each open file,
                                        but this should give enough time to 
                                        clear the socket */
-                                       cERROR(1,("close with pending writes"));
+#ifdef CONFIG_CIFS_DEBUG2
+                                       cFYI(1,("close delay, write pending"));
+#endif /* DEBUG2 */
                                        msleep(timeout);
                                        timeout *= 4;
-                               } 
-                               write_unlock(&file->f_owner.lock);
+                               }
+                               if(atomic_read(&pSMBFile->wrtPending))
+                                       cERROR(1,("close with pending writes"));
                                rc = CIFSSMBClose(xid, pTcon,
                                                  pSMBFile->netfid);
-                               write_lock(&file->f_owner.lock);
                        }
                }
+
+               /* Delete any outstanding lock records.
+                  We'll lose them when the file is closed anyway. */
+               down(&pSMBFile->lock_sem);
+               list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
+                       list_del(&li->llist);
+                       kfree(li);
+               }
+               up(&pSMBFile->lock_sem);
+
                write_lock(&GlobalSMBSeslock);
                list_del(&pSMBFile->flist);
                list_del(&pSMBFile->tlist);
                write_unlock(&GlobalSMBSeslock);
-               write_unlock(&file->f_owner.lock);
                kfree(pSMBFile->search_resume_name);
                kfree(file->private_data);
                file->private_data = NULL;
@@ -531,7 +545,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
            (struct cifsFileInfo *)file->private_data;
        char *ptmp;
 
-       cFYI(1, ("Closedir inode = 0x%p with ", inode));
+       cFYI(1, ("Closedir inode = 0x%p", inode));
 
        xid = GetXid();
 
@@ -553,13 +567,16 @@ int cifs_closedir(struct inode *inode, struct file *file)
                }
                ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
                if (ptmp) {
-   /* BB removeme BB */        cFYI(1, ("freeing smb buf in srch struct in closedir"));
+                       cFYI(1, ("closedir free smb buf in srch struct"));
                        pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
-                       cifs_buf_release(ptmp);
+                       if(pCFileStruct->srch_inf.smallBuf)
+                               cifs_small_buf_release(ptmp);
+                       else
+                               cifs_buf_release(ptmp);
                }
                ptmp = pCFileStruct->search_resume_name;
                if (ptmp) {
-   /* BB removeme BB */        cFYI(1, ("freeing resume name in closedir"));
+                       cFYI(1, ("closedir free resume name"));
                        pCFileStruct->search_resume_name = NULL;
                        kfree(ptmp);
                }
@@ -571,16 +588,33 @@ int cifs_closedir(struct inode *inode, struct file *file)
        return rc;
 }
 
+static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
+                               __u64 offset, __u8 lockType)
+{
+       struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
+       if (li == NULL)
+               return -ENOMEM;
+       li->offset = offset;
+       li->length = len;
+       li->type = lockType;
+       down(&fid->lock_sem);
+       list_add(&li->llist, &fid->llist);
+       up(&fid->lock_sem);
+       return 0;
+}
+
 int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 {
        int rc, xid;
-       __u32 lockType = LOCKING_ANDX_LARGE_FILES;
        __u32 numLock = 0;
        __u32 numUnlock = 0;
        __u64 length;
        int wait_flag = FALSE;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
+       __u16 netfid;
+       __u8 lockType = LOCKING_ANDX_LARGE_FILES;
+       int posix_locking;
 
        length = 1 + pfLock->fl_end - pfLock->fl_start;
        rc = -EACCES;
@@ -592,16 +626,16 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                pfLock->fl_end));
 
        if (pfLock->fl_flags & FL_POSIX)
-               cFYI(1, ("Posix "));
+               cFYI(1, ("Posix"));
        if (pfLock->fl_flags & FL_FLOCK)
-               cFYI(1, ("Flock "));
+               cFYI(1, ("Flock"));
        if (pfLock->fl_flags & FL_SLEEP) {
-               cFYI(1, ("Blocking lock "));
+               cFYI(1, ("Blocking lock"));
                wait_flag = TRUE;
        }
        if (pfLock->fl_flags & FL_ACCESS)
                cFYI(1, ("Process suspended by mandatory locking - "
-                        "not implemented yet "));
+                        "not implemented yet"));
        if (pfLock->fl_flags & FL_LEASE)
                cFYI(1, ("Lease on file - not implemented yet"));
        if (pfLock->fl_flags & 
@@ -612,21 +646,23 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                cFYI(1, ("F_WRLCK "));
                numLock = 1;
        } else if (pfLock->fl_type == F_UNLCK) {
-               cFYI(1, ("F_UNLCK "));
+               cFYI(1, ("F_UNLCK"));
                numUnlock = 1;
+               /* Check if unlock includes more than
+               one lock range */
        } else if (pfLock->fl_type == F_RDLCK) {
-               cFYI(1, ("F_RDLCK "));
+               cFYI(1, ("F_RDLCK"));
                lockType |= LOCKING_ANDX_SHARED_LOCK;
                numLock = 1;
        } else if (pfLock->fl_type == F_EXLCK) {
-               cFYI(1, ("F_EXLCK "));
+               cFYI(1, ("F_EXLCK"));
                numLock = 1;
        } else if (pfLock->fl_type == F_SHLCK) {
-               cFYI(1, ("F_SHLCK "));
+               cFYI(1, ("F_SHLCK"));
                lockType |= LOCKING_ANDX_SHARED_LOCK;
                numLock = 1;
        } else
-               cFYI(1, ("Unknown type of lock "));
+               cFYI(1, ("Unknown type of lock"));
 
        cifs_sb = CIFS_SB(file->f_dentry->d_sb);
        pTcon = cifs_sb->tcon;
@@ -635,27 +671,40 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                FreeXid(xid);
                return -EBADF;
        }
+       netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
+
+       posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
+                       (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability));
 
+       /* BB add code here to normalize offset and length to
+       account for negative length which we can not accept over the
+       wire */
        if (IS_GETLK(cmd)) {
-               rc = CIFSSMBLock(xid, pTcon,
-                                ((struct cifsFileInfo *)file->
-                                 private_data)->netfid,
-                                length,
-                                pfLock->fl_start, 0, 1, lockType,
-                                0 /* wait flag */ );
+               if(posix_locking) {
+                       int posix_lock_type;
+                       if(lockType & LOCKING_ANDX_SHARED_LOCK)
+                               posix_lock_type = CIFS_RDLCK;
+                       else
+                               posix_lock_type = CIFS_WRLCK;
+                       rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
+                                       length, pfLock,
+                                       posix_lock_type, wait_flag);
+                       FreeXid(xid);
+                       return rc;
+               }
+
+               /* BB we could chain these into one lock request BB */
+               rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+                                0, 1, lockType, 0 /* wait flag */ );
                if (rc == 0) {
-                       rc = CIFSSMBLock(xid, pTcon,
-                                        ((struct cifsFileInfo *) file->
-                                         private_data)->netfid,
-                                        length,
+                       rc = CIFSSMBLock(xid, pTcon, netfid, length, 
                                         pfLock->fl_start, 1 /* numUnlock */ ,
                                         0 /* numLock */ , lockType,
                                         0 /* wait flag */ );
                        pfLock->fl_type = F_UNLCK;
                        if (rc != 0)
                                cERROR(1, ("Error unlocking previously locked "
-                                          "range %d during test of lock ",
-                                          rc));
+                                          "range %d during test of lock", rc));
                        rc = 0;
 
                } else {
@@ -668,11 +717,63 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                return rc;
        }
 
-       rc = CIFSSMBLock(xid, pTcon,
-                        ((struct cifsFileInfo *) file->private_data)->
-                        netfid, length,
-                        pfLock->fl_start, numUnlock, numLock, lockType,
-                        wait_flag);
+       if (!numLock && !numUnlock) {
+               /* if no lock or unlock then nothing
+               to do since we do not know what it is */
+               FreeXid(xid);
+               return -EOPNOTSUPP;
+       }
+
+       if (posix_locking) {
+               int posix_lock_type;
+               if(lockType & LOCKING_ANDX_SHARED_LOCK)
+                       posix_lock_type = CIFS_RDLCK;
+               else
+                       posix_lock_type = CIFS_WRLCK;
+               
+               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;
+
+               if (numLock) {
+                       rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+                                       0, numLock, lockType, wait_flag);
+
+                       if (rc == 0) {
+                               /* For Windows locks we must store them. */
+                               rc = store_file_lock(fid, length,
+                                               pfLock->fl_start, lockType);
+                       }
+               } else if (numUnlock) {
+                       /* For each stored lock that this unlock overlaps
+                          completely, unlock it. */
+                       int stored_rc = 0;
+                       struct cifsLockInfo *li, *tmp;
+
+                       rc = 0;
+                       down(&fid->lock_sem);
+                       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,
+                                                       li->length, li->offset,
+                                                       1, 0, li->type, FALSE);
+                                       if (stored_rc)
+                                               rc = stored_rc;
+
+                                       list_del(&li->llist);
+                                       kfree(li);
+                               }
+                       }
+                       up(&fid->lock_sem);
+               }
+       }
+
        if (pfLock->fl_flags & FL_POSIX)
                posix_lock_file_wait(file, pfLock);
        FreeXid(xid);
@@ -868,10 +969,10 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
                                if (rc != 0)
                                        break;
                        }
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-                       /* BB FIXME We can not sign across two buffers yet */
-                       if((experimEnabled) && ((pTcon->ses->server->secMode & 
-                        (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) {
+                       if(experimEnabled || (pTcon->ses->server &&
+                               ((pTcon->ses->server->secMode & 
+                               (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+                               == 0))) {
                                struct kvec iov[2];
                                unsigned int len;
 
@@ -886,14 +987,13 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
                                                *poffset, &bytes_written,
                                                iov, 1, long_op);
                        } else
-                       /* BB FIXME fixup indentation of line below */
-#endif                 
-                       rc = CIFSSMBWrite(xid, pTcon,
-                                open_file->netfid,
-                                min_t(const int, cifs_sb->wsize, 
-                                      write_size - total_written),
-                                *poffset, &bytes_written,
-                                write_data + total_written, NULL, long_op);
+                               rc = CIFSSMBWrite(xid, pTcon,
+                                        open_file->netfid,
+                                        min_t(const int, cifs_sb->wsize,
+                                              write_size - total_written),
+                                        *poffset, &bytes_written,
+                                        write_data + total_written,
+                                        NULL, long_op);
                }
                if (rc || (bytes_written == 0)) {
                        if (total_written)
@@ -932,6 +1032,16 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
        struct cifsFileInfo *open_file;
        int rc;
 
+       /* Having a null inode here (because mapping->host was set to zero by
+       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"));
+               dump_stack();
+               return NULL;
+       }
+
        read_lock(&GlobalSMBSeslock);
        list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
                if (open_file->closePend)
@@ -1024,7 +1134,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
        return rc;
 }
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 static int cifs_writepages(struct address_space *mapping,
                           struct writeback_control *wbc)
 {
@@ -1033,9 +1142,9 @@ static int cifs_writepages(struct address_space *mapping,
        unsigned int bytes_written;
        struct cifs_sb_info *cifs_sb;
        int done = 0;
-       pgoff_t end = -1;
+       pgoff_t end;
        pgoff_t index;
-       int is_range = 0;
+       int range_whole = 0;
        struct kvec iov[32];
        int len;
        int n_iov = 0;
@@ -1058,12 +1167,11 @@ static int cifs_writepages(struct address_space *mapping,
        if (cifs_sb->wsize < PAGE_CACHE_SIZE)
                return generic_writepages(mapping, wbc);
 
-       /* BB FIXME we do not have code to sign across multiple buffers yet,
-          so go to older writepage style write which we can sign if needed */
        if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
                if(cifs_sb->tcon->ses->server->secMode &
                           (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-                       return generic_writepages(mapping, wbc);
+                       if(!experimEnabled)
+                               return generic_writepages(mapping, wbc);
 
        /*
         * BB: Is this meaningful for a non-block-device file system?
@@ -1077,16 +1185,14 @@ static int cifs_writepages(struct address_space *mapping,
        xid = GetXid();
 
        pagevec_init(&pvec, 0);
-       if (wbc->sync_mode == WB_SYNC_NONE)
+       if (wbc->range_cyclic) {
                index = mapping->writeback_index; /* Start from prev offset */
-       else {
-               index = 0;
-               scanned = 1;
-       }
-       if (wbc->start || wbc->end) {
-               index = wbc->start >> PAGE_CACHE_SHIFT;
-               end = wbc->end >> PAGE_CACHE_SHIFT;
-               is_range = 1;
+               end = -1;
+       } else {
+               index = wbc->range_start >> PAGE_CACHE_SHIFT;
+               end = wbc->range_end >> PAGE_CACHE_SHIFT;
+               if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
+                       range_whole = 1;
                scanned = 1;
        }
 retry:
@@ -1122,7 +1228,7 @@ retry:
                                break;
                        }
 
-                       if (unlikely(is_range) && (page->index > end)) {
+                       if (!wbc->range_cyclic && page->index > end) {
                                done = 1;
                                unlock_page(page);
                                break;
@@ -1193,7 +1299,6 @@ retry:
                                        /* BB what if continued retry is
                                           requested via mount flags? */
                                        set_bit(AS_EIO, &mapping->flags);
-                                       SetPageError(page);
                                } else {
                                        cifs_stats_bytes_written(cifs_sb->tcon,
                                                                 bytes_written);
@@ -1201,6 +1306,13 @@ retry:
                        }
                        for (i = 0; i < n_iov; i++) {
                                page = pvec.pages[first + i];
+                               /* Should we also set page error on
+                               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)
+                                       SetPageError(page);
                                kunmap(page);
                                unlock_page(page);
                                page_cache_release(page);
@@ -1220,14 +1332,13 @@ retry:
                index = 0;
                goto retry;
        }
-       if (!is_range)
+       if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
                mapping->writeback_index = index;
 
        FreeXid(xid);
 
        return rc;
 }
-#endif
 
 static int cifs_writepage(struct page* page, struct writeback_control *wbc)
 {
@@ -1327,7 +1438,7 @@ 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);
@@ -1337,7 +1448,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
        return rc;
 }
 
-/* static int cifs_sync_page(struct page *page)
+/* static void cifs_sync_page(struct page *page)
 {
        struct address_space *mapping;
        struct inode *inode;
@@ -1351,23 +1462,25 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
                return 0;
        inode = mapping->host;
        if (!inode)
-               return 0; */
+               return; */
 
 /*     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));
+/*     cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
 
+#if 0
        if (rc < 0)
                return rc;
        return 0;
+#endif
 } */
 
 /*
  * As file closes, flush all cached write data for this inode checking
  * for write behind errors.
  */
-int cifs_flush(struct file *file)
+int cifs_flush(struct file *file, fl_owner_t id)
 {
        struct inode * inode = file->f_dentry->d_inode;
        int rc = 0;
@@ -1426,6 +1539,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
                rc = -EAGAIN;
                smb_read_data = NULL;
                while (rc == -EAGAIN) {
+                       int buf_type = CIFS_NO_BUFFER;
                        if ((open_file->invalidHandle) && 
                            (!open_file->closePend)) {
                                rc = cifs_reopen_file(file->f_dentry->d_inode,
@@ -1434,20 +1548,24 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
                                        break;
                        }
                        rc = CIFSSMBRead(xid, pTcon,
-                                       open_file->netfid,
-                                       current_read_size, *poffset,
-                                       &bytes_read, &smb_read_data);
+                                        open_file->netfid,
+                                        current_read_size, *poffset,
+                                        &bytes_read, &smb_read_data,
+                                        &buf_type);
                        pSMBr = (struct smb_com_read_rsp *)smb_read_data;
-                       if (copy_to_user(current_offset, 
-                                        smb_read_data + 4 /* RFC1001 hdr */
-                                        + le16_to_cpu(pSMBr->DataOffset), 
-                                        bytes_read)) {
-                               rc = -EFAULT;
-                               FreeXid(xid);
-                               return rc;
-            }
                        if (smb_read_data) {
-                               cifs_buf_release(smb_read_data);
+                               if (copy_to_user(current_offset,
+                                               smb_read_data +
+                                               4 /* RFC1001 length field */ +
+                                               le16_to_cpu(pSMBr->DataOffset),
+                                               bytes_read)) {
+                                       rc = -EFAULT;
+                               }
+
+                               if(buf_type == CIFS_SMALL_BUFFER)
+                                       cifs_small_buf_release(smb_read_data);
+                               else if(buf_type == CIFS_LARGE_BUFFER)
+                                       cifs_buf_release(smb_read_data);
                                smb_read_data = NULL;
                        }
                }
@@ -1480,6 +1598,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
        int xid;
        char *current_offset;
        struct cifsFileInfo *open_file;
+       int buf_type = CIFS_NO_BUFFER;
 
        xid = GetXid();
        cifs_sb = CIFS_SB(file->f_dentry->d_sb);
@@ -1516,9 +1635,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
                                        break;
                        }
                        rc = CIFSSMBRead(xid, pTcon,
-                                       open_file->netfid,
-                                       current_read_size, *poffset,
-                                       &bytes_read, &current_offset);
+                                        open_file->netfid,
+                                        current_read_size, *poffset,
+                                        &bytes_read, &current_offset,
+                                        &buf_type);
                }
                if (rc || (bytes_read == 0)) {
                        if (total_read) {
@@ -1616,6 +1736,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
        struct smb_com_read_rsp *pSMBr;
        struct pagevec lru_pvec;
        struct cifsFileInfo *open_file;
+       int buf_type = CIFS_NO_BUFFER;
 
        xid = GetXid();
        if (file->private_data == NULL) {
@@ -1672,27 +1793,23 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                        }
 
                        rc = CIFSSMBRead(xid, pTcon,
-                                       open_file->netfid,
-                                       read_size, offset,
-                                       &bytes_read, &smb_read_data);
-
+                                        open_file->netfid,
+                                        read_size, offset,
+                                        &bytes_read, &smb_read_data,
+                                        &buf_type);
                        /* BB more RC checks ? */
                        if (rc== -EAGAIN) {
                                if (smb_read_data) {
-                                       cifs_buf_release(smb_read_data);
+                                       if(buf_type == CIFS_SMALL_BUFFER)
+                                               cifs_small_buf_release(smb_read_data);
+                                       else if(buf_type == CIFS_LARGE_BUFFER)
+                                               cifs_buf_release(smb_read_data);
                                        smb_read_data = NULL;
                                }
                        }
                }
                if ((rc < 0) || (smb_read_data == NULL)) {
                        cFYI(1, ("Read error in readpages: %d", rc));
-                       /* clean up remaing pages off list */
-                       while (!list_empty(page_list) && (i < num_pages)) {
-                               page = list_entry(page_list->prev, struct page,
-                                                 lru);
-                               list_del(&page->lru);
-                               page_cache_release(page);
-                       }
                        break;
                } else if (bytes_read > 0) {
                        pSMBr = (struct smb_com_read_rsp *)smb_read_data;
@@ -1711,13 +1828,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                                   this case is ok - if we are at server EOF 
                                   we will hit it on next read */
 
-                       /* while (!list_empty(page_list) && (i < num_pages)) {
-                                       page = list_entry(page_list->prev, 
-                                                         struct page, list);
-                                       list_del(&page->list);
-                                       page_cache_release(page);
-                               }
-                               break; */
+                               /* break; */
                        }
                } else {
                        cFYI(1, ("No bytes read (%d) at offset %lld . "
@@ -1725,18 +1836,13 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                                 bytes_read, offset));
                        /* BB turn off caching and do new lookup on 
                           file size at server? */
-                       while (!list_empty(page_list) && (i < num_pages)) {
-                               page = list_entry(page_list->prev, struct page,
-                                                 lru);
-                               list_del(&page->lru);
-
-                               /* BB removeme - replace with zero of page? */
-                               page_cache_release(page);
-                       }
                        break;
                }
                if (smb_read_data) {
-                       cifs_buf_release(smb_read_data);
+                       if(buf_type == CIFS_SMALL_BUFFER)
+                               cifs_small_buf_release(smb_read_data);
+                       else if(buf_type == CIFS_LARGE_BUFFER)
+                               cifs_buf_release(smb_read_data);
                        smb_read_data = NULL;
                }
                bytes_read = 0;
@@ -1746,7 +1852,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 
 /* need to free smb_read_data buf before exit */
        if (smb_read_data) {
-               cifs_buf_release(smb_read_data);
+               if(buf_type == CIFS_SMALL_BUFFER)
+                       cifs_small_buf_release(smb_read_data);
+               else if(buf_type == CIFS_LARGE_BUFFER)
+                       cifs_buf_release(smb_read_data);
                smb_read_data = NULL;
        } 
 
@@ -1769,7 +1878,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
        if (rc < 0)
                goto io_error;
        else
-               cFYI(1, ("Bytes read %d ",rc));
+               cFYI(1, ("Bytes read %d",rc));
                                                                                                                            
        file->f_dentry->d_inode->i_atime =
                current_fs_time(file->f_dentry->d_inode->i_sb);
@@ -1825,10 +1934,20 @@ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
                open_file =  find_writable_file(cifsInode);
  
        if(open_file) {
+               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 
+                       we can change size safely */
+                       return 1;
+               }
+
                return 0;
        } else
                return 1;
@@ -1869,13 +1988,27 @@ static int cifs_prepare_write(struct file *file, struct page *page,
        return 0;
 }
 
-struct address_space_operations cifs_addr_ops = {
+const struct address_space_operations cifs_addr_ops = {
        .readpage = cifs_readpage,
        .readpages = cifs_readpages,
        .writepage = cifs_writepage,
-#ifdef CONFIG_CIFS_EXPERIMENTAL
        .writepages = cifs_writepages,
-#endif
+       .prepare_write = cifs_prepare_write,
+       .commit_write = cifs_commit_write,
+       .set_page_dirty = __set_page_dirty_nobuffers,
+       /* .sync_page = cifs_sync_page, */
+       /* .direct_IO = */
+};
+
+/*
+ * cifs_readpages requires the server to support a buffer large enough to
+ * contain the header plus one complete page of data.  Otherwise, we need
+ * to leave cifs_readpages out of the address space operations.
+ */
+const struct address_space_operations cifs_addr_ops_smallbuf = {
+       .readpage = cifs_readpage,
+       .writepage = cifs_writepage,
+       .writepages = cifs_writepages,
        .prepare_write = cifs_prepare_write,
        .commit_write = cifs_commit_write,
        .set_page_dirty = __set_page_dirty_nobuffers,