Commit 3de18c09 authored by Pavel Shilovsky's avatar Pavel Shilovsky

Fixes in 2.6.34

- oplock handling - update from longterm tree
parent 6e40cfce
...@@ -1054,7 +1054,7 @@ init_cifs(void) ...@@ -1054,7 +1054,7 @@ init_cifs(void)
goto out_unregister_filesystem; goto out_unregister_filesystem;
#endif #endif
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
rc = register_key_type(&key_type_dns_resolver); rc = cifs_init_dns_resolver();
if (rc) if (rc)
goto out_unregister_key_type; goto out_unregister_key_type;
#endif #endif
...@@ -1066,7 +1066,7 @@ init_cifs(void) ...@@ -1066,7 +1066,7 @@ init_cifs(void)
out_unregister_resolver_key: out_unregister_resolver_key:
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
unregister_key_type(&key_type_dns_resolver); cifs_exit_dns_resolver();
out_unregister_key_type: out_unregister_key_type:
#endif #endif
#ifdef CONFIG_CIFS_UPCALL #ifdef CONFIG_CIFS_UPCALL
...@@ -1092,7 +1092,7 @@ exit_cifs(void) ...@@ -1092,7 +1092,7 @@ exit_cifs(void)
cifs_proc_clean(); cifs_proc_clean();
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
cifs_dfs_release_automount_timer(); cifs_dfs_release_automount_timer();
unregister_key_type(&key_type_dns_resolver); cifs_exit_dns_resolver();
#endif #endif
#ifdef CONFIG_CIFS_UPCALL #ifdef CONFIG_CIFS_UPCALL
unregister_key_type(&cifs_spnego_key_type); unregister_key_type(&cifs_spnego_key_type);
......
...@@ -95,8 +95,10 @@ extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode, ...@@ -95,8 +95,10 @@ extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode,
__u16 fileHandle, struct file *file, __u16 fileHandle, struct file *file,
struct vfsmount *mnt, unsigned int oflags); struct vfsmount *mnt, unsigned int oflags);
extern int cifs_posix_open(char *full_path, struct inode **pinode, extern int cifs_posix_open(char *full_path, struct inode **pinode,
struct vfsmount *mnt, int mode, int oflags, struct vfsmount *mnt,
__u32 *poplock, __u16 *pnetfid, int xid); struct super_block *sb,
int mode, int oflags,
__u32 *poplock, __u16 *pnetfid, int xid);
extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
FILE_UNIX_BASIC_INFO *info, FILE_UNIX_BASIC_INFO *info,
struct cifs_sb_info *cifs_sb); struct cifs_sb_info *cifs_sb);
...@@ -326,7 +328,8 @@ extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen, ...@@ -326,7 +328,8 @@ extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
const __u16 netfid, const __u64 len, const __u64 offset, const __u16 netfid, const __u64 len, const __u64 offset,
const __u32 numUnlock, const __u32 numLock, const __u32 numUnlock, const __u32 numLock,
const __u8 lockType, const bool waitFlag); const __u8 lockType, const bool waitFlag,
const __u8 oplock_level);
extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
const __u16 smb_file_id, const int get_flag, const __u16 smb_file_id, const int get_flag,
const __u64 len, struct file_lock *, const __u64 len, struct file_lock *,
......
...@@ -1660,7 +1660,7 @@ int ...@@ -1660,7 +1660,7 @@ int
CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
const __u16 smb_file_id, const __u64 len, const __u64 offset, const __u16 smb_file_id, const __u64 len, const __u64 offset,
const __u32 numUnlock, const __u32 numLock, const __u8 lockType, const __u32 numUnlock, const __u32 numLock, const __u8 lockType,
const bool waitFlag) const bool waitFlag, const __u8 oplock_level)
{ {
int rc = 0; int rc = 0;
LOCK_REQ *pSMB = NULL; LOCK_REQ *pSMB = NULL;
...@@ -1688,6 +1688,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, ...@@ -1688,6 +1688,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
pSMB->NumberOfLocks = cpu_to_le16(numLock); pSMB->NumberOfLocks = cpu_to_le16(numLock);
pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
pSMB->LockType = lockType; pSMB->LockType = lockType;
pSMB->OplockLevel = oplock_level;
pSMB->AndXCommand = 0xFF; /* none */ pSMB->AndXCommand = 0xFF; /* none */
pSMB->Fid = smb_file_id; /* netfid stays le */ pSMB->Fid = smb_file_id; /* netfid stays le */
......
...@@ -183,13 +183,14 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, ...@@ -183,13 +183,14 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
} }
int cifs_posix_open(char *full_path, struct inode **pinode, int cifs_posix_open(char *full_path, struct inode **pinode,
struct vfsmount *mnt, int mode, int oflags, struct vfsmount *mnt, struct super_block *sb,
__u32 *poplock, __u16 *pnetfid, int xid) int mode, int oflags,
__u32 *poplock, __u16 *pnetfid, int xid)
{ {
int rc; int rc;
FILE_UNIX_BASIC_INFO *presp_data; FILE_UNIX_BASIC_INFO *presp_data;
__u32 posix_flags = 0; __u32 posix_flags = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_fattr fattr; struct cifs_fattr fattr;
cFYI(1, ("posix open %s", full_path)); cFYI(1, ("posix open %s", full_path));
...@@ -242,7 +243,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, ...@@ -242,7 +243,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
/* get new inode and set it up */ /* get new inode and set it up */
if (*pinode == NULL) { if (*pinode == NULL) {
*pinode = cifs_iget(mnt->mnt_sb, &fattr); *pinode = cifs_iget(sb, &fattr);
if (!*pinode) { if (!*pinode) {
rc = -ENOMEM; rc = -ENOMEM;
goto posix_open_ret; goto posix_open_ret;
...@@ -251,7 +252,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode, ...@@ -251,7 +252,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
cifs_fattr_to_inode(*pinode, &fattr); cifs_fattr_to_inode(*pinode, &fattr);
} }
cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, oflags); if (mnt)
cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, oflags);
posix_open_ret: posix_open_ret:
kfree(presp_data); kfree(presp_data);
...@@ -315,14 +317,15 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -315,14 +317,15 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
if (nd && (nd->flags & LOOKUP_OPEN)) if (nd && (nd->flags & LOOKUP_OPEN))
oflags = nd->intent.open.flags; oflags = nd->intent.open.flags;
else else
oflags = FMODE_READ; oflags = FMODE_READ | SMB_O_CREAT;
if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP & (CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) { le64_to_cpu(tcon->fsUnixInfo.Capability))) {
rc = cifs_posix_open(full_path, &newinode, nd->path.mnt, rc = cifs_posix_open(full_path, &newinode,
mode, oflags, &oplock, &fileHandle, xid); nd ? nd->path.mnt : NULL,
inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
/* EIO could indicate that (posix open) operation is not /* EIO could indicate that (posix open) operation is not
supported, despite what server claimed in capability supported, despite what server claimed in capability
negotation. EREMOTE indicates DFS junction, which is not negotation. EREMOTE indicates DFS junction, which is not
...@@ -681,6 +684,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -681,6 +684,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
(nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
(nd->intent.open.flags & O_CREAT)) { (nd->intent.open.flags & O_CREAT)) {
rc = cifs_posix_open(full_path, &newInode, nd->path.mnt, rc = cifs_posix_open(full_path, &newInode, nd->path.mnt,
parent_dir_inode->i_sb,
nd->intent.open.create_mode, nd->intent.open.create_mode,
nd->intent.open.flags, &oplock, nd->intent.open.flags, &oplock,
&fileHandle, xid); &fileHandle, xid);
......
...@@ -24,12 +24,16 @@ ...@@ -24,12 +24,16 @@
*/ */
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/keyctl.h>
#include <linux/key-type.h>
#include <keys/user-type.h> #include <keys/user-type.h>
#include "dns_resolve.h" #include "dns_resolve.h"
#include "cifsglob.h" #include "cifsglob.h"
#include "cifsproto.h" #include "cifsproto.h"
#include "cifs_debug.h" #include "cifs_debug.h"
static const struct cred *dns_resolver_cache;
/* Checks if supplied name is IP address /* Checks if supplied name is IP address
* returns: * returns:
* 1 - name is IP * 1 - name is IP
...@@ -94,6 +98,7 @@ struct key_type key_type_dns_resolver = { ...@@ -94,6 +98,7 @@ struct key_type key_type_dns_resolver = {
int int
dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
{ {
const struct cred *saved_cred;
int rc = -EAGAIN; int rc = -EAGAIN;
struct key *rkey = ERR_PTR(-EAGAIN); struct key *rkey = ERR_PTR(-EAGAIN);
char *name; char *name;
...@@ -133,8 +138,15 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) ...@@ -133,8 +138,15 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
goto skip_upcall; goto skip_upcall;
} }
saved_cred = override_creds(dns_resolver_cache);
rkey = request_key(&key_type_dns_resolver, name, ""); rkey = request_key(&key_type_dns_resolver, name, "");
revert_creds(saved_cred);
if (!IS_ERR(rkey)) { if (!IS_ERR(rkey)) {
if (!(rkey->perm & KEY_USR_VIEW)) {
down_read(&rkey->sem);
rkey->perm |= KEY_USR_VIEW;
up_read(&rkey->sem);
}
len = rkey->type_data.x[0]; len = rkey->type_data.x[0];
data = rkey->payload.data; data = rkey->payload.data;
} else { } else {
...@@ -165,4 +177,61 @@ out: ...@@ -165,4 +177,61 @@ out:
return rc; return rc;
} }
int __init cifs_init_dns_resolver(void)
{
struct cred *cred;
struct key *keyring;
int ret;
printk(KERN_NOTICE "Registering the %s key type\n",
key_type_dns_resolver.name);
/* create an override credential set with a special thread keyring in
* which DNS requests are cached
*
* this is used to prevent malicious redirections from being installed
* with add_key().
*/
cred = prepare_kernel_cred(NULL);
if (!cred)
return -ENOMEM;
keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred,
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ,
KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto failed_put_cred;
}
ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
if (ret < 0)
goto failed_put_key;
ret = register_key_type(&key_type_dns_resolver);
if (ret < 0)
goto failed_put_key;
/* instruct request_key() to use this special keyring as a cache for
* the results it looks up */
cred->thread_keyring = keyring;
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
dns_resolver_cache = cred;
return 0;
failed_put_key:
key_put(keyring);
failed_put_cred:
put_cred(cred);
return ret;
}
void cifs_exit_dns_resolver(void)
{
key_revoke(dns_resolver_cache->thread_keyring);
unregister_key_type(&key_type_dns_resolver);
put_cred(dns_resolver_cache);
printk(KERN_NOTICE "Unregistered %s key type\n",
key_type_dns_resolver.name);
}
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
#define _DNS_RESOLVE_H #define _DNS_RESOLVE_H
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/key-type.h> extern int __init cifs_init_dns_resolver(void);
extern struct key_type key_type_dns_resolver; extern void cifs_exit_dns_resolver(void);
extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr); extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
#endif /* KERNEL */ #endif /* KERNEL */
......
...@@ -305,10 +305,12 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -305,10 +305,12 @@ int cifs_open(struct inode *inode, struct file *file)
(CIFS_UNIX_POSIX_PATH_OPS_CAP & (CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) { le64_to_cpu(tcon->fsUnixInfo.Capability))) {
int oflags = (int) cifs_posix_convert_flags(file->f_flags); int oflags = (int) cifs_posix_convert_flags(file->f_flags);
oflags |= SMB_O_CREAT;
/* can not refresh inode info since size could be stale */ /* can not refresh inode info since size could be stale */
rc = cifs_posix_open(full_path, &inode, file->f_path.mnt, rc = cifs_posix_open(full_path, &inode, file->f_path.mnt,
cifs_sb->mnt_file_mode /* ignored */, inode->i_sb,
oflags, &oplock, &netfid, xid); cifs_sb->mnt_file_mode /* ignored */,
oflags, &oplock, &netfid, xid);
if (rc == 0) { if (rc == 0) {
cFYI(1, ("posix open succeeded")); cFYI(1, ("posix open succeeded"));
/* no need for special case handling of setting mode /* no need for special case handling of setting mode
...@@ -524,8 +526,9 @@ reopen_error_exit: ...@@ -524,8 +526,9 @@ reopen_error_exit:
int oflags = (int) cifs_posix_convert_flags(file->f_flags); int oflags = (int) cifs_posix_convert_flags(file->f_flags);
/* can not refresh inode info since size could be stale */ /* can not refresh inode info since size could be stale */
rc = cifs_posix_open(full_path, NULL, file->f_path.mnt, rc = cifs_posix_open(full_path, NULL, file->f_path.mnt,
cifs_sb->mnt_file_mode /* ignored */, inode->i_sb,
oflags, &oplock, &netfid, xid); cifs_sb->mnt_file_mode /* ignored */,
oflags, &oplock, &netfid, xid);
if (rc == 0) { if (rc == 0) {
cFYI(1, ("posix reopen succeeded")); cFYI(1, ("posix reopen succeeded"));
goto reopen_success; goto reopen_success;
...@@ -837,12 +840,12 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -837,12 +840,12 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
/* BB we could chain these into one lock request BB */ /* BB we could chain these into one lock request BB */
rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start, rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
0, 1, lockType, 0 /* wait flag */ ); 0, 1, lockType, 0 /* wait flag */, 0);
if (rc == 0) { if (rc == 0) {
rc = CIFSSMBLock(xid, tcon, netfid, length, rc = CIFSSMBLock(xid, tcon, netfid, length,
pfLock->fl_start, 1 /* numUnlock */ , pfLock->fl_start, 1 /* numUnlock */ ,
0 /* numLock */ , lockType, 0 /* numLock */ , lockType,
0 /* wait flag */ ); 0 /* wait flag */, 0);
pfLock->fl_type = F_UNLCK; pfLock->fl_type = F_UNLCK;
if (rc != 0) if (rc != 0)
cERROR(1, ("Error unlocking previously locked " cERROR(1, ("Error unlocking previously locked "
...@@ -859,13 +862,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -859,13 +862,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
rc = CIFSSMBLock(xid, tcon, netfid, length, rc = CIFSSMBLock(xid, tcon, netfid, length,
pfLock->fl_start, 0, 1, pfLock->fl_start, 0, 1,
lockType | LOCKING_ANDX_SHARED_LOCK, lockType | LOCKING_ANDX_SHARED_LOCK,
0 /* wait flag */); 0 /* wait flag */, 0);
if (rc == 0) { if (rc == 0) {
rc = CIFSSMBLock(xid, tcon, netfid, rc = CIFSSMBLock(xid, tcon, netfid,
length, pfLock->fl_start, 1, 0, length, pfLock->fl_start, 1, 0,
lockType | lockType |
LOCKING_ANDX_SHARED_LOCK, LOCKING_ANDX_SHARED_LOCK,
0 /* wait flag */); 0 /* wait flag */, 0);
pfLock->fl_type = F_RDLCK; pfLock->fl_type = F_RDLCK;
if (rc != 0) if (rc != 0)
cERROR(1, ("Error unlocking " cERROR(1, ("Error unlocking "
...@@ -910,7 +913,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -910,7 +913,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
if (numLock) { if (numLock) {
rc = CIFSSMBLock(xid, tcon, netfid, length, rc = CIFSSMBLock(xid, tcon, netfid, length,
pfLock->fl_start, 0, numLock, lockType, pfLock->fl_start, 0, numLock, lockType,
wait_flag); wait_flag, 0);
if (rc == 0) { if (rc == 0) {
/* For Windows locks we must store them. */ /* For Windows locks we must store them. */
...@@ -932,7 +935,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -932,7 +935,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
stored_rc = CIFSSMBLock(xid, tcon, stored_rc = CIFSSMBLock(xid, tcon,
netfid, li->length, netfid, li->length,
li->offset, 1, 0, li->offset, 1, 0,
li->type, false); li->type, false, 0);
if (stored_rc) if (stored_rc)
rc = stored_rc; rc = stored_rc;
else { else {
...@@ -2386,7 +2389,8 @@ cifs_oplock_break(struct slow_work *work) ...@@ -2386,7 +2389,8 @@ cifs_oplock_break(struct slow_work *work)
*/ */
if (!cfile->closePend && !cfile->oplock_break_cancelled) { if (!cfile->closePend && !cfile->oplock_break_cancelled) {
rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0, rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0,
LOCKING_ANDX_OPLOCK_RELEASE, false); LOCKING_ANDX_OPLOCK_RELEASE, false,
cinode->clientCanCacheRead ? 1 : 0);
cFYI(1, ("Oplock release rc = %d", rc)); cFYI(1, ("Oplock release rc = %d", rc));
} }
} }
......
...@@ -1389,6 +1389,10 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, ...@@ -1389,6 +1389,10 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
if (rc == 0 || rc != -ETXTBSY) if (rc == 0 || rc != -ETXTBSY)
return rc; return rc;
/* open-file renames don't work across directories */
if (to_dentry->d_parent != from_dentry->d_parent)
return rc;
/* open the file to be renamed -- we need DELETE perms */ /* open the file to be renamed -- we need DELETE perms */
rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE, FILE_SHARE_ALL, rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE, FILE_SHARE_ALL,
CREATE_NOT_DIR, &srcfid, &oplock, NULL, CREATE_NOT_DIR, &srcfid, &oplock, NULL,
......
...@@ -723,15 +723,7 @@ ssetup_ntlmssp_authenticate: ...@@ -723,15 +723,7 @@ ssetup_ntlmssp_authenticate:
/* calculate session key */ /* calculate session key */
setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
if (first_time) /* should this be moved into common code /* FIXME: calculate MAC key */
with similar ntlmv2 path? */
/* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key,
response BB FIXME, v2_sess_key); */
/* copy session key */
/* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE);
bcc_ptr += LM2_SESS_KEY_SIZE; */
memcpy(bcc_ptr, (char *)v2_sess_key, memcpy(bcc_ptr, (char *)v2_sess_key,
sizeof(struct ntlmv2_resp)); sizeof(struct ntlmv2_resp));
bcc_ptr += sizeof(struct ntlmv2_resp); bcc_ptr += sizeof(struct ntlmv2_resp);
......
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