public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Maneesh Soni <maneesh@in.ibm.com>
To: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrew Morton <akpm@osdl.org>,
	Benjamin Herrenschmidt <benh@kernel.crashing.org>,
	Greg KH <greg@kroah.com>, David Brownell <david-b@pacbell.net>,
	viro@math.psu.edu,
	USB development list <linux-usb-devel@lists.sourceforge.net>,
	Kernel development list <linux-kernel@vger.kernel.org>
Subject: Re: [linux-usb-devel] [PATCH] back out sysfs reference count change
Date: Fri, 2 Apr 2004 10:08:14 +0530	[thread overview]
Message-ID: <20040402043814.GA6993@in.ibm.com> (raw)
In-Reply-To: <Pine.LNX.4.44L0.0404010945210.838-100000@ida.rowland.org>

On Thu, Apr 01, 2004 at 09:56:16AM -0500, Alan Stern wrote:
> On Thu, 1 Apr 2004, Maneesh Soni wrote:
> 
> > On Wed, Mar 31, 2004 at 10:11:37AM -0500, Alan Stern wrote:
> > > 
> > > Here's a suggestion.  At the start of check_perm() grab the dentry 
> > > semaphore, then check whether d_fsdata is NULL, if it isn't then do the 
> > > kobject_get(), then unlock the semaphore.
> > > 
> > 
> > I have tried this with no luck. I still get 
> > (Badness in kobject_get at lib/kobject.c:42) which means it is not correct fix.
> 
> Did you remember to set dentry->d_fsdata to NULL?  This has to be done in
> sysfs_remove_dir() sometime during the period when dentry->d_inode->i_sem
> is held.  Right now the pointer to the kobject never gets erased. That 
> Badness message is an indication that you are using a valid pointer to a 
> kobject whose refcount is 0.
> 

Yes, see the patch below. Probably the race window has become smaller but
Badness message is also an indication that somewhere kobject_cleanup has 
started. I have not yet seen why race is still there.

There is one more bigger problem in this approach. It may miss kobject_put() in 
sysfs_release() call and result will be memory leak, ->release() is not called,
rmmod hang, etc etc. So using ->d_fsdata for this purpose is not the proper
solution, IMO.

cpu 0                      kobj->refcount              cpu 1
kobject_unregister()         	 (1)               sysfs_open_file()
  kobject_del()                                      check_perm()
    sysfs_remove_dir()           (2)                    kobject_get(->d_fsdata) 
	(->d_fsdata = NULL)
  kobject_put()                  (1)                  
						   sysfs_release()
							kobj == NULL


diff -urN linux-2.6.5-rc2/fs/sysfs/dir.c linux-2.6.5-rc2-race-fix/fs/sysfs/dir.c
--- linux-2.6.5-rc2/fs/sysfs/dir.c	2004-03-20 05:41:05.000000000 +0530
+++ linux-2.6.5-rc2-race-fix/fs/sysfs/dir.c	2004-04-02 09:36:53.174323584 +0530
@@ -132,6 +132,11 @@
 	pr_debug("sysfs %s: removing dir\n",dentry->d_name.name);
 	down(&dentry->d_inode->i_sem);
 
+	/* try to avoid further references to kobject even if dentry
+	 * is alive after remove dir.
+	 */
+	dentry->d_fsdata = NULL;
+
 	spin_lock(&dcache_lock);
 restart:
 	node = dentry->d_subdirs.next;
