Skip to content

Commit 7ee1af7

Browse files
Jeremy AllisonSteve French
authored andcommitted
[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: Jeremy Allison <jra@samba.org> Signed-off-by: Steve French <sfrench@us.ibm.com> (cherry picked from 570d4d2d895569825d0d017d4e76b51138f68864 commit)
1 parent 6c3d890 commit 7ee1af7

File tree

7 files changed

+512
-296
lines changed

7 files changed

+512
-296
lines changed

fs/cifs/cifsglob.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* Copyright (C) International Business Machines Corp., 2002,2006
55
* Author(s): Steve French (sfrench@us.ibm.com)
6+
* Jeremy Allison (jra@samba.org)
67
*
78
* This library is free software; you can redistribute it and/or modify
89
* it under the terms of the GNU Lesser General Public License as published
@@ -267,14 +268,14 @@ struct cifsTconInfo {
267268
};
268269

269270
/*
270-
* This info hangs off the cifsFileInfo structure. This is used to track
271-
* byte stream locks on the file
271+
* This info hangs off the cifsFileInfo structure, pointed to by llist.
272+
* This is used to track byte stream locks on the file
272273
*/
273274
struct cifsLockInfo {
274-
struct cifsLockInfo *next;
275-
int start;
276-
int length;
277-
int type;
275+
struct list_head llist; /* pointer to next cifsLockInfo */
276+
__u64 offset;
277+
__u64 length;
278+
__u8 type;
278279
};
279280

280281
/*
@@ -305,6 +306,8 @@ struct cifsFileInfo {
305306
/* lock scope id (0 if none) */
306307
struct file * pfile; /* needed for writepage */
307308
struct inode * pInode; /* needed for oplock break */
309+
struct semaphore lock_sem;
310+
struct list_head llist; /* list of byte range locks we have. */
308311
unsigned closePend:1; /* file is marked to close */
309312
unsigned invalidHandle:1; /* file closed via session abend */
310313
atomic_t wrtPending; /* handle in use - defer close */

fs/cifs/cifsproto.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
5050
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
5151
struct kvec *, int /* nvec to send */,
5252
int * /* type of buf returned */ , const int long_op);
53+
extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *,
54+
struct smb_hdr * /* input */ ,
55+
struct smb_hdr * /* out */ ,
56+
int * /* bytes returned */);
5357
extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
5458
extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
5559
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);

fs/cifs/cifssmb.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,8 +1460,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
14601460
pSMB->hdr.smb_buf_length += count;
14611461
pSMB->ByteCount = cpu_to_le16(count);
14621462

