Re: Bug: devfs is sure to have the bug.

2011-08-08 Thread Kohji Okuno
Hi Kostic and Jaakko,

 On Fri, Aug 05, 2011 at 06:45:22PM +0300, Jaakko Heinonen wrote:
 On 2011-08-03, Kostik Belousov wrote:
  On Wed, Aug 03, 2011 at 02:44:23PM +0900, Kohji Okuno wrote:
devfs_populate(), and the context holds only dm-dm_lock in
devfs_populate().

On the other hand, devfs_generation is incremented in devfs_create()
and devfs_destroy() the context holds only devmtx in devfs_create()
and devfs_destroy().

If a context executes devfs_create() when other context is executing
(***), then dm-dm_generation is updated incorrect value.
As a result, we can not open the last detected device (we receive 
ENOENT).
  
  I think the problem you described is real, and suggested change is right.
  Initially, I thought that we should work with devfs_generation as with
  the atomic type due to unlocked access in the devfs_populate(), but then
  convinced myself that this is not needed.
  
  But also, I think there is another half of the problem. Namely,
  devfs_lookup() calls devfs_populate_vp(), and then does lookup with the
  help of devfs_lookupx(). We will miss the generation update
  happen after the drop of the dm_lock in devfs_populate_vp() to reacquire
  the directory vnode lock.
 
 I don't understand this. devfs_generation is not protected with dm_lock
 in devfs_create() and devfs_destroy(). On the other hand if you mean
 that another thread calls devfs_populate() while we drop dm_lock in
 devfs_populate_vp(), isn't the mount point up to date when we re-lock
 dm_lock?
 Yes, I was not quite exact in describing what I mean, and the reference
 to dm_lock drop is both vague and not correct.
 
 I am after the fact that we do allow the situation where it is externally
 visible that new cdev node was successfully created before the lookup
 returns ENOENT for the path of the node.
 
 
  @@ -630,13 +630,15 @@ devfs_populate_loop(struct devfs_mount *dm, int 
  cleanup)
   void
   devfs_populate(struct devfs_mount *dm)
   {
  +  unsigned gen;
   
 sx_assert(dm-dm_lock, SX_XLOCKED);
  -  if (dm-dm_generation == devfs_generation)
  +  gen = devfs_generation;
  +  if (dm-dm_generation == gen)
 return;
 while (devfs_populate_loop(dm, 0))
 continue;
  -  dm-dm_generation = devfs_generation;
  +  dm-dm_generation = gen;
   }
 
 After this change dm-dm_generation may be stale although the mount
 point is up to date? This is probably harmless, though.
 This must be harmless, in the worst case it will cause more calls to
 the populate. In fact, this even allows the dm_generation to roll backward,
 which is again harmless.

After all, do we only have to fix only devfs_populate()?
I think that there is no problem while I am testing the 8.1-RELEASE
environment that fix only devfs_populate().

Many thanks,
 Kohji Okuno
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: Bug: devfs is sure to have the bug.

2011-08-05 Thread Jaakko Heinonen
On 2011-08-03, Kostik Belousov wrote:
 On Wed, Aug 03, 2011 at 02:44:23PM +0900, Kohji Okuno wrote:
   devfs_populate(), and the context holds only dm-dm_lock in
   devfs_populate().
   
   On the other hand, devfs_generation is incremented in devfs_create()
   and devfs_destroy() the context holds only devmtx in devfs_create()
   and devfs_destroy().
   
   If a context executes devfs_create() when other context is executing
   (***), then dm-dm_generation is updated incorrect value.
   As a result, we can not open the last detected device (we receive ENOENT).
 
 I think the problem you described is real, and suggested change is right.
 Initially, I thought that we should work with devfs_generation as with
 the atomic type due to unlocked access in the devfs_populate(), but then
 convinced myself that this is not needed.
 
 But also, I think there is another half of the problem. Namely,
 devfs_lookup() calls devfs_populate_vp(), and then does lookup with the
 help of devfs_lookupx(). We will miss the generation update
 happen after the drop of the dm_lock in devfs_populate_vp() to reacquire
 the directory vnode lock.

I don't understand this. devfs_generation is not protected with dm_lock
in devfs_create() and devfs_destroy(). On the other hand if you mean
that another thread calls devfs_populate() while we drop dm_lock in
devfs_populate_vp(), isn't the mount point up to date when we re-lock
dm_lock?

 @@ -630,13 +630,15 @@ devfs_populate_loop(struct devfs_mount *dm, int cleanup)
  void
  devfs_populate(struct devfs_mount *dm)
  {
 + unsigned gen;
  
   sx_assert(dm-dm_lock, SX_XLOCKED);
 - if (dm-dm_generation == devfs_generation)
 + gen = devfs_generation;
 + if (dm-dm_generation == gen)
   return;
   while (devfs_populate_loop(dm, 0))
   continue;
 - dm-dm_generation = devfs_generation;
 + dm-dm_generation = gen;
  }

