diff options
author | Jeremy Allison <jra@samba.com> | 2006-08-02 17:56:33 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2006-08-11 17:28:47 -0400 |
commit | 7ee1af765dfa3146aef958258003245e082284e5 (patch) | |
tree | 90ab87a136d63c937064e595fd8062e5bc721e03 /fs/cifs/file.c | |
parent | 6c3d8909d85b2c18fd7a6e64f0ca757a257b40fa (diff) |
[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)
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 95 |
1 files changed, 80 insertions, 15 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 52e2e4c8794b..e9c5ba9084fc 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * | 5 | * |
6 | * Copyright (C) International Business Machines Corp., 2002,2003 | 6 | * Copyright (C) International Business Machines Corp., 2002,2003 |
7 | * Author(s): Steve French (sfrench@us.ibm.com) | 7 | * Author(s): Steve French (sfrench@us.ibm.com) |
8 | * Jeremy Allison (jra@samba.org) | ||
8 | * | 9 | * |
9 | * This library is free software; you can redistribute it and/or modify | 10 | * This library is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU Lesser General Public License as published | 11 | * 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 | private_data->netfid = netfid; | 48 | private_data->netfid = netfid; |
48 | private_data->pid = current->tgid; | 49 | private_data->pid = current->tgid; |
49 | init_MUTEX(&private_data->fh_sem); | 50 | init_MUTEX(&private_data->fh_sem); |
51 | init_MUTEX(&private_data->lock_sem); | ||
52 | INIT_LIST_HEAD(&private_data->llist); | ||
50 | private_data->pfile = file; /* needed for writepage */ | 53 | private_data->pfile = file; /* needed for writepage */ |
51 | private_data->pInode = inode; | 54 | private_data->pInode = inode; |
52 | private_data->invalidHandle = FALSE; | 55 | private_data->invalidHandle = FALSE; |
@@ -473,6 +476,8 @@ int cifs_close(struct inode *inode, struct file *file) | |||
473 | cifs_sb = CIFS_SB(inode->i_sb); | 476 | cifs_sb = CIFS_SB(inode->i_sb); |
474 | pTcon = cifs_sb->tcon; | 477 | pTcon = cifs_sb->tcon; |
475 | if (pSMBFile) { | 478 | if (pSMBFile) { |
479 | struct cifsLockInfo *li, *tmp; | ||
480 | |||
476 | pSMBFile->closePend = TRUE; | 481 | pSMBFile->closePend = TRUE; |
477 | if (pTcon) { | 482 | if (pTcon) { |
478 | /* no sense reconnecting to close a file that is | 483 | /* no sense reconnecting to close a file that is |
@@ -496,6 +501,16 @@ int cifs_close(struct inode *inode, struct file *file) | |||
496 | pSMBFile->netfid); | 501 | pSMBFile->netfid); |
497 | } | 502 | } |
498 | } | 503 | } |
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 | |||
499 | write_lock(&GlobalSMBSeslock); | 514 | write_lock(&GlobalSMBSeslock); |
500 | list_del(&pSMBFile->flist); | 515 | list_del(&pSMBFile->flist); |
501 | list_del(&pSMBFile->tlist); | 516 | list_del(&pSMBFile->tlist); |
@@ -570,6 +585,21 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
570 | return rc; | 585 | return rc; |
571 | } | 586 | } |
572 | 587 | ||
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 | |||
573 | int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | 603 | int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) |
574 | { | 604 | { |
575 | int rc, xid; | 605 | int rc, xid; |
@@ -581,6 +611,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
581 | struct cifsTconInfo *pTcon; | 611 | struct cifsTconInfo *pTcon; |
582 | __u16 netfid; | 612 | __u16 netfid; |
583 | __u8 lockType = LOCKING_ANDX_LARGE_FILES; | 613 | __u8 lockType = LOCKING_ANDX_LARGE_FILES; |
614 | int posix_locking; | ||
584 | 615 | ||
585 | length = 1 + pfLock->fl_end - pfLock->fl_start; | 616 | length = 1 + pfLock->fl_end - pfLock->fl_start; |
586 | rc = -EACCES; | 617 | rc = -EACCES; |
@@ -639,14 +670,14 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
639 | } | 670 | } |
640 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; | 671 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; |
641 | 672 | ||
673 | posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) && | ||
674 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability)); | ||
642 | 675 | ||
643 | /* BB add code here to normalize offset and length to | 676 | /* BB add code here to normalize offset and length to |
644 | account for negative length which we can not accept over the | 677 | account for negative length which we can not accept over the |
645 | wire */ | 678 | wire */ |
646 | if (IS_GETLK(cmd)) { | 679 | if (IS_GETLK(cmd)) { |
647 | if((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && | 680 | if(posix_locking) { |
648 | (CIFS_UNIX_FCNTL_CAP & | ||
649 | le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) { | ||
650 | int posix_lock_type; | 681 | int posix_lock_type; |
651 | if(lockType & LOCKING_ANDX_SHARED_LOCK) | 682 | if(lockType & LOCKING_ANDX_SHARED_LOCK) |
652 | posix_lock_type = CIFS_RDLCK; | 683 | posix_lock_type = CIFS_RDLCK; |
@@ -682,9 +713,15 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
682 | FreeXid(xid); | 713 | FreeXid(xid); |
683 | return rc; | 714 | return rc; |
684 | } | 715 | } |
685 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && | 716 | |
686 | (CIFS_UNIX_FCNTL_CAP & | 717 | if (!numLock && !numUnlock) { |
687 | le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) { | 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) { | ||
688 | int posix_lock_type; | 725 | int posix_lock_type; |
689 | if(lockType & LOCKING_ANDX_SHARED_LOCK) | 726 | if(lockType & LOCKING_ANDX_SHARED_LOCK) |
690 | posix_lock_type = CIFS_RDLCK; | 727 | posix_lock_type = CIFS_RDLCK; |
@@ -693,18 +730,46 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
693 | 730 | ||
694 | if(numUnlock == 1) | 731 | if(numUnlock == 1) |
695 | posix_lock_type = CIFS_UNLCK; | 732 | posix_lock_type = CIFS_UNLCK; |
696 | else if(numLock == 0) { | 733 | |
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 | } | ||
702 | rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */, | 734 | rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */, |
703 | length, pfLock, | 735 | length, pfLock, |
704 | posix_lock_type, wait_flag); | 736 | posix_lock_type, wait_flag); |
705 | } else | 737 | } else { |
706 | rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, | 738 | struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data; |
707 | numUnlock, numLock, lockType, wait_flag); | 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 | |||
708 | if (pfLock->fl_flags & FL_POSIX) | 773 | if (pfLock->fl_flags & FL_POSIX) |
709 | posix_lock_file_wait(file, pfLock); | 774 | posix_lock_file_wait(file, pfLock); |
710 | FreeXid(xid); | 775 | FreeXid(xid); |