@@ -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
new file mode 100644
@@ -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 <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;
+ }
+ 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;
+}
new file mode 100644
@@ -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);
+