aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fcntl.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-02-02 00:38:15 -0500
committerTejun Heo <tj@kernel.org>2010-02-02 00:38:15 -0500
commitab386128f20c44c458a90039ab1bdc265ac474c9 (patch)
tree2ad188744922b1bb951fd10ff50dc04c83acce22 /fs/fcntl.c
parentdbfc196a3cc1a2514ad0737a82f764de23bd65e6 (diff)
parentab658321f32770b903a4426e2a6fae0392757755 (diff)
Merge branch 'master' into percpu
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r--fs/fcntl.c108
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)
199static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, 199static 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
217int __f_setown(struct file *filp, struct pid *pid, enum pid_type type, 219int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
@@ -618,60 +620,90 @@ static DEFINE_RWLOCK(fasync_lock);
618static struct kmem_cache *fasync_cache __read_mostly; 620static 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 */
625int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) 633static 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 */
661static 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
665out: 688out:
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 */
700int 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
675EXPORT_SYMBOL(fasync_helper); 707EXPORT_SYMBOL(fasync_helper);
676 708
677void __kill_fasync(struct fasync_struct *fa, int sig, int band) 709void __kill_fasync(struct fasync_struct *fa, int sig, int band)