diff options
author | Pavel Shilovsky <piastry@etersoft.ru> | 2012-11-27 09:38:53 -0500 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2012-12-07 13:40:50 -0500 |
commit | 081c0414dcdfd13c4276db30a775a5d0f72ad91a (patch) | |
tree | 159016804499d95239267b764a6b3f394eada4af /fs/cifs | |
parent | eb1b3fa5cdb9c27bdec8f262acf757a06588eb2d (diff) |
CIFS: Do not permit write to a range mandatory locked with a read lock
We don't need to permit a write to the area locked with a read lock
by any process including the process that issues the write.
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/cifsproto.h | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 27 |
2 files changed, 19 insertions, 10 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 15a8cb66a07b..a152f3645b09 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -186,7 +186,7 @@ extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); | |||
186 | extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, | 186 | extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, |
187 | __u64 length, __u8 type, | 187 | __u64 length, __u8 type, |
188 | struct cifsLockInfo **conf_lock, | 188 | struct cifsLockInfo **conf_lock, |
189 | bool rw_check); | 189 | int rw_check); |
190 | extern void cifs_add_pending_open(struct cifs_fid *fid, | 190 | extern void cifs_add_pending_open(struct cifs_fid *fid, |
191 | struct tcon_link *tlink, | 191 | struct tcon_link *tlink, |
192 | struct cifs_pending_open *open); | 192 | struct cifs_pending_open *open); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index bceffa8c034e..ebebbb2bc1fb 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -759,10 +759,15 @@ cifs_del_lock_waiters(struct cifsLockInfo *lock) | |||
759 | } | 759 | } |
760 | } | 760 | } |
761 | 761 | ||
762 | #define CIFS_LOCK_OP 0 | ||
763 | #define CIFS_READ_OP 1 | ||
764 | #define CIFS_WRITE_OP 2 | ||
765 | |||
766 | /* @rw_check : 0 - no op, 1 - read, 2 - write */ | ||
762 | static bool | 767 | static bool |
763 | cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, | 768 | cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, |
764 | __u64 length, __u8 type, struct cifsFileInfo *cfile, | 769 | __u64 length, __u8 type, struct cifsFileInfo *cfile, |
765 | struct cifsLockInfo **conf_lock, bool rw_check) | 770 | struct cifsLockInfo **conf_lock, int rw_check) |
766 | { | 771 | { |
767 | struct cifsLockInfo *li; | 772 | struct cifsLockInfo *li; |
768 | struct cifsFileInfo *cur_cfile = fdlocks->cfile; | 773 | struct cifsFileInfo *cur_cfile = fdlocks->cfile; |
@@ -772,9 +777,13 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, | |||
772 | if (offset + length <= li->offset || | 777 | if (offset + length <= li->offset || |
773 | offset >= li->offset + li->length) | 778 | offset >= li->offset + li->length) |
774 | continue; | 779 | continue; |
775 | if (rw_check && server->ops->compare_fids(cfile, cur_cfile) && | 780 | if (rw_check != CIFS_LOCK_OP && current->tgid == li->pid && |
776 | current->tgid == li->pid) | 781 | server->ops->compare_fids(cfile, cur_cfile)) { |
777 | continue; | 782 | /* shared lock prevents write op through the same fid */ |
783 | if (!(li->type & server->vals->shared_lock_type) || | ||
784 | rw_check != CIFS_WRITE_OP) | ||
785 | continue; | ||
786 | } | ||
778 | if ((type & server->vals->shared_lock_type) && | 787 | if ((type & server->vals->shared_lock_type) && |
779 | ((server->ops->compare_fids(cfile, cur_cfile) && | 788 | ((server->ops->compare_fids(cfile, cur_cfile) && |
780 | current->tgid == li->pid) || type == li->type)) | 789 | current->tgid == li->pid) || type == li->type)) |
@@ -789,7 +798,7 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, | |||
789 | bool | 798 | bool |
790 | cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, | 799 | cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, |
791 | __u8 type, struct cifsLockInfo **conf_lock, | 800 | __u8 type, struct cifsLockInfo **conf_lock, |
792 | bool rw_check) | 801 | int rw_check) |
793 | { | 802 | { |
794 | bool rc = false; | 803 | bool rc = false; |
795 | struct cifs_fid_locks *cur; | 804 | struct cifs_fid_locks *cur; |
@@ -825,7 +834,7 @@ cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length, | |||
825 | down_read(&cinode->lock_sem); | 834 | down_read(&cinode->lock_sem); |
826 | 835 | ||
827 | exist = cifs_find_lock_conflict(cfile, offset, length, type, | 836 | exist = cifs_find_lock_conflict(cfile, offset, length, type, |
828 | &conf_lock, false); | 837 | &conf_lock, CIFS_LOCK_OP); |
829 | if (exist) { | 838 | if (exist) { |
830 | flock->fl_start = conf_lock->offset; | 839 | flock->fl_start = conf_lock->offset; |
831 | flock->fl_end = conf_lock->offset + conf_lock->length - 1; | 840 | flock->fl_end = conf_lock->offset + conf_lock->length - 1; |
@@ -872,7 +881,7 @@ try_again: | |||
872 | down_write(&cinode->lock_sem); | 881 | down_write(&cinode->lock_sem); |
873 | 882 | ||
874 | exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length, | 883 | exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length, |
875 | lock->type, &conf_lock, false); | 884 | lock->type, &conf_lock, CIFS_LOCK_OP); |
876 | if (!exist && cinode->can_cache_brlcks) { | 885 | if (!exist && cinode->can_cache_brlcks) { |
877 | list_add_tail(&lock->llist, &cfile->llist->locks); | 886 | list_add_tail(&lock->llist, &cfile->llist->locks); |
878 | up_write(&cinode->lock_sem); | 887 | up_write(&cinode->lock_sem); |
@@ -2466,7 +2475,7 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov, | |||
2466 | down_read(&cinode->lock_sem); | 2475 | down_read(&cinode->lock_sem); |
2467 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), | 2476 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), |
2468 | server->vals->exclusive_lock_type, NULL, | 2477 | server->vals->exclusive_lock_type, NULL, |
2469 | true)) { | 2478 | CIFS_WRITE_OP)) { |
2470 | mutex_lock(&inode->i_mutex); | 2479 | mutex_lock(&inode->i_mutex); |
2471 | rc = __generic_file_aio_write(iocb, iov, nr_segs, | 2480 | rc = __generic_file_aio_write(iocb, iov, nr_segs, |
2472 | &iocb->ki_pos); | 2481 | &iocb->ki_pos); |
@@ -2901,7 +2910,7 @@ cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, | |||
2901 | down_read(&cinode->lock_sem); | 2910 | down_read(&cinode->lock_sem); |
2902 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), | 2911 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), |
2903 | tcon->ses->server->vals->shared_lock_type, | 2912 | tcon->ses->server->vals->shared_lock_type, |
2904 | NULL, true)) | 2913 | NULL, CIFS_READ_OP)) |
2905 | rc = generic_file_aio_read(iocb, iov, nr_segs, pos); | 2914 | rc = generic_file_aio_read(iocb, iov, nr_segs, pos); |
2906 | up_read(&cinode->lock_sem); | 2915 | up_read(&cinode->lock_sem); |
2907 | return rc; | 2916 | return rc; |