summaryrefslogtreecommitdiff
path: root/fs/cifs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsfs.c100
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/connect.c2
-rw-r--r--fs/cifs/dir.c13
-rw-r--r--fs/cifs/file.c2
-rw-r--r--fs/cifs/sess.c10
6 files changed, 49 insertions, 80 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 3e298997629..bc4b12ca537 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -35,6 +35,7 @@
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
+#include <linux/namei.h>
#include <net/ipv6.h>
#include "cifsfs.h"
#include "cifspdu.h"
@@ -542,14 +543,12 @@ static const struct super_operations cifs_super_ops = {
static struct dentry *
cifs_get_root(struct smb_vol *vol, struct super_block *sb)
{
- int xid, rc;
- struct inode *inode;
- struct qstr name;
- struct dentry *dparent = NULL, *dchild = NULL, *alias;
+ struct dentry *dentry;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
- unsigned int i, full_len, len;
- char *full_path = NULL, *pstart;
+ char *full_path = NULL;
+ char *s, *p;
char sep;
+ int xid;
full_path = cifs_build_path_to_root(vol, cifs_sb,
cifs_sb_master_tcon(cifs_sb));
@@ -560,73 +559,32 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
xid = GetXid();
sep = CIFS_DIR_SEP(cifs_sb);
- dparent = dget(sb->s_root);
- full_len = strlen(full_path);
- full_path[full_len] = sep;
- pstart = full_path + 1;
-
- for (i = 1, len = 0; i <= full_len; i++) {
- if (full_path[i] != sep || !len) {
- len++;
- continue;
- }
-
- full_path[i] = 0;
- cFYI(1, "get dentry for %s", pstart);
-
- name.name = pstart;
- name.len = len;
- name.hash = full_name_hash(pstart, len);
- dchild = d_lookup(dparent, &name);
- if (dchild == NULL) {
- cFYI(1, "not exists");
- dchild = d_alloc(dparent, &name);
- if (dchild == NULL) {
- dput(dparent);
- dparent = ERR_PTR(-ENOMEM);
- goto out;
- }
- }
-
- cFYI(1, "get inode");
- if (dchild->d_inode == NULL) {
- cFYI(1, "not exists");
- inode = NULL;
- if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
- rc = cifs_get_inode_info_unix(&inode, full_path,
- sb, xid);
- else
- rc = cifs_get_inode_info(&inode, full_path,
- NULL, sb, xid, NULL);
- if (rc) {
- dput(dchild);
- dput(dparent);
- dparent = ERR_PTR(rc);
- goto out;
- }
- alias = d_materialise_unique(dchild, inode);
- if (alias != NULL) {
- dput(dchild);
- if (IS_ERR(alias)) {
- dput(dparent);
- dparent = ERR_PTR(-EINVAL); /* XXX */
- goto out;
- }
- dchild = alias;
- }
- }
- cFYI(1, "parent %p, child %p", dparent, dchild);
-
- dput(dparent);
- dparent = dchild;
- len = 0;
- pstart = full_path + i + 1;
- full_path[i] = sep;
- }
-out:
+ dentry = dget(sb->s_root);
+ p = s = full_path;
+
+ do {
+ struct inode *dir = dentry->d_inode;
+ struct dentry *child;
+
+ /* skip separators */
+ while (*s == sep)
+ s++;
+ if (!*s)
+ break;
+ p = s++;
+ /* next separator */
+ while (*s && *s != sep)
+ s++;
+
+ mutex_lock(&dir->i_mutex);
+ child = lookup_one_len(p, dentry, s - p);
+ mutex_unlock(&dir->i_mutex);
+ dput(dentry);
+ dentry = child;
+ } while (!IS_ERR(dentry));
_FreeXid(xid);
kfree(full_path);
- return dparent;
+ return dentry;
}
static int cifs_set_super(struct super_block *sb, void *data)
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 0900e1658c9..036ca83e5f4 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -129,5 +129,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops;
#endif /* CIFS_NFSD_EXPORT */
-#define CIFS_VERSION "1.73"
+#define CIFS_VERSION "1.74"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index dbd669cc5bc..ccc1afa0bf3 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3485,7 +3485,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
goto out;
}
- snprintf(username, MAX_USERNAME_SIZE, "krb50x%x", fsuid);
+ snprintf(username, sizeof(username), "krb50x%x", fsuid);
vol_info->username = username;
vol_info->local_nls = cifs_sb->local_nls;
vol_info->linux_uid = fsuid;
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 81914df47ef..fa8c21d913b 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -55,6 +55,7 @@ build_path_from_dentry(struct dentry *direntry)
char dirsep;
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+ unsigned seq;
if (direntry == NULL)
return NULL; /* not much we can do if dentry is freed and
@@ -68,22 +69,29 @@ build_path_from_dentry(struct dentry *direntry)
dfsplen = 0;
cifs_bp_rename_retry:
namelen = dfsplen;
+ seq = read_seqbegin(&rename_lock);
+ rcu_read_lock();
for (temp = direntry; !IS_ROOT(temp);) {
namelen += (1 + temp->d_name.len);
temp = temp->d_parent;
if (temp == NULL) {
cERROR(1, "corrupt dentry");
+ rcu_read_unlock();
return NULL;
}
}
+ rcu_read_unlock();
full_path = kmalloc(namelen+1, GFP_KERNEL);
if (full_path == NULL)
return full_path;
full_path[namelen] = 0; /* trailing null */
+ rcu_read_lock();
for (temp = direntry; !IS_ROOT(temp);) {
+ spin_lock(&temp->d_lock);
namelen -= 1 + temp->d_name.len;
if (namelen < 0) {
+ spin_unlock(&temp->d_lock);
break;
} else {
full_path[namelen] = dirsep;
@@ -91,14 +99,17 @@ cifs_bp_rename_retry:
temp->d_name.len);
cFYI(0, "name: %s", full_path + namelen);
}
+ spin_unlock(&temp->d_lock);
temp = temp->d_parent;
if (temp == NULL) {
cERROR(1, "corrupt dentry");
+ rcu_read_unlock();
kfree(full_path);
return NULL;
}
}
- if (namelen != dfsplen) {
+ rcu_read_unlock();
+ if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
cERROR(1, "did not end path lookup where expected namelen is %d",
namelen);
/* presumably this is only possible if racing with a rename
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index bb71471a4d9..a9b4a24f2a1 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1737,7 +1737,7 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
io_parms.pid = pid;
io_parms.tcon = pTcon;
io_parms.offset = *poffset;
- io_parms.length = len;
+ io_parms.length = cur_len;
rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
&read_data, &buf_type);
pSMBr = (struct smb_com_read_rsp *)read_data;
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 3892ab817a3..d3e619692ee 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -428,8 +428,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
flags |= NTLMSSP_NEGOTIATE_SIGN;
if (!ses->server->session_estab)
- flags |= NTLMSSP_NEGOTIATE_KEY_XCH |
- NTLMSSP_NEGOTIATE_EXTENDED_SEC;
+ flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
}
sec_blob->NegotiateFlags = cpu_to_le32(flags);
@@ -465,10 +464,11 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
if (ses->server->sec_mode &
- (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
flags |= NTLMSSP_NEGOTIATE_SIGN;
- if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED)
- flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
+ if (!ses->server->session_estab)
+ flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
+ }
tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE);
sec_blob->NegotiateFlags = cpu_to_le32(flags);