aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-03-22 20:05:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-03-22 20:05:31 -0400
commit0d995b2b446c2304c04058bedba49460823adbf7 (patch)
treecc6c66b7344f6a4b77aab0d533046c439cad0bf7 /fs
parent130eb4653550ff9c73e09858464446cc9d59ff7b (diff)
parent04b6e6ec1a9340ab77637cae9b51b984d9d706d8 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: [CIFS] Fix mem leak on dfs referral [CIFS] file create with acl support enabled is slow [CIFS] Fix mtime on cp -p when file data cached but written out too late [CIFS] Fix build problem [CIFS] cifs: replace remaining __FUNCTION__ occurrences [CIFS] DFS patch that connects inode with dfs handling ops
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/cifs_dfs_ref.c18
-rw-r--r--fs/cifs/cifsacl.c25
-rw-r--r--fs/cifs/cifsproto.h9
-rw-r--r--fs/cifs/dir.c5
-rw-r--r--fs/cifs/dns_resolve.c8
-rw-r--r--fs/cifs/file.c4
-rw-r--r--fs/cifs/inode.c161
-rw-r--r--fs/cifs/link.c2
8 files changed, 130 insertions, 102 deletions
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index 7f8838253410..a1a95b027136 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -74,7 +74,7 @@ static char *cifs_get_share_name(const char *node_name)
74 pSep = memchr(UNC+2, '\\', len-2); 74 pSep = memchr(UNC+2, '\\', len-2);
75 if (!pSep) { 75 if (!pSep) {
76 cERROR(1, ("%s: no server name end in node name: %s", 76 cERROR(1, ("%s: no server name end in node name: %s",
77 __FUNCTION__, node_name)); 77 __func__, node_name));
78 kfree(UNC); 78 kfree(UNC);
79 return NULL; 79 return NULL;
80 } 80 }
@@ -84,7 +84,7 @@ static char *cifs_get_share_name(const char *node_name)
84 pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC)); 84 pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC));
85 if (!pSep) { 85 if (!pSep) {
86 cERROR(1, ("%s:2 cant find share name in node name: %s", 86 cERROR(1, ("%s:2 cant find share name in node name: %s",
87 __FUNCTION__, node_name)); 87 __func__, node_name));
88 kfree(UNC); 88 kfree(UNC);
89 return NULL; 89 return NULL;
90 } 90 }
@@ -127,7 +127,7 @@ static char *compose_mount_options(const char *sb_mountdata,
127 rc = dns_resolve_server_name_to_ip(*devname, &srvIP); 127 rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
128 if (rc != 0) { 128 if (rc != 0) {
129 cERROR(1, ("%s: Failed to resolve server part of %s to IP", 129 cERROR(1, ("%s: Failed to resolve server part of %s to IP",
130 __FUNCTION__, *devname)); 130 __func__, *devname));
131 mountdata = ERR_PTR(rc); 131 mountdata = ERR_PTR(rc);
132 goto compose_mount_options_out; 132 goto compose_mount_options_out;
133 } 133 }
@@ -181,8 +181,8 @@ static char *compose_mount_options(const char *sb_mountdata,
181 } 181 }
182 } 182 }
183 183
184 /*cFYI(1,("%s: parent mountdata: %s", __FUNCTION__,sb_mountdata));*/ 184 /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
185 /*cFYI(1, ("%s: submount mountdata: %s", __FUNCTION__, mountdata ));*/ 185 /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/
186 186
187compose_mount_options_out: 187compose_mount_options_out:
188 kfree(srvIP); 188 kfree(srvIP);
@@ -302,7 +302,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
302 int rc = 0; 302 int rc = 0;
303 struct vfsmount *mnt = ERR_PTR(-ENOENT); 303 struct vfsmount *mnt = ERR_PTR(-ENOENT);
304 304
305 cFYI(1, ("in %s", __FUNCTION__)); 305 cFYI(1, ("in %s", __func__));
306 BUG_ON(IS_ROOT(dentry)); 306 BUG_ON(IS_ROOT(dentry));
307 307
308 xid = GetXid(); 308 xid = GetXid();
@@ -336,7 +336,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
336 len = strlen(referrals[i].node_name); 336 len = strlen(referrals[i].node_name);
337 if (len < 2) { 337 if (len < 2) {
338 cERROR(1, ("%s: Net Address path too short: %s", 338 cERROR(1, ("%s: Net Address path too short: %s",
339 __FUNCTION__, referrals[i].node_name)); 339 __func__, referrals[i].node_name));
340 rc = -EINVAL; 340 rc = -EINVAL;
341 goto out_err; 341 goto out_err;
342 } 342 }
@@ -344,7 +344,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
344 nd->path.dentry, 344 nd->path.dentry,
345 referrals[i].node_name); 345 referrals[i].node_name);
346 cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", 346 cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
347 __FUNCTION__, 347 __func__,
348 referrals[i].node_name, mnt)); 348 referrals[i].node_name, mnt));
349 349
350 /* complete mount procedure if we accured submount */ 350 /* complete mount procedure if we accured submount */
@@ -365,7 +365,7 @@ out:
365 FreeXid(xid); 365 FreeXid(xid);
366 free_dfs_info_array(referrals, num_referrals); 366 free_dfs_info_array(referrals, num_referrals);
367 kfree(full_path); 367 kfree(full_path);
368 cFYI(1, ("leaving %s" , __FUNCTION__)); 368 cFYI(1, ("leaving %s" , __func__));
369 return ERR_PTR(rc); 369 return ERR_PTR(rc);
370out_err: 370out_err:
371 path_put(&nd->path); 371 path_put(&nd->path);
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index f93932c21772..1f5a4289b848 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * fs/cifs/cifsacl.c 2 * fs/cifs/cifsacl.c
3 * 3 *
4 * Copyright (C) International Business Machines Corp., 2007 4 * Copyright (C) International Business Machines Corp., 2007,2008
5 * Author(s): Steve French (sfrench@us.ibm.com) 5 * Author(s): Steve French (sfrench@us.ibm.com)
6 * 6 *
7 * Contains the routines for mapping CIFS/NTFS ACLs 7 * Contains the routines for mapping CIFS/NTFS ACLs
@@ -556,9 +556,9 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
556 556
557/* Retrieve an ACL from the server */ 557/* Retrieve an ACL from the server */
558static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, 558static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
559 const char *path) 559 const char *path, const __u16 *pfid)
560{ 560{
561 struct cifsFileInfo *open_file; 561 struct cifsFileInfo *open_file = NULL;
562 int unlock_file = FALSE; 562 int unlock_file = FALSE;
563 int xid; 563 int xid;
564 int rc = -EIO; 564 int rc = -EIO;
@@ -573,7 +573,11 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
573 return NULL; 573 return NULL;
574 574
575 xid = GetXid(); 575 xid = GetXid();
576 open_file = find_readable_file(CIFS_I(inode)); 576 if (pfid == NULL)
577 open_file = find_readable_file(CIFS_I(inode));
578 else
579 fid = *pfid;
580
577 sb = inode->i_sb; 581 sb = inode->i_sb;
578 if (sb == NULL) { 582 if (sb == NULL) {
579 FreeXid(xid); 583 FreeXid(xid);
@@ -584,7 +588,7 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
584 if (open_file) { 588 if (open_file) {
585 unlock_file = TRUE; 589 unlock_file = TRUE;
586 fid = open_file->netfid; 590 fid = open_file->netfid;
587 } else { 591 } else if (pfid == NULL) {
588 int oplock = FALSE; 592 int oplock = FALSE;
589 /* open file */ 593 /* open file */
590 rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, 594 rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
@@ -600,10 +604,11 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
600 604
601 rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); 605 rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
602 cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen)); 606 cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen));
603 if (unlock_file == TRUE) 607 if (unlock_file == TRUE) /* find_readable_file increments ref count */
604 atomic_dec(&open_file->wrtPending); 608 atomic_dec(&open_file->wrtPending);
605 else 609 else if (pfid == NULL) /* if opened above we have to close the handle */
606 CIFSSMBClose(xid, cifs_sb->tcon, fid); 610 CIFSSMBClose(xid, cifs_sb->tcon, fid);
611 /* else handle was passed in by caller */
607 612
608 FreeXid(xid); 613 FreeXid(xid);
609 return pntsd; 614 return pntsd;
@@ -664,14 +669,14 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
664} 669}
665 670
666/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ 671/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
667void acl_to_uid_mode(struct inode *inode, const char *path) 672void acl_to_uid_mode(struct inode *inode, const char *path, const __u16 *pfid)
668{ 673{
669 struct cifs_ntsd *pntsd = NULL; 674 struct cifs_ntsd *pntsd = NULL;
670 u32 acllen = 0; 675 u32 acllen = 0;
671 int rc = 0; 676 int rc = 0;
672 677
673 cFYI(DBG2, ("converting ACL to mode for %s", path)); 678 cFYI(DBG2, ("converting ACL to mode for %s", path));
674 pntsd = get_cifs_acl(&acllen, inode, path); 679 pntsd = get_cifs_acl(&acllen, inode, path, pfid);
675 680
676 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ 681 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
677 if (pntsd) 682 if (pntsd)
@@ -694,7 +699,7 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
694 cFYI(DBG2, ("set ACL from mode for %s", path)); 699 cFYI(DBG2, ("set ACL from mode for %s", path));
695 700
696 /* Get the security descriptor */ 701 /* Get the security descriptor */
697 pntsd = get_cifs_acl(&acllen, inode, path); 702 pntsd = get_cifs_acl(&acllen, inode, path, NULL);
698 703
699 /* Add three ACEs for owner, group, everyone getting rid of 704 /* Add three ACEs for owner, group, everyone getting rid of
700 other ACEs as chmod disables ACEs and set the security descriptor */ 705 other ACEs as chmod disables ACEs and set the security descriptor */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 0af63e6b426b..7e5e0e78cd72 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -39,8 +39,8 @@ extern int smb_send(struct socket *, struct smb_hdr *,
39 unsigned int /* length */ , struct sockaddr *); 39 unsigned int /* length */ , struct sockaddr *);
40extern unsigned int _GetXid(void); 40extern unsigned int _GetXid(void);
41extern void _FreeXid(unsigned int); 41extern void _FreeXid(unsigned int);
42#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid)); 42#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid));
43#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));} 43#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));}
44extern char *build_path_from_dentry(struct dentry *); 44extern char *build_path_from_dentry(struct dentry *);
45extern char *build_wildcard_path_from_dentry(struct dentry *direntry); 45extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
46/* extern void renew_parental_timestamps(struct dentry *direntry);*/ 46/* extern void renew_parental_timestamps(struct dentry *direntry);*/
@@ -92,11 +92,12 @@ extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
92extern int cifs_get_inode_info(struct inode **pinode, 92extern int cifs_get_inode_info(struct inode **pinode,
93 const unsigned char *search_path, 93 const unsigned char *search_path,
94 FILE_ALL_INFO * pfile_info, 94 FILE_ALL_INFO * pfile_info,
95 struct super_block *sb, int xid); 95 struct super_block *sb, int xid, const __u16 *pfid);
96extern int cifs_get_inode_info_unix(struct inode **pinode, 96extern int cifs_get_inode_info_unix(struct inode **pinode,
97 const unsigned char *search_path, 97 const unsigned char *search_path,
98 struct super_block *sb, int xid); 98 struct super_block *sb, int xid);
99extern void acl_to_uid_mode(struct inode *inode, const char *search_path); 99extern void acl_to_uid_mode(struct inode *inode, const char *path,
100 const __u16 *pfid);
100extern int mode_to_acl(struct inode *inode, const char *path, __u64); 101extern int mode_to_acl(struct inode *inode, const char *path, __u64);
101 102
102extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, 103extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 4e83b47c4b34..0f5c62ba4038 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -229,7 +229,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
229 inode->i_sb, xid); 229 inode->i_sb, xid);
230 else { 230 else {
231 rc = cifs_get_inode_info(&newinode, full_path, 231 rc = cifs_get_inode_info(&newinode, full_path,
232 buf, inode->i_sb, xid); 232 buf, inode->i_sb, xid,
233 &fileHandle);
233 if (newinode) { 234 if (newinode) {
234 newinode->i_mode = mode; 235 newinode->i_mode = mode;
235 if ((oplock & CIFS_CREATE_ACTION) && 236 if ((oplock & CIFS_CREATE_ACTION) &&
@@ -483,7 +484,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
483 parent_dir_inode->i_sb, xid); 484 parent_dir_inode->i_sb, xid);
484 else 485 else
485 rc = cifs_get_inode_info(&newInode, full_path, NULL, 486 rc = cifs_get_inode_info(&newInode, full_path, NULL,
486 parent_dir_inode->i_sb, xid); 487 parent_dir_inode->i_sb, xid, NULL);
487 488
488 if ((rc == 0) && (newInode != NULL)) { 489 if ((rc == 0) && (newInode != NULL)) {
489 if (pTcon->nocase) 490 if (pTcon->nocase)
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index ef7f43824347..7cc86c418182 100644
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -77,14 +77,14 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
77 /* search for server name delimiter */ 77 /* search for server name delimiter */
78 len = strlen(unc); 78 len = strlen(unc);
79 if (len < 3) { 79 if (len < 3) {
80 cFYI(1, ("%s: unc is too short: %s", __FUNCTION__, unc)); 80 cFYI(1, ("%s: unc is too short: %s", __func__, unc));
81 return -EINVAL; 81 return -EINVAL;
82 } 82 }
83 len -= 2; 83 len -= 2;
84 name = memchr(unc+2, '\\', len); 84 name = memchr(unc+2, '\\', len);
85 if (!name) { 85 if (!name) {
86 cFYI(1, ("%s: probably server name is whole unc: %s", 86 cFYI(1, ("%s: probably server name is whole unc: %s",
87 __FUNCTION__, unc)); 87 __func__, unc));
88 } else { 88 } else {
89 len = (name - unc) - 2/* leading // */; 89 len = (name - unc) - 2/* leading // */;
90 } 90 }
@@ -104,7 +104,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
104 if (*ip_addr) { 104 if (*ip_addr) {
105 memcpy(*ip_addr, rkey->payload.data, len); 105 memcpy(*ip_addr, rkey->payload.data, len);
106 (*ip_addr)[len] = '\0'; 106 (*ip_addr)[len] = '\0';
107 cFYI(1, ("%s: resolved: %s to %s", __FUNCTION__, 107 cFYI(1, ("%s: resolved: %s to %s", __func__,
108 rkey->description, 108 rkey->description,
109 *ip_addr 109 *ip_addr
110 )); 110 ));
@@ -114,7 +114,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
114 } 114 }
115 key_put(rkey); 115 key_put(rkey);
116 } else { 116 } else {
117 cERROR(1, ("%s: unable to resolve: %s", __FUNCTION__, name)); 117 cERROR(1, ("%s: unable to resolve: %s", __func__, name));
118 } 118 }
119 119
120 kfree(name); 120 kfree(name);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index fa849c91d323..40b690073fc1 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -145,7 +145,7 @@ client_can_cache:
145 full_path, inode->i_sb, xid); 145 full_path, inode->i_sb, xid);
146 else 146 else
147 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode, 147 rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
148 full_path, buf, inode->i_sb, xid); 148 full_path, buf, inode->i_sb, xid, NULL);
149 149
150 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { 150 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
151 pCifsInode->clientCanCacheAll = TRUE; 151 pCifsInode->clientCanCacheAll = TRUE;
@@ -440,7 +440,7 @@ reopen_error_exit:
440 else 440 else
441 rc = cifs_get_inode_info(&inode, 441 rc = cifs_get_inode_info(&inode,
442 full_path, NULL, inode->i_sb, 442 full_path, NULL, inode->i_sb,
443 xid); 443 xid, NULL);
444 } /* else we are writing out data to server already 444 } /* else we are writing out data to server already
445 and could deadlock if we tried to flush data, and 445 and could deadlock if we tried to flush data, and
446 since we do not know if we have data that would 446 since we do not know if we have data that would
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 24eb4d392155..bc673c8c1e6b 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -30,7 +30,7 @@
30#include "cifs_fs_sb.h" 30#include "cifs_fs_sb.h"
31 31
32 32
33static void cifs_set_ops(struct inode *inode) 33static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
34{ 34{
35 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 35 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
36 36
@@ -57,8 +57,16 @@ static void cifs_set_ops(struct inode *inode)
57 inode->i_data.a_ops = &cifs_addr_ops; 57 inode->i_data.a_ops = &cifs_addr_ops;
58 break; 58 break;
59 case S_IFDIR: 59 case S_IFDIR:
60 inode->i_op = &cifs_dir_inode_ops; 60#ifdef CONFIG_CIFS_DFS_UPCALL
61 inode->i_fop = &cifs_dir_ops; 61 if (is_dfs_referral) {
62 inode->i_op = &cifs_dfs_referral_inode_operations;
63 } else {
64#else /* NO DFS support, treat as a directory */
65 {
66#endif
67 inode->i_op = &cifs_dir_inode_ops;
68 inode->i_fop = &cifs_dir_ops;
69 }
62 break; 70 break;
63 case S_IFLNK: 71 case S_IFLNK:
64 inode->i_op = &cifs_symlink_inode_ops; 72 inode->i_op = &cifs_symlink_inode_ops;
@@ -153,6 +161,30 @@ static void cifs_unix_info_to_inode(struct inode *inode,
153 spin_unlock(&inode->i_lock); 161 spin_unlock(&inode->i_lock);
154} 162}
155 163
164static const unsigned char *cifs_get_search_path(struct cifsTconInfo *pTcon,
165 const char *search_path)
166{
167 int tree_len;
168 int path_len;
169 char *tmp_path;
170
171 if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS))
172 return search_path;
173
174 /* use full path name for working with DFS */
175 tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1);
176 path_len = strnlen(search_path, MAX_PATHCONF);
177
178 tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL);
179 if (tmp_path == NULL)
180 return search_path;
181
182 strncpy(tmp_path, pTcon->treeName, tree_len);
183 strncpy(tmp_path+tree_len, search_path, path_len);
184 tmp_path[tree_len+path_len] = 0;
185 return tmp_path;
186}
187
156int cifs_get_inode_info_unix(struct inode **pinode, 188int cifs_get_inode_info_unix(struct inode **pinode,
157 const unsigned char *search_path, struct super_block *sb, int xid) 189 const unsigned char *search_path, struct super_block *sb, int xid)
158{ 190{
@@ -161,41 +193,31 @@ int cifs_get_inode_info_unix(struct inode **pinode,
161 struct cifsTconInfo *pTcon; 193 struct cifsTconInfo *pTcon;
162 struct inode *inode; 194 struct inode *inode;
163 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 195 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
164 char *tmp_path; 196 const unsigned char *full_path;
197 bool is_dfs_referral = false;
165 198
166 pTcon = cifs_sb->tcon; 199 pTcon = cifs_sb->tcon;
167 cFYI(1, ("Getting info on %s", search_path)); 200 cFYI(1, ("Getting info on %s", search_path));
201
202 full_path = cifs_get_search_path(pTcon, search_path);
203
204try_again_CIFSSMBUnixQPathInfo:
168 /* could have done a find first instead but this returns more info */ 205 /* could have done a find first instead but this returns more info */
169 rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, 206 rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData,
170 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 207 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
171 CIFS_MOUNT_MAP_SPECIAL_CHR); 208 CIFS_MOUNT_MAP_SPECIAL_CHR);
172/* dump_mem("\nUnixQPathInfo return data", &findData, 209/* dump_mem("\nUnixQPathInfo return data", &findData,
173 sizeof(findData)); */ 210 sizeof(findData)); */
174 if (rc) { 211 if (rc) {
175 if (rc == -EREMOTE) { 212 if (rc == -EREMOTE && !is_dfs_referral) {
176 tmp_path = 213 is_dfs_referral = true;
177 kmalloc(strnlen(pTcon->treeName, 214 if (full_path != search_path) {
178 MAX_TREE_SIZE + 1) + 215 kfree(full_path);
179 strnlen(search_path, MAX_PATHCONF) + 1, 216 full_path = search_path;
180 GFP_KERNEL); 217 }
181 if (tmp_path == NULL) 218 goto try_again_CIFSSMBUnixQPathInfo;
182 return -ENOMEM;
183
184 /* have to skip first of the double backslash of
185 UNC name */
186 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
187 strncat(tmp_path, search_path, MAX_PATHCONF);
188 rc = connect_to_dfs_path(xid, pTcon->ses,
189 /* treename + */ tmp_path,
190 cifs_sb->local_nls,
191 cifs_sb->mnt_cifs_flags &
192 CIFS_MOUNT_MAP_SPECIAL_CHR);
193 kfree(tmp_path);
194
195 /* BB fix up inode etc. */
196 } else if (rc) {
197 return rc;
198 } 219 }
220 goto cgiiu_exit;
199 } else { 221 } else {
200 struct cifsInodeInfo *cifsInfo; 222 struct cifsInodeInfo *cifsInfo;
201 __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes); 223 __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
@@ -204,8 +226,10 @@ int cifs_get_inode_info_unix(struct inode **pinode,
204 /* get new inode */ 226 /* get new inode */
205 if (*pinode == NULL) { 227 if (*pinode == NULL) {
206 *pinode = new_inode(sb); 228 *pinode = new_inode(sb);
207 if (*pinode == NULL) 229 if (*pinode == NULL) {
208 return -ENOMEM; 230 rc = -ENOMEM;
231 goto cgiiu_exit;
232 }
209 /* Is an i_ino of zero legal? */ 233 /* Is an i_ino of zero legal? */
210 /* Are there sanity checks we can use to ensure that 234 /* Are there sanity checks we can use to ensure that
211 the server is really filling in that field? */ 235 the server is really filling in that field? */
@@ -237,8 +261,11 @@ int cifs_get_inode_info_unix(struct inode **pinode,
237 (unsigned long) inode->i_size, 261 (unsigned long) inode->i_size,
238 (unsigned long long)inode->i_blocks)); 262 (unsigned long long)inode->i_blocks));
239 263
240 cifs_set_ops(inode); 264 cifs_set_ops(inode, is_dfs_referral);
241 } 265 }
266cgiiu_exit:
267 if (full_path != search_path)
268 kfree(full_path);
242 return rc; 269 return rc;
243} 270}
244 271
@@ -347,15 +374,16 @@ static int get_sfu_mode(struct inode *inode,
347 374
348int cifs_get_inode_info(struct inode **pinode, 375int cifs_get_inode_info(struct inode **pinode,
349 const unsigned char *search_path, FILE_ALL_INFO *pfindData, 376 const unsigned char *search_path, FILE_ALL_INFO *pfindData,
350 struct super_block *sb, int xid) 377 struct super_block *sb, int xid, const __u16 *pfid)
351{ 378{
352 int rc = 0; 379 int rc = 0;
353 struct cifsTconInfo *pTcon; 380 struct cifsTconInfo *pTcon;
354 struct inode *inode; 381 struct inode *inode;
355 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 382 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
356 char *tmp_path; 383 const unsigned char *full_path = NULL;
357 char *buf = NULL; 384 char *buf = NULL;
358 int adjustTZ = FALSE; 385 int adjustTZ = FALSE;
386 bool is_dfs_referral = false;
359 387
360 pTcon = cifs_sb->tcon; 388 pTcon = cifs_sb->tcon;
361 cFYI(1, ("Getting info on %s", search_path)); 389 cFYI(1, ("Getting info on %s", search_path));
@@ -373,8 +401,12 @@ int cifs_get_inode_info(struct inode **pinode,
373 if (buf == NULL) 401 if (buf == NULL)
374 return -ENOMEM; 402 return -ENOMEM;
375 pfindData = (FILE_ALL_INFO *)buf; 403 pfindData = (FILE_ALL_INFO *)buf;
404
405 full_path = cifs_get_search_path(pTcon, search_path);
406
407try_again_CIFSSMBQPathInfo:
376 /* could do find first instead but this returns more info */ 408 /* could do find first instead but this returns more info */
377 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, 409 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
378 0 /* not legacy */, 410 0 /* not legacy */,
379 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 411 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
380 CIFS_MOUNT_MAP_SPECIAL_CHR); 412 CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -382,7 +414,7 @@ int cifs_get_inode_info(struct inode **pinode,
382 when server claims no NT SMB support and the above call 414 when server claims no NT SMB support and the above call
383 failed at least once - set flag in tcon or mount */ 415 failed at least once - set flag in tcon or mount */
384 if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { 416 if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
385 rc = SMBQueryInformation(xid, pTcon, search_path, 417 rc = SMBQueryInformation(xid, pTcon, full_path,
386 pfindData, cifs_sb->local_nls, 418 pfindData, cifs_sb->local_nls,
387 cifs_sb->mnt_cifs_flags & 419 cifs_sb->mnt_cifs_flags &
388 CIFS_MOUNT_MAP_SPECIAL_CHR); 420 CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -391,31 +423,15 @@ int cifs_get_inode_info(struct inode **pinode,
391 } 423 }
392 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ 424 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
393 if (rc) { 425 if (rc) {
394 if (rc == -EREMOTE) { 426 if (rc == -EREMOTE && !is_dfs_referral) {
395 tmp_path = 427 is_dfs_referral = true;
396 kmalloc(strnlen 428 if (full_path != search_path) {
397 (pTcon->treeName, 429 kfree(full_path);
398 MAX_TREE_SIZE + 1) + 430 full_path = search_path;
399 strnlen(search_path, MAX_PATHCONF) + 1,
400 GFP_KERNEL);
401 if (tmp_path == NULL) {
402 kfree(buf);
403 return -ENOMEM;
404 } 431 }
405 432 goto try_again_CIFSSMBQPathInfo;
406 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
407 strncat(tmp_path, search_path, MAX_PATHCONF);
408 rc = connect_to_dfs_path(xid, pTcon->ses,
409 /* treename + */ tmp_path,
410 cifs_sb->local_nls,
411 cifs_sb->mnt_cifs_flags &
412 CIFS_MOUNT_MAP_SPECIAL_CHR);
413 kfree(tmp_path);
414 /* BB fix up inode etc. */
415 } else if (rc) {
416 kfree(buf);
417 return rc;
418 } 433 }
434 goto cgii_exit;
419 } else { 435 } else {
420 struct cifsInodeInfo *cifsInfo; 436 struct cifsInodeInfo *cifsInfo;
421 __u32 attr = le32_to_cpu(pfindData->Attributes); 437 __u32 attr = le32_to_cpu(pfindData->Attributes);
@@ -424,8 +440,8 @@ int cifs_get_inode_info(struct inode **pinode,
424 if (*pinode == NULL) { 440 if (*pinode == NULL) {
425 *pinode = new_inode(sb); 441 *pinode = new_inode(sb);
426 if (*pinode == NULL) { 442 if (*pinode == NULL) {
427 kfree(buf); 443 rc = -ENOMEM;
428 return -ENOMEM; 444 goto cgii_exit;
429 } 445 }
430 /* Is an i_ino of zero legal? Can we use that to check 446 /* Is an i_ino of zero legal? Can we use that to check
431 if the server supports returning inode numbers? Are 447 if the server supports returning inode numbers? Are
@@ -559,7 +575,7 @@ int cifs_get_inode_info(struct inode **pinode,
559 /* fill in 0777 bits from ACL */ 575 /* fill in 0777 bits from ACL */
560 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { 576 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
561 cFYI(1, ("Getting mode bits from ACL")); 577 cFYI(1, ("Getting mode bits from ACL"));
562 acl_to_uid_mode(inode, search_path); 578 acl_to_uid_mode(inode, search_path, pfid);
563 } 579 }
564#endif 580#endif
565 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { 581 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
@@ -573,8 +589,11 @@ int cifs_get_inode_info(struct inode **pinode,
573 atomic_set(&cifsInfo->inUse, 1); 589 atomic_set(&cifsInfo->inUse, 1);
574 } 590 }
575 591
576 cifs_set_ops(inode); 592 cifs_set_ops(inode, is_dfs_referral);
577 } 593 }
594cgii_exit:
595 if (full_path != search_path)
596 kfree(full_path);
578 kfree(buf); 597 kfree(buf);
579 return rc; 598 return rc;
580} 599}
@@ -603,7 +622,8 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
603 if (cifs_sb->tcon->unix_ext) 622 if (cifs_sb->tcon->unix_ext)
604 rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); 623 rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
605 else 624 else
606 rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); 625 rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid,
626 NULL);
607 if (rc && cifs_sb->tcon->ipc) { 627 if (rc && cifs_sb->tcon->ipc) {
608 cFYI(1, ("ipc connection - fake read inode")); 628 cFYI(1, ("ipc connection - fake read inode"));
609 inode->i_mode |= S_IFDIR; 629 inode->i_mode |= S_IFDIR;
@@ -804,7 +824,7 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
804 local_size = tmp_inode->i_size; 824 local_size = tmp_inode->i_size;
805 825
806 cifs_unix_info_to_inode(tmp_inode, pData, 1); 826 cifs_unix_info_to_inode(tmp_inode, pData, 1);
807 cifs_set_ops(tmp_inode); 827 cifs_set_ops(tmp_inode, false);
808 828
809 if (!S_ISREG(tmp_inode->i_mode)) 829 if (!S_ISREG(tmp_inode->i_mode))
810 return; 830 return;
@@ -936,7 +956,7 @@ mkdir_get_info:
936 inode->i_sb, xid); 956 inode->i_sb, xid);
937 else 957 else
938 rc = cifs_get_inode_info(&newinode, full_path, NULL, 958 rc = cifs_get_inode_info(&newinode, full_path, NULL,
939 inode->i_sb, xid); 959 inode->i_sb, xid, NULL);
940 960
941 if (pTcon->nocase) 961 if (pTcon->nocase)
942 direntry->d_op = &cifs_ci_dentry_ops; 962 direntry->d_op = &cifs_ci_dentry_ops;
@@ -1218,7 +1238,7 @@ int cifs_revalidate(struct dentry *direntry)
1218 } 1238 }
1219 } else { 1239 } else {
1220 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL, 1240 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
1221 direntry->d_sb, xid); 1241 direntry->d_sb, xid, NULL);
1222 if (rc) { 1242 if (rc) {
1223 cFYI(1, ("error on getting revalidate info %d", rc)); 1243 cFYI(1, ("error on getting revalidate info %d", rc));
1224/* if (rc != -ENOENT) 1244/* if (rc != -ENOENT)
@@ -1407,11 +1427,10 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1407 } 1427 }
1408 cifsInode = CIFS_I(direntry->d_inode); 1428 cifsInode = CIFS_I(direntry->d_inode);
1409 1429
1410 /* BB check if we need to refresh inode from server now ? BB */ 1430 if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
1411
1412 if (attrs->ia_valid & ATTR_SIZE) {
1413 /* 1431 /*
1414 Flush data before changing file size on server. If the 1432 Flush data before changing file size or changing the last
1433 write time of the file on the server. If the
1415 flush returns error, store it to report later and continue. 1434 flush returns error, store it to report later and continue.
1416 BB: This should be smarter. Why bother flushing pages that 1435 BB: This should be smarter. Why bother flushing pages that
1417 will be truncated anyway? Also, should we error out here if 1436 will be truncated anyway? Also, should we error out here if
@@ -1422,7 +1441,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1422 CIFS_I(direntry->d_inode)->write_behind_rc = rc; 1441 CIFS_I(direntry->d_inode)->write_behind_rc = rc;
1423 rc = 0; 1442 rc = 0;
1424 } 1443 }
1444 }
1425 1445
1446 if (attrs->ia_valid & ATTR_SIZE) {
1426 /* To avoid spurious oplock breaks from server, in the case of 1447 /* To avoid spurious oplock breaks from server, in the case of
1427 inodes that we already have open, avoid doing path based 1448 inodes that we already have open, avoid doing path based
1428 setting of file size if we can do it by handle. 1449 setting of file size if we can do it by handle.
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 1d6fb01b8e6d..d4e7ec93285f 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -205,7 +205,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
205 inode->i_sb, xid); 205 inode->i_sb, xid);
206 else 206 else
207 rc = cifs_get_inode_info(&newinode, full_path, NULL, 207 rc = cifs_get_inode_info(&newinode, full_path, NULL,
208 inode->i_sb, xid); 208 inode->i_sb, xid, NULL);
209 209
210 if (rc != 0) { 210 if (rc != 0) {
211 cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d", 211 cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",