After this change dm-dm_generation may be stale although the mount
point is up to date? This is probably harmless, though.

-- 
Jaakko
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: Bug: devfs is sure to have the bug.

2011-08-05 Thread Kostik Belousov
On Fri, Aug 05, 2011 at 06:45:22PM +0300, Jaakko Heinonen wrote:
 On 2011-08-03, Kostik Belousov wrote:
  On Wed, Aug 03, 2011 at 02:44:23PM +0900, Kohji Okuno wrote:
devfs_populate(), and the context holds only dm-dm_lock in
devfs_populate().

On the other hand, devfs_generation is incremented in devfs_create()
and devfs_destroy() the context holds only devmtx in devfs_create()
and devfs_destroy().

If a context executes devfs_create() when other context is executing
(***), then dm-dm_generation is updated incorrect value.
As a result, we can not open the last detected device (we receive 
ENOENT).
  
  I think the problem you described is real, and suggested change is right.
  Initially, I thought that we should work with devfs_generation as with
  the atomic type due to unlocked access in the devfs_populate(), but then
  convinced myself that this is not needed.
  
  But also, I think there is another half of the problem. Namely,
  devfs_lookup() calls devfs_populate_vp(), and then does lookup with the
  help of devfs_lookupx(). We will miss the generation update
  happen after the drop of the dm_lock in devfs_populate_vp() to reacquire
  the directory vnode lock.
 
 I don't understand this. devfs_generation is not protected with dm_lock
 in devfs_create() and devfs_destroy(). On the other hand if you mean
 that another thread calls devfs_populate() while we drop dm_lock in
 devfs_populate_vp(), isn't the mount point up to date when we re-lock
 dm_lock?
Yes, I was not quite exact in describing what I mean, and the reference
to dm_lock drop is both vague and not correct.

I am after the fact that we do allow the situation where it is externally
visible that new cdev node was successfully created before the lookup
returns ENOENT for the path of the node.

 
  @@ -630,13 +630,15 @@ devfs_populate_loop(struct devfs_mount *dm, int 
  cleanup)
   void
   devfs_populate(struct devfs_mount *dm)
   {
  +   unsigned gen;
   
  sx_assert(dm-dm_lock, SX_XLOCKED);
  -   if (dm-dm_generation == devfs_generation)
  +   gen = devfs_generation;
  +   if (dm-dm_generation == gen)
  return;
  while (devfs_populate_loop(dm, 0))
  continue;
  -   dm-dm_generation = devfs_generation;
  +   dm-dm_generation = gen;
   }
 
 After this change dm-dm_generation may be stale although the mount
 point is up to date? This is probably harmless, though.
This must be harmless, in the worst case it will cause more calls to
the populate. In fact, this even allows the dm_generation to roll backward,
which is again harmless.


pgph7QBq5GQ8j.pgp
Description: PGP signature


Re: Bug: devfs is sure to have the bug.

