diff options
author | Tejun Heo <tj@kernel.org> | 2010-02-02 00:38:15 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2010-02-02 00:38:15 -0500 |
commit | ab386128f20c44c458a90039ab1bdc265ac474c9 (patch) | |
tree | 2ad188744922b1bb951fd10ff50dc04c83acce22 /fs/fcntl.c | |
parent | dbfc196a3cc1a2514ad0737a82f764de23bd65e6 (diff) | |
parent | ab658321f32770b903a4426e2a6fae0392757755 (diff) |
Merge branch 'master' into percpu
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r-- | fs/fcntl.c | 108 |
1 files changed, 70 insertions, 38 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c index 2cf93ec40a67..5ef953e6f908 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -199,7 +199,9 @@ static int setfl(int fd, struct file * filp, unsigned long arg) | |||
199 | static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, | 199 | static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, |
200 | int force) | 200 | int force) |
201 | { | 201 | { |
202 | write_lock_irq(&filp->f_owner.lock); | 202 | unsigned long flags; |
203 | |||
204 | write_lock_irqsave(&filp->f_owner.lock, flags); | ||
203 | if (force || !filp->f_owner.pid) { | 205 | if (force || !filp->f_owner.pid) { |
204 | put_pid(filp->f_owner.pid); | 206 | put_pid(filp->f_owner.pid); |
205 | filp->f_owner.pid = get_pid(pid); | 207 | filp->f_owner.pid = get_pid(pid); |
@@ -211,7 +213,7 @@ static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, | |||
211 | filp->f_owner.euid = cred->euid; | 213 | filp->f_owner.euid = cred->euid; |
212 | } | 214 | } |
213 | } | 215 | } |
214 | write_unlock_irq(&filp->f_owner.lock); | 216 | write_unlock_irqrestore(&filp->f_owner.lock, flags); |
215 | } | 217 | } |
216 | 218 | ||
217 | int __f_setown(struct file *filp, struct pid *pid, enum pid_type type, | 219 | int __f_setown(struct file *filp, struct pid *pid, enum pid_type type, |
@@ -618,60 +620,90 @@ static DEFINE_RWLOCK(fasync_lock); | |||
618 | static struct kmem_cache *fasync_cache __read_mostly; | 620 | static struct kmem_cache *fasync_cache __read_mostly; |
619 | 621 | ||
620 | /* | 622 | /* |
621 | * fasync_helper() is used by almost all character device drivers | 623 | * Remove a fasync entry. If successfully removed, return |
622 | * to set up the fasync queue. It returns negative on error, 0 if it did | 624 | * positive and clear the FASYNC flag. If no entry exists, |
623 | * no changes and positive if it added/deleted the entry. | 625 | * do nothing and return 0. |
626 | * | ||
627 | * NOTE! It is very important that the FASYNC flag always | ||
628 | * match the state "is the filp on a fasync list". | ||
629 | * | ||
630 | * We always take the 'filp->f_lock', in since fasync_lock | ||
631 | * needs to be irq-safe. | ||
624 | */ | 632 | */ |
625 | int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) | 633 | static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp) |
626 | { | 634 | { |
627 | struct fasync_struct *fa, **fp; | 635 | struct fasync_struct *fa, **fp; |
628 | struct fasync_struct *new = NULL; | ||
629 | int result = 0; | 636 | int result = 0; |
630 | 637 | ||
631 | if (on) { | 638 | spin_lock(&filp->f_lock); |
632 | new = kmem_cache_alloc(fasync_cache, GFP_KERNEL); | 639 | write_lock_irq(&fasync_lock); |
633 | if (!new) | 640 | for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { |
634 | return -ENOMEM; | 641 | if (fa->fa_file != filp) |
642 | continue; | ||
643 | *fp = fa->fa_next; | ||
644 | kmem_cache_free(fasync_cache, fa); | ||
645 | filp->f_flags &= ~FASYNC; | ||
646 | result = 1; | ||
647 | break; | ||
635 | } | 648 | } |
649 | write_unlock_irq(&fasync_lock); | ||
650 | spin_unlock(&filp->f_lock); | ||
651 | return result; | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * Add a fasync entry. Return negative on error, positive if | ||
656 | * added, and zero if did nothing but change an existing one. | ||
657 | * | ||
658 | * NOTE! It is very important that the FASYNC flag always | ||
659 | * match the state "is the filp on a fasync list". | ||
660 | */ | ||
661 | static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp) | ||
662 | { | ||
663 | struct fasync_struct *new, *fa, **fp; | ||
664 | int result = 0; | ||
665 | |||
666 | new = kmem_cache_alloc(fasync_cache, GFP_KERNEL); | ||
667 | if (!new) | ||
668 | return -ENOMEM; | ||
636 | 669 | ||
637 | /* | ||
638 | * We need to take f_lock first since it's not an IRQ-safe | ||
639 | * lock. | ||
640 | */ | ||
641 | spin_lock(&filp->f_lock); | 670 | spin_lock(&filp->f_lock); |
642 | write_lock_irq(&fasync_lock); | 671 | write_lock_irq(&fasync_lock); |
643 | for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { | 672 | for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { |
644 | if (fa->fa_file == filp) { | 673 | if (fa->fa_file != filp) |
645 | if(on) { | 674 | continue; |
646 | fa->fa_fd = fd; | 675 | fa->fa_fd = fd; |
647 | kmem_cache_free(fasync_cache, new); | 676 | kmem_cache_free(fasync_cache, new); |
648 | } else { | 677 | goto out; |
649 | *fp = fa->fa_next; | ||
650 | kmem_cache_free(fasync_cache, fa); | ||
651 | result = 1; | ||
652 | } | ||
653 | goto out; | ||
654 | } | ||
655 | } | 678 | } |
656 | 679 | ||
657 | if (on) { | 680 | new->magic = FASYNC_MAGIC; |
658 | new->magic = FASYNC_MAGIC; | 681 | new->fa_file = filp; |
659 | new->fa_file = filp; | 682 | new->fa_fd = fd; |
660 | new->fa_fd = fd; | 683 | new->fa_next = *fapp; |
661 | new->fa_next = *fapp; | 684 | *fapp = new; |
662 | *fapp = new; | 685 | result = 1; |
663 | result = 1; | 686 | filp->f_flags |= FASYNC; |
664 | } | 687 | |
665 | out: | 688 | out: |
666 | if (on) | ||
667 | filp->f_flags |= FASYNC; | ||
668 | else | ||
669 | filp->f_flags &= ~FASYNC; | ||
670 | write_unlock_irq(&fasync_lock); | 689 | write_unlock_irq(&fasync_lock); |
671 | spin_unlock(&filp->f_lock); | 690 | spin_unlock(&filp->f_lock); |
672 | return result; | 691 | return result; |
673 | } | 692 | } |
674 | 693 | ||
694 | /* | ||
695 | * fasync_helper() is used by almost all character device drivers | ||
696 | * to set up the fasync queue, and for regular files by the file | ||
697 | * lease code. It returns negative on error, 0 if it did no changes | ||
698 | * and positive if it added/deleted the entry. | ||
699 | */ | ||
700 | int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) | ||
701 | { | ||
702 | if (!on) | ||
703 | return fasync_remove_entry(filp, fapp); | ||
704 | return fasync_add_entry(fd, filp, fapp); | ||
705 | } | ||
706 | |||
675 | EXPORT_SYMBOL(fasync_helper); | 707 | EXPORT_SYMBOL(fasync_helper); |
676 | 708 | ||
677 | void __kill_fasync(struct fasync_struct *fa, int sig, int band) | 709 | void __kill_fasync(struct fasync_struct *fa, int sig, int band) |