diff -urN linux-2.6.5-rc2/fs/sysfs/file.c linux-2.6.5-rc2-race-fix/fs/sysfs/file.c
--- linux-2.6.5-rc2/fs/sysfs/file.c	2004-03-20 05:41:01.000000000 +0530
+++ linux-2.6.5-rc2-race-fix/fs/sysfs/file.c	2004-04-02 09:51:37.409899344 +0530
@@ -78,11 +78,22 @@
 static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer)
 {
 	struct attribute * attr = file->f_dentry->d_fsdata;
-	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+	struct dentry * kobj_dir = file->f_dentry->d_parent;
+	struct kobject * kobj = NULL;
 	struct sysfs_ops * ops = buffer->ops;
 	int ret = 0;
 	ssize_t count;
 
+	down(&kobj_dir->d_inode->i_sem);
+	/* No need to take a ref. on kobject, as it has been taken
+  	 * during ->open(), but ->d_fsdata can become NULL
+	 */
+	if (kobj_dir->d_fsdata)
+		kobj = kobj_dir->d_fsdata;
+	up(&kobj_dir->d_inode->i_sem);
+
+	if (!kobj)
+		return -EINVAL;
 	if (!buffer->page)
 		buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
 	if (!buffer->page)
@@ -199,9 +210,21 @@
 flush_write_buffer(struct file * file, struct sysfs_buffer * buffer, size_t count)
 {
 	struct attribute * attr = file->f_dentry->d_fsdata;
-	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+	struct dentry * kobj_dir = file->f_dentry->d_parent;
+	struct kobject * kobj = NULL;
 	struct sysfs_ops * ops = buffer->ops;
 
+	down(&kobj_dir->d_inode->i_sem);
+	/* No need to take a ref. on kobject, as it has been taken
+  	 * during ->open(), but ->d_fsdata can become NULL
+	 */
+	if (kobj_dir->d_fsdata) 
+		kobj = kobj_dir->d_fsdata;
+	up(&kobj_dir->d_inode->i_sem);
+
+	if (!kobj)
+		return -EINVAL;
+
 	return ops->store(kobj,attr,buffer->page,count);
 }
 
@@ -238,12 +261,18 @@
 
 static int check_perm(struct inode * inode, struct file * file)
 {
-	struct kobject * kobj = kobject_get(file->f_dentry->d_parent->d_fsdata);
+	struct dentry * kobj_dir = file->f_dentry->d_parent;
+	struct kobject * kobj = NULL;
 	struct attribute * attr = file->f_dentry->d_fsdata;
 	struct sysfs_buffer * buffer;
 	struct sysfs_ops * ops = NULL;
 	int error = 0;
 
+	down(&kobj_dir->d_inode->i_sem);
+	if (kobj_dir->d_fsdata)
+		kobj = kobject_get(kobj_dir->d_fsdata);
+	up(&kobj_dir->d_inode->i_sem);
+
 	if (!kobj || !attr)
 		goto Einval;
 
@@ -320,10 +349,19 @@
 
 static int sysfs_release(struct inode * inode, struct file * filp)
 {
-	struct kobject * kobj = filp->f_dentry->d_parent->d_fsdata;
+	struct dentry * kobj_dir = file->f_dentry->d_parent;
+	struct kobject * kobj = NULL;
 	struct attribute * attr = filp->f_dentry->d_fsdata;
 	struct sysfs_buffer * buffer = filp->private_data;
 
+	down(&kobj_dir->d_inode->i_sem);
+	/* No need to take a ref. on kobject, as it has been taken
+  	 * during ->open(), but ->d_fsdata can become NULL
+	 */
+	if (kobj_dir->d_fsdata) 
+		kobj = kobj_dir->d_fsdata;
+	up(&kobj_dir->d_inode->i_sem);
+
 	if (kobj) 
 		kobject_put(kobj);
 	module_put(attr->owner);
-- 
Maneesh Soni
Linux Technology Center, 
IBM Software Lab, Bangalore, India
email: maneesh@in.ibm.com
Phone: 91-80-25044999 Fax: 91-80-25268553
T/L : 9243696

  reply	other threads:[~2004-04-02  4:34 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20040328063711.GA6387@kroah.com>
     [not found] ` <Pine.LNX.4.44L0.0403281057100.17150-100000@netrider.rowland.org>
     [not found]   ` <20040328123857.55f04527.akpm@osdl.org>
     [not found]     ` <20040329210219.GA16735@kroah.com>
     [not found]       ` <20040329132551.23e12144.akpm@osdl.org>
2004-03-29 23:16         ` Unregistering interfaces Greg KH
2004-03-29 23:31           ` Andrew Morton
2004-03-30  0:01             ` Greg KH
2004-03-30  7:38               ` Maneesh Soni
2004-03-30 15:38               ` Alan Stern
2004-03-30  5:51             ` Maneesh Soni
2004-03-30 23:01               ` Greg KH
2004-03-30 23:16                 ` Andrew Morton
2004-03-30 23:30                   ` Greg KH
2004-03-30 23:57                     ` Greg KH
2004-03-30 23:56                   ` Alan Stern
2004-03-31  0:08                     ` David Brownell
2004-03-31  0:34                       ` Greg KH
2004-03-31 15:32                       ` Alan Stern
2004-03-31  0:33                     ` Greg KH
2004-03-31 15:54                       ` Alan Stern
2004-04-01  7:24                         ` Greg KH
2004-03-30 23:55                 ` [PATCH] back out sysfs reference count change Greg KH
2004-03-31  2:11                   ` [linux-usb-devel] " Benjamin Herrenschmidt
2004-03-31  2:19                     ` Andrew Morton
2004-03-31  9:26                       ` Maneesh Soni
2004-03-31 15:11                         ` Alan Stern
2004-04-01  5:17                           ` Maneesh Soni
2004-04-01  7:15                             ` Greg KH
2004-04-01 14:56                             ` Alan Stern
2004-04-02  4:38                               ` Maneesh Soni [this message]
2004-04-02 21:41                                 ` Alan Stern
2004-04-06 10:13                                   ` Maneesh Soni
2004-04-06 17:03                                     ` Alan Stern
2004-04-14 13:20                                     ` Maneesh Soni
2004-04-15 21:36                                       ` Greg KH
2004-04-15 22:10                                         ` Andrew Morton
2004-04-16  8:42                                           ` Maneesh Soni
2004-03-31 22:18                     ` Greg KH
2004-04-01  1:56                       ` Benjamin Herrenschmidt
2004-04-01  3:48                         ` Alan Stern
2004-04-01  6:55                         ` Greg KH
2004-04-01  7:13                           ` Benjamin Herrenschmidt

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=20040402043814.GA6993@in.ibm.com \
    --to=maneesh@in.ibm.com \
    --cc=akpm@osdl.org \
    --cc=benh@kernel.crashing.org \
    --cc=david-b@pacbell.net \
    --cc=greg@kroah.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb-devel@lists.sourceforge.net \
    --cc=stern@rowland.harvard.edu \
    --cc=viro@math.psu.edu \
    /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