Commit 9d798057 authored by Pavel Shilovsky's avatar Pavel Shilovsky

Update CentOS 7.0 sources (3.10.0-229.1.2)

parent 2f82a4e6
...@@ -65,5 +65,6 @@ struct cifs_sb_info { ...@@ -65,5 +65,6 @@ struct cifs_sb_info {
char *mountdata; /* options received at mount time or via DFS refs */ char *mountdata; /* options received at mount time or via DFS refs */
struct backing_dev_info bdi; struct backing_dev_info bdi;
struct delayed_work prune_tlinks; struct delayed_work prune_tlinks;
struct rcu_head rcu;
}; };
#endif /* _CIFS_FS_SB_H */ #endif /* _CIFS_FS_SB_H */
...@@ -865,8 +865,8 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, ...@@ -865,8 +865,8 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
return rc; return rc;
} }
static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
__u16 fid, u32 *pacllen) const struct cifs_fid *cifsfid, u32 *pacllen)
{ {
struct cifs_ntsd *pntsd = NULL; struct cifs_ntsd *pntsd = NULL;
unsigned int xid; unsigned int xid;
...@@ -877,7 +877,8 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, ...@@ -877,7 +877,8 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
return ERR_CAST(tlink); return ERR_CAST(tlink);
xid = get_xid(); xid = get_xid();
rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen); rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
pacllen);
free_xid(xid); free_xid(xid);
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
...@@ -895,9 +896,10 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, ...@@ -895,9 +896,10 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
int oplock = 0; int oplock = 0;
unsigned int xid; unsigned int xid;
int rc, create_options = 0; int rc, create_options = 0;
__u16 fid;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
struct cifs_fid fid;
struct cifs_open_parms oparms;
if (IS_ERR(tlink)) if (IS_ERR(tlink))
return ERR_CAST(tlink); return ERR_CAST(tlink);
...@@ -908,13 +910,20 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, ...@@ -908,13 +910,20 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
if (backup_cred(cifs_sb)) if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT; create_options |= CREATE_OPEN_BACKUP_INTENT;
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, oparms.tcon = tcon;
FILE_SHARE_ALL, create_options, &fid, &oplock, oparms.cifs_sb = cifs_sb;
NULL, cifs_sb->local_nls, oparms.desired_access = READ_CONTROL;
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); oparms.share_access = FILE_SHARE_ALL;
oparms.create_options = create_options;
oparms.disposition = FILE_OPEN;
oparms.path = path;
oparms.fid = &fid;
oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, NULL);
if (!rc) { if (!rc) {
rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
CIFSSMBClose(xid, tcon, fid); CIFSSMBClose(xid, tcon, fid.netfid);
} }
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
...@@ -939,7 +948,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, ...@@ -939,7 +948,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
if (!open_file) if (!open_file)
return get_cifs_acl_by_path(cifs_sb, path, pacllen); return get_cifs_acl_by_path(cifs_sb, path, pacllen);
pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen); pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
cifsFileInfo_put(open_file); cifsFileInfo_put(open_file);
return pntsd; return pntsd;
} }
...@@ -951,10 +960,11 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, ...@@ -951,10 +960,11 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
int oplock = 0; int oplock = 0;
unsigned int xid; unsigned int xid;
int rc, access_flags, create_options = 0; int rc, access_flags, create_options = 0;
__u16 fid;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
struct cifs_fid fid;
struct cifs_open_parms oparms;
if (IS_ERR(tlink)) if (IS_ERR(tlink))
return PTR_ERR(tlink); return PTR_ERR(tlink);
...@@ -970,19 +980,26 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, ...@@ -970,19 +980,26 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
else else
access_flags = WRITE_DAC; access_flags = WRITE_DAC;
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags, oparms.tcon = tcon;
FILE_SHARE_ALL, create_options, &fid, &oplock, oparms.cifs_sb = cifs_sb;
NULL, cifs_sb->local_nls, oparms.desired_access = access_flags;
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); oparms.share_access = FILE_SHARE_ALL;
oparms.create_options = create_options;
oparms.disposition = FILE_OPEN;
oparms.path = path;
oparms.fid = &fid;
oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, NULL);
if (rc) { if (rc) {
cifs_dbg(VFS, "Unable to open file to set ACL\n"); cifs_dbg(VFS, "Unable to open file to set ACL\n");
goto out; goto out;
} }
rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag); rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc); cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
CIFSSMBClose(xid, tcon, fid); CIFSSMBClose(xid, tcon, fid.netfid);
out: out:
free_xid(xid); free_xid(xid);
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
...@@ -992,19 +1009,31 @@ out: ...@@ -992,19 +1009,31 @@ out:
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
int int
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
struct inode *inode, const char *path, const __u16 *pfid) struct inode *inode, const char *path,
const struct cifs_fid *pfid)
{ {
struct cifs_ntsd *pntsd = NULL; struct cifs_ntsd *pntsd = NULL;
u32 acllen = 0; u32 acllen = 0;
int rc = 0; int rc = 0;
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
struct cifs_tcon *tcon;
cifs_dbg(NOISY, "converting ACL to mode for %s\n", path); cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
if (pfid) if (IS_ERR(tlink))
pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen); return PTR_ERR(tlink);
else tcon = tlink_tcon(tlink);
pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
if (pfid && (tcon->ses->server->ops->get_acl_by_fid))
pntsd = tcon->ses->server->ops->get_acl_by_fid(cifs_sb, pfid,
&acllen);
else if (tcon->ses->server->ops->get_acl)
pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
&acllen);
else {
cifs_put_tlink(tlink);
return -EOPNOTSUPP;
}
/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
if (IS_ERR(pntsd)) { if (IS_ERR(pntsd)) {
rc = PTR_ERR(pntsd); rc = PTR_ERR(pntsd);
...@@ -1016,6 +1045,8 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, ...@@ -1016,6 +1045,8 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc); cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
} }
cifs_put_tlink(tlink);
return rc; return rc;
} }
...@@ -1029,15 +1060,30 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, ...@@ -1029,15 +1060,30 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
__u32 secdesclen = 0; __u32 secdesclen = 0;
struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */ struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */ struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
struct cifs_tcon *tcon;
if (IS_ERR(tlink))
return PTR_ERR(tlink);
tcon = tlink_tcon(tlink);
cifs_dbg(NOISY, "set ACL from mode for %s\n", path); cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
/* Get the security descriptor */ /* Get the security descriptor */
pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
if (tcon->ses->server->ops->get_acl == NULL) {
cifs_put_tlink(tlink);
return -EOPNOTSUPP;
}
pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
&secdesclen);
if (IS_ERR(pntsd)) { if (IS_ERR(pntsd)) {
rc = PTR_ERR(pntsd); rc = PTR_ERR(pntsd);
cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc); cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
goto out; cifs_put_tlink(tlink);
return rc;
} }
/* /*
...@@ -1050,6 +1096,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, ...@@ -1050,6 +1096,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
pnntsd = kmalloc(secdesclen, GFP_KERNEL); pnntsd = kmalloc(secdesclen, GFP_KERNEL);
if (!pnntsd) { if (!pnntsd) {
kfree(pntsd); kfree(pntsd);
cifs_put_tlink(tlink);
return -ENOMEM; return -ENOMEM;
} }
...@@ -1058,14 +1105,18 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, ...@@ -1058,14 +1105,18 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc); cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
if (tcon->ses->server->ops->set_acl == NULL)
rc = -EOPNOTSUPP;
if (!rc) { if (!rc) {
/* Set the security descriptor */ /* Set the security descriptor */
rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag); rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
path, aclflag);
cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc); cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
} }
cifs_put_tlink(tlink);
kfree(pnntsd); kfree(pnntsd);
kfree(pntsd); kfree(pntsd);
out:
return rc; return rc;
} }
...@@ -548,7 +548,13 @@ static int ...@@ -548,7 +548,13 @@ static int
CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
{ {
int rc; int rc;
unsigned int offset = CIFS_SESS_KEY_SIZE + 8; struct ntlmv2_resp *ntlmv2 = (struct ntlmv2_resp *)
(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
unsigned int hash_len;
/* The MD5 hash starts at challenge_key.key */
hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE +
offsetof(struct ntlmv2_resp, challenge.key[0]));
if (!ses->server->secmech.sdeschmacmd5) { if (!ses->server->secmech.sdeschmacmd5) {
cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__); cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
...@@ -570,20 +576,21 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) ...@@ -570,20 +576,21 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
} }
if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED)
memcpy(ses->auth_key.response + offset, memcpy(ntlmv2->challenge.key,
ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
else else
memcpy(ses->auth_key.response + offset, memcpy(ntlmv2->challenge.key,
ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
ses->auth_key.response + offset, ses->auth_key.len - offset); ntlmv2->challenge.key, hash_len);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not update with response\n", __func__); cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
return rc; return rc;
} }
/* Note that the MD5 digest over writes anon.challenge_key.key */
rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
ses->auth_key.response + CIFS_SESS_KEY_SIZE); ntlmv2->ntlmv2_hash);
if (rc) if (rc)
cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
...@@ -627,7 +634,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -627,7 +634,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
int rc; int rc;
int baselen; int baselen;
unsigned int tilen; unsigned int tilen;
struct ntlmv2_resp *buf; struct ntlmv2_resp *ntlmv2;
char ntlmv2_hash[16]; char ntlmv2_hash[16];
unsigned char *tiblob = NULL; /* target info blob */ unsigned char *tiblob = NULL; /* target info blob */
...@@ -660,13 +667,14 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -660,13 +667,14 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
} }
ses->auth_key.len += baselen; ses->auth_key.len += baselen;
buf = (struct ntlmv2_resp *) ntlmv2 = (struct ntlmv2_resp *)
(ses->auth_key.response + CIFS_SESS_KEY_SIZE); (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
buf->blob_signature = cpu_to_le32(0x00000101); ntlmv2->blob_signature = cpu_to_le32(0x00000101);
buf->reserved = 0; ntlmv2->reserved = 0;
buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); /* Must be within 5 minutes of the server */
get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
buf->reserved2 = 0; get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
ntlmv2->reserved2 = 0;
memcpy(ses->auth_key.response + baselen, tiblob, tilen); memcpy(ses->auth_key.response + baselen, tiblob, tilen);
...@@ -706,7 +714,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -706,7 +714,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
} }
rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
ses->auth_key.response + CIFS_SESS_KEY_SIZE, ntlmv2->ntlmv2_hash,
CIFS_HMAC_MD5_HASH_SIZE); CIFS_HMAC_MD5_HASH_SIZE);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not update with response\n", __func__); cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
......
...@@ -87,10 +87,6 @@ extern mempool_t *cifs_mid_poolp; ...@@ -87,10 +87,6 @@ extern mempool_t *cifs_mid_poolp;
struct workqueue_struct *cifsiod_wq; struct workqueue_struct *cifsiod_wq;
#ifdef CONFIG_CIFS_SMB2
__u8 cifs_client_guid[SMB2_CLIENT_GUID_SIZE];
#endif
/* /*
* Bumps refcount for cifs super block. * Bumps refcount for cifs super block.
* Note that it should be only called if a referece to VFS super block is * Note that it should be only called if a referece to VFS super block is
...@@ -120,14 +116,16 @@ cifs_read_super(struct super_block *sb) ...@@ -120,14 +116,16 @@ cifs_read_super(struct super_block *sb)
{ {
struct inode *inode; struct inode *inode;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
int rc = 0; int rc = 0;
cifs_sb = CIFS_SB(sb); cifs_sb = CIFS_SB(sb);
tcon = cifs_sb_master_tcon(cifs_sb);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL)
sb->s_flags |= MS_POSIXACL; sb->s_flags |= MS_POSIXACL;
if (cifs_sb_master_tcon(cifs_sb)->ses->capabilities & CAP_LARGE_FILES) if (tcon->ses->capabilities & tcon->ses->server->vals->cap_large_files)
sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_maxbytes = MAX_LFS_FILESIZE;
else else
sb->s_maxbytes = MAX_NON_LFS; sb->s_maxbytes = MAX_NON_LFS;
...@@ -147,7 +145,7 @@ cifs_read_super(struct super_block *sb) ...@@ -147,7 +145,7 @@ cifs_read_super(struct super_block *sb)
goto out_no_root; goto out_no_root;
} }
if (cifs_sb_master_tcon(cifs_sb)->nocase) if (tcon->nocase)
sb->s_d_op = &cifs_ci_dentry_ops; sb->s_d_op = &cifs_ci_dentry_ops;
else else
sb->s_d_op = &cifs_dentry_ops; sb->s_d_op = &cifs_dentry_ops;
...@@ -249,8 +247,9 @@ cifs_alloc_inode(struct super_block *sb) ...@@ -249,8 +247,9 @@ cifs_alloc_inode(struct super_block *sb)
* server, can not assume caching of file data or metadata. * server, can not assume caching of file data or metadata.
*/ */
cifs_set_oplock_level(cifs_inode, 0); cifs_set_oplock_level(cifs_inode, 0);
cifs_inode->delete_pending = false; cifs_inode->flags = 0;
cifs_inode->invalid_mapping = false; spin_lock_init(&cifs_inode->writers_lock);
cifs_inode->writers = 0;
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
cifs_inode->server_eof = 0; cifs_inode->server_eof = 0;
cifs_inode->uniqueid = 0; cifs_inode->uniqueid = 0;
...@@ -295,7 +294,7 @@ cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) ...@@ -295,7 +294,7 @@ cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr; struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr;
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr; struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr;
seq_printf(s, ",addr="); seq_puts(s, ",addr=");
switch (server->dstaddr.ss_family) { switch (server->dstaddr.ss_family) {
case AF_INET: case AF_INET:
...@@ -307,7 +306,7 @@ cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) ...@@ -307,7 +306,7 @@ cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
seq_printf(s, "%%%u", sa6->sin6_scope_id); seq_printf(s, "%%%u", sa6->sin6_scope_id);
break; break;
default: default:
seq_printf(s, "(unknown)"); seq_puts(s, "(unknown)");
} }
} }
...@@ -317,45 +316,45 @@ cifs_show_security(struct seq_file *s, struct cifs_ses *ses) ...@@ -317,45 +316,45 @@ cifs_show_security(struct seq_file *s, struct cifs_ses *ses)
if (ses->sectype == Unspecified) if (ses->sectype == Unspecified)
return; return;
seq_printf(s, ",sec="); seq_puts(s, ",sec=");
switch (ses->sectype) { switch (ses->sectype) {
case LANMAN: case LANMAN:
seq_printf(s, "lanman"); seq_puts(s, "lanman");
break; break;
case NTLMv2: case NTLMv2:
seq_printf(s, "ntlmv2"); seq_puts(s, "ntlmv2");
break; break;
case NTLM: case NTLM:
seq_printf(s, "ntlm"); seq_puts(s, "ntlm");
break; break;
case Kerberos: case Kerberos:
seq_printf(s, "krb5"); seq_puts(s, "krb5");
break; break;
case RawNTLMSSP: case RawNTLMSSP:
seq_printf(s, "ntlmssp"); seq_puts(s, "ntlmssp");
break; break;
default: default:
/* shouldn't ever happen */ /* shouldn't ever happen */
seq_printf(s, "unknown"); seq_puts(s, "unknown");
break; break;
} }
if (ses->sign) if (ses->sign)
seq_printf(s, "i"); seq_puts(s, "i");
} }
static void static void
cifs_show_cache_flavor(struct seq_file *s, struct cifs_sb_info *cifs_sb) cifs_show_cache_flavor(struct seq_file *s, struct cifs_sb_info *cifs_sb)
{ {
seq_printf(s, ",cache="); seq_puts(s, ",cache=");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
seq_printf(s, "strict"); seq_puts(s, "strict");
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
seq_printf(s, "none"); seq_puts(s, "none");
else else
seq_printf(s, "loose"); seq_puts(s, "loose");
} }
static void static void
...@@ -388,7 +387,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root) ...@@ -388,7 +387,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
cifs_show_cache_flavor(s, cifs_sb); cifs_show_cache_flavor(s, cifs_sb);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
seq_printf(s, ",multiuser"); seq_puts(s, ",multiuser");
else if (tcon->ses->user_name) else if (tcon->ses->user_name)
seq_printf(s, ",username=%s", tcon->ses->user_name); seq_printf(s, ",username=%s", tcon->ses->user_name);
...@@ -414,16 +413,16 @@ cifs_show_options(struct seq_file *s, struct dentry *root) ...@@ -414,16 +413,16 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
seq_printf(s, ",uid=%u", seq_printf(s, ",uid=%u",
from_kuid_munged(&init_user_ns, cifs_sb->mnt_uid)); from_kuid_munged(&init_user_ns, cifs_sb->mnt_uid));
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
seq_printf(s, ",forceuid"); seq_puts(s, ",forceuid");
else else
seq_printf(s, ",noforceuid"); seq_puts(s, ",noforceuid");
seq_printf(s, ",gid=%u", seq_printf(s, ",gid=%u",
from_kgid_munged(&init_user_ns, cifs_sb->mnt_gid)); from_kgid_munged(&init_user_ns, cifs_sb->mnt_gid));
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
seq_printf(s, ",forcegid"); seq_puts(s, ",forcegid");
else else
seq_printf(s, ",noforcegid"); seq_puts(s, ",noforcegid");
cifs_show_address(s, tcon->ses->server); cifs_show_address(s, tcon->ses->server);
...@@ -435,50 +434,50 @@ cifs_show_options(struct seq_file *s, struct dentry *root) ...@@ -435,50 +434,50 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
cifs_show_nls(s, cifs_sb->local_nls); cifs_show_nls(s, cifs_sb->local_nls);
if (tcon->seal) if (tcon->seal)
seq_printf(s, ",seal"); seq_puts(s, ",seal");
if (tcon->nocase) if (tcon->nocase)
seq_printf(s, ",nocase"); seq_puts(s, ",nocase");
if (tcon->retry) if (tcon->retry)
seq_printf(s, ",hard"); seq_puts(s, ",hard");
if (tcon->unix_ext) if (tcon->unix_ext)
seq_printf(s, ",unix"); seq_puts(s, ",unix");
else else
seq_printf(s, ",nounix"); seq_puts(s, ",nounix");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
seq_printf(s, ",posixpaths"); seq_puts(s, ",posixpaths");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
seq_printf(s, ",setuids"); seq_puts(s, ",setuids");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
seq_printf(s, ",serverino"); seq_puts(s, ",serverino");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
seq_printf(s, ",rwpidforward"); seq_puts(s, ",rwpidforward");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL)
seq_printf(s, ",forcemand"); seq_puts(s, ",forcemand");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
seq_printf(s, ",nouser_xattr"); seq_puts(s, ",nouser_xattr");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
seq_printf(s, ",mapchars"); seq_puts(s, ",mapchars");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
seq_printf(s, ",sfu"); seq_puts(s, ",sfu");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
seq_printf(s, ",nobrl"); seq_puts(s, ",nobrl");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
seq_printf(s, ",cifsacl"); seq_puts(s, ",cifsacl");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
seq_printf(s, ",dynperm"); seq_puts(s, ",dynperm");
if (root->d_sb->s_flags & MS_POSIXACL) if (root->d_sb->s_flags & MS_POSIXACL)
seq_printf(s, ",acl"); seq_puts(s, ",acl");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
seq_printf(s, ",mfsymlinks"); seq_puts(s, ",mfsymlinks");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)
seq_printf(s, ",fsc"); seq_puts(s, ",fsc");
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) && if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) &&
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL)) (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL))
seq_printf(s, ",wine"); seq_puts(s, ",wine");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)
seq_printf(s, ",nostrictsync"); seq_puts(s, ",nostrictsync");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
seq_printf(s, ",noperm"); seq_puts(s, ",noperm");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID)
seq_printf(s, ",backupuid=%u", seq_printf(s, ",backupuid=%u",
from_kuid_munged(&init_user_ns, from_kuid_munged(&init_user_ns,
...@@ -732,19 +731,26 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -732,19 +731,26 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos) unsigned long nr_segs, loff_t pos)
{ {
struct inode *inode = file_inode(iocb->ki_filp); struct inode *inode = file_inode(iocb->ki_filp);
struct cifsInodeInfo *cinode = CIFS_I(inode);
ssize_t written; ssize_t written;
int rc; int rc;
written = cifs_get_writer(cinode);
if (written)
return written;
written = generic_file_aio_write(iocb, iov, nr_segs, pos); written = generic_file_aio_write(iocb, iov, nr_segs, pos);
if (CIFS_CACHE_WRITE(CIFS_I(inode))) if (CIFS_CACHE_WRITE(CIFS_I(inode)))
return written; goto out;
rc = filemap_fdatawrite(inode->i_mapping); rc = filemap_fdatawrite(inode->i_mapping);
if (rc) if (rc)
cifs_dbg(FYI, "cifs_file_aio_write: %d rc on %p inode\n", cifs_dbg(FYI, "cifs_file_aio_write: %d rc on %p inode\n",
rc, inode); rc, inode);
out:
cifs_put_writer(cinode);
return written; return written;
} }
...@@ -815,6 +821,12 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) ...@@ -815,6 +821,12 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
return -EAGAIN; return -EAGAIN;
} }
static int cifs_rename(struct inode *old_dir, struct dentry *old,
struct inode *new_dir, struct dentry *new)
{
return cifs_rename2(old_dir, old, new_dir, new, 0);
}
struct file_system_type cifs_fs_type = { struct file_system_type cifs_fs_type = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "cifs", .name = "cifs",
...@@ -823,7 +835,8 @@ struct file_system_type cifs_fs_type = { ...@@ -823,7 +835,8 @@ struct file_system_type cifs_fs_type = {
/* .fs_flags */ /* .fs_flags */
}; };
MODULE_ALIAS_FS("cifs"); MODULE_ALIAS_FS("cifs");
const struct inode_operations cifs_dir_inode_ops = { const struct inode_operations_wrapper cifs_dir_inode_ops = {
.ops = {
.create = cifs_create, .create = cifs_create,
.atomic_open = cifs_atomic_open, .atomic_open = cifs_atomic_open,
.lookup = cifs_lookup, .lookup = cifs_lookup,
...@@ -844,13 +857,14 @@ const struct inode_operations cifs_dir_inode_ops = { ...@@ -844,13 +857,14 @@ const struct inode_operations cifs_dir_inode_ops = {
.listxattr = cifs_listxattr, .listxattr = cifs_listxattr,
.removexattr = cifs_removexattr, .removexattr = cifs_removexattr,
#endif #endif
},
.rename2 = cifs_rename2,
}; };
const struct inode_operations cifs_file_inode_ops = { const struct inode_operations cifs_file_inode_ops = {
/* revalidate:cifs_revalidate, */ /* revalidate:cifs_revalidate, */
.setattr = cifs_setattr, .setattr = cifs_setattr,
.getattr = cifs_getattr, /* do we need this anymore? */ .getattr = cifs_getattr, /* do we need this anymore? */
.rename = cifs_rename,
.permission = cifs_permission, .permission = cifs_permission,
#ifdef CONFIG_CIFS_XATTR #ifdef CONFIG_CIFS_XATTR
.setxattr = cifs_setxattr, .setxattr = cifs_setxattr,
...@@ -863,7 +877,7 @@ const struct inode_operations cifs_file_inode_ops = { ...@@ -863,7 +877,7 @@ const struct inode_operations cifs_file_inode_ops = {
const struct inode_operations cifs_symlink_inode_ops = { const struct inode_operations cifs_symlink_inode_ops = {
.readlink = generic_readlink, .readlink = generic_readlink,
.follow_link = cifs_follow_link, .follow_link = cifs_follow_link,
.put_link = cifs_put_link, .put_link = kfree_put_link,
.permission = cifs_permission, .permission = cifs_permission,
/* BB add the following two eventually */ /* BB add the following two eventually */
/* revalidate: cifs_revalidate, /* revalidate: cifs_revalidate,
...@@ -1006,7 +1020,7 @@ cifs_init_once(void *inode) ...@@ -1006,7 +1020,7 @@ cifs_init_once(void *inode)
init_rwsem(&cifsi->lock_sem); init_rwsem(&cifsi->lock_sem);
} }
static int static int __init
cifs_init_inodecache(void) cifs_init_inodecache(void)
{ {
cifs_inode_cachep = kmem_cache_create("cifs_inode_cache", cifs_inode_cachep = kmem_cache_create("cifs_inode_cache",
...@@ -1181,10 +1195,6 @@ init_cifs(void) ...@@ -1181,10 +1195,6 @@ init_cifs(void)
spin_lock_init(&cifs_file_list_lock); spin_lock_init(&cifs_file_list_lock);
spin_lock_init(&GlobalMid_Lock); spin_lock_init(&GlobalMid_Lock);
#ifdef CONFIG_CIFS_SMB2
get_random_bytes(cifs_client_guid, SMB2_CLIENT_GUID_SIZE);
#endif
if (cifs_max_pending < 2) { if (cifs_max_pending < 2) {
cifs_max_pending = 2; cifs_max_pending = 2;
cifs_dbg(FYI, "cifs_max_pending set to min of 2\n"); cifs_dbg(FYI, "cifs_max_pending set to min of 2\n");
......
...@@ -22,20 +22,28 @@ ...@@ -22,20 +22,28 @@
#ifndef _CIFSFS_H #ifndef _CIFSFS_H
#define _CIFSFS_H #define _CIFSFS_H
#include <linux/hash.h>
#define ROOT_I 2 #define ROOT_I 2
/* /*
* ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down
* so that it will fit. * so that it will fit. We use hash_64 to convert the value to 31 bits, and
* then add 1, to ensure that we don't end up with a 0 as the value.
*/ */
#if BITS_PER_LONG == 64
static inline ino_t static inline ino_t
cifs_uniqueid_to_ino_t(u64 fileid) cifs_uniqueid_to_ino_t(u64 fileid)
{ {
ino_t ino = (ino_t) fileid; return (ino_t)fileid;
if (sizeof(ino_t) < sizeof(u64))
ino ^= fileid >> (sizeof(u64)-sizeof(ino_t)) * 8;
return ino;
} }
#else
static inline ino_t
cifs_uniqueid_to_ino_t(u64 fileid)
{
return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1;
}
#endif
extern struct file_system_type cifs_fs_type; extern struct file_system_type cifs_fs_type;
extern const struct address_space_operations cifs_addr_ops; extern const struct address_space_operations cifs_addr_ops;
...@@ -46,7 +54,7 @@ extern void cifs_sb_active(struct super_block *sb); ...@@ -46,7 +54,7 @@ extern void cifs_sb_active(struct super_block *sb);
extern void cifs_sb_deactive(struct super_block *sb); extern void cifs_sb_deactive(struct super_block *sb);
/* Functions related to inodes */ /* Functions related to inodes */
extern const struct inode_operations cifs_dir_inode_ops; extern const struct inode_operations_wrapper cifs_dir_inode_ops;
extern struct inode *cifs_root_iget(struct super_block *); extern struct inode *cifs_root_iget(struct super_block *);
extern int cifs_create(struct inode *, struct dentry *, umode_t, extern int cifs_create(struct inode *, struct dentry *, umode_t,
bool excl); bool excl);
...@@ -60,13 +68,15 @@ extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); ...@@ -60,13 +68,15 @@ extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
extern int cifs_mknod(struct inode *, struct dentry *, umode_t, dev_t); extern int cifs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
extern int cifs_mkdir(struct inode *, struct dentry *, umode_t); extern int cifs_mkdir(struct inode *, struct dentry *, umode_t);
extern int cifs_rmdir(struct inode *, struct dentry *); extern int cifs_rmdir(struct inode *, struct dentry *);
extern int cifs_rename(struct inode *, struct dentry *, struct inode *, extern int cifs_rename2(struct inode *, struct dentry *, struct inode *,
struct dentry *); struct dentry *, unsigned int);
extern int cifs_revalidate_file_attr(struct file *filp); extern int cifs_revalidate_file_attr(struct file *filp);
extern int cifs_revalidate_dentry_attr(struct dentry *); extern int cifs_revalidate_dentry_attr(struct dentry *);
extern int cifs_revalidate_file(struct file *filp); extern int cifs_revalidate_file(struct file *filp);
extern int cifs_revalidate_dentry(struct dentry *); extern int cifs_revalidate_dentry(struct dentry *);
extern int cifs_invalidate_mapping(struct inode *inode); extern int cifs_invalidate_mapping(struct inode *inode);
extern int cifs_revalidate_mapping(struct inode *inode);
extern int cifs_zap_mapping(struct inode *inode);
extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int cifs_setattr(struct dentry *, struct iattr *); extern int cifs_setattr(struct dentry *, struct iattr *);
...@@ -115,8 +125,6 @@ extern struct vfsmount *cifs_dfs_d_automount(struct path *path); ...@@ -115,8 +125,6 @@ extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
/* Functions related to symlinks */ /* Functions related to symlinks */
extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
extern void cifs_put_link(struct dentry *direntry,
struct nameidata *nd, void *);
extern int cifs_readlink(struct dentry *direntry, char __user *buffer, extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
int buflen); int buflen);
extern int cifs_symlink(struct inode *inode, struct dentry *direntry, extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
...@@ -132,5 +140,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); ...@@ -132,5 +140,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops; extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */ #endif /* CONFIG_CIFS_NFSD_EXPORT */
#define CIFS_VERSION "2.01" #define CIFS_VERSION "2.03"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -228,6 +228,8 @@ struct smb_version_operations { ...@@ -228,6 +228,8 @@ struct smb_version_operations {
/* verify the message */ /* verify the message */
int (*check_message)(char *, unsigned int); int (*check_message)(char *, unsigned int);
bool (*is_oplock_break)(char *, struct TCP_Server_Info *); bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
void (*downgrade_oplock)(struct TCP_Server_Info *,
struct cifsInodeInfo *, bool);
/* process transaction2 response */ /* process transaction2 response */
bool (*check_trans2)(struct mid_q_entry *, struct TCP_Server_Info *, bool (*check_trans2)(struct mid_q_entry *, struct TCP_Server_Info *,
char *, int); char *, int);
...@@ -261,7 +263,7 @@ struct smb_version_operations { ...@@ -261,7 +263,7 @@ struct smb_version_operations {
/* query path data from the server */ /* query path data from the server */
int (*query_path_info)(const unsigned int, struct cifs_tcon *, int (*query_path_info)(const unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, const char *, struct cifs_sb_info *, const char *,
FILE_ALL_INFO *, bool *); FILE_ALL_INFO *, bool *, bool *);
/* query file data from the server */ /* query file data from the server */
int (*query_file_info)(const unsigned int, struct cifs_tcon *, int (*query_file_info)(const unsigned int, struct cifs_tcon *,
struct cifs_fid *, FILE_ALL_INFO *); struct cifs_fid *, FILE_ALL_INFO *);
...@@ -278,6 +280,8 @@ struct smb_version_operations { ...@@ -278,6 +280,8 @@ struct smb_version_operations {
/* set attributes */ /* set attributes */
int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *, int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *,
const unsigned int); const unsigned int);
int (*set_compression)(const unsigned int, struct cifs_tcon *,
struct cifsFileInfo *);
/* check if we can send an echo or nor */ /* check if we can send an echo or nor */
bool (*can_echo)(struct TCP_Server_Info *); bool (*can_echo)(struct TCP_Server_Info *);
/* send echo request */ /* send echo request */
...@@ -369,8 +373,12 @@ struct smb_version_operations { ...@@ -369,8 +373,12 @@ struct smb_version_operations {
void (*new_lease_key)(struct cifs_fid *); void (*new_lease_key)(struct cifs_fid *);
int (*generate_signingkey)(struct cifs_ses *); int (*generate_signingkey)(struct cifs_ses *);
int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *); int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *);
int (*query_mf_symlink)(const unsigned char *, char *, unsigned int *, int (*query_mf_symlink)(unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, unsigned int); struct cifs_sb_info *, const unsigned char *,
char *, unsigned int *);
int (*create_mf_symlink)(unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, const unsigned char *,
char *, unsigned int *);
/* if we can do cache read operations */ /* if we can do cache read operations */
bool (*is_read_op)(__u32); bool (*is_read_op)(__u32);
/* set oplock level for the inode */ /* set oplock level for the inode */
...@@ -380,6 +388,22 @@ struct smb_version_operations { ...@@ -380,6 +388,22 @@ struct smb_version_operations {
char * (*create_lease_buf)(u8 *, u8); char * (*create_lease_buf)(u8 *, u8);
/* parse lease context buffer and return oplock/epoch info */ /* parse lease context buffer and return oplock/epoch info */
__u8 (*parse_lease_buf)(void *, unsigned int *); __u8 (*parse_lease_buf)(void *, unsigned int *);
int (*clone_range)(const unsigned int, struct cifsFileInfo *src_file,
struct cifsFileInfo *target_file, u64 src_off, u64 len,
u64 dest_off);
int (*validate_negotiate)(const unsigned int, struct cifs_tcon *);
ssize_t (*query_all_EAs)(const unsigned int, struct cifs_tcon *,
const unsigned char *, const unsigned char *, char *,
size_t, const struct nls_table *, int);
int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
const char *, const void *, const __u16,
const struct nls_table *, int);
struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *,
const char *, u32 *);
struct cifs_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *,
const struct cifs_fid *, u32 *);
int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
int);
}; };
struct smb_version_values { struct smb_version_values {
...@@ -535,6 +559,7 @@ struct TCP_Server_Info { ...@@ -535,6 +559,7 @@ struct TCP_Server_Info {
int echo_credits; /* echo reserved slots */ int echo_credits; /* echo reserved slots */
int oplock_credits; /* oplock break reserved slots */ int oplock_credits; /* oplock break reserved slots */
bool echoes:1; /* enable echoes */ bool echoes:1; /* enable echoes */
__u8 client_guid[SMB2_CLIENT_GUID_SIZE]; /* Client GUID */
#endif #endif
u16 dialect; /* dialect index that server chose */ u16 dialect; /* dialect index that server chose */
bool oplocks:1; /* enable oplocks */ bool oplocks:1; /* enable oplocks */
...@@ -621,11 +646,34 @@ set_credits(struct TCP_Server_Info *server, const int val) ...@@ -621,11 +646,34 @@ set_credits(struct TCP_Server_Info *server, const int val)
} }
static inline __u64 static inline __u64
get_next_mid(struct TCP_Server_Info *server) get_next_mid64(struct TCP_Server_Info *server)
{ {
return server->ops->get_next_mid(server); return server->ops->get_next_mid(server);
} }
static inline __le16
get_next_mid(struct TCP_Server_Info *server)
{
__u16 mid = get_next_mid64(server);
/*
* The value in the SMB header should be little endian for easy
* on-the-wire decoding.
*/
return cpu_to_le16(mid);
}
static inline __u16
get_mid(const struct smb_hdr *smb)
{
return le16_to_cpu(smb->Mid);
}
static inline bool
compare_mid(__u16 mid, const struct smb_hdr *smb)
{
return mid == le16_to_cpu(smb->Mid);
}
/* /*
* When the server supports very large reads and writes via POSIX extensions, * When the server supports very large reads and writes via POSIX extensions,
* we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
...@@ -829,6 +877,11 @@ struct cifs_tcon { ...@@ -829,6 +877,11 @@ struct cifs_tcon {
__u32 maximal_access; __u32 maximal_access;
__u32 vol_serial_number; __u32 vol_serial_number;
__le64 vol_create_time; __le64 vol_create_time;
__u32 ss_flags; /* sector size flags */
__u32 perf_sector_size; /* best sector size for perf */
__u32 max_chunks;
__u32 max_bytes_chunk;
__u32 max_bytes_copy;
#endif /* CONFIG_CIFS_SMB2 */ #endif /* CONFIG_CIFS_SMB2 */
#ifdef CONFIG_CIFS_FSCACHE #ifdef CONFIG_CIFS_FSCACHE
u64 resource_id; /* server resource id */ u64 resource_id; /* server resource id */
...@@ -1069,8 +1122,15 @@ struct cifsInodeInfo { ...@@ -1069,8 +1122,15 @@ struct cifsInodeInfo {
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
unsigned int oplock; /* oplock/lease level we have */ unsigned int oplock; /* oplock/lease level we have */
unsigned int epoch; /* used to track lease state changes */ unsigned int epoch; /* used to track lease state changes */
bool delete_pending; /* DELETE_ON_CLOSE is set */ #define CIFS_INODE_PENDING_OPLOCK_BREAK (0) /* oplock break in progress */
bool invalid_mapping; /* pagecache is invalid */ #define CIFS_INODE_PENDING_WRITERS (1) /* Writes in progress */
#define CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2 (2) /* Downgrade oplock to L2 */
#define CIFS_INO_DELETE_PENDING (3) /* delete pending on server */
#define CIFS_INO_INVALID_MAPPING (4) /* pagecache is invalid */
#define CIFS_INO_LOCK (5) /* lock bit for synchronization */
unsigned long flags;
spinlock_t writers_lock;
unsigned int writers; /* Number of writers on this inode */
unsigned long time; /* jiffies of last update of inode */ unsigned long time; /* jiffies of last update of inode */
u64 server_eof; /* current file size on server -- protected by i_lock */ u64 server_eof; /* current file size on server -- protected by i_lock */
u64 uniqueid; /* server inode number */ u64 uniqueid; /* server inode number */
...@@ -1277,6 +1337,7 @@ struct dfs_info3_param { ...@@ -1277,6 +1337,7 @@ struct dfs_info3_param {
#define CIFS_FATTR_DELETE_PENDING 0x2 #define CIFS_FATTR_DELETE_PENDING 0x2
#define CIFS_FATTR_NEED_REVAL 0x4 #define CIFS_FATTR_NEED_REVAL 0x4
#define CIFS_FATTR_INO_COLLISION 0x8 #define CIFS_FATTR_INO_COLLISION 0x8
#define CIFS_FATTR_UNKNOWN_NLINK 0x10
struct cifs_fattr { struct cifs_fattr {
u32 cf_flags; u32 cf_flags;
......
...@@ -436,7 +436,7 @@ struct smb_hdr { ...@@ -436,7 +436,7 @@ struct smb_hdr {
__u16 Tid; __u16 Tid;
__le16 Pid; __le16 Pid;
__u16 Uid; __u16 Uid;
__u16 Mid; __le16 Mid;
__u8 WordCount; __u8 WordCount;
} __attribute__((packed)); } __attribute__((packed));
...@@ -705,7 +705,13 @@ struct ntlmssp2_name { ...@@ -705,7 +705,13 @@ struct ntlmssp2_name {
} __attribute__((packed)); } __attribute__((packed));
struct ntlmv2_resp { struct ntlmv2_resp {
union {
char ntlmv2_hash[CIFS_ENCPWD_SIZE]; char ntlmv2_hash[CIFS_ENCPWD_SIZE];
struct {
__u8 reserved[8];
__u8 key[CIFS_SERVER_CHALLENGE_SIZE];
} __attribute__((packed)) challenge;
} __attribute__((packed));
__le32 blob_signature; __le32 blob_signature;
__u32 reserved; __u32 reserved;
__le64 time; __le64 time;
...@@ -1360,6 +1366,35 @@ typedef struct smb_com_transaction_ioctl_req { ...@@ -1360,6 +1366,35 @@ typedef struct smb_com_transaction_ioctl_req {
__u8 Data[1]; __u8 Data[1];
} __attribute__((packed)) TRANSACT_IOCTL_REQ; } __attribute__((packed)) TRANSACT_IOCTL_REQ;
typedef struct smb_com_transaction_compr_ioctl_req {
struct smb_hdr hdr; /* wct = 23 */
__u8 MaxSetupCount;
__u16 Reserved;
__le32 TotalParameterCount;
__le32 TotalDataCount;
__le32 MaxParameterCount;
__le32 MaxDataCount;
__le32 ParameterCount;
__le32 ParameterOffset;
__le32 DataCount;
__le32 DataOffset;
__u8 SetupCount; /* four setup words follow subcommand */
/* SNIA spec incorrectly included spurious pad here */
__le16 SubCommand; /* 2 = IOCTL/FSCTL */
__le32 FunctionCode;
__u16 Fid;
__u8 IsFsctl; /* 1 = File System Control 0 = device control (IOCTL) */
__u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS) */
__le16 ByteCount;
__u8 Pad[3];
__le16 compression_state; /* See below for valid flags */
} __attribute__((packed)) TRANSACT_COMPR_IOCTL_REQ;
/* compression state flags */
#define COMPRESSION_FORMAT_NONE 0x0000
#define COMPRESSION_FORMAT_DEFAULT 0x0001
#define COMPRESSION_FORMAT_LZNT1 0x0002
typedef struct smb_com_transaction_ioctl_rsp { typedef struct smb_com_transaction_ioctl_rsp {
struct smb_hdr hdr; /* wct = 19 */ struct smb_hdr hdr; /* wct = 19 */
__u8 Reserved[3]; __u8 Reserved[3];
...@@ -1499,15 +1534,30 @@ struct file_notify_information { ...@@ -1499,15 +1534,30 @@ struct file_notify_information {
__u8 FileName[0]; __u8 FileName[0];
} __attribute__((packed)); } __attribute__((packed));
struct reparse_data { /* For IO_REPARSE_TAG_SYMLINK */
__u32 ReparseTag; struct reparse_symlink_data {
__u16 ReparseDataLength; __le32 ReparseTag;
__le16 ReparseDataLength;
__u16 Reserved; __u16 Reserved;
__u16 SubstituteNameOffset; __le16 SubstituteNameOffset;
__u16 SubstituteNameLength; __le16 SubstituteNameLength;
__u16 PrintNameOffset; __le16 PrintNameOffset;
__u16 PrintNameLength; __le16 PrintNameLength;
__u32 Flags; __le32 Flags;
char PathBuffer[0];
} __attribute__((packed));
/* For IO_REPARSE_TAG_NFS */
#define NFS_SPECFILE_LNK 0x00000000014B4E4C
#define NFS_SPECFILE_CHR 0x0000000000524843
#define NFS_SPECFILE_BLK 0x00000000004B4C42
#define NFS_SPECFILE_FIFO 0x000000004F464946
#define NFS_SPECFILE_SOCK 0x000000004B434F53
struct reparse_posix_data {
__le32 ReparseTag;
__le16 ReparseDataLength;
__u16 Reserved;
__le64 InodeType; /* LNK, FIFO, CHR etc. */
char PathBuffer[0]; char PathBuffer[0];
} __attribute__((packed)); } __attribute__((packed));
...@@ -2208,6 +2258,9 @@ typedef struct { ...@@ -2208,6 +2258,9 @@ typedef struct {
__le32 DeviceCharacteristics; __le32 DeviceCharacteristics;
} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */ } __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */
/* minimum includes first three fields, and empty FS Name */
#define MIN_FS_ATTR_INFO_SIZE 12
typedef struct { typedef struct {
__le32 Attributes; __le32 Attributes;
__le32 MaxPathNameComponentLength; __le32 MaxPathNameComponentLength;
......
...@@ -127,6 +127,9 @@ extern u64 cifs_UnixTimeToNT(struct timespec); ...@@ -127,6 +127,9 @@ extern u64 cifs_UnixTimeToNT(struct timespec);
extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
int offset); int offset);
extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock); extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
extern int cifs_get_writer(struct cifsInodeInfo *cinode);
extern void cifs_put_writer(struct cifsInodeInfo *cinode);
extern void cifs_done_oplock_break(struct cifsInodeInfo *cinode);
extern int cifs_unlock_range(struct cifsFileInfo *cfile, extern int cifs_unlock_range(struct cifsFileInfo *cfile,
struct file_lock *flock, const unsigned int xid); struct file_lock *flock, const unsigned int xid);
extern int cifs_push_mandatory_locks(struct cifsFileInfo *cfile); extern int cifs_push_mandatory_locks(struct cifsFileInfo *cfile);
...@@ -151,7 +154,7 @@ extern struct inode *cifs_iget(struct super_block *sb, ...@@ -151,7 +154,7 @@ extern struct inode *cifs_iget(struct super_block *sb,
extern int cifs_get_inode_info(struct inode **inode, const char *full_path, extern int cifs_get_inode_info(struct inode **inode, const char *full_path,
FILE_ALL_INFO *data, struct super_block *sb, FILE_ALL_INFO *data, struct super_block *sb,
int xid, const __u16 *fid); int xid, const struct cifs_fid *fid);
extern int cifs_get_inode_info_unix(struct inode **pinode, extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path, const unsigned char *search_path,
struct super_block *sb, unsigned int xid); struct super_block *sb, unsigned int xid);
...@@ -162,11 +165,13 @@ extern int cifs_rename_pending_delete(const char *full_path, ...@@ -162,11 +165,13 @@ extern int cifs_rename_pending_delete(const char *full_path,
const unsigned int xid); const unsigned int xid);
extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
struct cifs_fattr *fattr, struct inode *inode, struct cifs_fattr *fattr, struct inode *inode,
const char *path, const __u16 *pfid); const char *path, const struct cifs_fid *pfid);
extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64, extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64,
kuid_t, kgid_t); kuid_t, kgid_t);
extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
const char *, u32 *); const char *, u32 *);
extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *,
const struct cifs_fid *, u32 *);
extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
const char *, int); const char *, int);
...@@ -360,11 +365,10 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid, ...@@ -360,11 +365,10 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid,
extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
__u16 fid, char **symlinkinfo, __u16 fid, char **symlinkinfo,
const struct nls_table *nls_codepage); const struct nls_table *nls_codepage);
extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, extern int CIFSSMB_set_compression(const unsigned int xid,
const char *fileName, const int disposition, struct cifs_tcon *tcon, __u16 fid);
const int access_flags, const int share_flags, const int omode, extern int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms,
__u16 *netfid, int *pOplock, FILE_ALL_INFO *, int *oplock, FILE_ALL_INFO *buf);
const struct nls_table *nls_codepage, int remap);
extern int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, extern int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
const char *fileName, const int disposition, const char *fileName, const int disposition,
const int access_flags, const int omode, const int access_flags, const int omode,
...@@ -474,10 +478,11 @@ extern int CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -474,10 +478,11 @@ extern int CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon, extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
const int netfid, __u64 *pExtAttrBits, __u64 *pMask); const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb); extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr); extern bool couldbe_mf_symlink(const struct cifs_fattr *fattr);
extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr, extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *path, struct cifs_sb_info *cifs_sb,
struct cifs_sb_info *cifs_sb, unsigned int xid); struct cifs_fattr *fattr,
const unsigned char *path);
extern int mdfour(unsigned char *, unsigned char *, int); extern int mdfour(unsigned char *, unsigned char *, int);
extern int E_md4hash(const unsigned char *passwd, unsigned char *p16, extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
const struct nls_table *codepage); const struct nls_table *codepage);
...@@ -494,7 +499,12 @@ void cifs_writev_complete(struct work_struct *work); ...@@ -494,7 +499,12 @@ void cifs_writev_complete(struct work_struct *work);
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages, struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
work_func_t complete); work_func_t complete);
void cifs_writedata_release(struct kref *refcount); void cifs_writedata_release(struct kref *refcount);
int open_query_close_cifs_symlink(const unsigned char *path, char *pbuf, int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb, struct cifs_sb_info *cifs_sb,
unsigned int xid); const unsigned char *path, char *pbuf,
unsigned int *pbytes_read);
int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const unsigned char *path, char *pbuf,
unsigned int *pbytes_written);
#endif /* _CIFSPROTO_H */ #endif /* _CIFSPROTO_H */
...@@ -2149,6 +2149,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info) ...@@ -2149,6 +2149,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
sizeof(tcp_ses->srcaddr)); sizeof(tcp_ses->srcaddr));
memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr, memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
sizeof(tcp_ses->dstaddr)); sizeof(tcp_ses->dstaddr));
#ifdef CONFIG_CIFS_SMB2
get_random_bytes(tcp_ses->client_guid, SMB2_CLIENT_GUID_SIZE);
#endif
/* /*
* at this point we are the only ones with the pointer * at this point we are the only ones with the pointer
* to the struct since the kernel thread not created yet * to the struct since the kernel thread not created yet
...@@ -2230,7 +2233,7 @@ static int match_session(struct cifs_ses *ses, struct smb_vol *vol) ...@@ -2230,7 +2233,7 @@ static int match_session(struct cifs_ses *ses, struct smb_vol *vol)
vol->username ? vol->username : "", vol->username ? vol->username : "",
CIFS_MAX_USERNAME_LEN)) CIFS_MAX_USERNAME_LEN))
return 0; return 0;
if (strlen(vol->username) != 0 && if ((vol->username && strlen(vol->username) != 0) &&
ses->password != NULL && ses->password != NULL &&
strncmp(ses->password, strncmp(ses->password,
vol->password ? vol->password : "", vol->password ? vol->password : "",
...@@ -2247,6 +2250,8 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) ...@@ -2247,6 +2250,8 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
if (ses->status == CifsExiting)
continue;
if (!match_session(ses, vol)) if (!match_session(ses, vol))
continue; continue;
++ses->ses_count; ++ses->ses_count;
...@@ -2260,24 +2265,37 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) ...@@ -2260,24 +2265,37 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
static void static void
cifs_put_smb_ses(struct cifs_ses *ses) cifs_put_smb_ses(struct cifs_ses *ses)
{ {
unsigned int xid; unsigned int rc, xid;
struct TCP_Server_Info *server = ses->server; struct TCP_Server_Info *server = ses->server;
cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count); cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
if (ses->status == CifsExiting) {
spin_unlock(&cifs_tcp_ses_lock);
return;
}
if (--ses->ses_count > 0) { if (--ses->ses_count > 0) {
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
return; return;
} }
if (ses->status == CifsGood)
list_del_init(&ses->smb_ses_list); ses->status = CifsExiting;
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
if (ses->status == CifsGood && server->ops->logoff) { if (ses->status == CifsExiting && server->ops->logoff) {
xid = get_xid(); xid = get_xid();
server->ops->logoff(xid, ses); rc = server->ops->logoff(xid, ses);
if (rc)
cifs_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
__func__, rc);
_free_xid(xid); _free_xid(xid);
} }
spin_lock(&cifs_tcp_ses_lock);
list_del_init(&ses->smb_ses_list);
spin_unlock(&cifs_tcp_ses_lock);
sesInfoFree(ses); sesInfoFree(ses);
cifs_put_tcp_session(server); cifs_put_tcp_session(server);
} }
...@@ -3760,6 +3778,13 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, ...@@ -3760,6 +3778,13 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
return rc; return rc;
} }
static void delayed_free(struct rcu_head *p)
{
struct cifs_sb_info *sbi = container_of(p, struct cifs_sb_info, rcu);
unload_nls(sbi->local_nls);
kfree(sbi);
}
void void
cifs_umount(struct cifs_sb_info *cifs_sb) cifs_umount(struct cifs_sb_info *cifs_sb)
{ {
...@@ -3784,8 +3809,7 @@ cifs_umount(struct cifs_sb_info *cifs_sb) ...@@ -3784,8 +3809,7 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
bdi_destroy(&cifs_sb->bdi); bdi_destroy(&cifs_sb->bdi);
kfree(cifs_sb->mountdata); kfree(cifs_sb->mountdata);
unload_nls(cifs_sb->local_nls); call_rcu(&cifs_sb->rcu, delayed_free);
kfree(cifs_sb);
} }
int int
......
...@@ -383,7 +383,7 @@ cifs_create_get_file_info: ...@@ -383,7 +383,7 @@ cifs_create_get_file_info:
xid); xid);
else { else {
rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb, rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,
xid, &fid->netfid); xid, fid);
if (newinode) { if (newinode) {
if (server->ops->set_lease_key) if (server->ops->set_lease_key)
server->ops->set_lease_key(newinode, fid); server->ops->set_lease_key(newinode, fid);
...@@ -570,12 +570,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -570,12 +570,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL; int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink; struct tcon_link *tlink;
struct cifs_tcon *pTcon; struct cifs_tcon *tcon;
struct cifs_io_parms io_parms; struct cifs_io_parms io_parms;
char *full_path = NULL; char *full_path = NULL;
struct inode *newinode = NULL; struct inode *newinode = NULL;
int oplock = 0; int oplock = 0;
u16 fileHandle; struct cifs_fid fid;
struct cifs_open_parms oparms;
FILE_ALL_INFO *buf = NULL; FILE_ALL_INFO *buf = NULL;
unsigned int bytes_written; unsigned int bytes_written;
struct win_dev *pdev; struct win_dev *pdev;
...@@ -588,7 +589,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -588,7 +589,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
if (IS_ERR(tlink)) if (IS_ERR(tlink))
return PTR_ERR(tlink); return PTR_ERR(tlink);
pTcon = tlink_tcon(tlink); tcon = tlink_tcon(tlink);
xid = get_xid(); xid = get_xid();
...@@ -598,7 +599,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -598,7 +599,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
goto mknod_out; goto mknod_out;
} }
if (pTcon->unix_ext) { if (tcon->unix_ext) {
struct cifs_unix_set_info_args args = { struct cifs_unix_set_info_args args = {
.mode = mode & ~current_umask(), .mode = mode & ~current_umask(),
.ctime = NO_CHANGE_64, .ctime = NO_CHANGE_64,
...@@ -613,7 +614,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -613,7 +614,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
args.uid = INVALID_UID; /* no change */ args.uid = INVALID_UID; /* no change */
args.gid = INVALID_GID; /* no change */ args.gid = INVALID_GID; /* no change */
} }
rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args, rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
...@@ -644,42 +645,45 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -644,42 +645,45 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
if (backup_cred(cifs_sb)) if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT; create_options |= CREATE_OPEN_BACKUP_INTENT;
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE, GENERIC_WRITE, oparms.tcon = tcon;
FILE_SHARE_ALL, create_options, &fileHandle, &oplock, oparms.cifs_sb = cifs_sb;
buf, cifs_sb->local_nls, oparms.desired_access = GENERIC_WRITE;
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); oparms.share_access = FILE_SHARE_ALL;
oparms.create_options = create_options;
oparms.disposition = FILE_CREATE;
oparms.path = full_path;
oparms.fid = &fid;
oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, buf);
if (rc) if (rc)
goto mknod_out; goto mknod_out;
/* BB Do not bother to decode buf since no local inode yet to put /*
* timestamps in, but we can reuse it safely */ * BB Do not bother to decode buf since no local inode yet to put
* timestamps in, but we can reuse it safely.
*/
pdev = (struct win_dev *)buf; pdev = (struct win_dev *)buf;
io_parms.netfid = fileHandle; io_parms.netfid = fid.netfid;
io_parms.pid = current->tgid; io_parms.pid = current->tgid;
io_parms.tcon = pTcon; io_parms.tcon = tcon;
io_parms.offset = 0; io_parms.offset = 0;
io_parms.length = sizeof(struct win_dev); io_parms.length = sizeof(struct win_dev);
if (S_ISCHR(mode)) { if (S_ISCHR(mode)) {
memcpy(pdev->type, "IntxCHR", 8); memcpy(pdev->type, "IntxCHR", 8);
pdev->major = pdev->major = cpu_to_le64(MAJOR(device_number));
cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number));
pdev->minor = rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev,
cpu_to_le64(MINOR(device_number));
rc = CIFSSMBWrite(xid, &io_parms,
&bytes_written, (char *)pdev,
NULL, 0); NULL, 0);
} else if (S_ISBLK(mode)) { } else if (S_ISBLK(mode)) {
memcpy(pdev->type, "IntxBLK", 8); memcpy(pdev->type, "IntxBLK", 8);
pdev->major = pdev->major = cpu_to_le64(MAJOR(device_number));
cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number));
pdev->minor = rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev,
cpu_to_le64(MINOR(device_number));
rc = CIFSSMBWrite(xid, &io_parms,
&bytes_written, (char *)pdev,
NULL, 0); NULL, 0);
} /* else if (S_ISFIFO) */ } /* else if (S_ISFIFO) */
CIFSSMBClose(xid, pTcon, fileHandle); CIFSSMBClose(xid, tcon, fid.netfid);
d_drop(direntry); d_drop(direntry);
/* FIXME: add code here to set EAs */ /* FIXME: add code here to set EAs */
...@@ -761,7 +765,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -761,7 +765,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
/* if it was once a directory (but how can we tell?) we could do /* if it was once a directory (but how can we tell?) we could do
shrink_dcache_parent(direntry); */ shrink_dcache_parent(direntry); */
} else if (rc != -EACCES) { } else if (rc != -EACCES) {
cifs_dbg(VFS, "Unexpected lookup error %d\n", rc); cifs_dbg(FYI, "Unexpected lookup error %d\n", rc);
/* We special case check for Access Denied - since that /* We special case check for Access Denied - since that
is a common return code */ is a common return code */
} }
......
...@@ -223,6 +223,13 @@ void __cifs_readpage_to_fscache(struct inode *inode, struct page *page) ...@@ -223,6 +223,13 @@ void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
fscache_uncache_page(CIFS_I(inode)->fscache, page); fscache_uncache_page(CIFS_I(inode)->fscache, page);
} }
void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages)
{
cifs_dbg(FYI, "%s: (fsc: %p, i: %p)\n",
__func__, CIFS_I(inode)->fscache, inode);
fscache_readpages_cancel(CIFS_I(inode)->fscache, pages);
}
void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
{ {
struct cifsInodeInfo *cifsi = CIFS_I(inode); struct cifsInodeInfo *cifsi = CIFS_I(inode);
......
...@@ -54,6 +54,7 @@ extern int __cifs_readpages_from_fscache(struct inode *, ...@@ -54,6 +54,7 @@ extern int __cifs_readpages_from_fscache(struct inode *,
struct address_space *, struct address_space *,
struct list_head *, struct list_head *,
unsigned *); unsigned *);
extern void __cifs_fscache_readpages_cancel(struct inode *, struct list_head *);
extern void __cifs_readpage_to_fscache(struct inode *, struct page *); extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
...@@ -91,6 +92,13 @@ static inline void cifs_readpage_to_fscache(struct inode *inode, ...@@ -91,6 +92,13 @@ static inline void cifs_readpage_to_fscache(struct inode *inode,
__cifs_readpage_to_fscache(inode, page); __cifs_readpage_to_fscache(inode, page);
} }
static inline void cifs_fscache_readpages_cancel(struct inode *inode,
struct list_head *pages)
{
if (CIFS_I(inode)->fscache)
return __cifs_fscache_readpages_cancel(inode, pages);
}
#else /* CONFIG_CIFS_FSCACHE */ #else /* CONFIG_CIFS_FSCACHE */
static inline int cifs_fscache_register(void) { return 0; } static inline int cifs_fscache_register(void) { return 0; }
static inline void cifs_fscache_unregister(void) {} static inline void cifs_fscache_unregister(void) {}
...@@ -131,6 +139,11 @@ static inline int cifs_readpages_from_fscache(struct inode *inode, ...@@ -131,6 +139,11 @@ static inline int cifs_readpages_from_fscache(struct inode *inode,
static inline void cifs_readpage_to_fscache(struct inode *inode, static inline void cifs_readpage_to_fscache(struct inode *inode,
struct page *page) {} struct page *page) {}
static inline void cifs_fscache_readpages_cancel(struct inode *inode,
struct list_head *pages)
{
}
#endif /* CONFIG_CIFS_FSCACHE */ #endif /* CONFIG_CIFS_FSCACHE */
#endif /* _CIFS_FSCACHE_H */ #endif /* _CIFS_FSCACHE_H */
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* vfs operations that deal with io control * vfs operations that deal with io control
* *
* Copyright (C) International Business Machines Corp., 2005,2007 * Copyright (C) International Business Machines Corp., 2005,2013
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -22,25 +22,121 @@ ...@@ -22,25 +22,121 @@
*/ */
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/file.h>
#include <linux/mount.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include "cifspdu.h" #include "cifspdu.h"
#include "cifsglob.h" #include "cifsglob.h"
#include "cifsproto.h" #include "cifsproto.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifsfs.h" #include "cifsfs.h"
#define CIFS_IOCTL_MAGIC 0xCF
#define CIFS_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int)
static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file,
unsigned long srcfd, u64 off, u64 len, u64 destoff)
{
int rc;
struct cifsFileInfo *smb_file_target = dst_file->private_data;
struct inode *target_inode = file_inode(dst_file);
struct cifs_tcon *target_tcon;
struct fd src_file;
struct cifsFileInfo *smb_file_src;
struct inode *src_inode;
struct cifs_tcon *src_tcon;
cifs_dbg(FYI, "ioctl clone range\n");
/* the destination must be opened for writing */
if (!(dst_file->f_mode & FMODE_WRITE)) {
cifs_dbg(FYI, "file target not open for write\n");
return -EINVAL;
}
/* check if target volume is readonly and take reference */
rc = mnt_want_write_file(dst_file);
if (rc) {
cifs_dbg(FYI, "mnt_want_write failed with rc %d\n", rc);
return rc;
}
src_file = fdget(srcfd);
if (!src_file.file) {
rc = -EBADF;
goto out_drop_write;
}
if ((!src_file.file->private_data) || (!dst_file->private_data)) {
rc = -EBADF;
cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n");
goto out_fput;
}
rc = -EXDEV;
smb_file_target = dst_file->private_data;
smb_file_src = src_file.file->private_data;
src_tcon = tlink_tcon(smb_file_src->tlink);
target_tcon = tlink_tcon(smb_file_target->tlink);
/* check if source and target are on same tree connection */
if (src_tcon != target_tcon) {
cifs_dbg(VFS, "file copy src and target on different volume\n");
goto out_fput;
}
src_inode = file_inode(src_file.file);
rc = -EINVAL;
if (S_ISDIR(src_inode->i_mode))
goto out_fput;
/*
* Note: cifs case is easier than btrfs since server responsible for
* checks for proper open modes and file type and if it wants
* server could even support copy of range where source = target
*/
lock_two_nondirectories(target_inode, src_inode);
/* determine range to clone */
rc = -EINVAL;
if (off + len > src_inode->i_size || off + len < off)
goto out_unlock;
if (len == 0)
len = src_inode->i_size - off;
cifs_dbg(FYI, "about to flush pages\n");
/* should we flush first and last page first */
truncate_inode_pages_range(&target_inode->i_data, destoff,
PAGE_CACHE_ALIGN(destoff + len)-1);
if (target_tcon->ses->server->ops->clone_range)
rc = target_tcon->ses->server->ops->clone_range(xid,
smb_file_src, smb_file_target, off, len, destoff);
/* force revalidate of size and timestamps of target file now
that target is updated on the server */
CIFS_I(target_inode)->time = 0;
out_unlock:
/* although unlocking in the reverse order from locking is not
strictly necessary here it is a little cleaner to be consistent */
unlock_two_nondirectories(src_inode, target_inode);
out_fput:
fdput(src_file);
out_drop_write:
mnt_drop_write_file(dst_file);
return rc;
}
long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
{ {
struct inode *inode = file_inode(filep); struct inode *inode = file_inode(filep);
int rc = -ENOTTY; /* strange error - but the precedent */ int rc = -ENOTTY; /* strange error - but the precedent */
unsigned int xid; unsigned int xid;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
#ifdef CONFIG_CIFS_POSIX
struct cifsFileInfo *pSMBFile = filep->private_data; struct cifsFileInfo *pSMBFile = filep->private_data;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
__u64 ExtAttrBits = 0; __u64 ExtAttrBits = 0;
__u64 ExtAttrMask = 0;
__u64 caps; __u64 caps;
#endif /* CONFIG_CIFS_POSIX */
xid = get_xid(); xid = get_xid();
...@@ -49,13 +145,14 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -49,13 +145,14 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
switch (command) { switch (command) {
#ifdef CONFIG_CIFS_POSIX
case FS_IOC_GETFLAGS: case FS_IOC_GETFLAGS:
if (pSMBFile == NULL) if (pSMBFile == NULL)
break; break;
tcon = tlink_tcon(pSMBFile->tlink); tcon = tlink_tcon(pSMBFile->tlink);
caps = le64_to_cpu(tcon->fsUnixInfo.Capability); caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
#ifdef CONFIG_CIFS_POSIX
if (CIFS_UNIX_EXTATTR_CAP & caps) { if (CIFS_UNIX_EXTATTR_CAP & caps) {
__u64 ExtAttrMask = 0;
rc = CIFSGetExtAttr(xid, tcon, rc = CIFSGetExtAttr(xid, tcon,
pSMBFile->fid.netfid, pSMBFile->fid.netfid,
&ExtAttrBits, &ExtAttrMask); &ExtAttrBits, &ExtAttrMask);
...@@ -63,29 +160,53 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -63,29 +160,53 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
rc = put_user(ExtAttrBits & rc = put_user(ExtAttrBits &
FS_FL_USER_VISIBLE, FS_FL_USER_VISIBLE,
(int __user *)arg); (int __user *)arg);
if (rc != EOPNOTSUPP)
break;
}
#endif /* CONFIG_CIFS_POSIX */
rc = 0;
if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED) {
/* add in the compressed bit */
ExtAttrBits = FS_COMPR_FL;
rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE,
(int __user *)arg);
} }
break; break;
case FS_IOC_SETFLAGS: case FS_IOC_SETFLAGS:
if (pSMBFile == NULL) if (pSMBFile == NULL)
break; break;
tcon = tlink_tcon(pSMBFile->tlink); tcon = tlink_tcon(pSMBFile->tlink);
caps = le64_to_cpu(tcon->fsUnixInfo.Capability); caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
if (CIFS_UNIX_EXTATTR_CAP & caps) {
if (get_user(ExtAttrBits, (int __user *)arg)) { if (get_user(ExtAttrBits, (int __user *)arg)) {
rc = -EFAULT; rc = -EFAULT;
break; break;
} }
/* /*
* rc = CIFSGetExtAttr(xid, tcon, * if (CIFS_UNIX_EXTATTR_CAP & caps)
* rc = CIFSSetExtAttr(xid, tcon,
* pSMBFile->fid.netfid, * pSMBFile->fid.netfid,
* extAttrBits, * extAttrBits,
* &ExtAttrMask); * &ExtAttrMask);
* if (rc != EOPNOTSUPP)
* break;
*/ */
/* Currently only flag we can set is compressed flag */
if ((ExtAttrBits & FS_COMPR_FL) == 0)
break;
/* Try to set compress flag */
if (tcon->ses->server->ops->set_compression) {
rc = tcon->ses->server->ops->set_compression(
xid, tcon, pSMBFile);
cifs_dbg(FYI, "set compress flag rc %d\n", rc);
} }
cifs_dbg(FYI, "set flags not implemented yet\n");
break; break;
#endif /* CONFIG_CIFS_POSIX */ case CIFS_IOC_COPYCHUNK_FILE:
rc = cifs_ioctl_clone(xid, filep, arg, 0, 0, 0);
break;
default: default:
cifs_dbg(FYI, "unsupported ioctl\n"); cifs_dbg(FYI, "unsupported ioctl\n");
break; break;
......
...@@ -278,7 +278,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -278,7 +278,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
} }
static int static int
check_smb_hdr(struct smb_hdr *smb, __u16 mid) check_smb_hdr(struct smb_hdr *smb)
{ {
/* does it have the right SMB "signature" ? */ /* does it have the right SMB "signature" ? */
if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) { if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) {
...@@ -287,13 +287,6 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid) ...@@ -287,13 +287,6 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid)
return 1; return 1;
} }
/* Make sure that message ids match */
if (mid != smb->Mid) {
cifs_dbg(VFS, "Mids do not match. received=%u expected=%u\n",
smb->Mid, mid);
return 1;
}
/* if it's a response then accept */ /* if it's a response then accept */
if (smb->Flags & SMBFLG_RESPONSE) if (smb->Flags & SMBFLG_RESPONSE)
return 0; return 0;
...@@ -302,7 +295,8 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid) ...@@ -302,7 +295,8 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid)
if (smb->Command == SMB_COM_LOCKING_ANDX) if (smb->Command == SMB_COM_LOCKING_ANDX)
return 0; return 0;
cifs_dbg(VFS, "Server sent request, not response. mid=%u\n", smb->Mid); cifs_dbg(VFS, "Server sent request, not response. mid=%u\n",
get_mid(smb));
return 1; return 1;
} }
...@@ -310,7 +304,6 @@ int ...@@ -310,7 +304,6 @@ int
checkSMB(char *buf, unsigned int total_read) checkSMB(char *buf, unsigned int total_read)
{ {
struct smb_hdr *smb = (struct smb_hdr *)buf; struct smb_hdr *smb = (struct smb_hdr *)buf;
__u16 mid = smb->Mid;
__u32 rfclen = be32_to_cpu(smb->smb_buf_length); __u32 rfclen = be32_to_cpu(smb->smb_buf_length);
__u32 clc_len; /* calculated length */ __u32 clc_len; /* calculated length */
cifs_dbg(FYI, "checkSMB Length: 0x%x, smb_buf_length: 0x%x\n", cifs_dbg(FYI, "checkSMB Length: 0x%x, smb_buf_length: 0x%x\n",
...@@ -348,7 +341,7 @@ checkSMB(char *buf, unsigned int total_read) ...@@ -348,7 +341,7 @@ checkSMB(char *buf, unsigned int total_read)
} }
/* otherwise, there is enough to get to the BCC */ /* otherwise, there is enough to get to the BCC */
if (check_smb_hdr(smb, mid)) if (check_smb_hdr(smb))
return -EIO; return -EIO;
clc_len = smbCalcSize(smb); clc_len = smbCalcSize(smb);
...@@ -359,6 +352,7 @@ checkSMB(char *buf, unsigned int total_read) ...@@ -359,6 +352,7 @@ checkSMB(char *buf, unsigned int total_read)
} }
if (4 + rfclen != clc_len) { if (4 + rfclen != clc_len) {
__u16 mid = get_mid(smb);
/* check if bcc wrapped around for large read responses */ /* check if bcc wrapped around for large read responses */
if ((rfclen > 64 * 1024) && (rfclen > clc_len)) { if ((rfclen > 64 * 1024) && (rfclen > clc_len)) {
/* check if lengths match mod 64K */ /* check if lengths match mod 64K */
...@@ -366,11 +360,11 @@ checkSMB(char *buf, unsigned int total_read) ...@@ -366,11 +360,11 @@ checkSMB(char *buf, unsigned int total_read)
return 0; /* bcc wrapped */ return 0; /* bcc wrapped */
} }
cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u\n", cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u\n",
clc_len, 4 + rfclen, smb->Mid); clc_len, 4 + rfclen, mid);
if (4 + rfclen < clc_len) { if (4 + rfclen < clc_len) {
cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n", cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n",
rfclen, smb->Mid); rfclen, mid);
return -EIO; return -EIO;
} else if (rfclen > clc_len + 512) { } else if (rfclen > clc_len + 512) {
/* /*
...@@ -383,7 +377,7 @@ checkSMB(char *buf, unsigned int total_read) ...@@ -383,7 +377,7 @@ checkSMB(char *buf, unsigned int total_read)
* data to 512 bytes. * data to 512 bytes.
*/ */
cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n", cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n",
rfclen, smb->Mid); rfclen, mid);
return -EIO; return -EIO;
} }
} }
...@@ -472,8 +466,22 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) ...@@ -472,8 +466,22 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
cifs_dbg(FYI, "file id match, oplock break\n"); cifs_dbg(FYI, "file id match, oplock break\n");
pCifsInode = CIFS_I(netfile->dentry->d_inode); pCifsInode = CIFS_I(netfile->dentry->d_inode);
cifs_set_oplock_level(pCifsInode, set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK,
pSMB->OplockLevel ? OPLOCK_READ : 0); &pCifsInode->flags);
/*
* Set flag if the server downgrades the oplock
* to L2 else clear.
*/
if (pSMB->OplockLevel)
set_bit(
CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
&pCifsInode->flags);
else
clear_bit(
CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
&pCifsInode->flags);
queue_work(cifsiod_wq, queue_work(cifsiod_wq,
&netfile->oplock_break); &netfile->oplock_break);
netfile->oplock_break_cancelled = false; netfile->oplock_break_cancelled = false;
...@@ -557,6 +565,62 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) ...@@ -557,6 +565,62 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
cinode->oplock = 0; cinode->oplock = 0;
} }
static int
cifs_oplock_break_wait(void *unused)
{
schedule();
return signal_pending(current) ? -ERESTARTSYS : 0;
}
/*
* We wait for oplock breaks to be processed before we attempt to perform
* writes.
*/
int cifs_get_writer(struct cifsInodeInfo *cinode)
{
int rc;
start:
rc = wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK,
cifs_oplock_break_wait, TASK_KILLABLE);
if (rc)
return rc;
spin_lock(&cinode->writers_lock);
if (!cinode->writers)
set_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
cinode->writers++;
/* Check to see if we have started servicing an oplock break */
if (test_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags)) {
cinode->writers--;
if (cinode->writers == 0) {
clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS);
}
spin_unlock(&cinode->writers_lock);
goto start;
}
spin_unlock(&cinode->writers_lock);
return 0;
}
void cifs_put_writer(struct cifsInodeInfo *cinode)
{
spin_lock(&cinode->writers_lock);
cinode->writers--;
if (cinode->writers == 0) {
clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS);
}
spin_unlock(&cinode->writers_lock);
}
void cifs_done_oplock_break(struct cifsInodeInfo *cinode)
{
clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags);
wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK);
}
bool bool
backup_cred(struct cifs_sb_info *cifs_sb) backup_cred(struct cifs_sb_info *cifs_sb)
{ {
......
...@@ -51,7 +51,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { ...@@ -51,7 +51,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
{ERRnoaccess, -EACCES}, {ERRnoaccess, -EACCES},
{ERRbadfid, -EBADF}, {ERRbadfid, -EBADF},
{ERRbadmcb, -EIO}, {ERRbadmcb, -EIO},
{ERRnomem, -ENOMEM}, {ERRnomem, -EREMOTEIO},
{ERRbadmem, -EFAULT}, {ERRbadmem, -EFAULT},
{ERRbadenv, -EFAULT}, {ERRbadenv, -EFAULT},
{ERRbadformat, -EINVAL}, {ERRbadformat, -EINVAL},
...@@ -780,7 +780,9 @@ static const struct { ...@@ -780,7 +780,9 @@ static const struct {
ERRDOS, ERRnoaccess, 0xc0000290}, { ERRDOS, ERRnoaccess, 0xc0000290}, {
ERRDOS, ERRbadfunc, 0xc000029c}, { ERRDOS, ERRbadfunc, 0xc000029c}, {
ERRDOS, ERRsymlink, NT_STATUS_STOPPED_ON_SYMLINK}, { ERRDOS, ERRsymlink, NT_STATUS_STOPPED_ON_SYMLINK}, {
ERRDOS, ERRinvlevel, 0x007c0001}, }; ERRDOS, ERRinvlevel, 0x007c0001}, {
0, 0, 0 }
};
/***************************************************************************** /*****************************************************************************
Print an error message from the status code Print an error message from the status code
...@@ -793,7 +795,7 @@ cifs_print_status(__u32 status_code) ...@@ -793,7 +795,7 @@ cifs_print_status(__u32 status_code)
while (nt_errs[idx].nt_errstr != NULL) { while (nt_errs[idx].nt_errstr != NULL) {
if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) == if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) ==
(status_code & 0xFFFFFF)) { (status_code & 0xFFFFFF)) {
printk(KERN_NOTICE "Status code returned 0x%08x %s\n", pr_notice("Status code returned 0x%08x %s\n",
status_code, nt_errs[idx].nt_errstr); status_code, nt_errs[idx].nt_errstr);
} }
idx++; idx++;
...@@ -939,8 +941,9 @@ cifs_UnixTimeToNT(struct timespec t) ...@@ -939,8 +941,9 @@ cifs_UnixTimeToNT(struct timespec t)
return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET; return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET;
} }
static int total_days_of_prev_months[] = static const int total_days_of_prev_months[] = {
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};
struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset) struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset)
{ {
......
...@@ -134,22 +134,6 @@ out: ...@@ -134,22 +134,6 @@ out:
dput(dentry); dput(dentry);
} }
/*
* Is it possible that this directory might turn out to be a DFS referral
* once we go to try and use it?
*/
static bool
cifs_dfs_is_possible(struct cifs_sb_info *cifs_sb)
{
#ifdef CONFIG_CIFS_DFS_UPCALL
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
return true;
#endif
return false;
}
static void static void
cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
{ {
...@@ -159,27 +143,22 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) ...@@ -159,27 +143,22 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
fattr->cf_dtype = DT_DIR; fattr->cf_dtype = DT_DIR;
/*
* Windows CIFS servers generally make DFS referrals look
* like directories in FIND_* responses with the reparse
* attribute flag also set (since DFS junctions are
* reparse points). We must revalidate at least these
* directory inodes before trying to use them (if
* they are DFS we will get PATH_NOT_COVERED back
* when queried directly and can then try to connect
* to the DFS target)
*/
if (cifs_dfs_is_possible(cifs_sb) &&
(fattr->cf_cifsattrs & ATTR_REPARSE))
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
} else if (fattr->cf_cifsattrs & ATTR_REPARSE) {
fattr->cf_mode = S_IFLNK;
fattr->cf_dtype = DT_LNK;
} else { } else {
fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
fattr->cf_dtype = DT_REG; fattr->cf_dtype = DT_REG;
} }
/*
* We need to revalidate it further to make a decision about whether it
* is a symbolic link, DFS referral or a reparse point with a direct
* access like junctions, deduplicated files, NFS symlinks.
*/
if (fattr->cf_cifsattrs & ATTR_REPARSE)
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
/* non-unix readdir doesn't provide nlink */
fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
if (fattr->cf_cifsattrs & ATTR_READONLY) if (fattr->cf_cifsattrs & ATTR_READONLY)
fattr->cf_mode &= ~S_IWUGO; fattr->cf_mode &= ~S_IWUGO;
...@@ -769,7 +748,7 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir, ...@@ -769,7 +748,7 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,
} }
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
CIFSCouldBeMFSymlink(&fattr)) couldbe_mf_symlink(&fattr))
/* /*
* trying to get the type and mode can be slow, * trying to get the type and mode can be slow,
* so just call those regular files for now, and mark * so just call those regular files for now, and mark
......
...@@ -500,9 +500,9 @@ select_sectype(struct TCP_Server_Info *server, enum securityEnum requested) ...@@ -500,9 +500,9 @@ select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
return NTLMv2; return NTLMv2;
if (global_secflags & CIFSSEC_MAY_NTLM) if (global_secflags & CIFSSEC_MAY_NTLM)
return NTLM; return NTLM;
/* Fallthrough */
default: default:
return Unspecified; /* Fallthrough to attempt LANMAN authentication next */
break;
} }
case CIFS_NEGFLAVOR_LANMAN: case CIFS_NEGFLAVOR_LANMAN:
switch (requested) { switch (requested) {
......
...@@ -67,7 +67,7 @@ send_nt_cancel(struct TCP_Server_Info *server, void *buf, ...@@ -67,7 +67,7 @@ send_nt_cancel(struct TCP_Server_Info *server, void *buf,
mutex_unlock(&server->srv_mutex); mutex_unlock(&server->srv_mutex);
cifs_dbg(FYI, "issued NT_CANCEL for mid %u, rc = %d\n", cifs_dbg(FYI, "issued NT_CANCEL for mid %u, rc = %d\n",
in_buf->Mid, rc); get_mid(in_buf), rc);
return rc; return rc;
} }
...@@ -101,7 +101,7 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer) ...@@ -101,7 +101,7 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
list_for_each_entry(mid, &server->pending_mid_q, qhead) { list_for_each_entry(mid, &server->pending_mid_q, qhead) {
if (mid->mid == buf->Mid && if (compare_mid(mid->mid, buf) &&
mid->mid_state == MID_REQUEST_SUBMITTED && mid->mid_state == MID_REQUEST_SUBMITTED &&
le16_to_cpu(mid->command) == buf->Command) { le16_to_cpu(mid->command) == buf->Command) {
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
...@@ -372,6 +372,16 @@ coalesce_t2(char *second_buf, struct smb_hdr *target_hdr) ...@@ -372,6 +372,16 @@ coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
return 0; return 0;
} }
static void
cifs_downgrade_oplock(struct TCP_Server_Info *server,
struct cifsInodeInfo *cinode, bool set_level2)
{
if (set_level2)
cifs_set_oplock_level(cinode, OPLOCK_READ);
else
cifs_set_oplock_level(cinode, 0);
}
static bool static bool
cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server, cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
char *buf, int malformed) char *buf, int malformed)
...@@ -534,10 +544,12 @@ cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -534,10 +544,12 @@ cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
static int static int
cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path, struct cifs_sb_info *cifs_sb, const char *full_path,
FILE_ALL_INFO *data, bool *adjustTZ) FILE_ALL_INFO *data, bool *adjustTZ, bool *symlink)
{ {
int rc; int rc;
*symlink = false;
/* could do find first instead but this returns more info */ /* could do find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, tcon, full_path, data, 0 /* not legacy */, rc = CIFSSMBQPathInfo(xid, tcon, full_path, data, 0 /* not legacy */,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
...@@ -554,6 +566,31 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -554,6 +566,31 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
*adjustTZ = true; *adjustTZ = true;
} }
if (!rc && (le32_to_cpu(data->Attributes) & ATTR_REPARSE)) {
int tmprc;
int oplock = 0;
struct cifs_fid fid;
struct cifs_open_parms oparms;
oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb;
oparms.desired_access = FILE_READ_ATTRIBUTES;
oparms.share_access = FILE_SHARE_ALL;
oparms.create_options = 0;
oparms.disposition = FILE_OPEN;
oparms.path = full_path;
oparms.fid = &fid;
oparms.reconnect = false;
/* Need to check if this is a symbolic link or not */
tmprc = CIFS_open(xid, &oparms, &oplock, NULL);
if (tmprc == -EOPNOTSUPP)
*symlink = true;
else
CIFSSMBClose(xid, tcon, fid.netfid);
}
return rc; return rc;
} }
...@@ -686,13 +723,7 @@ cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms, ...@@ -686,13 +723,7 @@ cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
oparms->cifs_sb->local_nls, oparms->cifs_sb->local_nls,
oparms->cifs_sb->mnt_cifs_flags oparms->cifs_sb->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR); & CIFS_MOUNT_MAP_SPECIAL_CHR);
return CIFSSMBOpen(xid, oparms->tcon, oparms->path, return CIFS_open(xid, oparms, oplock, buf);
oparms->disposition, oparms->desired_access,
oparms->share_access, oparms->create_options,
&oparms->fid->netfid, oplock, buf,
oparms->cifs_sb->local_nls,
oparms->cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
static void static void
...@@ -743,8 +774,9 @@ smb_set_file_info(struct inode *inode, const char *full_path, ...@@ -743,8 +774,9 @@ smb_set_file_info(struct inode *inode, const char *full_path,
{ {
int oplock = 0; int oplock = 0;
int rc; int rc;
__u16 netfid;
__u32 netpid; __u32 netpid;
struct cifs_fid fid;
struct cifs_open_parms oparms;
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
struct cifsInodeInfo *cinode = CIFS_I(inode); struct cifsInodeInfo *cinode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
...@@ -754,7 +786,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, ...@@ -754,7 +786,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
/* if the file is already open for write, just use that fileid */ /* if the file is already open for write, just use that fileid */
open_file = find_writable_file(cinode, true); open_file = find_writable_file(cinode, true);
if (open_file) { if (open_file) {
netfid = open_file->fid.netfid; fid.netfid = open_file->fid.netfid;
netpid = open_file->pid; netpid = open_file->pid;
tcon = tlink_tcon(open_file->tlink); tcon = tlink_tcon(open_file->tlink);
goto set_via_filehandle; goto set_via_filehandle;
...@@ -778,13 +810,18 @@ smb_set_file_info(struct inode *inode, const char *full_path, ...@@ -778,13 +810,18 @@ smb_set_file_info(struct inode *inode, const char *full_path,
goto out; goto out;
} }
cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n"); oparms.tcon = tcon;
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, oparms.cifs_sb = cifs_sb;
SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, FILE_SHARE_ALL, oparms.desired_access = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES;
CREATE_NOT_DIR, &netfid, &oplock, NULL, oparms.share_access = FILE_SHARE_ALL;
cifs_sb->local_nls, oparms.create_options = CREATE_NOT_DIR;
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); oparms.disposition = FILE_OPEN;
oparms.path = full_path;
oparms.fid = &fid;
oparms.reconnect = false;
cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n");
rc = CIFS_open(xid, &oparms, &oplock, NULL);
if (rc != 0) { if (rc != 0) {
if (rc == -EIO) if (rc == -EIO)
rc = -EINVAL; rc = -EINVAL;
...@@ -794,12 +831,12 @@ smb_set_file_info(struct inode *inode, const char *full_path, ...@@ -794,12 +831,12 @@ smb_set_file_info(struct inode *inode, const char *full_path,
netpid = current->tgid; netpid = current->tgid;
set_via_filehandle: set_via_filehandle:
rc = CIFSSMBSetFileInfo(xid, tcon, buf, netfid, netpid); rc = CIFSSMBSetFileInfo(xid, tcon, buf, fid.netfid, netpid);
if (!rc) if (!rc)
cinode->cifsAttrs = le32_to_cpu(buf->Attributes); cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
if (open_file == NULL) if (open_file == NULL)
CIFSSMBClose(xid, tcon, netfid); CIFSSMBClose(xid, tcon, fid.netfid);
else else
cifsFileInfo_put(open_file); cifsFileInfo_put(open_file);
out: out:
...@@ -809,6 +846,13 @@ out: ...@@ -809,6 +846,13 @@ out:
} }
static int static int
cifs_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
struct cifsFileInfo *cfile)
{
return CIFSSMB_set_compression(xid, tcon, cfile->fid.netfid);
}
static int
cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
const char *path, struct cifs_sb_info *cifs_sb, const char *path, struct cifs_sb_info *cifs_sb,
struct cifs_fid *fid, __u16 search_flags, struct cifs_fid *fid, __u16 search_flags,
...@@ -917,7 +961,8 @@ cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -917,7 +961,8 @@ cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
{ {
int rc; int rc;
int oplock = 0; int oplock = 0;
__u16 netfid; struct cifs_fid fid;
struct cifs_open_parms oparms;
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
...@@ -933,22 +978,28 @@ cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -933,22 +978,28 @@ cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
goto out; goto out;
} }
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, oparms.tcon = tcon;
FILE_READ_ATTRIBUTES, FILE_SHARE_ALL, oparms.cifs_sb = cifs_sb;
OPEN_REPARSE_POINT, &netfid, &oplock, NULL, oparms.desired_access = FILE_READ_ATTRIBUTES;
cifs_sb->local_nls, oparms.share_access = FILE_SHARE_ALL;
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); oparms.create_options = OPEN_REPARSE_POINT;
oparms.disposition = FILE_OPEN;
oparms.path = full_path;
oparms.fid = &fid;
oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, NULL);
if (rc) if (rc)
goto out; goto out;
rc = CIFSSMBQuerySymLink(xid, tcon, netfid, target_path, rc = CIFSSMBQuerySymLink(xid, tcon, fid.netfid, target_path,
cifs_sb->local_nls); cifs_sb->local_nls);
if (rc) if (rc)
goto out_close; goto out_close;
convert_delimiter(*target_path, '/'); convert_delimiter(*target_path, '/');
out_close: out_close:
CIFSSMBClose(xid, tcon, netfid); CIFSSMBClose(xid, tcon, fid.netfid);
out: out:
if (!rc) if (!rc)
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
...@@ -981,6 +1032,7 @@ struct smb_version_operations smb1_operations = { ...@@ -981,6 +1032,7 @@ struct smb_version_operations smb1_operations = {
.clear_stats = cifs_clear_stats, .clear_stats = cifs_clear_stats,
.print_stats = cifs_print_stats, .print_stats = cifs_print_stats,
.is_oplock_break = is_valid_oplock_break, .is_oplock_break = is_valid_oplock_break,
.downgrade_oplock = cifs_downgrade_oplock,
.check_trans2 = cifs_check_trans2, .check_trans2 = cifs_check_trans2,
.need_neg = cifs_need_neg, .need_neg = cifs_need_neg,
.negotiate = cifs_negotiate, .negotiate = cifs_negotiate,
...@@ -999,6 +1051,7 @@ struct smb_version_operations smb1_operations = { ...@@ -999,6 +1051,7 @@ struct smb_version_operations smb1_operations = {
.set_path_size = CIFSSMBSetEOF, .set_path_size = CIFSSMBSetEOF,
.set_file_size = CIFSSMBSetFileSize, .set_file_size = CIFSSMBSetFileSize,
.set_file_info = smb_set_file_info, .set_file_info = smb_set_file_info,
.set_compression = cifs_set_compression,
.echo = CIFSSMBEcho, .echo = CIFSSMBEcho,
.mkdir = CIFSSMBMkDir, .mkdir = CIFSSMBMkDir,
.mkdir_setinfo = cifs_mkdir_setinfo, .mkdir_setinfo = cifs_mkdir_setinfo,
...@@ -1025,8 +1078,18 @@ struct smb_version_operations smb1_operations = { ...@@ -1025,8 +1078,18 @@ struct smb_version_operations smb1_operations = {
.mand_lock = cifs_mand_lock, .mand_lock = cifs_mand_lock,
.mand_unlock_range = cifs_unlock_range, .mand_unlock_range = cifs_unlock_range,
.push_mand_locks = cifs_push_mandatory_locks, .push_mand_locks = cifs_push_mandatory_locks,
.query_mf_symlink = open_query_close_cifs_symlink, .query_mf_symlink = cifs_query_mf_symlink,
.create_mf_symlink = cifs_create_mf_symlink,
.is_read_op = cifs_is_read_op, .is_read_op = cifs_is_read_op,
#ifdef CONFIG_CIFS_XATTR
.query_all_EAs = CIFSSMBQAllEAs,
.set_EA = CIFSSMBSetEA,
#endif /* CIFS_XATTR */
#ifdef CONFIG_CIFS_ACL
.get_acl = get_cifs_acl,
.get_acl_by_fid = get_cifs_acl_by_fid,
.set_acl = set_cifs_acl,
#endif /* CIFS_ACL */
}; };
struct smb_version_values smb1_values = { struct smb_version_values smb1_values = {
......
...@@ -57,4 +57,7 @@ ...@@ -57,4 +57,7 @@
#define SMB2_CMACAES_SIZE (16) #define SMB2_CMACAES_SIZE (16)
#define SMB3_SIGNKEY_SIZE (16) #define SMB3_SIGNKEY_SIZE (16)
/* Maximum buffer size value we can send with 1 credit */
#define SMB2_MAX_BUFFER_SIZE 65536
#endif /* _SMB2_GLOB_H */ #endif /* _SMB2_GLOB_H */
...@@ -124,12 +124,13 @@ move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src) ...@@ -124,12 +124,13 @@ move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
int int
smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path, struct cifs_sb_info *cifs_sb, const char *full_path,
FILE_ALL_INFO *data, bool *adjust_tz) FILE_ALL_INFO *data, bool *adjust_tz, bool *symlink)
{ {
int rc; int rc;
struct smb2_file_all_info *smb2_data; struct smb2_file_all_info *smb2_data;
*adjust_tz = false; *adjust_tz = false;
*symlink = false;
smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2, smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
GFP_KERNEL); GFP_KERNEL);
...@@ -137,9 +138,16 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -137,9 +138,16 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
return -ENOMEM; return -ENOMEM;
rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path, rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path,
FILE_READ_ATTRIBUTES, FILE_OPEN, 0,
smb2_data, SMB2_OP_QUERY_INFO);
if (rc == -EOPNOTSUPP) {
*symlink = true;
/* Failed on a symbolic link - query a reparse point info */
rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path,
FILE_READ_ATTRIBUTES, FILE_OPEN, FILE_READ_ATTRIBUTES, FILE_OPEN,
OPEN_REPARSE_POINT, smb2_data, OPEN_REPARSE_POINT, smb2_data,
SMB2_OP_QUERY_INFO); SMB2_OP_QUERY_INFO);
}
if (rc) if (rc)
goto out; goto out;
......
...@@ -306,7 +306,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = { ...@@ -306,7 +306,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
{STATUS_NONEXISTENT_SECTOR, -EIO, "STATUS_NONEXISTENT_SECTOR"}, {STATUS_NONEXISTENT_SECTOR, -EIO, "STATUS_NONEXISTENT_SECTOR"},
{STATUS_MORE_PROCESSING_REQUIRED, -EIO, {STATUS_MORE_PROCESSING_REQUIRED, -EIO,
"STATUS_MORE_PROCESSING_REQUIRED"}, "STATUS_MORE_PROCESSING_REQUIRED"},
{STATUS_NO_MEMORY, -ENOMEM, "STATUS_NO_MEMORY"}, {STATUS_NO_MEMORY, -EREMOTEIO, "STATUS_NO_MEMORY"},
{STATUS_CONFLICTING_ADDRESSES, -EADDRINUSE, {STATUS_CONFLICTING_ADDRESSES, -EADDRINUSE,
"STATUS_CONFLICTING_ADDRESSES"}, "STATUS_CONFLICTING_ADDRESSES"},
{STATUS_NOT_MAPPED_VIEW, -EIO, "STATUS_NOT_MAPPED_VIEW"}, {STATUS_NOT_MAPPED_VIEW, -EIO, "STATUS_NOT_MAPPED_VIEW"},
......
...@@ -575,9 +575,21 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) ...@@ -575,9 +575,21 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
else else
cfile->oplock_break_cancelled = false; cfile->oplock_break_cancelled = false;
server->ops->set_oplock_level(cinode, set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK,
rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0, &cinode->flags);
0, NULL);
/*
* Set flag if the server downgrades the oplock
* to L2 else clear.
*/
if (rsp->OplockLevel)
set_bit(
CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
&cinode->flags);
else
clear_bit(
CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
&cinode->flags);
queue_work(cifsiod_wq, &cfile->oplock_break); queue_work(cifsiod_wq, &cfile->oplock_break);
......
...@@ -122,6 +122,23 @@ struct smb2_pdu { ...@@ -122,6 +122,23 @@ struct smb2_pdu {
__le16 StructureSize2; /* size of wct area (varies, request specific) */ __le16 StructureSize2; /* size of wct area (varies, request specific) */
} __packed; } __packed;
struct smb2_transform_hdr {
__be32 smb2_buf_length; /* big endian on wire */
/* length is only two or three bytes - with
one or two byte type preceding it that MBZ */
__u8 ProtocolId[4]; /* 0xFD 'S' 'M' 'B' */
__u8 Signature[16];
__u8 Nonce[11];
__u8 Reserved[5];
__le32 OriginalMessageSize;
__u16 Reserved1;
__le16 EncryptionAlgorithm;
__u64 SessionId;
} __packed;
/* Encryption Algorithms */
#define SMB2_ENCRYPTION_AES128_CCM __constant_cpu_to_le16(0x0001)
/* /*
* SMB2 flag definitions * SMB2 flag definitions
*/ */
...@@ -166,8 +183,6 @@ struct smb2_symlink_err_rsp { ...@@ -166,8 +183,6 @@ struct smb2_symlink_err_rsp {
#define SMB2_CLIENT_GUID_SIZE 16 #define SMB2_CLIENT_GUID_SIZE 16
extern __u8 cifs_client_guid[SMB2_CLIENT_GUID_SIZE];
struct smb2_negotiate_req { struct smb2_negotiate_req {
struct smb2_hdr hdr; struct smb2_hdr hdr;
__le16 StructureSize; /* Must be 36 */ __le16 StructureSize; /* Must be 36 */
...@@ -237,6 +252,7 @@ struct smb2_sess_setup_req { ...@@ -237,6 +252,7 @@ struct smb2_sess_setup_req {
/* Currently defined SessionFlags */ /* Currently defined SessionFlags */
#define SMB2_SESSION_FLAG_IS_GUEST 0x0001 #define SMB2_SESSION_FLAG_IS_GUEST 0x0001
#define SMB2_SESSION_FLAG_IS_NULL 0x0002 #define SMB2_SESSION_FLAG_IS_NULL 0x0002
#define SMB2_SESSION_FLAG_ENCRYPT_DATA 0x0004
struct smb2_sess_setup_rsp { struct smb2_sess_setup_rsp {
struct smb2_hdr hdr; struct smb2_hdr hdr;
__le16 StructureSize; /* Must be 9 */ __le16 StructureSize; /* Must be 9 */
...@@ -419,11 +435,15 @@ struct smb2_tree_disconnect_rsp { ...@@ -419,11 +435,15 @@ struct smb2_tree_disconnect_rsp {
#define SMB2_CREATE_SD_BUFFER "SecD" /* security descriptor */ #define SMB2_CREATE_SD_BUFFER "SecD" /* security descriptor */
#define SMB2_CREATE_DURABLE_HANDLE_REQUEST "DHnQ" #define SMB2_CREATE_DURABLE_HANDLE_REQUEST "DHnQ"
#define SMB2_CREATE_DURABLE_HANDLE_RECONNECT "DHnC" #define SMB2_CREATE_DURABLE_HANDLE_RECONNECT "DHnC"
#define SMB2_CREATE_ALLOCATION_SIZE "AlSi" #define SMB2_CREATE_ALLOCATION_SIZE "AISi"
#define SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST "MxAc" #define SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST "MxAc"
#define SMB2_CREATE_TIMEWARP_REQUEST "TWrp" #define SMB2_CREATE_TIMEWARP_REQUEST "TWrp"
#define SMB2_CREATE_QUERY_ON_DISK_ID "QFid" #define SMB2_CREATE_QUERY_ON_DISK_ID "QFid"
#define SMB2_CREATE_REQUEST_LEASE "RqLs" #define SMB2_CREATE_REQUEST_LEASE "RqLs"
#define SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 "DH2Q"
#define SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 "DH2C"
#define SMB2_CREATE_APP_INSTANCE_ID 0x45BCA66AEFA7F74A9008FA462E144D74
#define SVHDX_OPEN_DEVICE_CONTEXT 0x83CE6F1AD851E0986E34401CC9BCFCE9
struct smb2_create_req { struct smb2_create_req {
struct smb2_hdr hdr; struct smb2_hdr hdr;
...@@ -534,9 +554,16 @@ struct create_durable { ...@@ -534,9 +554,16 @@ struct create_durable {
} Data; } Data;
} __packed; } __packed;
#define COPY_CHUNK_RES_KEY_SIZE 24
struct resume_key_req {
char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
__le32 ContextLength; /* MBZ */
char Context[0]; /* ignored, Windows sets to 4 bytes of zero */
} __packed;
/* this goes in the ioctl buffer when doing a copychunk request */ /* this goes in the ioctl buffer when doing a copychunk request */
struct copychunk_ioctl { struct copychunk_ioctl {
char SourceKey[24]; char SourceKey[COPY_CHUNK_RES_KEY_SIZE];
__le32 ChunkCount; /* we are only sending 1 */ __le32 ChunkCount; /* we are only sending 1 */
__le32 Reserved; __le32 Reserved;
/* array will only be one chunk long for us */ /* array will only be one chunk long for us */
...@@ -546,13 +573,25 @@ struct copychunk_ioctl { ...@@ -546,13 +573,25 @@ struct copychunk_ioctl {
__u32 Reserved2; __u32 Reserved2;
} __packed; } __packed;
/* Response and Request are the same format */ struct copychunk_ioctl_rsp {
struct validate_negotiate_info { __le32 ChunksWritten;
__le32 ChunkBytesWritten;
__le32 TotalBytesWritten;
} __packed;
struct validate_negotiate_info_req {
__le32 Capabilities; __le32 Capabilities;
__u8 Guid[SMB2_CLIENT_GUID_SIZE]; __u8 Guid[SMB2_CLIENT_GUID_SIZE];
__le16 SecurityMode; __le16 SecurityMode;
__le16 DialectCount; __le16 DialectCount;
__le16 Dialect[1]; __le16 Dialects[1]; /* dialect (someday maybe list) client asked for */
} __packed;
struct validate_negotiate_info_rsp {
__le32 Capabilities;
__u8 Guid[SMB2_CLIENT_GUID_SIZE];
__le16 SecurityMode;
__le16 Dialect; /* Dialect in use for the connection */
} __packed; } __packed;
#define RSS_CAPABLE 0x00000001 #define RSS_CAPABLE 0x00000001
...@@ -569,6 +608,10 @@ struct network_interface_info_ioctl_rsp { ...@@ -569,6 +608,10 @@ struct network_interface_info_ioctl_rsp {
#define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */ #define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */
struct compress_ioctl {
__le16 CompressionState; /* See cifspdu.h for possible flag values */
} __packed;
struct smb2_ioctl_req { struct smb2_ioctl_req {
struct smb2_hdr hdr; struct smb2_hdr hdr;
__le16 StructureSize; /* Must be 57 */ __le16 StructureSize; /* Must be 57 */
...@@ -584,7 +627,7 @@ struct smb2_ioctl_req { ...@@ -584,7 +627,7 @@ struct smb2_ioctl_req {
__le32 MaxOutputResponse; __le32 MaxOutputResponse;
__le32 Flags; __le32 Flags;
__u32 Reserved2; __u32 Reserved2;
char Buffer[0]; __u8 Buffer[0];
} __packed; } __packed;
struct smb2_ioctl_rsp { struct smb2_ioctl_rsp {
...@@ -870,14 +913,16 @@ struct smb2_lease_ack { ...@@ -870,14 +913,16 @@ struct smb2_lease_ack {
/* File System Information Classes */ /* File System Information Classes */
#define FS_VOLUME_INFORMATION 1 /* Query */ #define FS_VOLUME_INFORMATION 1 /* Query */
#define FS_LABEL_INFORMATION 2 /* Set */ #define FS_LABEL_INFORMATION 2 /* Local only */
#define FS_SIZE_INFORMATION 3 /* Query */ #define FS_SIZE_INFORMATION 3 /* Query */
#define FS_DEVICE_INFORMATION 4 /* Query */ #define FS_DEVICE_INFORMATION 4 /* Query */
#define FS_ATTRIBUTE_INFORMATION 5 /* Query */ #define FS_ATTRIBUTE_INFORMATION 5 /* Query */
#define FS_CONTROL_INFORMATION 6 /* Query, Set */ #define FS_CONTROL_INFORMATION 6 /* Query, Set */
#define FS_FULL_SIZE_INFORMATION 7 /* Query */ #define FS_FULL_SIZE_INFORMATION 7 /* Query */
#define FS_OBJECT_ID_INFORMATION 8 /* Query, Set */ #define FS_OBJECT_ID_INFORMATION 8 /* Query, Set */
#define FS_DRIVER_PATH_INFORMATION 9 /* Query */ #define FS_DRIVER_PATH_INFORMATION 9 /* Local only */
#define FS_VOLUME_FLAGS_INFORMATION 10 /* Local only */
#define FS_SECTOR_SIZE_INFORMATION 11 /* SMB3 or later. Query */
struct smb2_fs_full_size_info { struct smb2_fs_full_size_info {
__le64 TotalAllocationUnits; __le64 TotalAllocationUnits;
...@@ -887,6 +932,22 @@ struct smb2_fs_full_size_info { ...@@ -887,6 +932,22 @@ struct smb2_fs_full_size_info {
__le32 BytesPerSector; __le32 BytesPerSector;
} __packed; } __packed;
#define SSINFO_FLAGS_ALIGNED_DEVICE 0x00000001
#define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 0x00000002
#define SSINFO_FLAGS_NO_SEEK_PENALTY 0x00000004
#define SSINFO_FLAGS_TRIM_ENABLED 0x00000008
/* sector size info struct */
struct smb3_fs_ss_info {
__le32 LogicalBytesPerSector;
__le32 PhysicalBytesPerSectorForAtomicity;
__le32 PhysicalBytesPerSectorForPerf;
__le32 FileSystemEffectivePhysicalBytesPerSectorForAtomicity;
__le32 Flags;
__le32 ByteOffsetForSectorAlignment;
__le32 ByteOffsetForPartitionAlignment;
} __packed;
/* partial list of QUERY INFO levels */ /* partial list of QUERY INFO levels */
#define FILE_DIRECTORY_INFORMATION 1 #define FILE_DIRECTORY_INFORMATION 1
#define FILE_FULL_DIRECTORY_INFORMATION 2 #define FILE_FULL_DIRECTORY_INFORMATION 2
......
...@@ -61,7 +61,7 @@ extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, ...@@ -61,7 +61,7 @@ extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, struct cifs_sb_info *cifs_sb,
const char *full_path, FILE_ALL_INFO *data, const char *full_path, FILE_ALL_INFO *data,
bool *adjust_tz); bool *adjust_tz, bool *symlink);
extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
const char *full_path, __u64 size, const char *full_path, __u64 size,
struct cifs_sb_info *cifs_sb, bool set_alloc); struct cifs_sb_info *cifs_sb, bool set_alloc);
...@@ -143,12 +143,16 @@ extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -143,12 +143,16 @@ extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, u64 persistent_fid, u64 volatile_fid,
FILE_BASIC_INFO *buf); FILE_BASIC_INFO *buf);
extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid);
extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
const u64 persistent_fid, const u64 volatile_fid, const u64 persistent_fid, const u64 volatile_fid,
const __u8 oplock_level); const __u8 oplock_level);
extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id, u64 persistent_file_id, u64 volatile_file_id,
struct kstatfs *FSData); struct kstatfs *FSData);
extern int SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id, int lvl);
extern int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon,
const __u64 persist_fid, const __u64 volatile_fid, const __u64 persist_fid, const __u64 volatile_fid,
const __u32 pid, const __u64 length, const __u64 offset, const __u32 pid, const __u64 length, const __u64 offset,
...@@ -159,5 +163,6 @@ extern int smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -159,5 +163,6 @@ extern int smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
struct smb2_lock_element *buf); struct smb2_lock_element *buf);
extern int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
__u8 *lease_key, const __le32 lease_state); __u8 *lease_key, const __le32 lease_state);
extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
#endif /* _SMB2PROTO_H */ #endif /* _SMB2PROTO_H */
...@@ -466,7 +466,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -466,7 +466,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
static inline void static inline void
smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr) smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr)
{ {
hdr->MessageId = get_next_mid(server); hdr->MessageId = get_next_mid64(server);
} }
static struct mid_q_entry * static struct mid_q_entry *
...@@ -516,13 +516,19 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf, ...@@ -516,13 +516,19 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
return -EAGAIN; return -EAGAIN;
} }
if (ses->status != CifsGood) { if (ses->status == CifsNew) {
/* check if SMB2 session is bad because we are setting it up */
if ((buf->Command != SMB2_SESSION_SETUP) && if ((buf->Command != SMB2_SESSION_SETUP) &&
(buf->Command != SMB2_NEGOTIATE)) (buf->Command != SMB2_NEGOTIATE))
return -EAGAIN; return -EAGAIN;
/* else ok - we are setting up session */ /* else ok - we are setting up session */
} }
if (ses->status == CifsExiting) {
if (buf->Command != SMB2_LOGOFF)
return -EAGAIN;
/* else ok - we are shutting down the session */
}
*mid = smb2_mid_entry_alloc(buf, ses->server); *mid = smb2_mid_entry_alloc(buf, ses->server);
if (*mid == NULL) if (*mid == NULL)
return -ENOMEM; return -ENOMEM;
......
...@@ -90,16 +90,30 @@ ...@@ -90,16 +90,30 @@
#define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */ #define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */
#define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */ #define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */
#define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */ #define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */
#define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 /* BB add struct */ #define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204
/* Perform server-side data movement */ /* Perform server-side data movement */
#define FSCTL_SRV_COPYCHUNK 0x001440F2 #define FSCTL_SRV_COPYCHUNK 0x001440F2
#define FSCTL_SRV_COPYCHUNK_WRITE 0x001480F2 #define FSCTL_SRV_COPYCHUNK_WRITE 0x001480F2
#define FSCTL_QUERY_NETWORK_INTERFACE_INFO 0x001401FC /* BB add struct */ #define FSCTL_QUERY_NETWORK_INTERFACE_INFO 0x001401FC /* BB add struct */
#define FSCTL_SRV_READ_HASH 0x001441BB /* BB add struct */ #define FSCTL_SRV_READ_HASH 0x001441BB /* BB add struct */
/* See FSCC 2.1.2.5 */
#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 #define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
#define IO_REPARSE_TAG_HSM 0xC0000004 #define IO_REPARSE_TAG_HSM 0xC0000004
#define IO_REPARSE_TAG_SIS 0x80000007 #define IO_REPARSE_TAG_SIS 0x80000007
#define IO_REPARSE_TAG_HSM2 0x80000006
#define IO_REPARSE_TAG_DRIVER_EXTENDER 0x80000005
/* Used by the DFS filter. See MS-DFSC */
#define IO_REPARSE_TAG_DFS 0x8000000A
/* Used by the DFS filter See MS-DFSC */
#define IO_REPARSE_TAG_DFSR 0x80000012
#define IO_REPARSE_TAG_FILTER_MANAGER 0x8000000B
/* See section MS-FSCC 2.1.2.4 */
#define IO_REPARSE_TAG_SYMLINK 0xA000000C
#define IO_REPARSE_TAG_DEDUP 0x80000013
#define IO_REPARSE_APPXSTREAM 0xC0000014
/* NFS symlinks, Win 8/SMB3 and later */
#define IO_REPARSE_TAG_NFS 0x80000014
/* fsctl flags */ /* fsctl flags */
/* If Flags is set to this value, the request is an FSCTL not ioctl request */ /* If Flags is set to this value, the request is an FSCTL not ioctl request */
......
...@@ -58,7 +58,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) ...@@ -58,7 +58,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
return temp; return temp;
else { else {
memset(temp, 0, sizeof(struct mid_q_entry)); memset(temp, 0, sizeof(struct mid_q_entry));
temp->mid = smb_buffer->Mid; /* always LE */ temp->mid = get_mid(smb_buffer);
temp->pid = current->pid; temp->pid = current->pid;
temp->command = cpu_to_le16(smb_buffer->Command); temp->command = cpu_to_le16(smb_buffer->Command);
cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command); cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
...@@ -439,8 +439,13 @@ static int ...@@ -439,8 +439,13 @@ static int
wait_for_free_request(struct TCP_Server_Info *server, const int timeout, wait_for_free_request(struct TCP_Server_Info *server, const int timeout,
const int optype) const int optype)
{ {
return wait_for_free_credits(server, timeout, int *val;
server->ops->get_credits_field(server, optype));
val = server->ops->get_credits_field(server, optype);
/* Since an echo is already inflight, no need to wait to send another */
if (*val <= 0 && optype == CIFS_ECHO_OP)
return -EAGAIN;
return wait_for_free_credits(server, timeout, val);
} }
static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
...@@ -455,13 +460,20 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, ...@@ -455,13 +460,20 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
return -EAGAIN; return -EAGAIN;
} }
if (ses->status != CifsGood) { if (ses->status == CifsNew) {
/* check if SMB session is bad because we are setting it up */
if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
(in_buf->Command != SMB_COM_NEGOTIATE)) (in_buf->Command != SMB_COM_NEGOTIATE))
return -EAGAIN; return -EAGAIN;
/* else ok - we are setting up session */ /* else ok - we are setting up session */
} }
if (ses->status == CifsExiting) {
/* check if SMB session is bad because we are setting it up */
if (in_buf->Command != SMB_COM_LOGOFF_ANDX)
return -EAGAIN;
/* else ok - we are shutting down session */
}
*ppmidQ = AllocMidQEntry(in_buf, ses->server); *ppmidQ = AllocMidQEntry(in_buf, ses->server);
if (*ppmidQ == NULL) if (*ppmidQ == NULL)
return -ENOMEM; return -ENOMEM;
......
...@@ -82,9 +82,11 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) ...@@ -82,9 +82,11 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
goto remove_ea_exit; goto remove_ea_exit;
ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL, if (pTcon->ses->server->ops->set_EA)
(__u16)0, cifs_sb->local_nls, rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); full_path, ea_name, NULL, (__u16)0,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
remove_ea_exit: remove_ea_exit:
kfree(full_path); kfree(full_path);
...@@ -149,18 +151,22 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, ...@@ -149,18 +151,22 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
cifs_dbg(FYI, "attempt to set cifs inode metadata\n"); cifs_dbg(FYI, "attempt to set cifs inode metadata\n");
ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, if (pTcon->ses->server->ops->set_EA)
(__u16)value_size, cifs_sb->local_nls, rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); full_path, ea_name, ea_value, (__u16)value_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)
== 0) { == 0) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto set_ea_exit; goto set_ea_exit;
ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, if (pTcon->ses->server->ops->set_EA)
(__u16)value_size, cifs_sb->local_nls, rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); full_path, ea_name, ea_value, (__u16)value_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
strlen(CIFS_XATTR_CIFS_ACL)) == 0) { strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
#ifdef CONFIG_CIFS_ACL #ifdef CONFIG_CIFS_ACL
...@@ -170,8 +176,12 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, ...@@ -170,8 +176,12 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
rc = -ENOMEM; rc = -ENOMEM;
} else { } else {
memcpy(pacl, ea_value, value_size); memcpy(pacl, ea_value, value_size);
rc = set_cifs_acl(pacl, value_size, if (pTcon->ses->server->ops->set_acl)
direntry->d_inode, full_path, CIFS_ACL_DACL); rc = pTcon->ses->server->ops->set_acl(pacl,
value_size, direntry->d_inode,
full_path, CIFS_ACL_DACL);
else
rc = -EOPNOTSUPP;
if (rc == 0) /* force revalidate of the inode */ if (rc == 0) /* force revalidate of the inode */
CIFS_I(direntry->d_inode)->time = 0; CIFS_I(direntry->d_inode)->time = 0;
kfree(pacl); kfree(pacl);
...@@ -272,17 +282,21 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, ...@@ -272,17 +282,21 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
/* revalidate/getattr then populate from inode */ /* revalidate/getattr then populate from inode */
} /* BB add else when above is implemented */ } /* BB add else when above is implemented */
ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, if (pTcon->ses->server->ops->query_all_EAs)
buf_size, cifs_sb->local_nls, rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); full_path, ea_name, ea_value, buf_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto get_ea_exit; goto get_ea_exit;
ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, if (pTcon->ses->server->ops->query_all_EAs)
buf_size, cifs_sb->local_nls, rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); full_path, ea_name, ea_value, buf_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
...@@ -313,8 +327,11 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, ...@@ -313,8 +327,11 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
u32 acllen; u32 acllen;
struct cifs_ntsd *pacl; struct cifs_ntsd *pacl;
pacl = get_cifs_acl(cifs_sb, direntry->d_inode, if (pTcon->ses->server->ops->get_acl == NULL)
full_path, &acllen); goto get_ea_exit; /* rc already EOPNOTSUPP */
pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
direntry->d_inode, full_path, &acllen);
if (IS_ERR(pacl)) { if (IS_ERR(pacl)) {
rc = PTR_ERR(pacl); rc = PTR_ERR(pacl);
cifs_dbg(VFS, "%s: error %zd getting sec desc\n", cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
...@@ -400,11 +417,12 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) ...@@ -400,11 +417,12 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
/* if proc/fs/cifs/streamstoxattr is set then /* if proc/fs/cifs/streamstoxattr is set then
search server for EAs or streams to search server for EAs or streams to
returns as xattrs */ returns as xattrs */
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data,
buf_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (pTcon->ses->server->ops->query_all_EAs)
rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
full_path, NULL, data, buf_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
list_ea_exit: list_ea_exit:
kfree(full_path); kfree(full_path);
free_xid(xid); free_xid(xid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment