mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@suse.de>
To: linux-kernel@vger.kernel.org, stable@kernel.org,
	stable-review@kernel.org
Cc: torvalds@linux-foundation.org, akpm@linux-foundation.org,
	Jeff Dike <jdike@addtoit.com>, Matt Mackall <mpm@selenic.com>,
	Greg Kroah-Hartman <gregkh@suse.de>
Subject: [PATCH 02/52] fasync: split 'fasync_helper()' into separate add/remove functions
Date: Thu, 14 Jan 2010 14:26:41 -0800	[thread overview]
Message-ID: <1263508051-7868-2-git-send-email-gregkh@suse.de> (raw)
In-Reply-To: <1263508051-7868-1-git-send-email-gregkh@suse.de>

From: Linus Torvalds <torvalds@linux-foundation.org>

commit 53281b6d34d44308372d16acb7fb5327609f68b6 upstream.

Yes, the add and remove cases do share the same basic loop and the
locking, but the compiler can inline and then CSE some of the end result
anyway.  And splitting it up makes the code way easier to follow,
and makes it clearer exactly what the semantics are.

In particular, we must make sure that the FASYNC flag in file->f_flags
exactly matches the state of "is this file on any fasync list", since
not only is that flag visible to user space (F_GETFL), but we also use
that flag to check whether we need to remove any fasync entries on file
close.

We got that wrong for the case of a mixed use of file locking (which
tries to remove any fasync entries for file leases) and fasync.

Splitting the function up also makes it possible to do some future
optimizations without making the function even messier.  In particular,
since the FASYNC flag has to match the state of "is this on a list", we
can do the following future optimizations:

 - on remove, we don't even need to get the locks and traverse the list
   if FASYNC isn't set, since we can know a priori that there is no
   point (this is effectively the same optimization that we already do
   in __fput() wrt removing fasync on file close)

 - on add, we can use the FASYNC flag to decide whether we are changing
   an existing entry or need to allocate a new one.

but this is just the cleanup + fix for the FASYNC flag.

Acked-by: Al Viro <viro@ZenIV.linux.org.uk>
Tested-by: Tavis Ormandy <taviso@google.com>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Matt Mackall <mpm@selenic.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 fs/fcntl.c |  102 ++++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 66 insertions(+), 36 deletions(-)

diff --git a/fs/fcntl.c b/fs/fcntl.c
index 2cf93ec..97e01dc 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -618,60 +618,90 @@ static DEFINE_RWLOCK(fasync_lock);
 static struct kmem_cache *fasync_cache __read_mostly;
 
 /*
- * fasync_helper() is used by almost all character device drivers
- * to set up the fasync queue. It returns negative on error, 0 if it did
- * no changes and positive if it added/deleted the entry.
+ * Remove a fasync entry. If successfully removed, return
+ * positive and clear the FASYNC flag. If no entry exists,
+ * do nothing and return 0.
+ *
+ * NOTE! It is very important that the FASYNC flag always
+ * match the state "is the filp on a fasync list".
+ *
+ * We always take the 'filp->f_lock', in since fasync_lock
+ * needs to be irq-safe.
  */
-int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
+static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
 {
 	struct fasync_struct *fa, **fp;
-	struct fasync_struct *new = NULL;
 	int result = 0;
 
-	if (on) {
-		new = kmem_cache_alloc(fasync_cache, GFP_KERNEL);
-		if (!new)
-			return -ENOMEM;
+	spin_lock(&filp->f_lock);
+	write_lock_irq(&fasync_lock);
+	for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
+		if (fa->fa_file != filp)
+			continue;
+		*fp = fa->fa_next;
+		kmem_cache_free(fasync_cache, fa);
+		filp->f_flags &= ~FASYNC;
+		result = 1;
+		break;
 	}
+	write_unlock_irq(&fasync_lock);
+	spin_unlock(&filp->f_lock);
+	return result;
+}
+
+/*
+ * Add a fasync entry. Return negative on error, positive if
+ * added, and zero if did nothing but change an existing one.
+ *
+ * NOTE! It is very important that the FASYNC flag always
+ * match the state "is the filp on a fasync list".
+ */
+static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp)
+{
+	struct fasync_struct *new, *fa, **fp;
+	int result = 0;
+
+	new = kmem_cache_alloc(fasync_cache, GFP_KERNEL);
+	if (!new)
+		return -ENOMEM;
 
-	/*
-	 * We need to take f_lock first since it's not an IRQ-safe
-	 * lock.
-	 */
 	spin_lock(&filp->f_lock);
 	write_lock_irq(&fasync_lock);
 	for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
-		if (fa->fa_file == filp) {
-			if(on) {
-				fa->fa_fd = fd;
-				kmem_cache_free(fasync_cache, new);
-			} else {
-				*fp = fa->fa_next;
-				kmem_cache_free(fasync_cache, fa);
-				result = 1;
-			}
-			goto out;
-		}
+		if (fa->fa_file != filp)
+			continue;
+		fa->fa_fd = fd;
+		kmem_cache_free(fasync_cache, new);
+		goto out;
 	}
 
