···618618static struct kmem_cache *fasync_cache __read_mostly;619619620620/*621621- * fasync_helper() is used by almost all character device drivers622622- * to set up the fasync queue. It returns negative on error, 0 if it did623623- * no changes and positive if it added/deleted the entry.621621+ * Remove a fasync entry. If successfully removed, return622622+ * positive and clear the FASYNC flag. If no entry exists,623623+ * do nothing and return 0.624624+ *625625+ * NOTE! It is very important that the FASYNC flag always626626+ * match the state "is the filp on a fasync list".627627+ *628628+ * We always take the 'filp->f_lock', in since fasync_lock629629+ * needs to be irq-safe.624630 */625625-int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)631631+static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)626632{627633 struct fasync_struct *fa, **fp;628628- struct fasync_struct *new = NULL;629634 int result = 0;630635631631- if (on) {632632- new = kmem_cache_alloc(fasync_cache, GFP_KERNEL);633633- if (!new)634634- return -ENOMEM;635635- }636636-637637- /*638638- * We need to take f_lock first since it's not an IRQ-safe639639- * lock.640640- */641636 spin_lock(&filp->f_lock);642637 write_lock_irq(&fasync_lock);643638 for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {644644- if (fa->fa_file == filp) {645645- if(on) {646646- fa->fa_fd = fd;647647- kmem_cache_free(fasync_cache, new);648648- } else {649649- *fp = fa->fa_next;650650- kmem_cache_free(fasync_cache, fa);651651- result = 1;652652- }653653- goto out;654654- }655655- }656656-657657- if (on) {658658- new->magic = FASYNC_MAGIC;659659- new->fa_file = filp;660660- new->fa_fd = fd;661661- new->fa_next = *fapp;662662- *fapp = new;663663- result = 1;664664- }665665-out:666666- if (on)667667- filp->f_flags |= FASYNC;668668- else639639+ if (fa->fa_file != filp)640640+ continue;641641+ *fp = fa->fa_next;642642+ kmem_cache_free(fasync_cache, fa);669643 filp->f_flags &= ~FASYNC;644644+ result = 1;645645+ break;646646+ }670647 write_unlock_irq(&fasync_lock);671648 spin_unlock(&filp->f_lock);672649 return result;650650+}651651+652652+/*653653+ * Add a fasync entry. Return negative on error, positive if654654+ * added, and zero if did nothing but change an existing one.655655+ *656656+ * NOTE! It is very important that the FASYNC flag always657657+ * match the state "is the filp on a fasync list".658658+ */659659+static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp)660660+{661661+ struct fasync_struct *new, *fa, **fp;662662+ int result = 0;663663+664664+ new = kmem_cache_alloc(fasync_cache, GFP_KERNEL);665665+ if (!new)666666+ return -ENOMEM;667667+668668+ spin_lock(&filp->f_lock);669669+ write_lock_irq(&fasync_lock);670670+ for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {671671+ if (fa->fa_file != filp)672672+ continue;673673+ fa->fa_fd = fd;674674+ kmem_cache_free(fasync_cache, new);675675+ goto out;676676+ }677677+678678+ new->magic = FASYNC_MAGIC;679679+ new->fa_file = filp;680680+ new->fa_fd = fd;681681+ new->fa_next = *fapp;682682+ *fapp = new;683683+ result = 1;684684+ filp->f_flags |= FASYNC;685685+686686+out:687687+ write_unlock_irq(&fasync_lock);688688+ spin_unlock(&filp->f_lock);689689+ return result;690690+}691691+692692+/*693693+ * fasync_helper() is used by almost all character device drivers694694+ * to set up the fasync queue, and for regular files by the file695695+ * lease code. It returns negative on error, 0 if it did no changes696696+ * and positive if it added/deleted the entry.697697+ */698698+int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)699699+{700700+ if (!on)701701+ return fasync_remove_entry(filp, fapp);702702+ return fasync_add_entry(fd, filp, fapp);673703}674704675705EXPORT_SYMBOL(fasync_helper);