aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fcntl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r--fs/fcntl.c33
1 files changed, 20 insertions, 13 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c
index bd215cc791da..d865ca66ccba 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -141,7 +141,7 @@ SYSCALL_DEFINE1(dup, unsigned int, fildes)
141 return ret; 141 return ret;
142} 142}
143 143
144#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC | O_DIRECT | O_NOATIME) 144#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
145 145
146static int setfl(int fd, struct file * filp, unsigned long arg) 146static int setfl(int fd, struct file * filp, unsigned long arg)
147{ 147{
@@ -177,21 +177,21 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
177 return error; 177 return error;
178 178
179 /* 179 /*
180 * We still need a lock here for now to keep multiple FASYNC calls 180 * ->fasync() is responsible for setting the FASYNC bit.
181 * from racing with each other.
182 */ 181 */
183 lock_kernel(); 182 if (((arg ^ filp->f_flags) & FASYNC) && filp->f_op &&
184 if ((arg ^ filp->f_flags) & FASYNC) { 183 filp->f_op->fasync) {
185 if (filp->f_op && filp->f_op->fasync) { 184 error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
186 error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); 185 if (error < 0)
187 if (error < 0) 186 goto out;
188 goto out; 187 if (error > 0)
189 } 188 error = 0;
190 } 189 }
191 190 spin_lock(&filp->f_lock);
192 filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK); 191 filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
192 spin_unlock(&filp->f_lock);
193
193 out: 194 out:
194 unlock_kernel();
195 return error; 195 return error;
196} 196}
197 197
@@ -516,7 +516,7 @@ static DEFINE_RWLOCK(fasync_lock);
516static struct kmem_cache *fasync_cache __read_mostly; 516static struct kmem_cache *fasync_cache __read_mostly;
517 517
518/* 518/*
519 * fasync_helper() is used by some character device drivers (mainly mice) 519 * fasync_helper() is used by almost all character device drivers
520 * to set up the fasync queue. It returns negative on error, 0 if it did 520 * to set up the fasync queue. It returns negative on error, 0 if it did
521 * no changes and positive if it added/deleted the entry. 521 * no changes and positive if it added/deleted the entry.
522 */ 522 */
@@ -555,6 +555,13 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap
555 result = 1; 555 result = 1;
556 } 556 }
557out: 557out:
558 /* Fix up FASYNC bit while still holding fasync_lock */
559 spin_lock(&filp->f_lock);
560 if (on)
561 filp->f_flags |= FASYNC;
562 else
563 filp->f_flags &= ~FASYNC;
564 spin_unlock(&filp->f_lock);
558 write_unlock_irq(&fasync_lock); 565 write_unlock_irq(&fasync_lock);
559 return result; 566 return result;
560} 567}