* [PATCH 0/6] Implement byte-range lock caching
@ 2011-10-07 13:10 Pavel Shilovsky
[not found] ` <1317993024-15003-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
0 siblings, 1 reply; 7+ messages in thread
From: Pavel Shilovsky @ 2011-10-07 13:10 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
This patchset is going to simplify brlocking code and add caching support for exclusive oplock cases. I splitted it into several independent parts - so, each can be applied separately once it's reviewed.
Any comments and testing are welcome!
Pavel Shilovsky (6):
CIFS: Simplify byte range locking code
CIFS: Move byte range lock list from fd to inode
CIFS: Implement caching mechanism for mandatory brlocks
CIFS: Implement caching mechanism for posix brlocks
CIFS: Send as many mandatory unlock ranges at once as possible
CIFS: Make cifs_push_locks send as many locks at once as possible
fs/cifs/cifsfs.c | 3 +-
fs/cifs/cifsglob.h | 10 +-
fs/cifs/cifsproto.h | 9 +-
fs/cifs/cifssmb.c | 52 +++-
fs/cifs/file.c | 766 ++++++++++++++++++++++++++++++++++++++++-----------
5 files changed, 660 insertions(+), 180 deletions(-)
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/6] CIFS: Simplify byte range locking code
[not found] ` <1317993024-15003-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2011-10-07 13:10 ` Pavel Shilovsky
2011-10-07 13:10 ` [PATCH 2/6] CIFS: Move byte range lock list from fd to inode Pavel Shilovsky
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Pavel Shilovsky @ 2011-10-07 13:10 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Split cifs_lock into several functions and let CIFSSMBLock get pid
as an argument.
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/cifsglob.h | 1 +
fs/cifs/cifsproto.h | 2 +-
fs/cifs/cifssmb.c | 4 +-
fs/cifs/file.c | 370 ++++++++++++++++++++++++++++-----------------------
4 files changed, 205 insertions(+), 172 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 95dad9d..84b0dd1 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -487,6 +487,7 @@ struct cifsLockInfo {
struct list_head llist; /* pointer to next cifsLockInfo */
__u64 offset;
__u64 length;
+ __u32 pid;
__u8 type;
};
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 8df28e9..0d57080 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -360,7 +360,7 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
int remap_special_chars);
extern int CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
- const __u16 netfid, const __u64 len,
+ const __u16 netfid, const __u32 netpid, const __u64 len,
const __u64 offset, const __u32 numUnlock,
const __u32 numLock, const __u8 lockType,
const bool waitFlag, const __u8 oplock_level);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index aac37d9..b79d7fd 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1965,7 +1965,7 @@ CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
int
CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
- const __u16 smb_file_id, const __u64 len,
+ const __u16 smb_file_id, const __u32 netpid, const __u64 len,
const __u64 offset, const __u32 numUnlock,
const __u32 numLock, const __u8 lockType,
const bool waitFlag, const __u8 oplock_level)
@@ -2001,7 +2001,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
pSMB->Fid = smb_file_id; /* netfid stays le */
if ((numLock != 0) || (numUnlock != 0)) {
- pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
+ pSMB->Locks[0].Pid = cpu_to_le16(netpid);
/* BB where to store pid high? */
pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 9f41a10..90e1720 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -631,8 +631,8 @@ 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)
+static int store_file_lock(struct cifsFileInfo *cfile, __u64 len,
+ __u64 offset, __u8 type, __u16 netfid)
{
struct cifsLockInfo *li =
kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
@@ -640,210 +640,241 @@ static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
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);
+ li->type = type;
+ li->pid = current->tgid;
+ mutex_lock(&cfile->lock_mutex);
+ list_add_tail(&li->llist, &cfile->llist);
+ mutex_unlock(&cfile->lock_mutex);
return 0;
}
-int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
+static void
+cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock,
+ bool *wait_flag)
{
- int rc, xid;
- __u32 numLock = 0;
- __u32 numUnlock = 0;
- __u64 length;
- bool wait_flag = false;
- struct cifs_sb_info *cifs_sb;
- struct cifs_tcon *tcon;
- __u16 netfid;
- __u8 lockType = LOCKING_ANDX_LARGE_FILES;
- bool posix_locking = 0;
-
- length = 1 + pfLock->fl_end - pfLock->fl_start;
- rc = -EACCES;
- xid = GetXid();
-
- cFYI(1, "Lock parm: 0x%x flockflags: "
- "0x%x flocktype: 0x%x start: %lld end: %lld",
- cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
- pfLock->fl_end);
-
- if (pfLock->fl_flags & FL_POSIX)
+ if (flock->fl_flags & FL_POSIX)
cFYI(1, "Posix");
- if (pfLock->fl_flags & FL_FLOCK)
+ if (flock->fl_flags & FL_FLOCK)
cFYI(1, "Flock");
- if (pfLock->fl_flags & FL_SLEEP) {
+ if (flock->fl_flags & FL_SLEEP) {
cFYI(1, "Blocking lock");
- wait_flag = true;
+ *wait_flag = true;
}
- if (pfLock->fl_flags & FL_ACCESS)
+ if (flock->fl_flags & FL_ACCESS)
cFYI(1, "Process suspended by mandatory locking - "
- "not implemented yet");
- if (pfLock->fl_flags & FL_LEASE)
+ "not implemented yet");
+ if (flock->fl_flags & FL_LEASE)
cFYI(1, "Lease on file - not implemented yet");
- if (pfLock->fl_flags &
+ if (flock->fl_flags &
(~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
- cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
+ cFYI(1, "Unknown lock flags 0x%x", flock->fl_flags);
- if (pfLock->fl_type == F_WRLCK) {
+ *type = LOCKING_ANDX_LARGE_FILES;
+ if (flock->fl_type == F_WRLCK) {
cFYI(1, "F_WRLCK ");
- numLock = 1;
- } else if (pfLock->fl_type == F_UNLCK) {
+ *lock = 1;
+ } else if (flock->fl_type == F_UNLCK) {
cFYI(1, "F_UNLCK");
- numUnlock = 1;
- /* Check if unlock includes more than
- one lock range */
- } else if (pfLock->fl_type == F_RDLCK) {
+ *unlock = 1;
+ /* Check if unlock includes more than one lock range */
+ } else if (flock->fl_type == F_RDLCK) {
cFYI(1, "F_RDLCK");
- lockType |= LOCKING_ANDX_SHARED_LOCK;
- numLock = 1;
- } else if (pfLock->fl_type == F_EXLCK) {
+ *type |= LOCKING_ANDX_SHARED_LOCK;
+ *lock = 1;
+ } else if (flock->fl_type == F_EXLCK) {
cFYI(1, "F_EXLCK");
- numLock = 1;
- } else if (pfLock->fl_type == F_SHLCK) {
+ *lock = 1;
+ } else if (flock->fl_type == F_SHLCK) {
cFYI(1, "F_SHLCK");
- lockType |= LOCKING_ANDX_SHARED_LOCK;
- numLock = 1;
+ *type |= LOCKING_ANDX_SHARED_LOCK;
+ *lock = 1;
} else
cFYI(1, "Unknown type of lock");
+}
- cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
- tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
- netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
-
- if ((tcon->ses->capabilities & CAP_UNIX) &&
- (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
- ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
- posix_locking = 1;
- /* BB add code here to normalize offset and length to
- account for negative length which we can not accept over the
- wire */
- if (IS_GETLK(cmd)) {
- if (posix_locking) {
- int posix_lock_type;
- if (lockType & LOCKING_ANDX_SHARED_LOCK)
- posix_lock_type = CIFS_RDLCK;
- else
- posix_lock_type = CIFS_WRLCK;
- rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
- length, pfLock, posix_lock_type,
- wait_flag);
- FreeXid(xid);
- return rc;
- }
-
- /* BB we could chain these into one lock request BB */
- rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
- 0, 1, lockType, 0 /* wait flag */, 0);
- if (rc == 0) {
- rc = CIFSSMBLock(xid, tcon, netfid, length,
- pfLock->fl_start, 1 /* numUnlock */ ,
- 0 /* numLock */ , lockType,
- 0 /* wait flag */, 0);
- pfLock->fl_type = F_UNLCK;
- if (rc != 0)
- cERROR(1, "Error unlocking previously locked "
- "range %d during test of lock", rc);
- rc = 0;
-
- } else {
- /* if rc == ERR_SHARING_VIOLATION ? */
- rc = 0;
+static int
+cifs_getlk(struct cifsFileInfo *cfile, struct file_lock *flock, __u8 type,
+ bool wait_flag, bool posix_lck, int xid)
+{
+ int rc = 0;
+ __u64 length = 1 + flock->fl_end - flock->fl_start;
+ __u16 netfid = cfile->netfid;
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
- 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 */, 0);
- if (rc == 0) {
- rc = CIFSSMBLock(xid, tcon, netfid,
- length, pfLock->fl_start, 1, 0,
- lockType |
- LOCKING_ANDX_SHARED_LOCK,
- 0 /* wait flag */, 0);
- 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;
- }
- }
- }
+ if (posix_lck) {
+ int posix_lock_type;
+ if (type & LOCKING_ANDX_SHARED_LOCK)
+ posix_lock_type = CIFS_RDLCK;
+ else
+ posix_lock_type = CIFS_WRLCK;
+ rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
+ length, flock, posix_lock_type,
+ wait_flag);
+ return rc;
+ }
- FreeXid(xid);
+ /* BB we could chain these into one lock request BB */
+ rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
+ flock->fl_start, 0, 1, type, 0, 0);
+ if (rc == 0) {
+ rc = CIFSSMBLock(xid, tcon, netfid, current->tgid,
+ length, flock->fl_start, 1, 0,
+ type, 0, 0);
+ flock->fl_type = F_UNLCK;
+ if (rc != 0)
+ cERROR(1, "Error unlocking previously locked "
+ "range %d during test of lock", rc);
+ rc = 0;
return rc;
}
- if (!numLock && !numUnlock) {
- /* if no lock or unlock then nothing
- to do since we do not know what it is */
- FreeXid(xid);
- return -EOPNOTSUPP;
+ if (type & LOCKING_ANDX_SHARED_LOCK) {
+ flock->fl_type = F_WRLCK;
+ rc = 0;
+ return rc;
}
- if (posix_locking) {
+ rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
+ flock->fl_start, 0, 1,
+ type | LOCKING_ANDX_SHARED_LOCK, 0, 0);
+ if (rc == 0) {
+ rc = CIFSSMBLock(xid, tcon, netfid, current->tgid,
+ length, flock->fl_start, 1, 0,
+ type | LOCKING_ANDX_SHARED_LOCK,
+ 0, 0);
+ flock->fl_type = F_RDLCK;
+ if (rc != 0)
+ cERROR(1, "Error unlocking previously locked "
+ "range %d during test of lock", rc);
+ } else
+ flock->fl_type = F_WRLCK;
+
+ rc = 0;
+ return rc;
+}
+
+static int
+cifs_setlk(struct file *file, struct file_lock *flock, __u8 type,
+ bool wait_flag, bool posix_lck, int lock, int unlock, int xid)
+{
+ int rc = 0;
+ __u64 length = 1 + flock->fl_end - flock->fl_start;
+ struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+ __u16 netfid = cfile->netfid;
+
+ if (posix_lck) {
int posix_lock_type;
- if (lockType & LOCKING_ANDX_SHARED_LOCK)
+ if (type & LOCKING_ANDX_SHARED_LOCK)
posix_lock_type = CIFS_RDLCK;
else
posix_lock_type = CIFS_WRLCK;
- if (numUnlock == 1)
+ if (unlock == 1)
posix_lock_type = CIFS_UNLCK;
- rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
- length, pfLock, posix_lock_type,
- wait_flag);
- } else {
- struct cifsFileInfo *fid = file->private_data;
-
- if (numLock) {
- rc = CIFSSMBLock(xid, tcon, netfid, length,
- pfLock->fl_start, 0, numLock, lockType,
- wait_flag, 0);
-
- if (rc == 0) {
- /* For Windows locks we must store them. */
- rc = store_file_lock(fid, length,
- pfLock->fl_start, lockType);
- }
- } else if (numUnlock) {
- /* For each stored lock that this unlock overlaps
- completely, unlock it. */
- int stored_rc = 0;
- struct cifsLockInfo *li, *tmp;
+ rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */, length,
+ flock, posix_lock_type, wait_flag);
+ goto out;
+ }
- 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, 0);
- if (stored_rc)
- rc = stored_rc;
- else {
- list_del(&li->llist);
- kfree(li);
- }
- }
+ if (lock) {
+ rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
+ flock->fl_start, 0, lock, type, wait_flag, 0);
+ if (rc == 0) {
+ /* For Windows locks we must store them. */
+ rc = store_file_lock(cfile, length, flock->fl_start,
+ type, netfid);
+ }
+ } else if (unlock) {
+ /*
+ * For each stored lock that this unlock overlaps completely,
+ * unlock it.
+ */
+ int stored_rc = 0;
+ struct cifsLockInfo *li, *tmp;
+
+ mutex_lock(&cfile->lock_mutex);
+ list_for_each_entry_safe(li, tmp, &cfile->llist, llist) {
+ if (flock->fl_start > li->offset ||
+ (flock->fl_start + length) <
+ (li->offset + li->length))
+ continue;
+ if (current->tgid != li->pid)
+ continue;
+
+ stored_rc = CIFSSMBLock(xid, tcon, netfid,
+ current->tgid, li->length,
+ li->offset, 1, 0, li->type,
+ 0, 0);
+ if (stored_rc)
+ rc = stored_rc;
+ else {
+ list_del(&li->llist);
+ kfree(li);
}
- mutex_unlock(&fid->lock_mutex);
}
+ mutex_unlock(&cfile->lock_mutex);
+ }
+out:
+ if (flock->fl_flags & FL_POSIX)
+ posix_lock_file_wait(file, flock);
+ return rc;
+}
+
+int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
+{
+ int rc, xid;
+ int lock = 0, unlock = 0;
+ bool wait_flag = false;
+ bool posix_lck = false;
+ struct cifs_sb_info *cifs_sb;
+ struct cifs_tcon *tcon;
+ struct cifsInodeInfo *cinode;
+ struct cifsFileInfo *cfile;
+ __u16 netfid;
+ __u8 type;
+
+ rc = -EACCES;
+ xid = GetXid();
+
+ cFYI(1, "Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld "
+ "end: %lld", cmd, flock->fl_flags, flock->fl_type,
+ flock->fl_start, flock->fl_end);
+
+ cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag);
+
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ cfile = (struct cifsFileInfo *)file->private_data;
+ tcon = tlink_tcon(cfile->tlink);
+ netfid = cfile->netfid;
+ cinode = CIFS_I(file->f_path.dentry->d_inode);
+
+ if ((tcon->ses->capabilities & CAP_UNIX) &&
+ (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
+ ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+ posix_lck = true;
+ /*
+ * BB add code here to normalize offset and length to account for
+ * negative length which we can not accept over the wire.
+ */
+ if (IS_GETLK(cmd)) {
+ rc = cifs_getlk(cfile, flock, type, wait_flag, posix_lck, xid);
+ FreeXid(xid);
+ return rc;
+ }
+
+ if (!lock && !unlock) {
+ /*
+ * if no lock or unlock then nothing to do since we do not
+ * know what it is
+ */
+ FreeXid(xid);
+ return -EOPNOTSUPP;
}
- if (pfLock->fl_flags & FL_POSIX)
- posix_lock_file_wait(file, pfLock);
+ rc = cifs_setlk(file, flock, type, wait_flag, posix_lck, lock, unlock,
+ xid);
FreeXid(xid);
return rc;
}
@@ -2415,8 +2446,9 @@ void cifs_oplock_break(struct work_struct *work)
* disconnected since oplock already released by the server
*/
if (!cfile->oplock_break_cancelled) {
- rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
- 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false,
+ rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid,
+ current->tgid, 0, 0, 0, 0,
+ LOCKING_ANDX_OPLOCK_RELEASE, false,
cinode->clientCanCacheRead ? 1 : 0);
cFYI(1, "Oplock release rc = %d", rc);
}
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/6] CIFS: Move byte range lock list from fd to inode
[not found] ` <1317993024-15003-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-07 13:10 ` [PATCH 1/6] CIFS: Simplify byte range locking code Pavel Shilovsky
@ 2011-10-07 13:10 ` Pavel Shilovsky
2011-10-07 13:10 ` [PATCH 3/6] CIFS: Implement caching mechanism for mandatory brlocks Pavel Shilovsky
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Pavel Shilovsky @ 2011-10-07 13:10 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
that let us do local lock checks before requesting to the server.
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/cifsfs.c | 3 ++-
fs/cifs/cifsglob.h | 7 ++++---
fs/cifs/file.c | 30 +++++++++++++++++-------------
3 files changed, 23 insertions(+), 17 deletions(-)
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index f93eb94..14201fb 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -940,7 +940,8 @@ cifs_init_once(void *inode)
struct cifsInodeInfo *cifsi = inode;
inode_init_once(&cifsi->vfs_inode);
- INIT_LIST_HEAD(&cifsi->lockList);
+ INIT_LIST_HEAD(&cifsi->llist);
+ mutex_init(&cifsi->lock_mutex);
}
static int
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 84b0dd1..865db31 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -489,6 +489,7 @@ struct cifsLockInfo {
__u64 length;
__u32 pid;
__u8 type;
+ __u16 netfid;
};
/*
@@ -521,8 +522,6 @@ struct cifsFileInfo {
struct dentry *dentry;
unsigned int f_flags;
struct tcon_link *tlink;
- struct mutex lock_mutex;
- struct list_head llist; /* list of byte range locks we have. */
bool invalidHandle:1; /* file closed via session abend */
bool oplock_break_cancelled:1;
int count; /* refcount protected by cifs_file_list_lock */
@@ -555,7 +554,9 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
*/
struct cifsInodeInfo {
- struct list_head lockList;
+ struct list_head llist; /* brlocks for this inode */
+ bool can_cache_brlcks;
+ struct mutex lock_mutex; /* protect two fields above */
/* BB add in lists for dirty pages i.e. write caching info for oplock */
struct list_head openFileList;
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 90e1720..aec848a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -258,8 +258,6 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
pCifsFile->invalidHandle = false;
pCifsFile->tlink = cifs_get_tlink(tlink);
mutex_init(&pCifsFile->fh_mutex);
- mutex_init(&pCifsFile->lock_mutex);
- INIT_LIST_HEAD(&pCifsFile->llist);
INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
spin_lock(&cifs_file_list_lock);
@@ -327,12 +325,14 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
/* Delete any outstanding lock records. We'll lose them when the file
* is closed anyway.
*/
- mutex_lock(&cifs_file->lock_mutex);
- list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) {
+ mutex_lock(&cifsi->lock_mutex);
+ list_for_each_entry_safe(li, tmp, &cifsi->llist, llist) {
+ if (li->netfid != cifs_file->netfid)
+ continue;
list_del(&li->llist);
kfree(li);
}
- mutex_unlock(&cifs_file->lock_mutex);
+ mutex_unlock(&cifsi->lock_mutex);
cifs_put_tlink(cifs_file->tlink);
dput(cifs_file->dentry);
@@ -631,20 +631,21 @@ int cifs_closedir(struct inode *inode, struct file *file)
return rc;
}
-static int store_file_lock(struct cifsFileInfo *cfile, __u64 len,
+static int store_file_lock(struct cifsInodeInfo *cinode, __u64 len,
__u64 offset, __u8 type, __u16 netfid)
{
struct cifsLockInfo *li =
kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
if (li == NULL)
return -ENOMEM;
+ li->netfid = netfid;
li->offset = offset;
li->length = len;
li->type = type;
li->pid = current->tgid;
- mutex_lock(&cfile->lock_mutex);
- list_add_tail(&li->llist, &cfile->llist);
- mutex_unlock(&cfile->lock_mutex);
+ mutex_lock(&cinode->lock_mutex);
+ list_add_tail(&li->llist, &cinode->llist);
+ mutex_unlock(&cinode->lock_mutex);
return 0;
}
@@ -761,6 +762,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type,
__u64 length = 1 + flock->fl_end - flock->fl_start;
struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+ struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode);
__u16 netfid = cfile->netfid;
if (posix_lck) {
@@ -783,7 +785,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type,
flock->fl_start, 0, lock, type, wait_flag, 0);
if (rc == 0) {
/* For Windows locks we must store them. */
- rc = store_file_lock(cfile, length, flock->fl_start,
+ rc = store_file_lock(cinode, length, flock->fl_start,
type, netfid);
}
} else if (unlock) {
@@ -794,14 +796,16 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type,
int stored_rc = 0;
struct cifsLockInfo *li, *tmp;
- mutex_lock(&cfile->lock_mutex);
- list_for_each_entry_safe(li, tmp, &cfile->llist, llist) {
+ mutex_lock(&cinode->lock_mutex);
+ list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
if (flock->fl_start > li->offset ||
(flock->fl_start + length) <
(li->offset + li->length))
continue;
if (current->tgid != li->pid)
continue;
+ if (cfile->netfid != li->netfid)
+ continue;
stored_rc = CIFSSMBLock(xid, tcon, netfid,
current->tgid, li->length,
@@ -814,7 +818,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type,
kfree(li);
}
}
- mutex_unlock(&cfile->lock_mutex);
+ mutex_unlock(&cinode->lock_mutex);
}
out:
if (flock->fl_flags & FL_POSIX)
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/6] CIFS: Implement caching mechanism for mandatory brlocks
[not found] ` <1317993024-15003-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-07 13:10 ` [PATCH 1/6] CIFS: Simplify byte range locking code Pavel Shilovsky
2011-10-07 13:10 ` [PATCH 2/6] CIFS: Move byte range lock list from fd to inode Pavel Shilovsky
@ 2011-10-07 13:10 ` Pavel Shilovsky
2011-10-07 13:10 ` [PATCH 4/6] CIFS: Implement caching mechanism for posix brlocks Pavel Shilovsky
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Pavel Shilovsky @ 2011-10-07 13:10 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
If we have an oplock and negotiate mandatory locking style we handle
all brlock requests on the client.
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/cifsglob.h | 2 +
fs/cifs/file.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 196 insertions(+), 11 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 865db31..2fd8a7d 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -485,6 +485,8 @@ extern struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb);
*/
struct cifsLockInfo {
struct list_head llist; /* pointer to next cifsLockInfo */
+ struct list_head blist; /* pointer to locks blocked on this */
+ wait_queue_head_t block_q;
__u64 offset;
__u64 length;
__u32 pid;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index aec848a..8c13cd4 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -270,11 +270,14 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
spin_unlock(&cifs_file_list_lock);
cifs_set_oplock_level(pCifsInode, oplock);
+ pCifsInode->can_cache_brlcks = pCifsInode->clientCanCacheAll;
file->private_data = pCifsFile;
return pCifsFile;
}
+static void cifs_del_lock_waiters(struct cifsLockInfo *lock);
+
/*
* Release a reference on the file private data. This may involve closing
* the filehandle out on the server. Must be called without holding
@@ -330,6 +333,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
if (li->netfid != cifs_file->netfid)
continue;
list_del(&li->llist);
+ cifs_del_lock_waiters(li);
kfree(li);
}
mutex_unlock(&cifsi->lock_mutex);
@@ -631,24 +635,181 @@ int cifs_closedir(struct inode *inode, struct file *file)
return rc;
}
-static int store_file_lock(struct cifsInodeInfo *cinode, __u64 len,
- __u64 offset, __u8 type, __u16 netfid)
+static struct cifsLockInfo *
+cifs_lock_init(__u64 len, __u64 offset, __u8 type, __u16 netfid)
{
struct cifsLockInfo *li =
kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
- if (li == NULL)
- return -ENOMEM;
+ if (!li)
+ return li;
li->netfid = netfid;
li->offset = offset;
li->length = len;
li->type = type;
li->pid = current->tgid;
+ INIT_LIST_HEAD(&li->blist);
+ init_waitqueue_head(&li->block_q);
+ return li;
+}
+
+static void
+cifs_del_lock_waiters(struct cifsLockInfo *lock)
+{
+ struct cifsLockInfo *li, *tmp;
+ list_for_each_entry_safe(li, tmp, &lock->blist, blist) {
+ list_del_init(&li->blist);
+ wake_up(&li->block_q);
+ }
+}
+
+static int
+cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, __u64 length,
+ __u8 type, __u16 netfid, struct file_lock *flock)
+{
+ int rc = 0;
+ struct cifsLockInfo *li, *tmp;
+ bool exist = false;
+
+ mutex_lock(&cinode->lock_mutex);
+
+ list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
+ if (offset + length <= li->offset ||
+ offset >= li->offset + li->length)
+ continue;
+ else if (type == li->type &&
+ (type & LOCKING_ANDX_SHARED_LOCK))
+ continue;
+ else {
+ exist = true;
+ break;
+ }
+ }
+
+ if (exist) {
+ flock->fl_start = li->offset;
+ flock->fl_end = li->offset + length - 1;
+ flock->fl_pid = li->pid;
+ if (li->type & LOCKING_ANDX_SHARED_LOCK)
+ flock->fl_type = F_RDLCK;
+ else
+ flock->fl_type = F_WRLCK;
+ } else if (!cinode->can_cache_brlcks)
+ rc = 1;
+ else
+ flock->fl_type = F_UNLCK;
+
+ mutex_unlock(&cinode->lock_mutex);
+ return rc;
+}
+
+static int
+cifs_lock_add(struct cifsInodeInfo *cinode, __u64 len, __u64 offset,
+ __u8 type, __u16 netfid)
+{
+ struct cifsLockInfo *li;
+
+ li = cifs_lock_init(len, offset, type, netfid);
+ if (!li)
+ return -ENOMEM;
+
mutex_lock(&cinode->lock_mutex);
list_add_tail(&li->llist, &cinode->llist);
mutex_unlock(&cinode->lock_mutex);
return 0;
}
+static int
+cifs_lock_add_if(struct cifsInodeInfo *cinode, __u64 offset, __u64 length,
+ __u8 type, __u16 netfid, bool wait)
+{
+ struct cifsLockInfo *lock, *li, *tmp;
+ bool exist;
+ int rc = 0;
+
+ lock = cifs_lock_init(length, offset, type, netfid);
+ if (!lock)
+ return -ENOMEM;
+
+try_again:
+ exist = false;
+ mutex_lock(&cinode->lock_mutex);
+
+ list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
+ if (offset + length <= li->offset ||
+ offset >= li->offset + li->length)
+ continue;
+ else if ((type & LOCKING_ANDX_SHARED_LOCK) &&
+ ((li->netfid == netfid && li->pid == current->tgid) ||
+ type == li->type))
+ continue;
+ else {
+ exist = true;
+ break;
+ }
+ }
+
+ if (!exist && cinode->can_cache_brlcks) {
+ list_add_tail(&lock->llist, &cinode->llist);
+ mutex_unlock(&cinode->lock_mutex);
+ return rc;
+ }
+
+ if (!exist && !cinode->can_cache_brlcks)
+ rc = 1;
+ else if (wait) {
+ list_add_tail(&lock->blist, &li->blist);
+ mutex_unlock(&cinode->lock_mutex);
+ rc = wait_event_interruptible(lock->block_q,
+ (lock->blist.prev == &lock->blist) &&
+ (lock->blist.next == &lock->blist));
+ if (!rc)
+ goto try_again;
+ else {
+ mutex_lock(&cinode->lock_mutex);
+ list_del_init(&lock->blist);
+ mutex_unlock(&cinode->lock_mutex);
+ }
+ } else
+ rc = -EACCES;
+
+ kfree(lock);
+ mutex_unlock(&cinode->lock_mutex);
+ return rc;
+}
+
+static int
+cifs_push_locks(struct cifsFileInfo *cfile)
+{
+ int xid, rc = 0, stored_rc;
+ struct cifsLockInfo *li, *tmp;
+ struct cifs_tcon *tcon;
+ struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+
+ xid = GetXid();
+ tcon = tlink_tcon(cfile->tlink);
+
+ mutex_lock(&cinode->lock_mutex);
+ if (!cinode->can_cache_brlcks) {
+ mutex_unlock(&cinode->lock_mutex);
+ FreeXid(xid);
+ return rc;
+ }
+
+ list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
+ stored_rc = CIFSSMBLock(xid, tcon, cfile->netfid,
+ li->pid, li->length, li->offset,
+ 0, 1, li->type, 0, 0);
+ if (stored_rc)
+ rc = stored_rc;
+ }
+
+ cinode->can_cache_brlcks = false;
+ mutex_unlock(&cinode->lock_mutex);
+
+ FreeXid(xid);
+ return rc;
+}
+
static void
cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock,
bool *wait_flag)
@@ -699,6 +860,7 @@ cifs_getlk(struct cifsFileInfo *cfile, struct file_lock *flock, __u8 type,
{
int rc = 0;
__u64 length = 1 + flock->fl_end - flock->fl_start;
+ struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
__u16 netfid = cfile->netfid;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
@@ -714,6 +876,11 @@ cifs_getlk(struct cifsFileInfo *cfile, struct file_lock *flock, __u8 type,
return rc;
}
+ rc = cifs_lock_test(cinode, flock->fl_start, length, type, netfid,
+ flock);
+ if (!rc)
+ return rc;
+
/* BB we could chain these into one lock request BB */
rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
flock->fl_start, 0, 1, type, 0, 0);
@@ -781,12 +948,19 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type,
}
if (lock) {
+ rc = cifs_lock_add_if(cinode, flock->fl_start, length,
+ type, netfid, wait_flag);
+ if (rc < 0)
+ return rc;
+ else if (!rc)
+ goto out;
+
rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
- flock->fl_start, 0, lock, type, wait_flag, 0);
+ flock->fl_start, 0, 1, type, wait_flag, 0);
if (rc == 0) {
/* For Windows locks we must store them. */
- rc = store_file_lock(cinode, length, flock->fl_start,
- type, netfid);
+ rc = cifs_lock_add(cinode, length, flock->fl_start,
+ type, netfid);
}
} else if (unlock) {
/*
@@ -807,10 +981,15 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type,
if (cfile->netfid != li->netfid)
continue;
- stored_rc = CIFSSMBLock(xid, tcon, netfid,
- current->tgid, li->length,
- li->offset, 1, 0, li->type,
- 0, 0);
+ if (!cinode->can_cache_brlcks)
+ stored_rc = CIFSSMBLock(xid, tcon, netfid,
+ current->tgid,
+ li->length, li->offset,
+ 1, 0, li->type, 0, 0);
+ else {
+ stored_rc = 0;
+ cifs_del_lock_waiters(li);
+ }
if (stored_rc)
rc = stored_rc;
else {
@@ -2443,6 +2622,10 @@ void cifs_oplock_break(struct work_struct *work)
cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
}
+ rc = cifs_push_locks(cfile);
+ if (rc)
+ cERROR(1, "Push locks rc = %d", rc);
+
/*
* releasing stale oplock after recent reconnect of smb session using
* a now incorrect file handle is not a data integrity issue but do
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/6] CIFS: Implement caching mechanism for posix brlocks
[not found] ` <1317993024-15003-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (2 preceding siblings ...)
2011-10-07 13:10 ` [PATCH 3/6] CIFS: Implement caching mechanism for mandatory brlocks Pavel Shilovsky
@ 2011-10-07 13:10 ` Pavel Shilovsky
2011-10-07 13:10 ` [PATCH 5/6] CIFS: Send as many mandatory unlock ranges at once as possible Pavel Shilovsky
2011-10-07 13:10 ` [PATCH 6/6] CIFS: Make cifs_push_locks send as many locks " Pavel Shilovsky
5 siblings, 0 replies; 7+ messages in thread
From: Pavel Shilovsky @ 2011-10-07 13:10 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
to handle all lock requests on the client in an exclusive oplock case.
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/cifsproto.h | 4 +-
fs/cifs/cifssmb.c | 8 ++--
fs/cifs/file.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 147 insertions(+), 15 deletions(-)
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 0d57080..276def2 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -365,8 +365,8 @@ extern int CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
const __u32 numLock, const __u8 lockType,
const bool waitFlag, const __u8 oplock_level);
extern int CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
- const __u16 smb_file_id, const int get_flag,
- const __u64 len, struct file_lock *,
+ const __u16 smb_file_id, const __u32 netpid,
+ const int get_flag, const __u64 len, struct file_lock *,
const __u16 lock_type, const bool waitFlag);
extern int CIFSSMBTDis(const int xid, struct cifs_tcon *tcon);
extern int CIFSSMBEcho(struct TCP_Server_Info *server);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index b79d7fd..43b1843 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2035,9 +2035,9 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
int
CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
- const __u16 smb_file_id, const int get_flag, const __u64 len,
- struct file_lock *pLockData, const __u16 lock_type,
- const bool waitFlag)
+ const __u16 smb_file_id, const __u32 netpid, const int get_flag,
+ const __u64 len, struct file_lock *pLockData,
+ const __u16 lock_type, const bool waitFlag)
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
@@ -2095,7 +2095,7 @@ CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
} else
pSMB->Timeout = 0;
- parm_data->pid = cpu_to_le32(current->tgid);
+ parm_data->pid = cpu_to_le32(netpid);
parm_data->start = cpu_to_le64(pLockData->fl_start);
parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 8c13cd4..888227f 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -778,7 +778,42 @@ try_again:
}
static int
-cifs_push_locks(struct cifsFileInfo *cfile)
+cifs_posix_lock_test(struct file *file, struct file_lock *flock)
+{
+ int rc = 0;
+ struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode);
+ unsigned char saved_type = flock->fl_type;
+
+ mutex_lock(&cinode->lock_mutex);
+ posix_test_lock(file, flock);
+
+ if (flock->fl_type == F_UNLCK && !cinode->can_cache_brlcks) {
+ flock->fl_type = saved_type;
+ rc = 1;
+ }
+
+ mutex_unlock(&cinode->lock_mutex);
+ return rc;
+}
+
+static int
+cifs_posix_lock_set(struct file *file, struct file_lock *flock)
+{
+ struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode);
+ int rc;
+
+ mutex_lock(&cinode->lock_mutex);
+ if (!cinode->can_cache_brlcks) {
+ mutex_unlock(&cinode->lock_mutex);
+ return 1;
+ }
+ rc = posix_lock_file_wait(file, flock);
+ mutex_unlock(&cinode->lock_mutex);
+ return rc;
+}
+
+static int
+cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
{
int xid, rc = 0, stored_rc;
struct cifsLockInfo *li, *tmp;
@@ -810,6 +845,91 @@ cifs_push_locks(struct cifsFileInfo *cfile)
return rc;
}
+/* copied from fs/locks.c with a name change */
+#define cifs_for_each_lock(inode, lockp) \
+ for (lockp = &inode->i_flock; *lockp != NULL; \
+ lockp = &(*lockp)->fl_next)
+
+static int
+cifs_push_posix_locks(struct cifsFileInfo *cfile)
+{
+ struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+ struct file_lock *flock, **before;
+ struct cifsLockInfo *lck, *tmp;
+ int rc = 0, xid, type;
+ __u64 length;
+ struct list_head locks_to_send;
+
+ xid = GetXid();
+
+ mutex_lock(&cinode->lock_mutex);
+ if (!cinode->can_cache_brlcks) {
+ mutex_unlock(&cinode->lock_mutex);
+ FreeXid(xid);
+ return rc;
+ }
+
+ INIT_LIST_HEAD(&locks_to_send);
+
+ lock_flocks();
+ cifs_for_each_lock(cfile->dentry->d_inode, before) {
+ flock = *before;
+ length = 1 + flock->fl_end - flock->fl_start;
+ if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK)
+ type = CIFS_RDLCK;
+ else
+ type = CIFS_WRLCK;
+
+ lck = cifs_lock_init(length, flock->fl_start, type,
+ cfile->netfid);
+ if (!lck) {
+ rc = -ENOMEM;
+ goto send_locks;
+ }
+ lck->pid = flock->fl_pid;
+
+ list_add_tail(&lck->llist, &locks_to_send);
+ }
+
+send_locks:
+ unlock_flocks();
+
+ list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
+ struct file_lock tmp_lock;
+ int stored_rc;
+
+ tmp_lock.fl_start = lck->offset;
+ stored_rc = CIFSSMBPosixLock(xid, tcon, lck->netfid, lck->pid,
+ 0, lck->length, &tmp_lock,
+ lck->type, 0);
+ if (stored_rc)
+ rc = stored_rc;
+ list_del(&lck->llist);
+ kfree(lck);
+ }
+
+ cinode->can_cache_brlcks = false;
+ mutex_unlock(&cinode->lock_mutex);
+
+ FreeXid(xid);
+ return rc;
+}
+
+static int
+cifs_push_locks(struct cifsFileInfo *cfile)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+
+ if ((tcon->ses->capabilities & CAP_UNIX) &&
+ (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
+ ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+ return cifs_push_posix_locks(cfile);
+
+ return cifs_push_mandatory_locks(cfile);
+}
+
static void
cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock,
bool *wait_flag)
@@ -855,24 +975,30 @@ cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock,
}
static int
-cifs_getlk(struct cifsFileInfo *cfile, struct file_lock *flock, __u8 type,
+cifs_getlk(struct file *file, struct file_lock *flock, __u8 type,
bool wait_flag, bool posix_lck, int xid)
{
int rc = 0;
__u64 length = 1 + flock->fl_end - flock->fl_start;
+ struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
__u16 netfid = cfile->netfid;
- struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
if (posix_lck) {
int posix_lock_type;
+
+ rc = cifs_posix_lock_test(file, flock);
+ if (!rc)
+ return rc;
+
if (type & LOCKING_ANDX_SHARED_LOCK)
posix_lock_type = CIFS_RDLCK;
else
posix_lock_type = CIFS_WRLCK;
- rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
- length, flock, posix_lock_type,
- wait_flag);
+ rc = CIFSSMBPosixLock(xid, tcon, netfid, current->tgid,
+ 1 /* get */, length, flock,
+ posix_lock_type, wait_flag);
return rc;
}
@@ -934,6 +1060,11 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type,
if (posix_lck) {
int posix_lock_type;
+
+ rc = cifs_posix_lock_set(file, flock);
+ if (!rc || rc < 0)
+ return rc;
+
if (type & LOCKING_ANDX_SHARED_LOCK)
posix_lock_type = CIFS_RDLCK;
else
@@ -942,8 +1073,9 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type,
if (unlock == 1)
posix_lock_type = CIFS_UNLCK;
- rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */, length,
- flock, posix_lock_type, wait_flag);
+ rc = CIFSSMBPosixLock(xid, tcon, netfid, current->tgid,
+ 0 /* set */, length, flock,
+ posix_lock_type, wait_flag);
goto out;
}
@@ -1042,7 +1174,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
* negative length which we can not accept over the wire.
*/
if (IS_GETLK(cmd)) {
- rc = cifs_getlk(cfile, flock, type, wait_flag, posix_lck, xid);
+ rc = cifs_getlk(file, flock, type, wait_flag, posix_lck, xid);
FreeXid(xid);
return rc;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5/6] CIFS: Send as many mandatory unlock ranges at once as possible
[not found] ` <1317993024-15003-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (3 preceding siblings ...)
2011-10-07 13:10 ` [PATCH 4/6] CIFS: Implement caching mechanism for posix brlocks Pavel Shilovsky
@ 2011-10-07 13:10 ` Pavel Shilovsky
2011-10-07 13:10 ` [PATCH 6/6] CIFS: Make cifs_push_locks send as many locks " Pavel Shilovsky
5 siblings, 0 replies; 7+ messages in thread
From: Pavel Shilovsky @ 2011-10-07 13:10 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
that reduces a traffic and increases a performance.
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/cifsproto.h | 3 +
fs/cifs/cifssmb.c | 40 +++++++++++++++++
fs/cifs/file.c | 116 +++++++++++++++++++++++++++++++++++----------------
3 files changed, 123 insertions(+), 36 deletions(-)
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 276def2..a7c62c7 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -359,6 +359,9 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
const struct nls_table *nls_codepage,
int remap_special_chars);
+extern int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
+ const __u8 lock_type, const __u32 num_unlock,
+ const __u32 num_lock, LOCKING_ANDX_RANGE *buf);
extern int CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
const __u16 netfid, const __u32 netpid, const __u64 len,
const __u64 offset, const __u32 numUnlock,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 43b1843..f70e204 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1962,6 +1962,46 @@ CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
return rc;
}
+int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
+ const __u8 lock_type, const __u32 num_unlock,
+ const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
+{
+ int rc = 0;
+ LOCK_REQ *pSMB = NULL;
+ struct kvec iov[2];
+ int resp_buf_type;
+ __u16 count;
+
+ cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
+
+ rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
+ if (rc)
+ return rc;
+
+ pSMB->Timeout = 0;
+ pSMB->NumberOfLocks = cpu_to_le16(num_lock);
+ pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
+ pSMB->LockType = lock_type;
+ pSMB->AndXCommand = 0xFF; /* none */
+ pSMB->Fid = netfid; /* netfid stays le */
+
+ count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
+ inc_rfc1001_len(pSMB, count);
+ pSMB->ByteCount = cpu_to_le16(count);
+
+ iov[0].iov_base = (char *)pSMB;
+ iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
+ (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
+ iov[1].iov_base = (char *)buf;
+ iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
+
+ cifs_stats_inc(&tcon->num_locks);
+ rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
+ if (rc)
+ cFYI(1, "Send error in cifs_lockv = %d", rc);
+
+ return rc;
+}
int
CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 888227f..59410a8 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1048,6 +1048,84 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u8 type,
}
static int
+cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid)
+{
+ int rc = 0, stored_rc;
+ int types[] = {LOCKING_ANDX_LARGE_FILES,
+ LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES};
+ unsigned int i;
+ unsigned int max_num, num;
+ LOCKING_ANDX_RANGE *buf, *cur;
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+ struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+ struct cifsLockInfo *li, *tmp;
+ __u64 length = 1 + flock->fl_end - flock->fl_start;
+
+ max_num = (tcon->ses->server->maxBuf - sizeof(struct smb_hdr)) /
+ sizeof(LOCKING_ANDX_RANGE);
+ buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&cinode->lock_mutex);
+ for (i = 0; i < 2; i++) {
+ cur = buf;
+ num = 0;
+ list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
+ if (flock->fl_start > li->offset ||
+ (flock->fl_start + length) <
+ (li->offset + li->length))
+ continue;
+ if (current->tgid != li->pid)
+ continue;
+ if (cfile->netfid != li->netfid)
+ continue;
+ if (types[i] != li->type)
+ continue;
+
+ if (!cinode->can_cache_brlcks) {
+ cur->Pid = cpu_to_le16(li->pid);
+ cur->LengthLow = cpu_to_le32((u32)li->length);
+ cur->LengthHigh =
+ cpu_to_le32((u32)(li->length>>32));
+ cur->OffsetLow = cpu_to_le32((u32)li->offset);
+ cur->OffsetHigh =
+ cpu_to_le32((u32)(li->offset>>32));
+ if (++num == max_num) {
+ stored_rc = cifs_lockv(xid, tcon,
+ cfile->netfid,
+ li->type, num,
+ 0, buf);
+ if (stored_rc)
+ rc = stored_rc;
+ cur = buf;
+ num = 0;
+ } else
+ cur++;
+ } else {
+ stored_rc = 0;
+ cifs_del_lock_waiters(li);
+ }
+ if (stored_rc)
+ rc = stored_rc;
+ else {
+ list_del(&li->llist);
+ kfree(li);
+ }
+ }
+ if (num) {
+ stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+ types[i], num, 0, buf);
+ if (stored_rc)
+ rc = stored_rc;
+ }
+ }
+ kfree(buf);
+ mutex_unlock(&cinode->lock_mutex);
+ return rc;
+}
+
+static int
cifs_setlk(struct file *file, struct file_lock *flock, __u8 type,
bool wait_flag, bool posix_lck, int lock, int unlock, int xid)
{
@@ -1094,43 +1172,9 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type,
rc = cifs_lock_add(cinode, length, flock->fl_start,
type, netfid);
}
- } else if (unlock) {
- /*
- * For each stored lock that this unlock overlaps completely,
- * unlock it.
- */
- int stored_rc = 0;
- struct cifsLockInfo *li, *tmp;
+ } else if (unlock)
+ rc = cifs_unlock_range(cfile, flock, xid);
- mutex_lock(&cinode->lock_mutex);
- list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
- if (flock->fl_start > li->offset ||
- (flock->fl_start + length) <
- (li->offset + li->length))
- continue;
- if (current->tgid != li->pid)
- continue;
- if (cfile->netfid != li->netfid)
- continue;
-
- if (!cinode->can_cache_brlcks)
- stored_rc = CIFSSMBLock(xid, tcon, netfid,
- current->tgid,
- li->length, li->offset,
- 1, 0, li->type, 0, 0);
- else {
- stored_rc = 0;
- cifs_del_lock_waiters(li);
- }
- if (stored_rc)
- rc = stored_rc;
- else {
- list_del(&li->llist);
- kfree(li);
- }
- }
- mutex_unlock(&cinode->lock_mutex);
- }
out:
if (flock->fl_flags & FL_POSIX)
posix_lock_file_wait(file, flock);
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 6/6] CIFS: Make cifs_push_locks send as many locks at once as possible
[not found] ` <1317993024-15003-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (4 preceding siblings ...)
2011-10-07 13:10 ` [PATCH 5/6] CIFS: Send as many mandatory unlock ranges at once as possible Pavel Shilovsky
@ 2011-10-07 13:10 ` Pavel Shilovsky
5 siblings, 0 replies; 7+ messages in thread
From: Pavel Shilovsky @ 2011-10-07 13:10 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
that reduces a traffic and increases a performance.
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/file.c | 49 +++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 43 insertions(+), 6 deletions(-)
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 59410a8..777b837 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -819,6 +819,11 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
struct cifsLockInfo *li, *tmp;
struct cifs_tcon *tcon;
struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+ unsigned int num, max_num;
+ LOCKING_ANDX_RANGE *buf, *cur;
+ int types[] = {LOCKING_ANDX_LARGE_FILES,
+ LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES};
+ int i;
xid = GetXid();
tcon = tlink_tcon(cfile->tlink);
@@ -830,17 +835,49 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
return rc;
}
- list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
- stored_rc = CIFSSMBLock(xid, tcon, cfile->netfid,
- li->pid, li->length, li->offset,
- 0, 1, li->type, 0, 0);
- if (stored_rc)
- rc = stored_rc;
+ max_num = (tcon->ses->server->maxBuf - sizeof(struct smb_hdr)) /
+ sizeof(LOCKING_ANDX_RANGE);
+ buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
+ if (!buf) {
+ mutex_unlock(&cinode->lock_mutex);
+ FreeXid(xid);
+ return rc;
+ }
+
+ for (i = 0; i < 2; i++) {
+ cur = buf;
+ num = 0;
+ list_for_each_entry_safe(li, tmp, &cinode->llist, llist) {
+ if (li->type != types[i])
+ continue;
+ cur->Pid = cpu_to_le16(li->pid);
+ cur->LengthLow = cpu_to_le32((u32)li->length);
+ cur->LengthHigh = cpu_to_le32((u32)(li->length>>32));
+ cur->OffsetLow = cpu_to_le32((u32)li->offset);
+ cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32));
+ if (++num == max_num) {
+ stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+ li->type, 0, num, buf);
+ if (stored_rc)
+ rc = stored_rc;
+ cur = buf;
+ num = 0;
+ } else
+ cur++;
+ }
+
+ if (num) {
+ stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+ types[i], 0, num, buf);
+ if (stored_rc)
+ rc = stored_rc;
+ }
}
cinode->can_cache_brlcks = false;
mutex_unlock(&cinode->lock_mutex);
+ kfree(buf);
FreeXid(xid);
return rc;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2011-10-07 13:10 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-10-07 13:10 [PATCH 0/6] Implement byte-range lock caching Pavel Shilovsky
[not found] ` <1317993024-15003-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2011-10-07 13:10 ` [PATCH 1/6] CIFS: Simplify byte range locking code Pavel Shilovsky
2011-10-07 13:10 ` [PATCH 2/6] CIFS: Move byte range lock list from fd to inode Pavel Shilovsky
2011-10-07 13:10 ` [PATCH 3/6] CIFS: Implement caching mechanism for mandatory brlocks Pavel Shilovsky
2011-10-07 13:10 ` [PATCH 4/6] CIFS: Implement caching mechanism for posix brlocks Pavel Shilovsky
2011-10-07 13:10 ` [PATCH 5/6] CIFS: Send as many mandatory unlock ranges at once as possible Pavel Shilovsky
2011-10-07 13:10 ` [PATCH 6/6] CIFS: Make cifs_push_locks send as many locks " Pavel Shilovsky
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.