diff options
Diffstat (limited to 'fs/cifs/misc.c')
-rw-r--r-- | fs/cifs/misc.c | 74 |
1 files changed, 72 insertions, 2 deletions
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(netfile->dentry->d_inode); |
468 | 468 | ||
469 | cifs_set_oplock_level(pCifsInode, | 469 | set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, |
470 | pSMB->OplockLevel ? OPLOCK_READ : 0); | 470 | &pCifsInode->flags); |
471 | |||
472 | /* | ||
473 | * Set flag if the server downgrades the oplock | ||
474 | * to L2 else clear. | ||
475 | */ | ||
476 | if (pSMB->OplockLevel) | ||
477 | set_bit( | ||
478 | CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, | ||
479 | &pCifsInode->flags); | ||
480 | else | ||
481 | clear_bit( | ||
482 | CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, | ||
483 | &pCifsInode->flags); | ||
484 | |||
471 | queue_work(cifsiod_wq, | 485 | queue_work(cifsiod_wq, |
472 | &netfile->oplock_break); | 486 | &netfile->oplock_break); |
473 | netfile->oplock_break_cancelled = false; | 487 | netfile->oplock_break_cancelled = false; |
@@ -551,6 +565,62 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) | |||
551 | cinode->oplock = 0; | 565 | cinode->oplock = 0; |
552 | } | 566 | } |
553 | 567 | ||
568 | static int | ||
569 | cifs_oplock_break_wait(void *unused) | ||
570 | { | ||
571 | schedule(); | ||
572 | return signal_pending(current) ? -ERESTARTSYS : 0; | ||
573 | } | ||
574 | |||
575 | /* | ||
576 | * We wait for oplock breaks to be processed before we attempt to perform | ||
577 | * writes. | ||
578 | */ | ||
579 | int cifs_get_writer(struct cifsInodeInfo *cinode) | ||
580 | { | ||
581 | int rc; | ||
582 | |||
583 | start: | ||
584 | rc = wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK, | ||
585 | cifs_oplock_break_wait, TASK_KILLABLE); | ||
586 | if (rc) | ||
587 | return rc; | ||
588 | |||
589 | spin_lock(&cinode->writers_lock); | ||
590 | if (!cinode->writers) | ||
591 | set_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags); | ||
592 | cinode->writers++; | ||
593 | /* Check to see if we have started servicing an oplock break */ | ||
594 | if (test_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags)) { | ||
595 | cinode->writers--; | ||
596 | if (cinode->writers == 0) { | ||
597 | clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags); | ||
598 | wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS); | ||
599 | } | ||
600 | spin_unlock(&cinode->writers_lock); | ||
601 | goto start; | ||
602 | } | ||
603 | spin_unlock(&cinode->writers_lock); | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | void cifs_put_writer(struct cifsInodeInfo *cinode) | ||
608 | { | ||
609 | spin_lock(&cinode->writers_lock); | ||
610 | cinode->writers--; | ||
611 | if (cinode->writers == 0) { | ||
612 | clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags); | ||
613 | wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS); | ||
614 | } | ||
615 | spin_unlock(&cinode->writers_lock); | ||
616 | } | ||
617 | |||
618 | void cifs_done_oplock_break(struct cifsInodeInfo *cinode) | ||
619 | { | ||
620 | clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags); | ||
621 | wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK); | ||
622 | } | ||
623 | |||
554 | bool | 624 | bool |
555 | backup_cred(struct cifs_sb_info *cifs_sb) | 625 | backup_cred(struct cifs_sb_info *cifs_sb) |
556 | { | 626 | { |