Commit 7ee1af76 authored by Jeremy Allison's avatar Jeremy Allison Committed by Steve French

[CIFS]

Allow Windows blocking locks to be cancelled via a
CANCEL_LOCK call. TODO - restrict this to servers
that support NT_STATUS codes (Win9x will probably
not support this call).
Signed-off-by: default avatarJeremy Allison <jra@samba.org>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
(cherry picked from 570d4d2d895569825d0d017d4e76b51138f68864 commit)
parent 6c3d8909
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* *
* Copyright (C) International Business Machines Corp., 2002,2006 * Copyright (C) International Business Machines Corp., 2002,2006
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* Jeremy Allison (jra@samba.org)
* *
* This library is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU Lesser General Public License as published
...@@ -267,14 +268,14 @@ struct cifsTconInfo { ...@@ -267,14 +268,14 @@ struct cifsTconInfo {
}; };
/* /*
* This info hangs off the cifsFileInfo structure. This is used to track * This info hangs off the cifsFileInfo structure, pointed to by llist.
* byte stream locks on the file * This is used to track byte stream locks on the file
*/ */
struct cifsLockInfo { struct cifsLockInfo {
struct cifsLockInfo *next; struct list_head llist; /* pointer to next cifsLockInfo */
int start; __u64 offset;
int length; __u64 length;
int type; __u8 type;
}; };
/* /*
...@@ -305,6 +306,8 @@ struct cifsFileInfo { ...@@ -305,6 +306,8 @@ struct cifsFileInfo {
/* lock scope id (0 if none) */ /* lock scope id (0 if none) */
struct file * pfile; /* needed for writepage */ struct file * pfile; /* needed for writepage */
struct inode * pInode; /* needed for oplock break */ struct inode * pInode; /* needed for oplock break */
struct semaphore lock_sem;
struct list_head llist; /* list of byte range locks we have. */
unsigned closePend:1; /* file is marked to close */ unsigned closePend:1; /* file is marked to close */
unsigned invalidHandle:1; /* file closed via session abend */ unsigned invalidHandle:1; /* file closed via session abend */
atomic_t wrtPending; /* handle in use - defer close */ atomic_t wrtPending; /* handle in use - defer close */
......
...@@ -50,6 +50,10 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, ...@@ -50,6 +50,10 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
struct kvec *, int /* nvec to send */, struct kvec *, int /* nvec to send */,
int * /* type of buf returned */ , const int long_op); int * /* type of buf returned */ , const int long_op);
extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *,
struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ ,
int * /* bytes returned */);
extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
......
...@@ -1460,8 +1460,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, ...@@ -1460,8 +1460,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
pSMB->hdr.smb_buf_length += count; pSMB->hdr.smb_buf_length += count;
pSMB->ByteCount = cpu_to_le16(count); pSMB->ByteCount = cpu_to_le16(count);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, if (waitFlag) {
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned);
} else {
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, timeout); (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
}
cifs_stats_inc(&tcon->num_locks); cifs_stats_inc(&tcon->num_locks);
if (rc) { if (rc) {
cFYI(1, ("Send error in Lock = %d", rc)); cFYI(1, ("Send error in Lock = %d", rc));
...@@ -1546,8 +1551,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, ...@@ -1546,8 +1551,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
pSMB->Reserved4 = 0; pSMB->Reserved4 = 0;
pSMB->hdr.smb_buf_length += byte_count; pSMB->hdr.smb_buf_length += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count); pSMB->ByteCount = cpu_to_le16(byte_count);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, if (waitFlag) {
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned);
} else {
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, timeout); (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
}
if (rc) { if (rc) {
cFYI(1, ("Send error in Posix Lock = %d", rc)); cFYI(1, ("Send error in Posix Lock = %d", rc));
} else if (get_flag) { } else if (get_flag) {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* *
* Copyright (C) International Business Machines Corp., 2002,2003 * Copyright (C) International Business Machines Corp., 2002,2003
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* Jeremy Allison (jra@samba.org)
* *
* This library is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU Lesser General Public License as published
...@@ -47,6 +48,8 @@ static inline struct cifsFileInfo *cifs_init_private( ...@@ -47,6 +48,8 @@ static inline struct cifsFileInfo *cifs_init_private(
private_data->netfid = netfid; private_data->netfid = netfid;
private_data->pid = current->tgid; private_data->pid = current->tgid;
init_MUTEX(&private_data->fh_sem); init_MUTEX(&private_data->fh_sem);
init_MUTEX(&private_data->lock_sem);
INIT_LIST_HEAD(&private_data->llist);
private_data->pfile = file; /* needed for writepage */ private_data->pfile = file; /* needed for writepage */
private_data->pInode = inode; private_data->pInode = inode;
private_data->invalidHandle = FALSE; private_data->invalidHandle = FALSE;
...@@ -473,6 +476,8 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -473,6 +476,8 @@ int cifs_close(struct inode *inode, struct file *file)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if (pSMBFile) { if (pSMBFile) {
struct cifsLockInfo *li, *tmp;
pSMBFile->closePend = TRUE; pSMBFile->closePend = TRUE;
if (pTcon) { if (pTcon) {
/* no sense reconnecting to close a file that is /* no sense reconnecting to close a file that is
...@@ -496,6 +501,16 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -496,6 +501,16 @@ int cifs_close(struct inode *inode, struct file *file)
pSMBFile->netfid); pSMBFile->netfid);
} }
} }
/* Delete any outstanding lock records.
We'll lose them when the file is closed anyway. */
down(&pSMBFile->lock_sem);
list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
list_del(&li->llist);
kfree(li);
}
up(&pSMBFile->lock_sem);
write_lock(&GlobalSMBSeslock); write_lock(&GlobalSMBSeslock);
list_del(&pSMBFile->flist); list_del(&pSMBFile->flist);
list_del(&pSMBFile->tlist); list_del(&pSMBFile->tlist);
...@@ -570,6 +585,21 @@ int cifs_closedir(struct inode *inode, struct file *file) ...@@ -570,6 +585,21 @@ int cifs_closedir(struct inode *inode, struct file *file)
return rc; 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;
down(&fid->lock_sem);
list_add(&li->llist, &fid->llist);
up(&fid->lock_sem);
return 0;
}
int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
{ {
int rc, xid; int rc, xid;
...@@ -581,6 +611,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -581,6 +611,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
__u16 netfid; __u16 netfid;
__u8 lockType = LOCKING_ANDX_LARGE_FILES; __u8 lockType = LOCKING_ANDX_LARGE_FILES;
int posix_locking;
length = 1 + pfLock->fl_end - pfLock->fl_start; length = 1 + pfLock->fl_end - pfLock->fl_start;
rc = -EACCES; rc = -EACCES;
...@@ -639,14 +670,14 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -639,14 +670,14 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
} }
netfid = ((struct cifsFileInfo *)file->private_data)->netfid; netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability));
/* BB add code here to normalize offset and length to /* BB add code here to normalize offset and length to
account for negative length which we can not accept over the account for negative length which we can not accept over the
wire */ wire */
if (IS_GETLK(cmd)) { if (IS_GETLK(cmd)) {
if((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && if(posix_locking) {
(CIFS_UNIX_FCNTL_CAP &
le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
int posix_lock_type; int posix_lock_type;
if(lockType & LOCKING_ANDX_SHARED_LOCK) if(lockType & LOCKING_ANDX_SHARED_LOCK)
posix_lock_type = CIFS_RDLCK; posix_lock_type = CIFS_RDLCK;
...@@ -682,9 +713,15 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -682,9 +713,15 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
(CIFS_UNIX_FCNTL_CAP & if (!numLock && !numUnlock) {
le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) { /* if no lock or unlock then nothing
to do since we do not know what it is */
FreeXid(xid);
return -EOPNOTSUPP;
}
if (posix_locking) {
int posix_lock_type; int posix_lock_type;
if(lockType & LOCKING_ANDX_SHARED_LOCK) if(lockType & LOCKING_ANDX_SHARED_LOCK)
posix_lock_type = CIFS_RDLCK; posix_lock_type = CIFS_RDLCK;
...@@ -693,18 +730,46 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -693,18 +730,46 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
if(numUnlock == 1) if(numUnlock == 1)
posix_lock_type = CIFS_UNLCK; posix_lock_type = CIFS_UNLCK;
else if(numLock == 0) {
/* if no lock or unlock then nothing
to do since we do not know what it is */
FreeXid(xid);
return -EOPNOTSUPP;
}
rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */, rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
length, pfLock, length, pfLock,
posix_lock_type, wait_flag); posix_lock_type, wait_flag);
} else } else {
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data;
numUnlock, numLock, lockType, wait_flag);
if (numLock) {
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
0, numLock, lockType, wait_flag);
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;
down(&fid->lock_sem);
list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
if (pfLock->fl_start <= li->offset &&
length >= li->length) {
stored_rc = CIFSSMBLock(xid, pTcon, netfid,
li->length, li->offset,
1, 0, li->type, FALSE);
if (stored_rc)
rc = stored_rc;
list_del(&li->llist);
kfree(li);
}
}
up(&fid->lock_sem);
}
}
if (pfLock->fl_flags & FL_POSIX) if (pfLock->fl_flags & FL_POSIX)
posix_lock_file_wait(file, pfLock); posix_lock_file_wait(file, pfLock);
FreeXid(xid); FreeXid(xid);
......
...@@ -72,6 +72,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { ...@@ -72,6 +72,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
{ERRinvlevel,-EOPNOTSUPP}, {ERRinvlevel,-EOPNOTSUPP},
{ERRdirnotempty, -ENOTEMPTY}, {ERRdirnotempty, -ENOTEMPTY},
{ERRnotlocked, -ENOLCK}, {ERRnotlocked, -ENOLCK},
{ERRcancelviolation, -ENOLCK},
{ERRalreadyexists, -EEXIST}, {ERRalreadyexists, -EEXIST},
{ERRmoredata, -EOVERFLOW}, {ERRmoredata, -EOVERFLOW},
{ERReasnotsupported,-EOPNOTSUPP}, {ERReasnotsupported,-EOPNOTSUPP},
......
...@@ -95,6 +95,7 @@ ...@@ -95,6 +95,7 @@
#define ERRinvlevel 124 #define ERRinvlevel 124
#define ERRdirnotempty 145 #define ERRdirnotempty 145
#define ERRnotlocked 158 #define ERRnotlocked 158
#define ERRcancelviolation 173
#define ERRalreadyexists 183 #define ERRalreadyexists 183
#define ERRbadpipe 230 #define ERRbadpipe 230
#define ERRpipebusy 231 #define ERRpipebusy 231
......
This diff is collapsed.
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