From patchwork Tue Feb 24 14:36:58 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Shilovsky X-Patchwork-Id: 8596 Received: from lists.samba.org (mail.samba.org [66.70.73.150]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n1OEaRCW002299 for ; Tue, 24 Feb 2009 14:36:27 GMT Received: from dp.samba.org (localhost [127.0.0.1]) by lists.samba.org (Postfix) with ESMTP id 83BBA163C52 for ; Tue, 24 Feb 2009 14:36:13 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.1.7 (2006-10-05) on dp.samba.org X-Spam-Level: X-Spam-Status: No, score=-2.6 required=3.8 tests=BAYES_00 autolearn=ham version=3.1.7 X-Original-To: linux-cifs-client@lists.samba.org Delivered-To: linux-cifs-client@lists.samba.org Received: from mail.etersoft.ru (mail.etersoft.ru [87.249.47.46]) by lists.samba.org (Postfix) with ESMTP id 94E1D163BB6 for ; Tue, 24 Feb 2009 14:35:46 +0000 (GMT) Received: from localhost (as.office.etersoft.ru [192.168.0.10]) by mail.etersoft.ru (Postfix) with ESMTP id 91CC0289307 for ; Tue, 24 Feb 2009 17:35:59 +0300 (MSK) X-Virus-Scanned: amavisd-new at office.etersoft.ru Received: from mail.etersoft.ru ([192.168.0.1]) by localhost (as.office.etersoft.ru [192.168.0.10]) (amavisd-new, port 10024) with LMTP id C1vD6-3cwZnu for ; Tue, 24 Feb 2009 17:35:57 +0300 (MSK) Message-ID: <49A4060A.4000708@etersoft.ru> Date: Tue, 24 Feb 2009 17:36:58 +0300 From: Pavel Shilovsky User-Agent: Thunderbird 2.0.0.18 (X11/20081125) MIME-Version: 1.0 To: linux-cifs-client@lists.samba.org Subject: [linux-cifs-client] [PATCH 1/2] cifs_lock_storage module X-BeenThere: linux-cifs-client@lists.samba.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: The Linux CIFS VFS client List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-cifs-client-bounces+patchwork-cifs-client=patchwork.kernel.org@lists.samba.org Errors-To: linux-cifs-client-bounces+patchwork-cifs-client=patchwork.kernel.org@lists.samba.org +/* 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 diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 6ba43fb..3a01491 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_CIFS) += cifs.o cifs-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 fcntl.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 cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o diff --git a/fs/cifs/cifs_lock_storage.c b/fs/cifs/cifs_lock_storage.c new file mode 100644 index 0000000..1e9371c --- /dev/null +++ b/fs/cifs/cifs_lock_storage.c @@ -0,0 +1,202 @@ +/* + * 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 +#include +#include +#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; + } + 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; +} diff --git a/fs/cifs/cifs_lock_storage.h b/fs/cifs/cifs_lock_storage.h new file mode 100644 index 0000000..479a019 --- /dev/null +++ b/fs/cifs/cifs_lock_storage.h @@ -0,0 +1,36 @@ +/* + * 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); +