1463-
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1463+
if (waitFlag) {
1464+
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1465+
(struct smb_hdr *) pSMBr, &bytes_returned);
1466+
} else {
1467+
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
14641468
(struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1469+
}
14651470
cifs_stats_inc(&tcon->num_locks);
14661471
if (rc) {
14671472
cFYI(1, ("Send error in Lock = %d", rc));
@@ -1546,8 +1551,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
15461551
pSMB->Reserved4 = 0;
15471552
pSMB->hdr.smb_buf_length += byte_count;
15481553
pSMB->ByteCount = cpu_to_le16(byte_count);
1549-
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1554+
if (waitFlag) {
1555+
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1556+
(struct smb_hdr *) pSMBr, &bytes_returned);
1557+
} else {
1558+
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
15501559
(struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1560+
}
1561+
15511562
if (rc) {
15521563
cFYI(1, ("Send error in Posix Lock = %d", rc));
15531564
} else if (get_flag) {

fs/cifs/file.c

Lines changed: 80 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*
66
* Copyright (C) International Business Machines Corp., 2002,2003
77
* Author(s): Steve French (sfrench@us.ibm.com)
8+
* Jeremy Allison (jra@samba.org)
89
*
910
* This library is free software; you can redistribute it and/or modify
1011
* it under the terms of the GNU Lesser General Public License as published
@@ -47,6 +48,8 @@ static inline struct cifsFileInfo *cifs_init_private(
4748
private_data->netfid = netfid;
4849
private_data->pid = current->tgid;
4950
init_MUTEX(&private_data->fh_sem);
51+
init_MUTEX(&private_data->lock_sem);
52+
INIT_LIST_HEAD(&private_data->llist);
5053
private_data->pfile = file; /* needed for writepage */
5154
private_data->pInode = inode;
5255
private_data->invalidHandle = FALSE;
@@ -473,6 +476,8 @@ int cifs_close(struct inode *inode, struct file *file)
473476
cifs_sb = CIFS_SB(inode->i_sb);
474477
pTcon = cifs_sb->tcon;
475478
if (pSMBFile) {
479+
struct cifsLockInfo *li, *tmp;
480+
476481
pSMBFile->closePend = TRUE;
477482
if (pTcon) {
478483
/* no sense reconnecting to close a file that is
@@ -496,6 +501,16 @@ int cifs_close(struct inode *inode, struct file *file)
496501
pSMBFile->netfid);
497502
}
498503
}
504+
505+
/* Delete any outstanding lock records.
506+
We'll lose them when the file is closed anyway. */
507+
down(&pSMBFile->lock_sem);
508+
list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
509+
list_del(&li->llist);
510+
kfree(li);
511+
}
512+
up(&pSMBFile->lock_sem);
513+
499514
write_lock(&GlobalSMBSeslock);
500515
list_del(&pSMBFile->flist);
501516
list_del(&pSMBFile->tlist);
@@ -570,6 +585,21 @@ int cifs_closedir(struct inode *inode, struct file *file)
570585
return rc;
571586
}
572587

588+
static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
589+
__u64 offset, __u8 lockType)
590+
{
591+
struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
592+
if (li == NULL)
593+
return -ENOMEM;
594+
li->offset = offset;
595+
li->length = len;
596+
li->type = lockType;
597+
down(&fid->lock_sem);
598+
list_add(&li->llist, &fid->llist);
599+
up(&fid->lock_sem);
600+
return 0;
601+
}
602+
573603
int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
574604
{
575605
int rc, xid;
@@ -581,6 +611,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
581611
struct cifsTconInfo *pTcon;
582612
__u16 netfid;
583613
__u8 lockType = LOCKING_ANDX_LARGE_FILES;
614+
int posix_locking;
584615

585616
length = 1 + pfLock->fl_end - pfLock->fl_start;
586617
rc = -EACCES;
@@ -639,14 +670,14 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
639670
}
640671
netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
641672

673+
posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
674+
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability));
642675

643676
/* BB add code here to normalize offset and length to
644677
account for negative length which we can not accept over the
645678
wire */
646679
if (IS_GETLK(cmd)) {
647-
if((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
648-
(CIFS_UNIX_FCNTL_CAP &
649-
le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
680+
if(posix_locking) {
650681
int posix_lock_type;
651682
if(lockType & LOCKING_ANDX_SHARED_LOCK)
652683
posix_lock_type = CIFS_RDLCK;
@@ -682,9 +713,15 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
682713
FreeXid(xid);
683714
return rc;
684715
}
685-
if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
686-
(CIFS_UNIX_FCNTL_CAP &
687-
le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
716+
717+
if (!numLock && !numUnlock) {
718+
/* if no lock or unlock then nothing
719+
to do since we do not know what it is */
720+
FreeXid(xid);
721+
return -EOPNOTSUPP;
722+
}
723+
724+
if (posix_locking) {
688725
int posix_lock_type;
689726
if(lockType & LOCKING_ANDX_SHARED_LOCK)
690727
posix_lock_type = CIFS_RDLCK;
@@ -693,18 +730,46 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
693730

694731
if(numUnlock == 1)
695732
posix_lock_type = CIFS_UNLCK;
696-
else if(numLock == 0) {
697-
/* if no lock or unlock then nothing
698-
to do since we do not know what it is */
699-
FreeXid(xid);
700-
return -EOPNOTSUPP;
701-
}
733+
702734
rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
703735
length, pfLock,
704736
posix_lock_type, wait_flag);
705-
} else
706-
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
707-
numUnlock, numLock, lockType, wait_flag);
737+
} else {
738+
struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data;
739+
740+
if (numLock) {
741+
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
742+
0, numLock, lockType, wait_flag);
743+
744+
if (rc == 0) {
745+
/* For Windows locks we must store them. */
746+
rc = store_file_lock(fid, length,
747+
pfLock->fl_start, lockType);
748+
}
749+
} else if (numUnlock) {
750+
/* For each stored lock that this unlock overlaps
751+
completely, unlock it. */
752+
int stored_rc = 0;
753+
struct cifsLockInfo *li, *tmp;
754+
755+
down(&fid->lock_sem);
756+
list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
757+
if (pfLock->fl_start <= li->offset &&
758+
length >= li->length) {
759+
stored_rc = CIFSSMBLock(xid, pTcon, netfid,
760+
li->length, li->offset,
761+
1, 0, li->type, FALSE);
762+
if (stored_rc)
763+
rc = stored_rc;
764+
765+
list_del(&li->llist);
766+
kfree(li);
767+
}
768+
}
769+
up(&fid->lock_sem);
770+
}
771+
}
772+
708773
if (pfLock->fl_flags & FL_POSIX)
709774
posix_lock_file_wait(file, pfLock);
710775
FreeXid(xid);

fs/cifs/netmisc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
7272
{ERRinvlevel,-EOPNOTSUPP},
7373
{ERRdirnotempty, -ENOTEMPTY},
7474
{ERRnotlocked, -ENOLCK},
75+
{ERRcancelviolation, -ENOLCK},
7576
{ERRalreadyexists, -EEXIST},
7677
{ERRmoredata, -EOVERFLOW},
7778
{ERReasnotsupported,-EOPNOTSUPP},

fs/cifs/smberr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
#define ERRinvlevel 124
9696
#define ERRdirnotempty 145
9797
#define ERRnotlocked 158
98+
#define ERRcancelviolation 173
9899
#define ERRalreadyexists 183
99100
#define ERRbadpipe 230
100101
#define ERRpipebusy 231

0 commit comments

Comments
 (0)