Skip to content

Commit 127aa93

Browse files
committed
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS fixes from Steve French: "Misc small cifs fixes" * 'for-next' of git://git.samba.org/sfrench/cifs-2.6: CIFS: Don't let read only caching for mandatory byte-range locked files CIFS: Fix write after setting a read lock for read oplock files Revert "CIFS: Fix write after setting a read lock for read oplock files" cifs: adjust sequence number downward after signing NT_CANCEL request cifs: move check for NULL socket into smb_send_rqst
2 parents d287b87 + 63b7d3a commit 127aa93

File tree

6 files changed

+90
-70
lines changed

6 files changed

+90
-70
lines changed

fs/cifs/cifsfs.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,6 @@ cifs_alloc_inode(struct super_block *sb)
228228
cifs_set_oplock_level(cifs_inode, 0);
229229
cifs_inode->delete_pending = false;
230230
cifs_inode->invalid_mapping = false;
231-
cifs_inode->leave_pages_clean = false;
232231
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
233232
cifs_inode->server_eof = 0;
234233
cifs_inode->uniqueid = 0;

fs/cifs/cifsglob.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ struct smb_version_values {
386386
unsigned int cap_unix;
387387
unsigned int cap_nt_find;
388388
unsigned int cap_large_files;
389+
unsigned int oplock_read;
389390
};
390391

391392
#define HEADER_SIZE(server) (server->vals->header_size)
@@ -1030,7 +1031,6 @@ struct cifsInodeInfo {
10301031
bool clientCanCacheAll; /* read and writebehind oplock */
10311032
bool delete_pending; /* DELETE_ON_CLOSE is set */
10321033
bool invalid_mapping; /* pagecache is invalid */
1033-
bool leave_pages_clean; /* protected by i_mutex, not set pages dirty */
10341034
unsigned long time; /* jiffies of last update of inode */
10351035
u64 server_eof; /* current file size on server -- protected by i_lock */
10361036
u64 uniqueid; /* server inode number */

fs/cifs/file.c

Lines changed: 76 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,23 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
238238
return rc;
239239
}
240240

241+
static bool
242+
cifs_has_mand_locks(struct cifsInodeInfo *cinode)
243+
{
244+
struct cifs_fid_locks *cur;
245+
bool has_locks = false;
246+
247+
down_read(&cinode->lock_sem);
248+
list_for_each_entry(cur, &cinode->llist, llist) {
249+
if (!list_empty(&cur->locks)) {
250+
has_locks = true;
251+
break;
252+
}
253+
}
254+
up_read(&cinode->lock_sem);
255+
return has_locks;
256+
}
257+
241258
struct cifsFileInfo *
242259
cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
243260
struct tcon_link *tlink, __u32 oplock)
@@ -248,6 +265,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
248265
struct cifsFileInfo *cfile;
249266
struct cifs_fid_locks *fdlocks;
250267
struct cifs_tcon *tcon = tlink_tcon(tlink);
268+
struct TCP_Server_Info *server = tcon->ses->server;
251269

252270
cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
253271
if (cfile == NULL)
@@ -276,12 +294,22 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
276294
INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
277295
mutex_init(&cfile->fh_mutex);
278296

297+
/*
298+
* If the server returned a read oplock and we have mandatory brlocks,
299+
* set oplock level to None.
300+
*/
301+
if (oplock == server->vals->oplock_read &&
302+
cifs_has_mand_locks(cinode)) {
303+
cFYI(1, "Reset oplock val from read to None due to mand locks");
304+
oplock = 0;
305+
}
306+
279307
spin_lock(&cifs_file_list_lock);
280-
if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE)
308+
if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock)
281309
oplock = fid->pending_open->oplock;
282310
list_del(&fid->pending_open->olist);
283311

284-
tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock);
312+
server->ops->set_fid(cfile, fid, oplock);
285313

286314
list_add(&cfile->tlist, &tcon->openFileList);
287315
/* if readable file instance put first in list*/
@@ -1422,6 +1450,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
14221450
struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
14231451
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
14241452
struct TCP_Server_Info *server = tcon->ses->server;
1453+
struct inode *inode = cfile->dentry->d_inode;
14251454