-	if (on) {
-		new->magic = FASYNC_MAGIC;
-		new->fa_file = filp;
-		new->fa_fd = fd;
-		new->fa_next = *fapp;
-		*fapp = new;
-		result = 1;
-	}
+	new->magic = FASYNC_MAGIC;
+	new->fa_file = filp;
+	new->fa_fd = fd;
+	new->fa_next = *fapp;
+	*fapp = new;
+	result = 1;
+	filp->f_flags |= FASYNC;
+
 out:
-	if (on)
-		filp->f_flags |= FASYNC;
-	else
-		filp->f_flags &= ~FASYNC;
 	write_unlock_irq(&fasync_lock);
 	spin_unlock(&filp->f_lock);
 	return result;
 }
 
+/*
+ * fasync_helper() is used by almost all character device drivers
+ * to set up the fasync queue, and for regular files by the file
+ * lease code. It returns negative on error, 0 if it did no changes
+ * and positive if it added/deleted the entry.
+ */
+int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
+{
+	if (!on)
+		return fasync_remove_entry(filp, fapp);
+	return fasync_add_entry(fd, filp, fapp);
+}
+
 EXPORT_SYMBOL(fasync_helper);
 
 void __kill_fasync(struct fasync_struct *fa, int sig, int band)
-- 
1.6.6


  reply	other threads:[~2010-01-14 22:40 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-01-14 22:25 [00/52] 2.6.32.4-stable review Greg KH
2010-01-14 22:26 ` [PATCH 01/52] untangle the do_mremap() mess Greg Kroah-Hartman
2010-01-14 22:26   ` Greg Kroah-Hartman [this message]
2010-01-14 22:26     ` [PATCH 03/52] ASoC: fix params_rate() macro use in several codecs Greg Kroah-Hartman
2010-01-14 22:26       ` [PATCH 04/52] modules: Skip empty sections when exporting section notes Greg Kroah-Hartman
2010-01-14 22:26         ` [PATCH 05/52] exofs: simple_write_end does not mark_inode_dirty Greg Kroah-Hartman
2010-01-14 22:26           ` [PATCH 06/52] Revert "x86: Side-step lguest problem by only building cmpxchg8b_emu for pre-Pentium" Greg Kroah-Hartman
2010-01-14 22:26             ` [PATCH 07/52] nfsd: make sure data is on disk before calling ->fsync Greg Kroah-Hartman
2010-01-14 22:26               ` [PATCH 08/52] sunrpc: fix peername failed on closed listener Greg Kroah-Hartman
2010-01-14 22:26                 ` [PATCH 09/52] SUNRPC: Fix up an error return value in gss_import_sec_context_kerberos() Greg Kroah-Hartman
2010-01-14 22:26                   ` [PATCH 10/52] SUNRPC: Fix the return value in gss_import_sec_context() Greg Kroah-Hartman
2010-01-14 22:26                     ` [PATCH 11/52] sunrpc: on successful gss error pipe write, don't return error Greg Kroah-Hartman
2010-01-14 22:26                       ` [PATCH 12/52] drm/i915: Update LVDS connector status when receiving ACPI LID event Greg Kroah-Hartman
2010-01-14 22:26                         ` [PATCH 13/52] drm/i915: fix order of fence release wrt flushing Greg Kroah-Hartman
2010-01-14 22:26                           ` [PATCH 14/52] drm/i915: Permit pinning whilst the device is 'suspended' Greg Kroah-Hartman
2010-01-14 22:26                             ` [PATCH 15/52] drm: remove address mask param for drm_pci_alloc() Greg Kroah-Hartman
2010-01-14 22:26                               ` [PATCH 16/52] drm/i915: Enable/disable the dithering for LVDS based on VBT setting Greg Kroah-Hartman
2010-01-14 22:26                                 ` [PATCH 17/52] drm/i915: Make the BPC in FDI rx/transcoder be consistent with that in pipeconf on Ironlake Greg Kroah-Hartman
2010-01-14 22:26                                   ` [PATCH 18/52] drm/i915: Select the correct BPC for LVDS " Greg Kroah-Hartman
2010-01-14 22:26                                     ` [PATCH 19/52] drm/i915: fix unused var Greg Kroah-Hartman
2010-01-14 22:26                                       ` [PATCH 20/52] rtc_cmos: convert shutdown to new pnp_driver->shutdown Greg Kroah-Hartman
2010-01-14 22:27                                         ` [PATCH 21/52] drivers/cpuidle/governors/menu.c: fix undefined reference to `__udivdi3' Greg Kroah-Hartman
2010-01-14 22:27                                           ` [PATCH 22/52] cgroups: fix 2.6.32 regression causing BUG_ON() in cgroup_diput() Greg Kroah-Hartman
2010-01-14 22:27                                             ` [PATCH 23/52] lib/rational.c needs module.h Greg Kroah-Hartman
2010-01-14 22:27                                               ` [PATCH 24/52] dma-debug: allow DMA_BIDIRECTIONAL mappings to be synced with DMA_FROM_DEVICE and Greg Kroah-Hartman
2010-01-14 22:27                                                 ` [PATCH 25/52] kernel/signal.c: fix kernel information leak with print-fatal-signals=1 Greg Kroah-Hartman
2010-01-14 22:27                                                   ` [PATCH 26/52] mmc_block: add dev_t initialization check Greg Kroah-Hartman
2010-01-14 22:27                                                     ` [PATCH 27/52] mmc_block: fix probe error cleanup bug Greg Kroah-Hartman
2010-01-14 22:27                                                       ` [PATCH 28/52] mmc_block: fix queue cleanup Greg Kroah-Hartman
2010-01-14 22:27                                                         ` [PATCH 29/52] ALSA: hda - Fix ALC861-VD capture source mixer Greg Kroah-Hartman
2010-01-14 22:27                                                           ` [PATCH 30/52] ALSA: ac97: Add Dell Dimension 2400 to Headphone/Line Jack Sense blacklist Greg Kroah-Hartman
2010-01-14 22:27                                                             ` [PATCH 31/52] ALSA: atiixp: Specify codec for Foxconn RC4107MA-RS2 Greg Kroah-Hartman
2010-01-14 22:27                                                               ` [PATCH 32/52] ASoC: Fix WM8350 DSP mode B configuration Greg Kroah-Hartman
2010-01-14 22:27                                                                 ` [PATCH 33/52] netfilter: ebtables: enforce CAP_NET_ADMIN Greg Kroah-Hartman
2010-01-14 22:27                                                                   ` [PATCH 34/52] netfilter: nf_ct_ftp: fix out of bounds read in update_nl_seq() Greg Kroah-Hartman
2010-01-14 22:27                                                                     ` [PATCH 35/52] hwmon: (coretemp) Fix TjMax for Atom N450/D410/D510 CPUs Greg Kroah-Hartman
2010-01-14 22:27                                                                       ` [PATCH 36/52] hwmon: (adt7462) Fix pin 28 monitoring Greg Kroah-Hartman
2010-01-14 22:27                                                                         ` [PATCH 37/52] quota: Fix dquot_transfer for filesystems different from ext4 Greg Kroah-Hartman
2010-01-14 22:27                                                                           ` [PATCH 38/52] xen: fix hang on suspend Greg Kroah-Hartman
2010-01-14 22:27                                                                             ` [PATCH 39/52] iwlwifi: fix iwl_queue_used bug when read_ptr == write_ptr Greg Kroah-Hartman
2010-01-14 22:27                                                                               ` [PATCH 40/52] ath5k: Fix eeprom checksum check for custom sized eeproms Greg Kroah-Hartman
2010-01-14 22:27                                                                                 ` [PATCH 41/52] cfg80211: fix syntax error on user regulatory hints Greg Kroah-Hartman
2010-01-14 22:27                                                                                   ` [PATCH 42/52] iwl: off by one bug Greg Kroah-Hartman
2010-01-14 22:27                                                                                     ` [PATCH 43/52] mac80211: add missing sanity checks for action frames Greg Kroah-Hartman
2010-01-14 22:27                                                                                       ` [PATCH 44/52] drm/i915: remove render reclock support Greg Kroah-Hartman
2010-01-14 22:27                                                                                         ` [PATCH 45/52] libertas: Remove carrier signaling from the scan code Greg Kroah-Hartman
2010-01-14 22:27                                                                                           ` [PATCH 46/52] kernel/sysctl.c: fix stable merge error in NOMMU mmap_min_addr Greg Kroah-Hartman
2010-01-14 22:27                                                                                             ` [PATCH 47/52] mac80211: fix skb buffering issue (and fixes to that) Greg Kroah-Hartman
2010-01-14 22:27                                                                                               ` [PATCH 48/52] fix braindamage in audit_tree.c untag_chunk() Greg Kroah-Hartman
2010-01-14 22:27                                                                                                 ` [PATCH 49/52] fix more leaks in audit_tree.c tag_chunk() Greg Kroah-Hartman
2010-01-14 22:27                                                                                                   ` [PATCH 50/52] module: handle ppc64 relocating kcrctabs when CONFIG_RELOCATABLE=y Greg Kroah-Hartman
2010-01-14 22:27                                                                                                     ` [PATCH 51/52] ipv6: skb_dst() can be NULL in ipv6_hop_jumbo() Greg Kroah-Hartman
2010-01-14 22:27                                                                                                       ` [PATCH 52/52] Linux 2.6.32.4-rc1 Greg Kroah-Hartman
2010-01-14 23:38                               ` [Stable-review] [PATCH 15/52] drm: remove address mask param for drm_pci_alloc() Ben Hutchings
2010-01-14 23:45                                 ` Greg KH
2010-01-15  0:56                                   ` Zhenyu Wang
2010-01-16  0:15                                     ` Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1263508051-7868-2-git-send-email-gregkh@suse.de \
    --to=gregkh@suse.de \
    --cc=akpm@linux-foundation.org \
    --cc=jdike@addtoit.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mpm@selenic.com \
    --cc=stable-review@kernel.org \
    --cc=stable@kernel.org \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome