All of lore.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.