aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/file.c
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2012-11-27 09:38:53 -0500
committerSteve French <smfrench@gmail.com>2012-12-07 13:40:50 -0500
commit081c0414dcdfd13c4276db30a775a5d0f72ad91a (patch)
tree159016804499d95239267b764a6b3f394eada4af /fs/cifs/file.c
parenteb1b3fa5cdb9c27bdec8f262acf757a06588eb2d (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/file.c')
-rw-r--r--fs/cifs/file.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index bceffa8c034..ebebbb2bc1f 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 */
762static bool 767static bool
763cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, 768cifs_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,
789bool 798bool
790cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, 799cifs_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;