summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/CHANGES3
-rw-r--r--fs/cifs/cifs_dfs_ref.c25
-rw-r--r--fs/cifs/cifsfs.c66
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifspdu.h2
-rw-r--r--fs/cifs/dns_resolve.c62
6 files changed, 104 insertions, 56 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 05c9da6181c..8355e918fdd 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,6 @@
+Version 1.53
+------------
+
Version 1.52
------------
Fix oops on second mount to server when null auth is used.
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index 95024c066d8..f6fdecf6598 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -93,15 +93,11 @@ static char *cifs_get_share_name(const char *node_name)
/* find sharename end */
pSep++;
pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC));
- if (!pSep) {
- cERROR(1, ("%s:2 cant find share name in node name: %s",
- __func__, node_name));
- kfree(UNC);
- return NULL;
+ if (pSep) {
+ /* trim path up to sharename end
+ * now we have share name in UNC */
+ *pSep = 0;
}
- /* trim path up to sharename end
- * * now we have share name in UNC */
- *pSep = 0;
return UNC;
}
@@ -188,7 +184,7 @@ static char *compose_mount_options(const char *sb_mountdata,
tkn_e = strchr(tkn_e+1, '\\');
if (tkn_e) {
strcat(mountdata, ",prefixpath=");
- strcat(mountdata, tkn_e);
+ strcat(mountdata, tkn_e+1);
}
}
@@ -244,7 +240,8 @@ static char *build_full_dfs_path_from_dentry(struct dentry *dentry)
return NULL;
if (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS) {
- /* we should use full path name to correct working with DFS */
+ int i;
+ /* we should use full path name for correct working with DFS */
l_max_len = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE+1) +
strnlen(search_path, MAX_PATHCONF) + 1;
tmp_path = kmalloc(l_max_len, GFP_KERNEL);
@@ -253,8 +250,14 @@ static char *build_full_dfs_path_from_dentry(struct dentry *dentry)
return NULL;
}
strncpy(tmp_path, cifs_sb->tcon->treeName, l_max_len);
- strcat(tmp_path, search_path);
tmp_path[l_max_len-1] = 0;
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+ for (i = 0; i < l_max_len; i++) {
+ if (tmp_path[i] == '\\')
+ tmp_path[i] = '/';
+ }
+ strncat(tmp_path, search_path, l_max_len - strlen(tmp_path));
+
full_path = tmp_path;
kfree(search_path);
} else {
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 39c2cbdface..68f1cdf6aed 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -222,50 +222,50 @@ static int
cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
- int xid;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct cifsTconInfo *tcon = cifs_sb->tcon;
int rc = -EOPNOTSUPP;
- struct cifs_sb_info *cifs_sb;
- struct cifsTconInfo *pTcon;
+ int xid;
xid = GetXid();
- cifs_sb = CIFS_SB(sb);
- pTcon = cifs_sb->tcon;
-
buf->f_type = CIFS_MAGIC_NUMBER;
- /* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */
- buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would
- presumably be total path, but note
- that some servers (includinng Samba 3)
- have a shorter maximum path */
+ /*
+ * PATH_MAX may be too long - it would presumably be total path,
+ * but note that some servers (includinng Samba 3) have a shorter
+ * maximum path.
+ *
+ * Instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO.
+ */
+ buf->f_namelen = PATH_MAX;
buf->f_files = 0; /* undefined */
buf->f_ffree = 0; /* unlimited */
-/* BB we could add a second check for a QFS Unix capability bit */
-/* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */
- if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_POSIX_EXTENSIONS &
- le64_to_cpu(pTcon->fsUnixInfo.Capability)))
- rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf);
-
- /* Only need to call the old QFSInfo if failed
- on newer one */
- if (rc)
- if (pTcon->ses->capabilities & CAP_NT_SMBS)
- rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */
-
- /* Some old Windows servers also do not support level 103, retry with
- older level one if old server failed the previous call or we
- bypassed it because we detected that this was an older LANMAN sess */
+ /*
+ * We could add a second check for a QFS Unix capability bit
+ */
+ if ((tcon->ses->capabilities & CAP_UNIX) &&
+ (CIFS_POSIX_EXTENSIONS & le64_to_cpu(tcon->fsUnixInfo.Capability)))
+ rc = CIFSSMBQFSPosixInfo(xid, tcon, buf);
+
+ /*
+ * Only need to call the old QFSInfo if failed on newer one,
+ * e.g. by OS/2.
+ **/
+ if (rc && (tcon->ses->capabilities & CAP_NT_SMBS))
+ rc = CIFSSMBQFSInfo(xid, tcon, buf);
+
+ /*
+ * Some old Windows servers also do not support level 103, retry with
+ * older level one if old server failed the previous call or we
+ * bypassed it because we detected that this was an older LANMAN sess
+ */
if (rc)
- rc = SMBOldQFSInfo(xid, pTcon, buf);
- /* int f_type;
- __fsid_t f_fsid;
- int f_namelen; */
- /* BB get from info in tcon struct at mount time call to QFSAttrInfo */
+ rc = SMBOldQFSInfo(xid, tcon, buf);
+
FreeXid(xid);
- return 0; /* always return success? what if volume is no
- longer available? */
+ return 0;
}
static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd)
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index e1dd9f32e1d..503f6aa734a 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -110,5 +110,5 @@ extern int cifs_ioctl(struct inode *inode, struct file *filep,
extern const struct export_operations cifs_export_ops;
#endif /* EXPERIMENTAL */
-#define CIFS_VERSION "1.52"
+#define CIFS_VERSION "1.53"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 9f49c2f3582..a0d26b540d4 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -2050,7 +2050,7 @@ typedef struct {
to 0xFFFF00 */
#define CIFS_UNIX_LARGE_WRITE_CAP 0x00000080
#define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x00000100 /* can do SPNEGO crypt */
-#define CIFS_UNIX_TRANPSORT_ENCRYPTION_MANDATORY_CAP 0x00000200 /* must do */
+#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x00000200 /* must do */
#define CIFS_UNIX_PROXY_CAP 0x00000400 /* Proxy cap: 0xACE ioctl and
QFS PROXY call */
#ifdef CONFIG_CIFS_POSIX
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index 7cc86c41818..939e256f849 100644
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -55,6 +55,32 @@ struct key_type key_type_dns_resolver = {
.match = user_match,
};
+/* Checks if supplied name is IP address
+ * returns:
+ * 1 - name is IP
+ * 0 - name is not IP
+ */
+static int is_ip(const char *name)
+{
+ int rc;
+ struct sockaddr_in sin_server;
+ struct sockaddr_in6 sin_server6;
+
+ rc = cifs_inet_pton(AF_INET, name,
+ &sin_server.sin_addr.s_addr);
+
+ if (rc <= 0) {
+ /* not ipv4 address, try ipv6 */
+ rc = cifs_inet_pton(AF_INET6, name,
+ &sin_server6.sin6_addr.in6_u);
+ if (rc > 0)
+ return 1;
+ } else {
+ return 1;
+ }
+ /* we failed translating address */
+ return 0;
+}
/* Resolves server name to ip address.
* input:
@@ -67,8 +93,9 @@ int
dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
{
int rc = -EAGAIN;
- struct key *rkey;
+ struct key *rkey = ERR_PTR(-EAGAIN);
char *name;
+ char *data = NULL;
int len;
if (!ip_addr || !unc)
@@ -97,26 +124,41 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
memcpy(name, unc+2, len);
name[len] = 0;
+ if (is_ip(name)) {
+ cFYI(1, ("%s: it is IP, skipping dns upcall: %s",
+ __func__, name));
+ data = name;
+ goto skip_upcall;
+ }
+
rkey = request_key(&key_type_dns_resolver, name, "");
if (!IS_ERR(rkey)) {
- len = strlen(rkey->payload.data);
- *ip_addr = kmalloc(len+1, GFP_KERNEL);
- if (*ip_addr) {
- memcpy(*ip_addr, rkey->payload.data, len);
- (*ip_addr)[len] = '\0';
- cFYI(1, ("%s: resolved: %s to %s", __func__,
+ data = rkey->payload.data;
+ cFYI(1, ("%s: resolved: %s to %s", __func__,
rkey->description,
*ip_addr
));
+ } else {
+ cERROR(1, ("%s: unable to resolve: %s", __func__, name));
+ goto out;
+ }
+
+skip_upcall:
+ if (data) {
+ len = strlen(data);
+ *ip_addr = kmalloc(len+1, GFP_KERNEL);
+ if (*ip_addr) {
+ memcpy(*ip_addr, data, len);
+ (*ip_addr)[len] = '\0';
rc = 0;
} else {
rc = -ENOMEM;
}
- key_put(rkey);
- } else {
- cERROR(1, ("%s: unable to resolve: %s", __func__, name));
+ if (!IS_ERR(rkey))
+ key_put(rkey);
}
+out:
kfree(name);
return rc;
}