2011-08-04 Thread Kostik Belousov
On Thu, Aug 04, 2011 at 11:41:39AM +0900, Kohji Okuno wrote:
 Hello Kostik,
 
 From: Kostik Belousov kostik...@gmail.com
 Subject: Re: Bug: devfs is sure to have the bug.
 Date: Wed, 3 Aug 2011 16:50:44 +0300
  I think the problem you described is real, and suggested change is right.
  Initially, I thought that we should work with devfs_generation as with
  the atomic type due to unlocked access in the devfs_populate(), but then
  convinced myself that this is not needed.
  
  But also, I think there is another half of the problem. Namely,
  devfs_lookup() calls devfs_populate_vp(), and then does lookup with the
  help of devfs_lookupx(). We will miss the generation update
  happen after the drop of the dm_lock in devfs_populate_vp() to reacquire
  the directory vnode lock.
  
  I propose the change below, consisting of your fix and also retry of
  population and lookup in case generations do not match for ENOENT
 case.
  
  diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c
  index d72ada0..8ff9bc2 100644
  --- a/sys/fs/devfs/devfs_devs.c
  +++ b/sys/fs/devfs/devfs_devs.c
  @@ -63,7 +63,7 @@ static MALLOC_DEFINE(M_CDEVP, DEVFS1, DEVFS cdev_priv 
  storage);
   
   static SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, DEVFS 
  filesystem);
   
  -static unsigned devfs_generation;
  +unsigned devfs_generation;
   SYSCTL_UINT(_vfs_devfs, OID_AUTO, generation, CTLFLAG_RD,
  devfs_generation, 0, DEVFS generation number);
   
  @@ -630,13 +630,15 @@ devfs_populate_loop(struct devfs_mount *dm, int 
  cleanup)
   void
   devfs_populate(struct devfs_mount *dm)
   {
  +   unsigned gen;
   
  sx_assert(dm-dm_lock, SX_XLOCKED);
  -   if (dm-dm_generation == devfs_generation)
  +   gen = devfs_generation;
  +   if (dm-dm_generation == gen)
  return;
  while (devfs_populate_loop(dm, 0))
  continue;
  -   dm-dm_generation = devfs_generation;
  +   dm-dm_generation = gen;
   }
   
   /*
  diff --git a/sys/fs/devfs/devfs_int.h b/sys/fs/devfs/devfs_int.h
  index cdc6aba..cb01ad1 100644
  --- a/sys/fs/devfs/devfs_int.h
  +++ b/sys/fs/devfs/devfs_int.h
  @@ -71,6 +71,8 @@ struct cdev_priv {
   
   #definecdev2priv(c)member2struct(cdev_priv, cdp_c, c)
   
  +extern unsigned devfs_generation;
  +
   struct cdev*devfs_alloc(int);
   intdevfs_dev_exists(const char *);
   void   devfs_free(struct cdev *);
  diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
  index 955bd8b..2603caa 100644
  --- a/sys/fs/devfs/devfs_vnops.c
  +++ b/sys/fs/devfs/devfs_vnops.c
  @@ -188,7 +188,7 @@ devfs_clear_cdevpriv(void)
* On success devfs_populate_vp() returns with dmp-dm_lock held.
*/
   static int
  -devfs_populate_vp(struct vnode *vp)
  +devfs_populate_vp(struct vnode *vp, int dm_locked)
   {
  struct devfs_dirent *de;
  struct devfs_mount *dmp;
  @@ -199,7 +199,8 @@ devfs_populate_vp(struct vnode *vp)
  dmp = VFSTODEVFS(vp-v_mount);
  locked = VOP_ISLOCKED(vp);
   
  -   sx_xlock(dmp-dm_lock);
  +   if (!dm_locked)
  +   sx_xlock(dmp-dm_lock);
  DEVFS_DMP_HOLD(dmp);
   
  /* Can't call devfs_populate() with the vnode lock held. */
  @@ -242,7 +243,7 @@ devfs_vptocnp(struct vop_vptocnp_args *ap)
   
  dmp = VFSTODEVFS(vp-v_mount);
   
  -   error = devfs_populate_vp(vp);
  +   error = devfs_populate_vp(vp, 0);
  if (error != 0)
  return (error);
   
  @@ -643,7 +644,7 @@ devfs_getattr(struct vop_getattr_args *ap)
  struct devfs_mount *dmp;
  struct cdev *dev;
   
  -   error = devfs_populate_vp(vp);
  +   error = devfs_populate_vp(vp, 0);
  if (error != 0)
  return (error);
   
  @@ -903,7 +904,7 @@ devfs_lookupx(struct vop_lookup_args *ap, int 
  *dm_unlock)
   
  if (cdev == NULL)
  sx_xlock(dmp-dm_lock);
  -   else if (devfs_populate_vp(dvp) != 0) {
  +   else if (devfs_populate_vp(dvp, 0) != 0) {
  *dm_unlock = 0;
  sx_xlock(dmp-dm_lock);
  if (DEVFS_DMP_DROP(dmp)) {
  @@ -966,19 +967,30 @@ devfs_lookupx(struct vop_lookup_args *ap, int 
  *dm_unlock)
   static int
   devfs_lookup(struct vop_lookup_args *ap)
   {
  -   int j;
  struct devfs_mount *dmp;
  -   int dm_unlock;
  +   int error, dm_unlock;
   
  -   if (devfs_populate_vp(ap-a_dvp) != 0)
  +   dm_unlock = 0;
  +retry:
  +   if (devfs_populate_vp(ap-a_dvp, dm_unlock) != 0)
  return (ENOTDIR);
   
  dmp = VFSTODEVFS(ap-a_dvp-v_mount);
  dm_unlock = 1;
  -   j = devfs_lookupx(ap, dm_unlock);
  -   if (dm_unlock == 1)
  +   error = devfs_lookupx(ap, dm_unlock);
  +   if (error == ENOENT) {
  +   if (dm_unlock)
  +   sx_assert(dmp-dm_lock, SA_XLOCKED);
  +   else {
  +   sx_xlock(dmp-dm_lock);
  +   dm_unlock = 1;
  +   }
  +   if (devfs_generation != dmp-dm_generation

Re: Bug: devfs is sure to have the bug.

2011-08-04 Thread Kohji Okuno
Hello Kostik,

 On Thu, Aug 04, 2011 at 11:41:39AM +0900, Kohji Okuno wrote:
 Hello Kostik,
 
 From: Kostik Belousov kostik...@gmail.com
 Subject: Re: Bug: devfs is sure to have the bug.
 Date: Wed, 3 Aug 2011 16:50:44 +0300
  I think the problem you described is real, and suggested change is right.
  Initially, I thought that we should work with devfs_generation as with
  the atomic type due to unlocked access in the devfs_populate(), but then
  convinced myself that this is not needed.
  
  But also, I think there is another half of the problem. Namely,
  devfs_lookup() calls devfs_populate_vp(), and then does lookup with the
  help of devfs_lookupx(). We will miss the generation update
  happen after the drop of the dm_lock in devfs_populate_vp() to reacquire
  the directory vnode lock.
  
  I propose the change below, consisting of your fix and also retry of
  population and lookup in case generations do not match for ENOENT
 case.
  
  diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c
  index d72ada0..8ff9bc2 100644
  --- a/sys/fs/devfs/devfs_devs.c
  +++ b/sys/fs/devfs/devfs_devs.c
  @@ -63,7 +63,7 @@ static MALLOC_DEFINE(M_CDEVP, DEVFS1, DEVFS cdev_priv 
  storage);
   
   static SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, DEVFS 
  filesystem);
   
  -static unsigned devfs_generation;
  +unsigned devfs_generation;
   SYSCTL_UINT(_vfs_devfs, OID_AUTO, generation, CTLFLAG_RD,
 devfs_generation, 0, DEVFS generation number);
   
  @@ -630,13 +630,15 @@ devfs_populate_loop(struct devfs_mount *dm, int 
  cleanup)
   void
   devfs_populate(struct devfs_mount *dm)
   {
  +  unsigned gen;
   
 sx_assert(dm-dm_lock, SX_XLOCKED);
  -  if (dm-dm_generation == devfs_generation)
  +  gen = devfs_generation;
  +  if (dm-dm_generation == gen)
 return;
 while (devfs_populate_loop(dm, 0))
 continue;
  -  dm-dm_generation = devfs_generation;
  +  dm-dm_generation = gen;
   }
   
   /*
  diff --git a/sys/fs/devfs/devfs_int.h b/sys/fs/devfs/devfs_int.h
  index cdc6aba..cb01ad1 100644
  --- a/sys/fs/devfs/devfs_int.h
  +++ b/sys/fs/devfs/devfs_int.h
  @@ -71,6 +71,8 @@ struct cdev_priv {
   
   #define   cdev2priv(c)member2struct(cdev_priv, cdp_c, c)
   
  +extern unsigned devfs_generation;
  +
   struct cdev   *devfs_alloc(int);
   int   devfs_dev_exists(const char *);
   void  devfs_free(struct cdev *);
  diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
  index 955bd8b..2603caa 100644
  --- a/sys/fs/devfs/devfs_vnops.c
  +++ b/sys/fs/devfs/devfs_vnops.c
  @@ -188,7 +188,7 @@ devfs_clear_cdevpriv(void)
* On success devfs_populate_vp() returns with dmp-dm_lock held.
*/
   static int
  -devfs_populate_vp(struct vnode *vp)
  +devfs_populate_vp(struct vnode *vp, int dm_locked)
   {
 struct devfs_dirent *de;
 struct devfs_mount *dmp;
  @@ -199,7 +199,8 @@ devfs_populate_vp(struct vnode *vp)
 dmp = VFSTODEVFS(vp-v_mount);
 locked = VOP_ISLOCKED(vp);
   
  -  sx_xlock(dmp-dm_lock);
  +  if (!dm_locked)
  +  sx_xlock(dmp-dm_lock);
 DEVFS_DMP_HOLD(dmp);
   
 /* Can't call devfs_populate() with the vnode lock held. */
  @@ -242,7 +243,7 @@ devfs_vptocnp(struct vop_vptocnp_args *ap)
   
 dmp = VFSTODEVFS(vp-v_mount);
   
  -  error = devfs_populate_vp(vp);
  +  error = devfs_populate_vp(vp, 0);
 if (error != 0)
 return (error);
   
  @@ -643,7 +644,7 @@ devfs_getattr(struct vop_getattr_args *ap)
 struct devfs_mount *dmp;
 struct cdev *dev;
   
  -  error = devfs_populate_vp(vp);
  +  error = devfs_populate_vp(vp, 0);
 if (error != 0)
 return (error);
   
  @@ -903,7 +904,7 @@ devfs_lookupx(struct vop_lookup_args *ap, int 
  *dm_unlock)
   
 if (cdev == NULL)
 sx_xlock(dmp-dm_lock);
  -  else if (devfs_populate_vp(dvp) != 0) {
  +  else if (devfs_populate_vp(dvp, 0) != 0) {
 *dm_unlock = 0;
 sx_xlock(dmp-dm_lock);
 if (DEVFS_DMP_DROP(dmp)) {
  @@ -966,19 +967,30 @@ devfs_lookupx(struct vop_lookup_args *ap, int 
  *dm_unlock)
   static int
   devfs_lookup(struct vop_lookup_args *ap)
   {
  -  int j;
 struct devfs_mount *dmp;
  -  int dm_unlock;
  +  int error, dm_unlock;
   
  -  if (devfs_populate_vp(ap-a_dvp) != 0)
  +  dm_unlock = 0;
  +retry:
  +  if (devfs_populate_vp(ap-a_dvp, dm_unlock) != 0)
 return (ENOTDIR);
   
 dmp = VFSTODEVFS(ap-a_dvp-v_mount);
 dm_unlock = 1;
  -  j = devfs_lookupx(ap, dm_unlock);
  -  if (dm_unlock == 1)
  +  error = devfs_lookupx(ap, dm_unlock);
  +  if (error == ENOENT) {
  +  if (dm_unlock)
  +  sx_assert(dmp-dm_lock, SA_XLOCKED);
  +  else {
  +  sx_xlock(dmp-dm_lock);
  +  dm_unlock = 1;
  +  }
  +  if (devfs_generation != dmp-dm_generation)
  +  goto retry;
  +  }
  +  if (dm_unlock

Re: Bug: devfs is sure to have the bug.

2011-08-04 Thread Kostik Belousov
On Thu, Aug 04, 2011 at 06:56:00PM +0900, Kohji Okuno wrote:
 Hello Kostik,
 
  On Thu, Aug 04, 2011 at 11:41:39AM +0900, Kohji Okuno wrote:
  But, now I'm using 8.1-RELEASE. May I have advice about 8.X ?
  Do you mean a patch for the stable/8 ? I believe it is enough to
  apply rev. 211628 to stable/8, then the patch I posted yesterday
  should be compilable.
 
 I'm sorry.
 I need a patch for 8.1-RELEASE. Could you propose patch?
Did you tried to apply the 211628 and the patch I mailed, to 8.1 ?
I am not very interested in porting this stuff for such old system.
On the other hand, I am unaware of large changes in devfs between
8.1 and latest stable.


pgpTYJZNBuDhX.pgp
Description: PGP signature


Re: Bug: devfs is sure to have the bug.

2011-08-04 Thread Kohji Okuno
Hello Kostik,

  On Thu, Aug 04, 2011 at 11:41:39AM +0900, Kohji Okuno wrote:
  But, now I'm using 8.1-RELEASE. May I have advice about 8.X ?
  Do you mean a patch for the stable/8 ? I believe it is enough to
  apply rev. 211628 to stable/8, then the patch I posted yesterday
  should be compilable.
 
 I'm sorry.
 I need a patch for 8.1-RELEASE. Could you propose patch?
 Did you tried to apply the 211628 and the patch I mailed, to 8.1 ?
 I am not very interested in porting this stuff for such old system.
 On the other hand, I am unaware of large changes in devfs between
 8.1 and latest stable.

No. Because the difference was large as you were poingint out, I did
not your patch. Now, I'm trying the following patch.

 devfs_populate(struct devfs_mount *dm)
 {
 
+#if 1
+   unsigned gen;
+   sx_assert(dm-dm_lock, SX_XLOCKED);
+   gen = devfs_generation;
+   if (dm-dm_generation == gen)
+   return;
+   while (devfs_populate_loop(dm, 0))
+   continue;
+   dm-dm_generation = gen;
+#else
sx_assert(dm-dm_lock, SX_XLOCKED);
if (dm-dm_generation == devfs_generation)
return;
while (devfs_populate_loop(dm, 0))
continue;
dm-dm_generation = devfs_generation;
+#endif
 }
 
 /*
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


Re: Bug: devfs is sure to have the bug.

2011-08-03 Thread Kostik Belousov
On Wed, Aug 03, 2011 at 02:44:23PM +0900, Kohji Okuno wrote:
 Hello,
 
  Hello,
  
  I think that devfs is sure to have the bug.
  I found that I couldn't open /dev/XXX though the kernel detected XXX
  device.
  
  
  dm-dm_generation is updated with devfs_generation in
  devfs_populate(), and the context holds only dm-dm_lock in
  devfs_populate().
  
  On the other hand, devfs_generation is incremented in devfs_create()
  and devfs_destroy() the context holds only devmtx in devfs_create()
  and devfs_destroy().
  
  If a context executes devfs_create() when other context is executing
  (***), then dm-dm_generation is updated incorrect value.
  As a result, we can not open the last detected device (we receive ENOENT).
  
  I think that we should change the lock method.
  May I have advice?
  
  void
  devfs_populate(struct devfs_mount *dm)
  {
  
  sx_assert(dm-dm_lock, SX_XLOCKED);
  if (dm-dm_generation == devfs_generation)
  return;
  while (devfs_populate_loop(dm, 0))
  continue;
  (***)
  dm-dm_generation = devfs_generation;
  }
  
  void
  devfs_create(struct cdev *dev)
  {
  struct cdev_priv *cdp;
  
  mtx_assert(devmtx, MA_OWNED);
  cdp = cdev2priv(dev);
  cdp-cdp_flags |= CDP_ACTIVE;
  cdp-cdp_inode = alloc_unrl(devfs_inos);
  dev_refl(dev);
  TAILQ_INSERT_TAIL(cdevp_list, cdp, cdp_list);
  devfs_generation++;
  }
  
  void
  devfs_destroy(struct cdev *dev)
  {
  struct cdev_priv *cdp;
  
  mtx_assert(devmtx, MA_OWNED);
  cdp = cdev2priv(dev);
  cdp-cdp_flags = ~CDP_ACTIVE;
  devfs_generation++;
  }
  
  Thanks.
 
 I propose the solution. May I have advice?
 
 void
 devfs_populate(struct devfs_mount *dm)
 {
 
 sx_assert(dm-dm_lock, SX_XLOCKED);
 #if 1 /* I propose... */
 int tmp_generation;
 retry:
 tmp_generation = devfs_generation;
 if (dm-dm_generation == tmp_generation)
 return;
 while (devfs_populate_loop(dm, 0))
 continue;
 if (tmp_generation != devfs_generation)
 goto retry;
 dm-dm_generation = tmp_generation;
 #else /* Original */
 if (dm-dm_generation == devfs_generation)
 return;
 while (devfs_populate_loop(dm, 0))
 continue;
 dm-dm_generation = devfs_generation;
 #endif
 }

I think the problem you described is real, and suggested change is right.
Initially, I thought that we should work with devfs_generation as with
the atomic type due to unlocked access in the devfs_populate(), but then
convinced myself that this is not needed.

But also, I think there is another half of the problem. Namely,
devfs_lookup() calls devfs_populate_vp(), and then does lookup with the
help of devfs_lookupx(). We will miss the generation update
happen after the drop of the dm_lock in devfs_populate_vp() to reacquire
the directory vnode lock.

I propose the change below, consisting of your fix and also retry of
population and lookup in case generations do not match for ENOENT case.

diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c
index d72ada0..8ff9bc2 100644
--- a/sys/fs/devfs/devfs_devs.c
+++ b/sys/fs/devfs/devfs_devs.c
@@ -63,7 +63,7 @@ static MALLOC_DEFINE(M_CDEVP, DEVFS1, DEVFS cdev_priv 
storage);
 
 static SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, DEVFS filesystem);
 
-static unsigned devfs_generation;
+unsigned devfs_generation;
 SYSCTL_UINT(_vfs_devfs, OID_AUTO, generation, CTLFLAG_RD,
devfs_generation, 0, DEVFS generation number);
 
@@ -630,13 +630,15 @@ devfs_populate_loop(struct devfs_mount *dm, int cleanup)
 void
 devfs_populate(struct devfs_mount *dm)
 {
+   unsigned gen;
 
sx_assert(dm-dm_lock, SX_XLOCKED);
-   if (dm-dm_generation == devfs_generation)
+   gen = devfs_generation;
+   if (dm-dm_generation == gen)
return;
while (devfs_populate_loop(dm, 0))
continue;
-   dm-dm_generation = devfs_generation;
+   dm-dm_generation = gen;
 }
 
 /*
diff --git a/sys/fs/devfs/devfs_int.h b/sys/fs/devfs/devfs_int.h
index cdc6aba..cb01ad1 100644
--- a/sys/fs/devfs/devfs_int.h
+++ b/sys/fs/devfs/devfs_int.h
@@ -71,6 +71,8 @@ struct cdev_priv {
 
 #definecdev2priv(c)member2struct(cdev_priv, cdp_c, c)
 
+extern unsigned devfs_generation;
+
 struct cdev*devfs_alloc(int);
 intdevfs_dev_exists(const char *);
 void   devfs_free(struct cdev *);
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index 955bd8b..2603caa 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -188,7 +188,7 @@ devfs_clear_cdevpriv(void)
  * On success devfs_populate_vp() returns with dmp-dm_lock held.
  */
 static int
-devfs_populate_vp(struct vnode *vp)
+devfs_populate_vp(struct vnode *vp, int dm_locked)
 {
struct devfs_dirent *de;

Re: Bug: devfs is sure to have the bug.

2011-08-03 Thread Kohji Okuno
Hello Kostik,

From: Kostik Belousov kostik...@gmail.com
Subject: Re: Bug: devfs is sure to have the bug.
Date: Wed, 3 Aug 2011 16:50:44 +0300
Message-ID: 20110803135044.gm17...@deviant.kiev.zoral.com.ua

 On Wed, Aug 03, 2011 at 02:44:23PM +0900, Kohji Okuno wrote:
 Hello,
 
  Hello,
  
  I think that devfs is sure to have the bug.
  I found that I couldn't open /dev/XXX though the kernel detected XXX
  device.
  
  
  dm-dm_generation is updated with devfs_generation in
  devfs_populate(), and the context holds only dm-dm_lock in
  devfs_populate().
  
  On the other hand, devfs_generation is incremented in devfs_create()
  and devfs_destroy() the context holds only devmtx in devfs_create()
  and devfs_destroy().
  
  If a context executes devfs_create() when other context is executing
  (***), then dm-dm_generation is updated incorrect value.
  As a result, we can not open the last detected device (we receive ENOENT).
  
  I think that we should change the lock method.
  May I have advice?
  
  void
  devfs_populate(struct devfs_mount *dm)
  {
  
  sx_assert(dm-dm_lock, SX_XLOCKED);
  if (dm-dm_generation == devfs_generation)
  return;
  while (devfs_populate_loop(dm, 0))
  continue;
  (***)
  dm-dm_generation = devfs_generation;
  }
  
  void
  devfs_create(struct cdev *dev)
  {
  struct cdev_priv *cdp;
  
  mtx_assert(devmtx, MA_OWNED);
  cdp = cdev2priv(dev);
  cdp-cdp_flags |= CDP_ACTIVE;
  cdp-cdp_inode = alloc_unrl(devfs_inos);
  dev_refl(dev);
  TAILQ_INSERT_TAIL(cdevp_list, cdp, cdp_list);
  devfs_generation++;
  }
  
  void
  devfs_destroy(struct cdev *dev)
  {
  struct cdev_priv *cdp;
  
  mtx_assert(devmtx, MA_OWNED);
  cdp = cdev2priv(dev);
  cdp-cdp_flags = ~CDP_ACTIVE;
  devfs_generation++;
  }
  
  Thanks.
 
 I propose the solution. May I have advice?
 
 void
 devfs_populate(struct devfs_mount *dm)
 {
 
 sx_assert(dm-dm_lock, SX_XLOCKED);
 #if 1 /* I propose... */
 int tmp_generation;
 retry:
 tmp_generation = devfs_generation;
 if (dm-dm_generation == tmp_generation)
 return;
 while (devfs_populate_loop(dm, 0))
 continue;
 if (tmp_generation != devfs_generation)
 goto retry;
 dm-dm_generation = tmp_generation;
 #else /* Original */
 if (dm-dm_generation == devfs_generation)
 return;
 while (devfs_populate_loop(dm, 0))
 continue;
 dm-dm_generation = devfs_generation;
 #endif
 }
 
 I think the problem you described is real, and suggested change is right.
 Initially, I thought that we should work with devfs_generation as with
 the atomic type due to unlocked access in the devfs_populate(), but then
 convinced myself that this is not needed.
 
 But also, I think there is another half of the problem. Namely,
 devfs_lookup() calls devfs_populate_vp(), and then does lookup with the
 help of devfs_lookupx(). We will miss the generation update
 happen after the drop of the dm_lock in devfs_populate_vp() to reacquire
 the directory vnode lock.
 
 I propose the change below, consisting of your fix and also retry of
 population and lookup in case generations do not match for ENOENT
case.
 
 diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c
 index d72ada0..8ff9bc2 100644
 --- a/sys/fs/devfs/devfs_devs.c
 +++ b/sys/fs/devfs/devfs_devs.c
 @@ -63,7 +63,7 @@ static MALLOC_DEFINE(M_CDEVP, DEVFS1, DEVFS cdev_priv 
 storage);
  
  static SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, DEVFS filesystem);
  
 -static unsigned devfs_generation;
 +unsigned devfs_generation;
  SYSCTL_UINT(_vfs_devfs, OID_AUTO, generation, CTLFLAG_RD,
   devfs_generation, 0, DEVFS generation number);
  
 @@ -630,13 +630,15 @@ devfs_populate_loop(struct devfs_mount *dm, int cleanup)
  void
  devfs_populate(struct devfs_mount *dm)
  {
 + unsigned gen;
  
   sx_assert(dm-dm_lock, SX_XLOCKED);
 - if (dm-dm_generation == devfs_generation)
 + gen = devfs_generation;
 + if (dm-dm_generation == gen)
   return;
   while (devfs_populate_loop(dm, 0))
   continue;
 - dm-dm_generation = devfs_generation;
 + dm-dm_generation = gen;
  }
  
  /*
 diff --git a/sys/fs/devfs/devfs_int.h b/sys/fs/devfs/devfs_int.h
 index cdc6aba..cb01ad1 100644
 --- a/sys/fs/devfs/devfs_int.h
 +++ b/sys/fs/devfs/devfs_int.h
 @@ -71,6 +71,8 @@ struct cdev_priv {
  
  #define  cdev2priv(c)member2struct(cdev_priv, cdp_c, c)
  
 +extern unsigned devfs_generation;
 +
  struct cdev  *devfs_alloc(int);
  int  devfs_dev_exists(const char *);
  void devfs_free(struct cdev *);
 diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
 index 955bd8b..2603caa 100644
 --- a/sys/fs/devfs/devfs_vnops.c
 +++ b/sys/fs/devfs/devfs_vnops.c
 @@ -188,7 +188,7

Re: Bug: devfs is sure to have the bug.

2011-08-02 Thread Kohji Okuno
Hello,

 Hello,
 
 I think that devfs is sure to have the bug.
 I found that I couldn't open /dev/XXX though the kernel detected XXX
 device.
 
 
 dm-dm_generation is updated with devfs_generation in
 devfs_populate(), and the context holds only dm-dm_lock in
 devfs_populate().
 
 On the other hand, devfs_generation is incremented in devfs_create()
 and devfs_destroy() the context holds only devmtx in devfs_create()
 and devfs_destroy().
 
 If a context executes devfs_create() when other context is executing
 (***), then dm-dm_generation is updated incorrect value.
 As a result, we can not open the last detected device (we receive ENOENT).
 
 I think that we should change the lock method.
 May I have advice?
 
 void
 devfs_populate(struct devfs_mount *dm)
 {
 
 sx_assert(dm-dm_lock, SX_XLOCKED);
 if (dm-dm_generation == devfs_generation)
 return;
 while (devfs_populate_loop(dm, 0))
 continue;
 (***)
 dm-dm_generation = devfs_generation;
 }
 
 void
 devfs_create(struct cdev *dev)
 {
 struct cdev_priv *cdp;
 
 mtx_assert(devmtx, MA_OWNED);
 cdp = cdev2priv(dev);
 cdp-cdp_flags |= CDP_ACTIVE;
 cdp-cdp_inode = alloc_unrl(devfs_inos);
 dev_refl(dev);
 TAILQ_INSERT_TAIL(cdevp_list, cdp, cdp_list);
 devfs_generation++;
 }
 
 void
 devfs_destroy(struct cdev *dev)
 {
 struct cdev_priv *cdp;
 
 mtx_assert(devmtx, MA_OWNED);
 cdp = cdev2priv(dev);
 cdp-cdp_flags = ~CDP_ACTIVE;
 devfs_generation++;
 }
 
 Thanks.

I propose the solution. May I have advice?

void
devfs_populate(struct devfs_mount *dm)
{

sx_assert(dm-dm_lock, SX_XLOCKED);
#if 1 /* I propose... */
int tmp_generation;
retry:
tmp_generation = devfs_generation;
if (dm-dm_generation == tmp_generation)
return;
while (devfs_populate_loop(dm, 0))
continue;
if (tmp_generation != devfs_generation)
goto retry;
dm-dm_generation = tmp_generation;
#else /* Original */
if (dm-dm_generation == devfs_generation)
return;
while (devfs_populate_loop(dm, 0))
continue;
dm-dm_generation = devfs_generation;
#endif
}

Thanks,
  Kohji Okuno (okuno.ko...@jp.panasonic.com)
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org