14261455
if (posix_lck) {
14271456
int posix_lock_type;
@@ -1459,6 +1488,21 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
14591488
if (!rc)
14601489
goto out;
14611490

1491+
/*
1492+
* Windows 7 server can delay breaking lease from read to None
1493+
* if we set a byte-range lock on a file - break it explicitly
1494+
* before sending the lock to the server to be sure the next
1495+
* read won't conflict with non-overlapted locks due to
1496+
* pagereading.
1497+
*/
1498+
if (!CIFS_I(inode)->clientCanCacheAll &&
1499+
CIFS_I(inode)->clientCanCacheRead) {
1500+
cifs_invalidate_mapping(inode);
1501+
cFYI(1, "Set no oplock for inode=%p due to mand locks",
1502+
inode);
1503+
CIFS_I(inode)->clientCanCacheRead = false;
1504+
}
1505+
14621506
rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
14631507
type, 1, 0, wait_flag);
14641508
if (rc) {
@@ -2103,15 +2147,7 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
21032147
} else {
21042148
rc = copied;
21052149
pos += copied;
2106-
/*
2107-
* When we use strict cache mode and cifs_strict_writev was run
2108-
* with level II oplock (indicated by leave_pages_clean field of
2109-
* CIFS_I(inode)), we can leave pages clean - cifs_strict_writev
2110-
* sent the data to the server itself.
2111-
*/
2112-
if (!CIFS_I(inode)->leave_pages_clean ||
2113-
!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO))
2114-
set_page_dirty(page);
2150+
set_page_dirty(page);
21152151
}
21162152

21172153
if (rc > 0) {
@@ -2462,8 +2498,8 @@ ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
24622498
}
24632499

24642500
static ssize_t
2465-
cifs_pagecache_writev(struct kiocb *iocb, const struct iovec *iov,
2466-
unsigned long nr_segs, loff_t pos, bool cache_ex)
2501+
cifs_writev(struct kiocb *iocb, const struct iovec *iov,
2502+
unsigned long nr_segs, loff_t pos)
24672503
{
24682504
struct file *file = iocb->ki_filp;
24692505
struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
@@ -2485,12 +2521,8 @@ cifs_pagecache_writev(struct kiocb *iocb, const struct iovec *iov,
24852521
server->vals->exclusive_lock_type, NULL,
24862522
CIFS_WRITE_OP)) {
24872523
mutex_lock(&inode->i_mutex);
2488-
if (!cache_ex)
2489-
cinode->leave_pages_clean = true;
24902524
rc = __generic_file_aio_write(iocb, iov, nr_segs,
2491-
&iocb->ki_pos);
2492-
if (!cache_ex)
2493-
cinode->leave_pages_clean = false;
2525+
&iocb->ki_pos);
24942526
mutex_unlock(&inode->i_mutex);
24952527
}
24962528

@@ -2517,60 +2549,32 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
25172549
struct cifsFileInfo *cfile = (struct cifsFileInfo *)
25182550
iocb->ki_filp->private_data;
25192551
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
2520-
ssize_t written, written2;
2521-
/*
2522-
* We need to store clientCanCacheAll here to prevent race
2523-
* conditions - this value can be changed during an execution
2524-
* of generic_file_aio_write. For CIFS it can be changed from
2525-
* true to false only, but for SMB2 it can be changed both from
2526-
* true to false and vice versa. So, we can end up with a data
2527-
* stored in the cache, not marked dirty and not sent to the
2528-
* server if this value changes its state from false to true
2529-
* after cifs_write_end.
2530-
*/
2531-
bool cache_ex = cinode->clientCanCacheAll;
2532-
bool cache_read = cinode->clientCanCacheRead;
2533-
int rc;
2534-
loff_t saved_pos;
2552+
ssize_t written;
25352553

