diff options
| -rw-r--r-- | fs/cifs/cifsglob.h | 2 | ||||
| -rw-r--r-- | fs/cifs/file.c | 24 | ||||
| -rw-r--r-- | fs/cifs/transport.c | 29 |
3 files changed, 36 insertions, 19 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index cf32f0393369..c0f3718b77a8 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -513,7 +513,7 @@ struct cifs_mnt_data { | |||
| 513 | static inline unsigned int | 513 | static inline unsigned int |
| 514 | get_rfc1002_length(void *buf) | 514 | get_rfc1002_length(void *buf) |
| 515 | { | 515 | { |
| 516 | return be32_to_cpu(*((__be32 *)buf)); | 516 | return be32_to_cpu(*((__be32 *)buf)) & 0xffffff; |
| 517 | } | 517 | } |
| 518 | 518 | ||
| 519 | static inline void | 519 | static inline void |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 53c15074bb36..834fce759d80 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -2579,31 +2579,19 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov, | |||
| 2579 | struct cifsInodeInfo *cinode = CIFS_I(inode); | 2579 | struct cifsInodeInfo *cinode = CIFS_I(inode); |
| 2580 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; | 2580 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; |
| 2581 | ssize_t rc = -EACCES; | 2581 | ssize_t rc = -EACCES; |
| 2582 | loff_t lock_pos = pos; | ||
| 2582 | 2583 | ||
| 2583 | BUG_ON(iocb->ki_pos != pos); | 2584 | if (file->f_flags & O_APPEND) |
| 2584 | 2585 | lock_pos = i_size_read(inode); | |
| 2585 | /* | 2586 | /* |
| 2586 | * We need to hold the sem to be sure nobody modifies lock list | 2587 | * We need to hold the sem to be sure nobody modifies lock list |
| 2587 | * with a brlock that prevents writing. | 2588 | * with a brlock that prevents writing. |
| 2588 | */ | 2589 | */ |
| 2589 | down_read(&cinode->lock_sem); | 2590 | down_read(&cinode->lock_sem); |
| 2590 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), | 2591 | if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs), |
| 2591 | server->vals->exclusive_lock_type, NULL, | 2592 | server->vals->exclusive_lock_type, NULL, |
| 2592 | CIFS_WRITE_OP)) { | 2593 | CIFS_WRITE_OP)) |
| 2593 | mutex_lock(&inode->i_mutex); | 2594 | rc = generic_file_aio_write(iocb, iov, nr_segs, pos); |
| 2594 | rc = __generic_file_aio_write(iocb, iov, nr_segs, | ||
| 2595 | &iocb->ki_pos); | ||
| 2596 | mutex_unlock(&inode->i_mutex); | ||
| 2597 | } | ||
| 2598 | |||
| 2599 | if (rc > 0) { | ||
| 2600 | ssize_t err; | ||
| 2601 | |||
| 2602 | err = generic_write_sync(file, iocb->ki_pos - rc, rc); | ||
| 2603 | if (err < 0) | ||
| 2604 | rc = err; | ||
| 2605 | } | ||
| 2606 | |||
| 2607 | up_read(&cinode->lock_sem); | 2595 | up_read(&cinode->lock_sem); |
| 2608 | return rc; | 2596 | return rc; |
| 2609 | } | 2597 | } |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index b37570952846..18cd5650a5fc 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
| @@ -270,6 +270,26 @@ cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx, | |||
| 270 | iov->iov_len = rqst->rq_pagesz; | 270 | iov->iov_len = rqst->rq_pagesz; |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | static unsigned long | ||
| 274 | rqst_len(struct smb_rqst *rqst) | ||
| 275 | { | ||
| 276 | unsigned int i; | ||
| 277 | struct kvec *iov = rqst->rq_iov; | ||
| 278 | unsigned long buflen = 0; | ||
| 279 | |||
| 280 | /* total up iov array first */ | ||
| 281 | for (i = 0; i < rqst->rq_nvec; i++) | ||
| 282 | buflen += iov[i].iov_len; | ||
| 283 | |||
| 284 | /* add in the page array if there is one */ | ||
| 285 | if (rqst->rq_npages) { | ||
| 286 | buflen += rqst->rq_pagesz * (rqst->rq_npages - 1); | ||
| 287 | buflen += rqst->rq_tailsz; | ||
| 288 | } | ||
| 289 | |||
| 290 | return buflen; | ||
| 291 | } | ||
| 292 | |||
| 273 | static int | 293 | static int |
| 274 | smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | 294 | smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) |
| 275 | { | 295 | { |
| @@ -277,6 +297,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
| 277 | struct kvec *iov = rqst->rq_iov; | 297 | struct kvec *iov = rqst->rq_iov; |
| 278 | int n_vec = rqst->rq_nvec; | 298 | int n_vec = rqst->rq_nvec; |
| 279 | unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base); | 299 | unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base); |
| 300 | unsigned long send_length; | ||
| 280 | unsigned int i; | 301 | unsigned int i; |
| 281 | size_t total_len = 0, sent; | 302 | size_t total_len = 0, sent; |
| 282 | struct socket *ssocket = server->ssocket; | 303 | struct socket *ssocket = server->ssocket; |
| @@ -285,6 +306,14 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
| 285 | if (ssocket == NULL) | 306 | if (ssocket == NULL) |
| 286 | return -ENOTSOCK; | 307 | return -ENOTSOCK; |
| 287 | 308 | ||
| 309 | /* sanity check send length */ | ||
| 310 | send_length = rqst_len(rqst); | ||
| 311 | if (send_length != smb_buf_length + 4) { | ||
| 312 | WARN(1, "Send length mismatch(send_length=%lu smb_buf_length=%u)\n", | ||
| 313 | send_length, smb_buf_length); | ||
| 314 | return -EIO; | ||
| 315 | } | ||
| 316 | |||
| 288 | cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length); | 317 | cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length); |
| 289 | dump_smb(iov[0].iov_base, iov[0].iov_len); | 318 | dump_smb(iov[0].iov_base, iov[0].iov_len); |
| 290 | 319 | ||
