Commit 48e35bf3 authored by Evgeny Sinelnikov's avatar Evgeny Sinelnikov

Fix broken module for 2.6.30

parent 6fad7dce
......@@ -6,7 +6,7 @@ obj-$(CONFIG_CIFS) += etercifs.o
etercifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \
md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o \
readdir.o ioctl.o sess.o export.o cifsacl.o
readdir.o ioctl.o sess.o export.o cifsacl.o cifs_lock_storage.o
etercifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
......
/*
* fs/cifs/cifs_lock_storage.c
*
* lock tree operations that provide posix behaviour on windows server
*
* Author(s): Pavel Shilovsky (piastryyy@gmail.com), Copyright (C) 2009.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/ctype.h>
#include <linux/kthread.h>
#include <linux/random.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
#include "cifs_lock_storage.h"
struct cifsPidTreeLock {
struct list_head lock_list;
__u8 type;
__u64 offset;
__u64 len;
__u16 fid;
unsigned long inodeId;
};
struct cifsPidTree {
struct cifsPidTree *left, *right;
__u64 priority;
__u32 pid;
struct list_head lock_list;
};
static struct cifsPidTree *LOCK_STORAGE;
static struct mutex storage_mutex;
void cifs_lock_storage_init(void)
{
mutex_init(&storage_mutex);
LOCK_STORAGE = NULL;
}
static int vertex_init(struct cifsPidTree **root, __u32 pid)
{
(*root) = kmalloc(sizeof(struct cifsPidTree), GFP_KERNEL);
if ((*root) == NULL) {
return -ENOMEM;
}
(*root)->pid = pid;
(*root)->left = (*root)->right = NULL;
(*root)->priority = ((random32() << 16) ^ random32());
INIT_LIST_HEAD(&(*root)->lock_list);
return 0;
}
static void cifs_pid_tree_split(struct cifsPidTree *root, struct cifsPidTree **left, struct cifsPidTree **right, __u32 pid)
{
if (!root) {
(*left) = (*right) = NULL;
return;
}
if (pid <= root->pid) {
(*right) = root;
cifs_pid_tree_split(root->left, left, &((*right)->left), pid);
} else {
(*left) = root;
cifs_pid_tree_split(root->right, &((*left)->right), right, pid);
}
}
static struct cifsPidTree * cifs_pid_tree_merge(struct cifsPidTree *left, struct cifsPidTree *right)
{
struct cifsPidTree *result = NULL;
if (!left) {
return right;
}
if (!right) {
return left;
}
if (left->priority <= right->priority) {
result = right;
result->left = cifs_pid_tree_merge(left, right->left);
} else {
result = left;
result->right = cifs_pid_tree_merge(left->right, right);
}
return result;
}
static struct cifsPidTree ** cifs_pid_tree_find_pid(struct cifsPidTree **root, __u32 pid)
{
if (!(*root)) {
return root;
}
if (pid == (*root)->pid) {
return root;
} else if (pid < (*root)->pid) {
return cifs_pid_tree_find_pid(&((*root)->left), pid);
} else {
return cifs_pid_tree_find_pid(&((*root)->right), pid);
}
}
static int __cifs_lock_storage_add_lock(struct cifsPidTree **root, __u32 pid, unsigned long inodeId, __u16 fid, __u64 offset, __u64 len, __u8 type)
{
struct cifsPidTreeLock *new_lock = NULL;
int rc = 0;
struct cifsPidTree **exist = NULL;
exist = cifs_pid_tree_find_pid(root, pid);
new_lock = kmalloc(sizeof(struct cifsPidTreeLock), GFP_KERNEL);
if (new_lock == NULL) {
return -ENOMEM;
}
new_lock->offset = offset;
new_lock->len = len;
new_lock->type = type;
new_lock->fid = fid;
new_lock->inodeId = inodeId;
if (!(*exist)) {
struct cifsPidTree *left = NULL, *right = NULL, *new_item = NULL;
rc = vertex_init(&new_item, pid);
if (rc) {
kfree(&new_lock);
return rc;
}
list_add(&new_lock->lock_list, &new_item->lock_list);
cifs_pid_tree_split((*root), &left, &right, pid);
(*root) = cifs_pid_tree_merge(left, new_item);
(*root) = cifs_pid_tree_merge((*root), right);
} else {
list_add(&new_lock->lock_list, &(*exist)->lock_list);
}
return rc;
}
static int __cifs_lock_storage_del_lock(int xid, struct cifsTconInfo *pTcon, struct cifsPidTree **root,
__u32 pid, unsigned long inodeId, __u64 offset, __u64 len, __u8 type)
{
struct cifsPidTree **exist;
int rc = 0;
struct cifsPidTreeLock *li, *tmp;
exist = cifs_pid_tree_find_pid(root, pid);
if (!(*exist)) {
return -1;
}
list_for_each_entry_safe(li, tmp, &(*exist)->lock_list, lock_list) {
if (li->offset >= offset && (li->offset+li->len <= offset+len) && (inodeId == li->inodeId)) {
int tmp_rc = CIFSSMBLock(xid, pTcon,
li->fid,
li->len, li->offset,
1, 0, li->type, false);
if (tmp_rc) {
rc = tmp_rc;
} else {
list_del(&li->lock_list);
kfree(li);
}
}
}
if (list_empty(&((*exist)->lock_list))) {
struct cifsPidTree *temp;
temp = (*exist);
(*exist) = cifs_pid_tree_merge((*exist)->left, (*exist)->right);
kfree(temp);
}
return rc;
}
int cifs_lock_storage_add_lock(__u32 pid, unsigned long inodeId, __u16 fid, __u64 offset, __u64 len, __u8 type)
{
int rc;
mutex_lock(&storage_mutex);
rc = __cifs_lock_storage_add_lock(&LOCK_STORAGE, pid, inodeId, fid, offset, len, type);
mutex_unlock(&storage_mutex);
return rc;
}
int cifs_lock_storage_del_lock(int xid, struct cifsTconInfo *pTcon, __u32 pid, unsigned long inodeId, __u64 offset, __u64 len, __u8 type)
{
int rc;
mutex_lock(&storage_mutex);
rc = __cifs_lock_storage_del_lock(xid, pTcon, &LOCK_STORAGE, pid, inodeId, offset, len, type);
mutex_unlock(&storage_mutex);
return rc;
}
/*
* fs/cifs/cifs_lock_storage.h
*
* lock tree operations that provide posix behaviour on windows server
*
* Author(s): Pavel Shilovsky (piastryyy@gmail.com), Copyright (C) 2009.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef CIFS_LOCK_STORAGE
#define CIFS_LOCK_STORAGE
/* creating lock tree */
void cifs_lock_storage_init(void);
/* inserting lock */
int cifs_lock_storage_add_lock(__u32 pid, unsigned long inodeId, __u16 fid, __u64 offset, __u64 len, __u8 type);
/* deleting lock */
int cifs_lock_storage_del_lock(int xid, struct cifsTconInfo *pTcon, __u32 pid, unsigned long inodeId, __u64 offset, __u64 len, __u8 type);
#endif
......@@ -43,6 +43,7 @@
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
#include "cifs_lock_storage.h"
#include <linux/mm.h>
#include <linux/key-type.h>
#include "dns_resolve.h"
......@@ -622,19 +623,6 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
return written;
}
static ssize_t cifs_file_read(struct file *file, char *user, size_t cnt, loff_t *pos)
{
if( file!=NULL && file->f_dentry!=NULL && CIFS_I(file->f_dentry->d_inode)!=NULL ) {
int retval = 0;
CIFS_I(file->f_dentry->d_inode)->needForceInvalidate = 1;
retval = cifs_revalidate(file->f_dentry);
if( retval < 0 )
return (ssize_t)retval;
}
return do_sync_read(file,user,cnt,pos);
}
static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
{
/* origin == SEEK_END => we must revalidate the cached file length */
......@@ -744,7 +732,7 @@ const struct inode_operations cifs_symlink_inode_ops = {
};
const struct file_operations cifs_file_ops = {
.read = cifs_file_read,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = generic_file_aio_read,
.aio_write = cifs_file_aio_write,
......@@ -1039,9 +1027,6 @@ static int cifs_oplock_thread(void *dummyarg)
to server still is disconnected since oplock
already released by the server in that case */
if (!pTcon->need_reconnect) {
/* PV: disable caching if oplock missed */
CIFS_I(inode)->clientCanCacheRead = false;
CIFS_I(inode)->clientCanCacheAll = false;
rc = CIFSSMBLock(0, pTcon, netfid,
0 /* len */ , 0 /* offset */, 0,
0, LOCKING_ANDX_OPLOCK_RELEASE,
......@@ -1091,6 +1076,7 @@ init_cifs(void)
rwlock_init(&GlobalSMBSeslock);
rwlock_init(&cifs_tcp_ses_lock);
spin_lock_init(&GlobalMid_Lock);
cifs_lock_storage_init();
if (cifs_max_pending < 2) {
cifs_max_pending = 2;
......
......@@ -182,6 +182,7 @@ struct TCP_Server_Info {
struct mac_key mac_signing_key;
char ntlmv2_hash[16];
unsigned long lstrp; /* when we got last response from this server */
struct completion done;
};
/*
......@@ -369,7 +370,6 @@ struct cifsInodeInfo {
bool clientCanCacheRead:1; /* read oplock */
bool clientCanCacheAll:1; /* read and writebehind oplock */
bool oplockPending:1;
unsigned needForceInvalidate:1;
bool delete_pending:1; /* DELETE_ON_CLOSE is set */
u64 server_eof; /* current file size on server */
struct inode vfs_inode;
......
......@@ -794,6 +794,12 @@ typedef struct smb_com_close_req {
__u16 ByteCount; /* 0 */
} __attribute__((packed)) CLOSE_REQ;
typedef struct smb_com_flush_req {
struct smb_hdr hdr; /* wct = 1 */
__u16 FileID;
__u16 ByteCount; /* 0 */
} __attribute__((packed)) FLUSH_REQ;
typedef struct smb_com_close_rsp {
struct smb_hdr hdr; /* wct = 0 */
__u16 ByteCount; /* bct = 0 */
......
......@@ -1860,8 +1860,21 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
}
parm_data = (struct cifs_posix_lock *)
((char *)&pSMBr->hdr.Protocol + data_offset);
if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
pLockData->fl_type = F_UNLCK;
else {
if (parm_data->lock_type ==
__constant_cpu_to_le16(CIFS_RDLCK))
pLockData->fl_type = F_RDLCK;
else if (parm_data->lock_type ==
__constant_cpu_to_le16(CIFS_WRLCK))
pLockData->fl_type = F_WRLCK;
pLockData->fl_start = parm_data->start;
pLockData->fl_end = parm_data->start +
parm_data->length - 1;
pLockData->fl_pid = parm_data->pid;
}
}
plk_err_exit:
......
......@@ -338,6 +338,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
bool isMultiRsp;
int reconnect;
init_completion(&server->done);
current->flags |= PF_MEMALLOC;
cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
......@@ -748,7 +749,6 @@ multi_t2_fnd:
kfree(server->hostname);
task_to_wake = xchg(&server->tsk, NULL);
kfree(server);
length = atomic_dec_return(&tcpSesAllocCount);
if (length > 0)
......@@ -765,6 +765,8 @@ multi_t2_fnd:
set_current_state(TASK_RUNNING);
}
complete_all(&server->done);
module_put_and_exit(0);
}
......@@ -1426,6 +1428,10 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
task = xchg(&server->tsk, NULL);
if (task)
force_sig(SIGKILL, task);
wait_for_completion_interruptible(&server->done);
kfree(server);
}
static struct TCP_Server_Info *
......
......@@ -38,6 +38,7 @@
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
#include "cifs_lock_storage.h"
static inline struct cifsFileInfo *cifs_init_private(
struct cifsFileInfo *private_data, struct inode *inode,
......@@ -126,7 +127,7 @@ static inline int cifs_get_disposition(unsigned int flags)
static inline int cifs_get_share_flags(unsigned int flags)
{
return ((~(flags>>20))&7);
return ((~(flags>>21))&7);
}
/* all arguments to this function must be checked for validity in caller */
......@@ -640,7 +641,6 @@ int cifs_close(struct inode *inode, struct file *file)
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
if (pSMBFile) {
struct cifsLockInfo *li, *tmp;
write_lock(&GlobalSMBSeslock);
pSMBFile->closePend = true;
if (pTcon) {
......@@ -674,15 +674,6 @@ int cifs_close(struct inode *inode, struct file *file)
} else
write_unlock(&GlobalSMBSeslock);
/* Delete any outstanding lock records.
We'll lose them when the file is closed anyway. */
mutex_lock(&pSMBFile->lock_mutex);
list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
list_del(&li->llist);
kfree(li);
}
mutex_unlock(&pSMBFile->lock_mutex);
write_lock(&GlobalSMBSeslock);
list_del(&pSMBFile->flist);
list_del(&pSMBFile->tlist);
......@@ -773,22 +764,6 @@ int cifs_closedir(struct inode *inode, struct file *file)
return rc;
}
static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
__u64 offset, __u8 lockType)
{
struct cifsLockInfo *li =
kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
if (li == NULL)
return -ENOMEM;
li->offset = offset;
li->length = len;
li->type = lockType;
mutex_lock(&fid->lock_mutex);
list_add(&li->llist, &fid->llist);
mutex_unlock(&fid->lock_mutex);
return 0;
}
int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
{
int rc, xid;
......@@ -896,8 +871,32 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
} else {
/* if rc == ERR_SHARING_VIOLATION ? */
rc = 0; /* do not change lock type to unlock
since range in use */
rc = 0;
if (lockType & LOCKING_ANDX_SHARED_LOCK) {
pfLock->fl_type = F_WRLCK;
} else {
rc = CIFSSMBLock(xid, tcon, netfid, length,
pfLock->fl_start, 0, 1,
lockType | LOCKING_ANDX_SHARED_LOCK,
0 /* wait flag */ );
if (rc == 0) {
rc = CIFSSMBLock(xid, tcon, netfid,
length, pfLock->fl_start, 1, 0,
lockType |
LOCKING_ANDX_SHARED_LOCK,
0 /* wait flag */ );
pfLock->fl_type = F_RDLCK;
if (rc != 0)
cERROR(1, ("Error unlocking "
"previously locked range %d "
"during test of lock", rc));
rc = 0;
} else {
pfLock->fl_type = F_WRLCK;
rc = 0;
}
}
}
FreeXid(xid);
......@@ -935,33 +934,18 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
if (rc == 0) {
/* For Windows locks we must store them. */
rc = store_file_lock(fid, length,
pfLock->fl_start, lockType);
rc = cifs_lock_storage_add_lock(fid->pid,
fid->pInode->i_ino,
fid->netfid, pfLock->fl_start,
length, lockType);
}
} else if (numUnlock) {
/* For each stored lock that this unlock overlaps
completely, unlock it. */
int stored_rc = 0;
struct cifsLockInfo *li, *tmp;
rc = 0;
mutex_lock(&fid->lock_mutex);
list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
if (pfLock->fl_start <= li->offset &&
(pfLock->fl_start + length) >=
(li->offset + li->length)) {
stored_rc = CIFSSMBLock(xid, tcon,
netfid,
li->length, li->offset,
1, 0, li->type, false);
if (stored_rc)
rc = stored_rc;
list_del(&li->llist);
kfree(li);
}
}
mutex_unlock(&fid->lock_mutex);
rc = cifs_lock_storage_del_lock(xid, tcon, fid->pid,
fid->pInode->i_ino,
pfLock->fl_start,
length, lockType);
}
}
......
......@@ -1079,7 +1079,7 @@ void posix_fill_in_inode(struct inode *tmp_inode,
local_mtime = tmp_inode->i_mtime;
local_size = tmp_inode->i_size;
cifs_unix_info_to_inode(tmp_inode, pData, 1);
cifs_unix_info_to_inode(tmp_inode, pData, 0);
cifs_set_ops(tmp_inode, false);
if (!S_ISREG(tmp_inode->i_mode))
......@@ -1519,7 +1519,7 @@ int cifs_revalidate(struct dentry *direntry)
direntry->d_inode->i_count.counter, direntry,
direntry->d_time, jiffies));
if (cifsInode->time == 0 || cifsInode->needForceInvalidate ) {
if (cifsInode->time == 0) {
/* was set to zero previously to force revalidate */
} else if (time_before(jiffies, cifsInode->time + HZ) &&
lookupCacheEnabled) {
......@@ -1561,10 +1561,9 @@ int cifs_revalidate(struct dentry *direntry)
/* if not oplocked, we invalidate inode pages if mtime or file size
had changed on server */
if (!cifsInode->needForceInvalidate &&
timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
(local_size == direntry->d_inode->i_size) ) {
cFYI(1, ("************** cifs_revalidate - inode unchanged"));
if (timespec_equal(&local_mtime, &direntry->d_inode->i_mtime) &&
(local_size == direntry->d_inode->i_size)) {
cFYI(1, ("cifs_revalidate - inode unchanged"));
} else {
/* file may have changed on server */
if (cifsInode->clientCanCacheRead) {
......@@ -1596,15 +1595,11 @@ int cifs_revalidate(struct dentry *direntry)
if (S_ISREG(direntry->d_inode->i_mode)) {
if (direntry->d_inode->i_mapping) {
wbrc = filemap_fdatawait(direntry->d_inode->i_mapping);
if( cifsInode->needForceInvalidate ) {
cFYI(1, ("Force invalidating."));
invalidate_remote_inode(direntry->d_inode);
cifsInode->needForceInvalidate = 0;
if (wbrc)
CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
}
/* may eventually have to do this for open files too */
} else if (list_empty(&(cifsInode->openFileList))) {
if (list_empty(&(cifsInode->openFileList))) {
/* changed on server - flush read ahead pages */
cFYI(1, ("Invalidating read ahead data on "
"closed file"));
......
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