diff options
| -rw-r--r-- | fs/cifs/cifsfs.c | 14 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 8 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 3 | ||||
| -rw-r--r-- | fs/cifs/file.c | 31 | ||||
| -rw-r--r-- | fs/cifs/misc.c | 74 | ||||
| -rw-r--r-- | fs/cifs/smb1ops.c | 11 | ||||
| -rw-r--r-- | fs/cifs/smb2misc.c | 18 | ||||
| -rw-r--r-- | fs/cifs/smb2ops.c | 14 |
8 files changed, 164 insertions, 9 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index df9c9141c099..5be1f997ecde 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -253,6 +253,11 @@ cifs_alloc_inode(struct super_block *sb) | |||
| 253 | cifs_set_oplock_level(cifs_inode, 0); | 253 | cifs_set_oplock_level(cifs_inode, 0); |
| 254 | cifs_inode->delete_pending = false; | 254 | cifs_inode->delete_pending = false; |
| 255 | cifs_inode->invalid_mapping = false; | 255 | cifs_inode->invalid_mapping = false; |
| 256 | clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cifs_inode->flags); | ||
| 257 | clear_bit(CIFS_INODE_PENDING_WRITERS, &cifs_inode->flags); | ||
| 258 | clear_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, &cifs_inode->flags); | ||
| 259 | spin_lock_init(&cifs_inode->writers_lock); | ||
| 260 | cifs_inode->writers = 0; | ||
| 256 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 261 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
| 257 | cifs_inode->server_eof = 0; | 262 | cifs_inode->server_eof = 0; |
| 258 | cifs_inode->uniqueid = 0; | 263 | cifs_inode->uniqueid = 0; |
| @@ -732,19 +737,26 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 732 | unsigned long nr_segs, loff_t pos) | 737 | unsigned long nr_segs, loff_t pos) |
| 733 | { | 738 | { |
| 734 | struct inode *inode = file_inode(iocb->ki_filp); | 739 | struct inode *inode = file_inode(iocb->ki_filp); |
| 740 | struct cifsInodeInfo *cinode = CIFS_I(inode); | ||
| 735 | ssize_t written; | 741 | ssize_t written; |
| 736 | int rc; | 742 | int rc; |
| 737 | 743 | ||
| 744 | written = cifs_get_writer(cinode); | ||
| 745 | if (written) | ||
| 746 | return written; | ||
| 747 | |||
| 738 | written = generic_file_aio_write(iocb, iov, nr_segs, pos); | 748 | written = generic_file_aio_write(iocb, iov, nr_segs, pos); |
| 739 | 749 | ||
| 740 | if (CIFS_CACHE_WRITE(CIFS_I(inode))) | 750 | if (CIFS_CACHE_WRITE(CIFS_I(inode))) |
| 741 | return written; | 751 | goto out; |
| 742 | 752 | ||
| 743 | rc = filemap_fdatawrite(inode->i_mapping); | 753 | rc = filemap_fdatawrite(inode->i_mapping); |
| 744 | if (rc) | 754 | if (rc) |
| 745 | cifs_dbg(FYI, "cifs_file_aio_write: %d rc on %p inode\n", | 755 | cifs_dbg(FYI, "cifs_file_aio_write: %d rc on %p inode\n", |
| 746 | rc, inode); | 756 | rc, inode); |
| 747 | 757 | ||
| 758 | out: | ||
| 759 | cifs_put_writer(cinode); | ||
| 748 | return written; | 760 | return written; |
| 749 | } | 761 | } |
| 750 | 762 | ||
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c0f3718b77a8..30f6e9251a4a 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -228,6 +228,8 @@ struct smb_version_operations { | |||
| 228 | /* verify the message */ | 228 | /* verify the message */ |
| 229 | int (*check_message)(char *, unsigned int); | 229 | int (*check_message)(char *, unsigned int); |
| 230 | bool (*is_oplock_break)(char *, struct TCP_Server_Info *); | 230 | bool (*is_oplock_break)(char *, struct TCP_Server_Info *); |
| 231 | void (*downgrade_oplock)(struct TCP_Server_Info *, | ||
| 232 | struct cifsInodeInfo *, bool); | ||
| 231 | /* process transaction2 response */ | 233 | /* process transaction2 response */ |
| 232 | bool (*check_trans2)(struct mid_q_entry *, struct TCP_Server_Info *, | 234 | bool (*check_trans2)(struct mid_q_entry *, struct TCP_Server_Info *, |
| 233 | char *, int); | 235 | char *, int); |
| @@ -1113,6 +1115,12 @@ struct cifsInodeInfo { | |||
| 1113 | unsigned int epoch; /* used to track lease state changes */ | 1115 | unsigned int epoch; /* used to track lease state changes */ |
| 1114 | bool delete_pending; /* DELETE_ON_CLOSE is set */ | 1116 | bool delete_pending; /* DELETE_ON_CLOSE is set */ |
| 1115 | bool invalid_mapping; /* pagecache is invalid */ | 1117 | bool invalid_mapping; /* pagecache is invalid */ |
| 1118 | unsigned long flags; | ||
| 1119 | #define CIFS_INODE_PENDING_OPLOCK_BREAK (0) /* oplock break in progress */ | ||
| 1120 | #define CIFS_INODE_PENDING_WRITERS (1) /* Writes in progress */ | ||
| 1121 | #define CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2 (2) /* Downgrade oplock to L2 */ | ||
| 1122 | spinlock_t writers_lock; | ||
| 1123 | unsigned int writers; /* Number of writers on this inode */ | ||
| 1116 | unsigned long time; /* jiffies of last update of inode */ | 1124 | unsigned long time; /* jiffies of last update of inode */ |
| 1117 | u64 server_eof; /* current file size on server -- protected by i_lock */ | 1125 | u64 server_eof; /* current file size on server -- protected by i_lock */ |
| 1118 | u64 uniqueid; /* server inode number */ | 1126 | u64 uniqueid; /* server inode number */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index acc4ee8ed075..ca7980a1e303 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -127,6 +127,9 @@ extern u64 cifs_UnixTimeToNT(struct timespec); | |||
| 127 | extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, | 127 | extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, |
| 128 | int offset); | 128 | int offset); |
| 129 | extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock); | 129 | extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock); |
| 130 | extern int cifs_get_writer(struct cifsInodeInfo *cinode); | ||
| 131 | extern void cifs_put_writer(struct cifsInodeInfo *cinode); | ||
| 132 | extern void cifs_done_oplock_break(struct cifsInodeInfo *cinode); | ||
| 130 | extern int cifs_unlock_range(struct cifsFileInfo *cfile, | 133 | extern int cifs_unlock_range(struct cifsFileInfo *cfile, |
| 131 | struct file_lock *flock, const unsigned int xid); | 134 | struct file_lock *flock, const unsigned int xid); |
| 132 | extern int cifs_push_mandatory_locks(struct cifsFileInfo *cfile); | 135 | extern int cifs_push_mandatory_locks(struct cifsFileInfo *cfile); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8add25538a3b..d8ee76241b64 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -2621,12 +2621,20 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, | |||
| 2621 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 2621 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
| 2622 | ssize_t written; | 2622 | ssize_t written; |
| 2623 | 2623 | ||
| 2624 | written = cifs_get_writer(cinode); | ||
| 2625 | if (written) | ||
| 2626 | return written; | ||
| 2627 | |||
| 2624 | if (CIFS_CACHE_WRITE(cinode)) { | 2628 | if (CIFS_CACHE_WRITE(cinode)) { |
| 2625 | if (cap_unix(tcon->ses) && | 2629 | if (cap_unix(tcon->ses) && |
| 2626 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) | 2630 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) |
| 2627 | && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) | 2631 | && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) { |
| 2628 | return generic_file_aio_write(iocb, iov, nr_segs, pos); | 2632 | written = generic_file_aio_write( |
| 2629 | return cifs_writev(iocb, iov, nr_segs, pos); | 2633 | iocb, iov, nr_segs, pos); |
| 2634 | goto out; | ||
| 2635 | } | ||
| 2636 | written = cifs_writev(iocb, iov, nr_segs, pos); | ||
| 2637 | goto out; | ||
| 2630 | } | 2638 | } |
| 2631 | /* | 2639 | /* |
| 2632 | * For non-oplocked files in strict cache mode we need to write the data | 2640 | * For non-oplocked files in strict cache mode we need to write the data |
| @@ -2646,6 +2654,8 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, | |||
| 2646 | inode); | 2654 | inode); |
| 2647 | cinode->oplock = 0; | 2655 | cinode->oplock = 0; |
| 2648 | } | 2656 | } |
| 2657 | out: | ||
| 2658 | cifs_put_writer(cinode); | ||
| 2649 | return written; | 2659 | return written; |
| 2650 | } | 2660 | } |
| 2651 | 2661 | ||
| @@ -3621,6 +3631,13 @@ static int cifs_launder_page(struct page *page) | |||
| 3621 | return rc; | 3631 | return rc; |
| 3622 | } | 3632 | } |
| 3623 | 3633 | ||
| 3634 | static int | ||
| 3635 | cifs_pending_writers_wait(void *unused) | ||
| 3636 | { | ||
| 3637 | schedule(); | ||
| 3638 | return 0; | ||
| 3639 | } | ||
| 3640 | |||
| 3624 | void cifs_oplock_break(struct work_struct *work) | 3641 | void cifs_oplock_break(struct work_struct *work) |
| 3625 | { | 3642 | { |
| 3626 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | 3643 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, |
| @@ -3628,8 +3645,15 @@ void cifs_oplock_break(struct work_struct *work) | |||
| 3628 | struct inode *inode = cfile->dentry->d_inode; | 3645 | struct inode *inode = cfile->dentry->d_inode; |
| 3629 | struct cifsInodeInfo *cinode = CIFS_I(inode); | 3646 | struct cifsInodeInfo *cinode = CIFS_I(inode); |
| 3630 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 3647 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
| 3648 | struct TCP_Server_Info *server = tcon->ses->server; | ||
| 3631 | int rc = 0; | 3649 | int rc = 0; |
| 3632 | 3650 | ||
| 3651 | wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS, | ||
| 3652 | cifs_pending_writers_wait, TASK_UNINTERRUPTIBLE); | ||
| 3653 | |||
| 3654 | server->ops->downgrade_oplock(server, cinode, | ||
| 3655 | test_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, &cinode->flags)); | ||
| 3656 | |||
| 3633 | if (!CIFS_CACHE_WRITE(cinode) && CIFS_CACHE_READ(cinode) && | 3657 | if (!CIFS_CACHE_WRITE(cinode) && CIFS_CACHE_READ(cinode) && |
| 3634 | cifs_has_mand_locks(cinode)) { | 3658 | cifs_has_mand_locks(cinode)) { |
| 3635 | cifs_dbg(FYI, "Reset oplock to None for inode=%p due to mand locks\n", | 3659 | cifs_dbg(FYI, "Reset oplock to None for inode=%p due to mand locks\n", |
| @@ -3666,6 +3690,7 @@ void cifs_oplock_break(struct work_struct *work) | |||
| 3666 | cinode); | 3690 | cinode); |
| 3667 | cifs_dbg(FYI, "Oplock release rc = %d\n", rc); | 3691 | cifs_dbg(FYI, "Oplock release rc = %d\n", rc); |
| 3668 | } | 3692 | } |
| 3693 | cifs_done_oplock_break(cinode); | ||
| 3669 | } | 3694 | } |
| 3670 | 3695 | ||
| 3671 | /* | 3696 | /* |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 2f9f3790679d..3b0c62e622da 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
| @@ -466,8 +466,22 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) | |||
| 466 | cifs_dbg(FYI, "file id match, oplock break\n"); | 466 | cifs_dbg(FYI, "file id match, oplock break\n"); |
| 467 | pCifsInode = CIFS_I(netfile->dentry->d_inode); | 467 | pCifsInode = CIFS_I(netfi |