2536-
if (cache_ex) {
2554+
if (cinode->clientCanCacheAll) {
25372555
if (cap_unix(tcon->ses) &&
2538-
((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) &&
2539-
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(
2540-
tcon->fsUnixInfo.Capability)))
2556+
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))
2557+
&& ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
25412558
return generic_file_aio_write(iocb, iov, nr_segs, pos);
2542-
return cifs_pagecache_writev(iocb, iov, nr_segs, pos, cache_ex);
2559+
return cifs_writev(iocb, iov, nr_segs, pos);
25432560
}
2544-
25452561
/*
2546-
* For files without exclusive oplock in strict cache mode we need to
2547-
* write the data to the server exactly from the pos to pos+len-1 rather
2548-
* than flush all affected pages because it may cause a error with
2549-
* mandatory locks on these pages but not on the region from pos to
2550-
* ppos+len-1.
2562+
* For non-oplocked files in strict cache mode we need to write the data
2563+
* to the server exactly from the pos to pos+len-1 rather than flush all
2564+
* affected pages because it may cause a error with mandatory locks on
2565+
* these pages but not on the region from pos to ppos+len-1.
25512566
*/
25522567
written = cifs_user_writev(iocb, iov, nr_segs, pos);
2553-
if (!cache_read || written <= 0)
2554-
return written;
2555-
2556-
saved_pos = iocb->ki_pos;
2557-
iocb->ki_pos = pos;
2558-
/* we have a read oplock - need to store a data in the page cache */
2559-
if (cap_unix(tcon->ses) &&
2560-
((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) &&
2561-
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(
2562-
tcon->fsUnixInfo.Capability)))
2563-
written2 = generic_file_aio_write(iocb, iov, nr_segs, pos);
2564-
else
2565-
written2 = cifs_pagecache_writev(iocb, iov, nr_segs, pos,
2566-
cache_ex);
2567-
/* errors occured during writing - invalidate the page cache */
2568-
if (written2 < 0) {
2569-
rc = cifs_invalidate_mapping(inode);
2570-
if (rc)
2571-
written = (ssize_t)rc;
2572-
else
2573-
iocb->ki_pos = saved_pos;
2568+
if (written > 0 && cinode->clientCanCacheRead) {
2569+
/*
2570+
* Windows 7 server can delay breaking level2 oplock if a write
2571+
* request comes - break it on the client to prevent reading
2572+
* an old data.
2573+
*/
2574+
cifs_invalidate_mapping(inode);
2575+
cFYI(1, "Set no oplock for inode=%p after a write operation",
2576+
inode);
2577+
cinode->clientCanCacheRead = false;
25742578
}
25752579
return written;
25762580
}
@@ -3577,6 +3581,13 @@ void cifs_oplock_break(struct work_struct *work)
35773581
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
35783582
int rc = 0;
35793583

3584+
if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead &&
3585+
cifs_has_mand_locks(cinode)) {
3586+
cFYI(1, "Reset oplock to None for inode=%p due to mand locks",
3587+
inode);
3588+
cinode->clientCanCacheRead = false;
3589+
}
3590+
35803591
if (inode && S_ISREG(inode->i_mode)) {
35813592
if (cinode->clientCanCacheRead)
35823593
break_lease(inode, O_RDONLY);

fs/cifs/smb1ops.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ send_nt_cancel(struct TCP_Server_Info *server, void *buf,
5353
mutex_unlock(&server->srv_mutex);
5454
return rc;
5555
}
56+
57+
/*
58+
* The response to this call was already factored into the sequence
59+
* number when the call went out, so we must adjust it back downward
60+
* after signing here.
61+
*/
62+
--server->sequence_number;
5663
rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
5764
mutex_unlock(&server->srv_mutex);
5865

@@ -952,4 +959,5 @@ struct smb_version_values smb1_values = {
952959
.cap_unix = CAP_UNIX,
953960
.cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
954961
.cap_large_files = CAP_LARGE_FILES,
962+
.oplock_read = OPLOCK_READ,
955963
};

fs/cifs/smb2ops.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ struct smb_version_values smb20_values = {
708708
.cap_unix = 0,
709709
.cap_nt_find = SMB2_NT_FIND,
710710
.cap_large_files = SMB2_LARGE_FILES,
711+
.oplock_read = SMB2_OPLOCK_LEVEL_II,
711712
};
712713

713714
struct smb_version_values smb21_values = {
@@ -725,6 +726,7 @@ struct smb_version_values smb21_values = {
725726
.cap_unix = 0,
726727
.cap_nt_find = SMB2_NT_FIND,
727728
.cap_large_files = SMB2_LARGE_FILES,
729+
.oplock_read = SMB2_OPLOCK_LEVEL_II,
728730
};
729731

730732
struct smb_version_values smb30_values = {

fs/cifs/transport.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,6 @@ smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec,
144144

145145
*sent = 0;
146146

147-
if (ssocket == NULL)
148-
return -ENOTSOCK; /* BB eventually add reconnect code here */
149-
150147
smb_msg.msg_name = (struct sockaddr *) &server->dstaddr;
151148
smb_msg.msg_namelen = sizeof(struct sockaddr);
152149
smb_msg.msg_control = NULL;
@@ -291,6 +288,9 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
291288
struct socket *ssocket = server->ssocket;
292289
int val = 1;
293290

291+
if (ssocket == NULL)
292+
return -ENOTSOCK;
293+
294294
cFYI(1, "Sending smb: smb_len=%u", smb_buf_length);
295295
dump_smb(iov[0].iov_base, iov[0].iov_len);
296296

0 commit comments

Comments
 (0)