]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/cifs/inode.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux...
[karo-tx-linux.git] / fs / cifs / inode.c
index 4f0ee67eb9540e51d2e980637595461827259758..e1031b9e2c55ccfb13182e89c899ba6e49c89f7d 100644 (file)
@@ -57,9 +57,13 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
                        inode->i_data.a_ops = &cifs_addr_ops;
                break;
        case S_IFDIR:
+#ifdef CONFIG_CIFS_DFS_UPCALL
                if (is_dfs_referral) {
                        inode->i_op = &cifs_dfs_referral_inode_operations;
                } else {
+#else /* NO DFS support, treat as a directory */
+               {
+#endif
                        inode->i_op = &cifs_dir_inode_ops;
                        inode->i_fop = &cifs_dir_ops;
                }
@@ -157,12 +161,14 @@ static void cifs_unix_info_to_inode(struct inode *inode,
        spin_unlock(&inode->i_lock);
 }
 
-static const unsigned char *cifs_get_search_path(struct cifsTconInfo *pTcon,
-                                       const char *search_path)
+static const unsigned char *cifs_get_search_path(struct cifs_sb_info *cifs_sb,
+                                               const char *search_path)
 {
        int tree_len;
        int path_len;
+       int i;
        char *tmp_path;
+       struct cifsTconInfo *pTcon = cifs_sb->tcon;
 
        if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS))
                return search_path;
@@ -176,6 +182,11 @@ static const unsigned char *cifs_get_search_path(struct cifsTconInfo *pTcon,
                return search_path;
 
        strncpy(tmp_path, pTcon->treeName, tree_len);
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+               for (i = 0; i < tree_len; i++) {
+                       if (tmp_path[i] == '\\')
+                               tmp_path[i] = '/';
+               }
        strncpy(tmp_path+tree_len, search_path, path_len);
        tmp_path[tree_len+path_len] = 0;
        return tmp_path;
@@ -195,7 +206,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
        pTcon = cifs_sb->tcon;
        cFYI(1, ("Getting info on %s", search_path));
 
-       full_path = cifs_get_search_path(pTcon, search_path);
+       full_path = cifs_get_search_path(cifs_sb, search_path);
 
 try_again_CIFSSMBUnixQPathInfo:
        /* could have done a find first instead but this returns more info */
@@ -207,7 +218,10 @@ try_again_CIFSSMBUnixQPathInfo:
        if (rc) {
                if (rc == -EREMOTE && !is_dfs_referral) {
                        is_dfs_referral = true;
-                       full_path = search_path;
+                       if (full_path != search_path) {
+                               kfree(full_path);
+                               full_path = search_path;
+                       }
                        goto try_again_CIFSSMBUnixQPathInfo;
                }
                goto cgiiu_exit;
@@ -367,7 +381,7 @@ static int get_sfu_mode(struct inode *inode,
 
 int cifs_get_inode_info(struct inode **pinode,
        const unsigned char *search_path, FILE_ALL_INFO *pfindData,
-       struct super_block *sb, int xid)
+       struct super_block *sb, int xid, const __u16 *pfid)
 {
        int rc = 0;
        struct cifsTconInfo *pTcon;
@@ -395,7 +409,7 @@ int cifs_get_inode_info(struct inode **pinode,
                        return -ENOMEM;
                pfindData = (FILE_ALL_INFO *)buf;
 
-               full_path = cifs_get_search_path(pTcon, search_path);
+               full_path = cifs_get_search_path(cifs_sb, search_path);
 
 try_again_CIFSSMBQPathInfo:
                /* could do find first instead but this returns more info */
@@ -418,7 +432,10 @@ try_again_CIFSSMBQPathInfo:
        if (rc) {
                if (rc == -EREMOTE && !is_dfs_referral) {
                        is_dfs_referral = true;
-                       full_path = search_path;
+                       if (full_path != search_path) {
+                               kfree(full_path);
+                               full_path = search_path;
+                       }
                        goto try_again_CIFSSMBQPathInfo;
                }
                goto cgii_exit;
@@ -565,7 +582,7 @@ try_again_CIFSSMBQPathInfo:
                /* fill in 0777 bits from ACL */
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
                        cFYI(1, ("Getting mode bits from ACL"));
-                       acl_to_uid_mode(inode, search_path);
+                       acl_to_uid_mode(inode, search_path, pfid);
                }
 #endif
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
@@ -612,7 +629,8 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
        if (cifs_sb->tcon->unix_ext)
                rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
        else
-               rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid);
+               rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid,
+                                        NULL);
        if (rc && cifs_sb->tcon->ipc) {
                cFYI(1, ("ipc connection - fake read inode"));
                inode->i_mode |= S_IFDIR;
@@ -945,7 +963,7 @@ mkdir_get_info:
                                                      inode->i_sb, xid);
                else
                        rc = cifs_get_inode_info(&newinode, full_path, NULL,
-                                                inode->i_sb, xid);
+                                                inode->i_sb, xid, NULL);
 
                if (pTcon->nocase)
                        direntry->d_op = &cifs_ci_dentry_ops;
@@ -1227,7 +1245,7 @@ int cifs_revalidate(struct dentry *direntry)
                }
        } else {
                rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
-                                        direntry->d_sb, xid);
+                                        direntry->d_sb, xid, NULL);
                if (rc) {
                        cFYI(1, ("error on getting revalidate info %d", rc));
 /*                     if (rc != -ENOENT)
@@ -1416,11 +1434,10 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
        }
        cifsInode = CIFS_I(direntry->d_inode);
 
-       /* BB check if we need to refresh inode from server now ? BB */
-
-       if (attrs->ia_valid & ATTR_SIZE) {
+       if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
                /*
-                  Flush data before changing file size on server. If the
+                  Flush data before changing file size or changing the last
+                  write time of the file on the server. If the
                   flush returns error, store it to report later and continue.
                   BB: This should be smarter. Why bother flushing pages that
                   will be truncated anyway? Also, should we error out here if
@@ -1431,7 +1448,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                        CIFS_I(direntry->d_inode)->write_behind_rc = rc;
                        rc = 0;
                }
+       }
 
+       if (attrs->ia_valid & ATTR_SIZE) {
                /* 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.