Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[pandora-kernel.git] / fs / cifs / file.c
index 5a28660..d843631 100644 (file)
@@ -104,53 +104,6 @@ static inline int cifs_get_disposition(unsigned int flags)
                return FILE_OPEN;
 }
 
-static inline int cifs_open_inode_helper(struct inode *inode,
-       struct cifsTconInfo *pTcon, __u32 oplock, FILE_ALL_INFO *buf,
-       char *full_path, int xid)
-{
-       struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
-       struct timespec temp;
-       int rc;
-
-       if (pCifsInode->clientCanCacheRead) {
-               /* we have the inode open somewhere else
-                  no need to discard cache data */
-               goto client_can_cache;
-       }
-
-       /* BB need same check in cifs_create too? */
-       /* if not oplocked, invalidate inode pages if mtime or file
-          size changed */
-       temp = cifs_NTtimeToUnix(buf->LastWriteTime);
-       if (timespec_equal(&inode->i_mtime, &temp) &&
-                          (inode->i_size ==
-                           (loff_t)le64_to_cpu(buf->EndOfFile))) {
-               cFYI(1, "inode unchanged on server");
-       } else {
-               if (inode->i_mapping) {
-                       /* BB no need to lock inode until after invalidate
-                       since namei code should already have it locked? */
-                       rc = filemap_write_and_wait(inode->i_mapping);
-                       mapping_set_error(inode->i_mapping, rc);
-               }
-               cFYI(1, "invalidating remote inode since open detected it "
-                        "changed");
-               invalidate_remote_inode(inode);
-       }
-
-client_can_cache:
-       if (pTcon->unix_ext)
-               rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
-                                             xid);
-       else
-               rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
-                                        xid, NULL);
-
-       cifs_set_oplock_level(pCifsInode, oplock);
-
-       return rc;
-}
-
 int cifs_posix_open(char *full_path, struct inode **pinode,
                        struct super_block *sb, int mode, unsigned int f_flags,
                        __u32 *poplock, __u16 *pnetfid, int xid)
@@ -213,6 +166,76 @@ posix_open_ret:
        return rc;
 }
 
+static int
+cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
+            struct cifsTconInfo *tcon, unsigned int f_flags, __u32 *poplock,
+            __u16 *pnetfid, int xid)
+{
+       int rc;
+       int desiredAccess;
+       int disposition;
+       FILE_ALL_INFO *buf;
+
+       desiredAccess = cifs_convert_flags(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
+ *     O_TRUNC               FILE_OVERWRITE
+ *     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
+ *     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
+ *?  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,
+ *      O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
+ *********************************************************************/
+
+       disposition = cifs_get_disposition(f_flags);
+
+       /* BB pass O_SYNC flag through on file attributes .. BB */
+
+       buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       if (tcon->ses->capabilities & CAP_NT_SMBS)
+               rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
+                        desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
+                        cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+                                & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       else
+               rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
+                       desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
+                       cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+                               & CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+       if (rc)
+               goto out;
+
+       if (tcon->unix_ext)
+               rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
+                                             xid);
+       else
+               rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
+                                        xid, pnetfid);
+
+out:
+       kfree(buf);
+       return rc;
+}
+
 struct cifsFileInfo *
 cifs_new_fileinfo(__u16 fileHandle, struct file *file,
                  struct tcon_link *tlink, __u32 oplock)
@@ -317,10 +340,8 @@ int cifs_open(struct inode *inode, struct file *file)
        struct cifsFileInfo *pCifsFile = NULL;
        struct cifsInodeInfo *pCifsInode;
        char *full_path = NULL;
-       int desiredAccess;
-       int disposition;
+       bool posix_open_ok = false;
        __u16 netfid;
-       FILE_ALL_INFO *buf = NULL;
 
        xid = GetXid();
 
@@ -358,17 +379,7 @@ int cifs_open(struct inode *inode, struct file *file)
                                file->f_flags, &oplock, &netfid, xid);
                if (rc == 0) {
                        cFYI(1, "posix open succeeded");
-
-                       pCifsFile = cifs_new_fileinfo(netfid, file, tlink,
-                                                     oplock);
-                       if (pCifsFile == NULL) {
-                               CIFSSMBClose(xid, tcon, netfid);
-                               rc = -ENOMEM;
-                       }
-
-                       cifs_fscache_set_inode_cookie(inode, file);
-
-                       goto out;
+                       posix_open_ok = true;
                } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
                        if (tcon->ses->serverNOS)
                                cERROR(1, "server %s of type %s returned"
@@ -385,103 +396,39 @@ int cifs_open(struct inode *inode, struct file *file)
                   or DFS errors */
        }
 
-       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
- *     O_TRUNC               FILE_OVERWRITE
- *     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
- *     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
- *?  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,
- *      O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
- *********************************************************************/
-
-       disposition = cifs_get_disposition(file->f_flags);
-
-       /* BB pass O_SYNC flag through on file attributes .. BB */
-
-       /* Also refresh inode by passing in file_info buf returned by SMBOpen
-          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
-          able to simply do a filemap_fdatawrite/filemap_fdatawait first */
-       buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
-       if (!buf) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       if (tcon->ses->capabilities & CAP_NT_SMBS)
-               rc = CIFSSMBOpen(xid, tcon, 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, tcon, full_path, disposition,
-                       desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
-                       cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
-                               & CIFS_MOUNT_MAP_SPECIAL_CHR);
-       }
-       if (rc) {
-               cFYI(1, "cifs_open returned 0x%x", rc);
-               goto out;
+       if (!posix_open_ok) {
+               rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
+                                 file->f_flags, &oplock, &netfid, xid);
+               if (rc)
+                       goto out;
        }
 
-       rc = cifs_open_inode_helper(inode, tcon, oplock, buf, full_path, xid);
-       if (rc != 0)
-               goto out;
-
        pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
        if (pCifsFile == NULL) {
+               CIFSSMBClose(xid, tcon, netfid);
                rc = -ENOMEM;
                goto out;
        }
 
        cifs_fscache_set_inode_cookie(inode, file);
 
-       if (oplock & CIFS_CREATE_ACTION) {
+       if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
                /* time to set mode which we can not set earlier due to
                   problems creating new read-only files */
-               if (tcon->unix_ext) {
-                       struct cifs_unix_set_info_args args = {
-                               .mode   = inode->i_mode,
-                               .uid    = NO_CHANGE_64,
-                               .gid    = NO_CHANGE_64,
-                               .ctime  = NO_CHANGE_64,
-                               .atime  = NO_CHANGE_64,
-                               .mtime  = NO_CHANGE_64,
-                               .device = 0,
-                       };
-                       CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
-                                              cifs_sb->local_nls,
-                                              cifs_sb->mnt_cifs_flags &
-                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
-               }
+               struct cifs_unix_set_info_args args = {
+                       .mode   = inode->i_mode,
+                       .uid    = NO_CHANGE_64,
+                       .gid    = NO_CHANGE_64,
+                       .ctime  = NO_CHANGE_64,
+                       .atime  = NO_CHANGE_64,
+                       .mtime  = NO_CHANGE_64,
+                       .device = 0,
+               };
+               CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid,
+                                       pCifsFile->pid);
        }
 
 out:
-       kfree(buf);
        kfree(full_path);
        FreeXid(xid);
        cifs_put_tlink(tlink);