diff mbox series

[3/3] Enable support for tmpfs quotas

Message ID 20240109134651.869887-4-cem@kernel.org (mailing list archive)
State New, archived
Headers show
Series Enable tmpfs quotas | expand

Commit Message

Carlos Maiolino Jan. 9, 2024, 1:46 p.m. UTC
From: Carlos Maiolino <cem@kernel.org>

To achieve so, add a new function handle_quota() to the quotaio subsystem,
this will call do_quotactl() with or without a valid quotadev, according to the
filesystem type.

Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
---
 mntopt.h          |  1 +
 quotaio.c         | 19 +++++++++++++++++--
 quotaio.h         |  2 ++
 quotaio_generic.c | 11 +++++------
 quotaio_meta.c    |  3 +--
 quotaio_v1.c      | 11 +++++------
 quotaio_v2.c      | 11 +++++------
 quotaio_xfs.c     |  4 ++--
 quotasys.c        | 20 +++++++++++++++++---
 9 files changed, 55 insertions(+), 27 deletions(-)

Comments

Jan Kara Jan. 17, 2024, 5:59 p.m. UTC | #1
On Tue 09-01-24 14:46:05, cem@kernel.org wrote:
> From: Carlos Maiolino <cem@kernel.org>
> 
> To achieve so, add a new function handle_quota() to the quotaio subsystem,
> this will call do_quotactl() with or without a valid quotadev, according to the
> filesystem type.
> 
> Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>

Thanks for the patch. Some comments bewow.

> diff --git a/quotaio.c b/quotaio.c
> index 9bebb5e..3cc2bb7 100644
> --- a/quotaio.c
> +++ b/quotaio.c
> @@ -34,6 +34,22 @@ struct disk_dqheader {
>  	u_int32_t dqh_version;
>  } __attribute__ ((packed));
>  
> +int handle_quota(int cmd, struct quota_handle *h, int id, void *addr)

Call this quotactl_handle()?

> +{
> +	int err = -EINVAL;
> +
> +	if (!h)
> +		return err;
> +
> +	if (!strcmp(h->qh_fstype, MNTTYPE_TMPFS))
> +		err = do_quotactl(QCMD(cmd, h->qh_type), NULL, h->qh_dir,
> +					id, addr);
> +	else
> +		err = do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev,
> +					h->qh_dir, id, addr);
> +
> +	return err;
> +}

...

> diff --git a/quotasys.c b/quotasys.c
> index 903816b..1f66302 100644
> --- a/quotasys.c
> +++ b/quotasys.c
> @@ -1384,7 +1390,11 @@ alloc:
>  			continue;
>  		}
>  
> -		if (!nfs_fstype(mnt->mnt_type)) {
> +		/*
> +		 * If devname and mnt->mnt_fsname matches, there is no real
> +		 * underlyin device, so skip these checks
> +		 */
> +		if (!nfs_fstype(mnt->mnt_type) && strcmp(devname, mnt->mnt_fsname)) {
>  			if (stat(devname, &st) < 0) {	/* Can't stat mounted device? */
>  				errstr(_("Cannot stat() mounted device %s: %s\n"), devname, strerror(errno));
>  				free((char *)devname);

I'm a bit uneasy about the added check because using device name the same
as filesystem name is just a common agreement but not enforced in any way.
So perhaps just add an explicit check for tmpfs? Later we can generalize
this if there are more filesystems like this...

								Honza
Carlos Maiolino Jan. 24, 2024, 11:42 a.m. UTC | #2
On Wed, Jan 17, 2024 at 06:59:54PM +0100, Jan Kara wrote:
> On Tue 09-01-24 14:46:05, cem@kernel.org wrote:
> > From: Carlos Maiolino <cem@kernel.org>
> >
> > To achieve so, add a new function handle_quota() to the quotaio subsystem,
> > this will call do_quotactl() with or without a valid quotadev, according to the
> > filesystem type.
> >
> > Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
> 
> Thanks for the patch. Some comments bewow.
> 
> > diff --git a/quotaio.c b/quotaio.c
> > index 9bebb5e..3cc2bb7 100644
> > --- a/quotaio.c
> > +++ b/quotaio.c
> > @@ -34,6 +34,22 @@ struct disk_dqheader {
> >  	u_int32_t dqh_version;
> >  } __attribute__ ((packed));
> >
> > +int handle_quota(int cmd, struct quota_handle *h, int id, void *addr)
> 
> Call this quotactl_handle()?
> 
> > +{
> > +	int err = -EINVAL;
> > +
> > +	if (!h)
> > +		return err;
> > +
> > +	if (!strcmp(h->qh_fstype, MNTTYPE_TMPFS))
> > +		err = do_quotactl(QCMD(cmd, h->qh_type), NULL, h->qh_dir,
> > +					id, addr);
> > +	else
> > +		err = do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev,
> > +					h->qh_dir, id, addr);
> > +
> > +	return err;
> > +}
> 
> ...
> 
> > diff --git a/quotasys.c b/quotasys.c
> > index 903816b..1f66302 100644
> > --- a/quotasys.c
> > +++ b/quotasys.c
> > @@ -1384,7 +1390,11 @@ alloc:
> >  			continue;
> >  		}
> >
> > -		if (!nfs_fstype(mnt->mnt_type)) {
> > +		/*
> > +		 * If devname and mnt->mnt_fsname matches, there is no real
> > +		 * underlyin device, so skip these checks
> > +		 */
> > +		if (!nfs_fstype(mnt->mnt_type) && strcmp(devname, mnt->mnt_fsname)) {
> >  			if (stat(devname, &st) < 0) {	/* Can't stat mounted device? */
> >  				errstr(_("Cannot stat() mounted device %s: %s\n"), devname, strerror(errno));
> >  				free((char *)devname);
> 
> I'm a bit uneasy about the added check because using device name the same
> as filesystem name is just a common agreement but not enforced in any way.
> So perhaps just add an explicit check for tmpfs? Later we can generalize
> this if there are more filesystems like this...

What about adding a new tmpfs_fstype() helper, to mimic nfs_fstype, and use it
here? like:

if (!nfs_fstype(mnt->mnt_type) && tmpfs_fstype(mnt->mnt_type))) {
	/* skipe S_ISBLK && S_ISCHR checks */
}

We could open code !strcmp(mnt->mnt_type, MNTTYPE_TMPFS), but it seems to me
adding a new tmpfs_fstype() helper is easier on the eyes, and also OCFS2 does
something similar.

Perhaps that's exactly what you meant as having an explicit check for tmpfs, but
I'm not really sure?!

Carlos

> 
> 								Honza
> --
> Jan Kara <jack@suse.com>
> SUSE Labs, CR
Jan Kara Jan. 24, 2024, 3:16 p.m. UTC | #3
On Wed 24-01-24 12:42:39, Carlos Maiolino wrote:
> On Wed, Jan 17, 2024 at 06:59:54PM +0100, Jan Kara wrote:
> > On Tue 09-01-24 14:46:05, cem@kernel.org wrote:
> > > diff --git a/quotasys.c b/quotasys.c
> > > index 903816b..1f66302 100644
> > > --- a/quotasys.c
> > > +++ b/quotasys.c
> > > @@ -1384,7 +1390,11 @@ alloc:
> > >  			continue;
> > >  		}
> > >
> > > -		if (!nfs_fstype(mnt->mnt_type)) {
> > > +		/*
> > > +		 * If devname and mnt->mnt_fsname matches, there is no real
> > > +		 * underlyin device, so skip these checks
> > > +		 */
> > > +		if (!nfs_fstype(mnt->mnt_type) && strcmp(devname, mnt->mnt_fsname)) {
> > >  			if (stat(devname, &st) < 0) {	/* Can't stat mounted device? */
> > >  				errstr(_("Cannot stat() mounted device %s: %s\n"), devname, strerror(errno));
> > >  				free((char *)devname);
> > 
> > I'm a bit uneasy about the added check because using device name the same
> > as filesystem name is just a common agreement but not enforced in any way.
> > So perhaps just add an explicit check for tmpfs? Later we can generalize
> > this if there are more filesystems like this...
> 
> What about adding a new tmpfs_fstype() helper, to mimic nfs_fstype, and use it
> here? like:
> 
> if (!nfs_fstype(mnt->mnt_type) && tmpfs_fstype(mnt->mnt_type))) {
> 	/* skipe S_ISBLK && S_ISCHR checks */
> }
> 
> We could open code !strcmp(mnt->mnt_type, MNTTYPE_TMPFS), but it seems to me
> adding a new tmpfs_fstype() helper is easier on the eyes, and also OCFS2 does
> something similar.
> 
> Perhaps that's exactly what you meant as having an explicit check for tmpfs, but
> I'm not really sure?!

Yes, this would be a nice way of doing it.

								Honza
diff mbox series

Patch

diff --git a/mntopt.h b/mntopt.h
index 0f3b0c5..9b71990 100644
--- a/mntopt.h
+++ b/mntopt.h
@@ -22,6 +22,7 @@ 
 #define MNTTYPE_MPFS		"mpfs"  /* EMC Celerra MPFS filesystem */
 #define MNTTYPE_OCFS2		"ocfs2"	/* Oracle Cluster filesystem */
 #define MNTTYPE_GFS2		"gfs2"	/* Red Hat Global filesystem 2 */
+#define MNTTYPE_TMPFS		"tmpfs"	/* tmpfs filesystem */
 
 #ifndef MNTTYPE_NFS
 #define MNTTYPE_NFS	"nfs"		/* Network file system.  */
diff --git a/quotaio.c b/quotaio.c
index 9bebb5e..3cc2bb7 100644
--- a/quotaio.c
+++ b/quotaio.c
@@ -34,6 +34,22 @@  struct disk_dqheader {
 	u_int32_t dqh_version;
 } __attribute__ ((packed));
 
+int handle_quota(int cmd, struct quota_handle *h, int id, void *addr)
+{
+	int err = -EINVAL;
+
+	if (!h)
+		return err;
+
+	if (!strcmp(h->qh_fstype, MNTTYPE_TMPFS))
+		err = do_quotactl(QCMD(cmd, h->qh_type), NULL, h->qh_dir,
+					id, addr);
+	else
+		err = do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev,
+					h->qh_dir, id, addr);
+
+	return err;
+}
 /*
  *	Detect quota format and initialize quota IO
  */
@@ -140,8 +156,7 @@  struct quota_handle *init_io(struct mount_entry *mnt, int type, int fmt, int fla
 		if (QIO_ENABLED(h)) {	/* Kernel uses same file? */
 			unsigned int cmd =
 				(kernel_iface == IFACE_GENERIC) ? Q_SYNC : Q_6_5_SYNC;
-			if (do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev,
-				     h->qh_dir, 0,  NULL) < 0) {
+			if (handle_quota(cmd, h, 0,  NULL) < 0) {
 				die(4, _("Cannot sync quotas on device %s: %s\n"),
 				    h->qh_quotadev, strerror(errno));
 			}
diff --git a/quotaio.h b/quotaio.h
index 2c373b2..44e71c4 100644
--- a/quotaio.h
+++ b/quotaio.h
@@ -182,4 +182,6 @@  struct dquot *get_empty_dquot(void);
 /* Check whether values in current dquot can be stored on disk */
 int check_dquot_range(struct dquot *dquot);
 
+/* Use quota_handle data to call quotactl() or quotactl_fd() */
+int handle_quota(int cmd, struct quota_handle *h, int id, void *addr);
 #endif /* GUARD_QUOTAIO_H */
diff --git a/quotaio_generic.c b/quotaio_generic.c
index 3c95872..862ab63 100644
--- a/quotaio_generic.c
+++ b/quotaio_generic.c
@@ -50,7 +50,7 @@  int vfs_get_info(struct quota_handle *h)
 {
 	struct if_dqinfo kinfo;
 
-	if (do_quotactl(QCMD(Q_GETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kinfo) < 0) {
+	if (handle_quota(Q_GETINFO, h, 0, (void *)&kinfo) < 0) {
 		errstr(_("Cannot get info for %s quota file from kernel on %s: %s\n"), type2name(h->qh_type), h->qh_quotadev, strerror(errno));
 		return -1;
 	}
@@ -68,7 +68,7 @@  int vfs_set_info(struct quota_handle *h, int flags)
 	kinfo.dqi_igrace = h->qh_info.dqi_igrace;
 	kinfo.dqi_valid = flags;
 
-	if (do_quotactl(QCMD(Q_SETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kinfo) < 0) {
+	if (handle_quota(Q_SETINFO, h, 0, (void *)&kinfo) < 0) {
 		errstr(_("Cannot set info for %s quota file from kernel on %s: %s\n"), type2name(h->qh_type), h->qh_quotadev, strerror(errno));
 		return -1;
 	}
@@ -80,7 +80,7 @@  int vfs_get_dquot(struct dquot *dquot)
 {
 	struct if_dqblk kdqblk;
 
-	if (do_quotactl(QCMD(Q_GETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) {
+	if (handle_quota(Q_GETQUOTA, dquot->dq_h, dquot->dq_id, (void *)&kdqblk) < 0) {
 		errstr(_("Cannot get quota for %s %d from kernel on %s: %s\n"), type2name(dquot->dq_h->qh_type), dquot->dq_id, dquot->dq_h->qh_quotadev, strerror(errno));
 		return -1;
 	}
@@ -95,7 +95,7 @@  int vfs_set_dquot(struct dquot *dquot, int flags)
 
 	generic_util2kerndqblk(&kdqblk, &dquot->dq_dqb);
 	kdqblk.dqb_valid = flags;
-	if (do_quotactl(QCMD(Q_SETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) {
+	if (handle_quota(Q_SETQUOTA, dquot->dq_h, dquot->dq_id, (void *)&kdqblk) < 0) {
 		errstr(_("Cannot set quota for %s %d from kernel on %s: %s\n"), type2name(dquot->dq_h->qh_type), dquot->dq_id, dquot->dq_h->qh_quotadev, strerror(errno));
 		return -1;
 	}
@@ -188,8 +188,7 @@  int vfs_scan_dquots(struct quota_handle *h,
 
 	dquot->dq_h = h;
 	while (1) {
-		ret = do_quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type),
-			       h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk);
+		ret = handle_quota(Q_GETNEXTQUOTA, h, id, (void *)&kdqblk);
 		if (ret < 0)
 			break;
 
diff --git a/quotaio_meta.c b/quotaio_meta.c
index 51ebbcf..e774c1d 100644
--- a/quotaio_meta.c
+++ b/quotaio_meta.c
@@ -59,8 +59,7 @@  static int meta_scan_dquots(struct quota_handle *h, int (*process_dquot)(struct
 	struct if_nextdqblk kdqblk;
 	int ret;
 
-	ret = do_quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), h->qh_quotadev,
-			  h->qh_dir, 0, (void *)&kdqblk);
+	ret = handle_quota(Q_GETNEXTQUOTA, h, 0, (void *)&kdqblk);
 	/*
 	 * Fall back to scanning using passwd if Q_GETNEXTQUOTA is not
 	 * supported
diff --git a/quotaio_v1.c b/quotaio_v1.c
index 187a5a5..90bf5a6 100644
--- a/quotaio_v1.c
+++ b/quotaio_v1.c
@@ -118,7 +118,7 @@  static int v1_init_io(struct quota_handle *h)
 		else {
 			struct v1_kern_dqblk kdqblk;
 
-			if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) {
+			if (handle_quota(Q_V1_GETQUOTA, h, 0, (void *)&kdqblk) < 0) {
 				if (errno == EPERM) {	/* We have no permission to get this information? */
 					h->qh_info.dqi_bgrace = h->qh_info.dqi_igrace = 0;	/* It hopefully won't be needed */
 				}
@@ -193,11 +193,11 @@  static int v1_write_info(struct quota_handle *h)
 		else {
 			struct v1_kern_dqblk kdqblk;
 
-			if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0)
+			if (handle_quota(Q_V1_GETQUOTA, h, 0, (void *)&kdqblk) < 0)
 				return -1;
 			kdqblk.dqb_btime = h->qh_info.dqi_bgrace;
 			kdqblk.dqb_itime = h->qh_info.dqi_igrace;
-			if (do_quotactl(QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0)
+			if (handle_quota(Q_V1_SETQUOTA, h, 0, (void *)&kdqblk) < 0)
 				return -1;
 		}
 	}
@@ -237,7 +237,7 @@  static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id)
 		else {
 			struct v1_kern_dqblk kdqblk;
 
-			if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk) < 0) {
+			if (handle_quota(Q_V1_GETQUOTA, h, id, (void *)&kdqblk) < 0) {
 				free(dquot);
 				return NULL;
 			}
@@ -299,8 +299,7 @@  static int v1_commit_dquot(struct dquot *dquot, int flags)
 			else
 				cmd = Q_V1_SETQUOTA;
 			v1_util2kerndqblk(&kdqblk, &dquot->dq_dqb);
-			if (do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, h->qh_dir, dquot->dq_id,
-			     (void *)&kdqblk) < 0)
+			if (handle_quota(cmd, h, dquot->dq_id, (void *)&kdqblk) < 0)
 				return -1;
 		}
 	}
diff --git a/quotaio_v2.c b/quotaio_v2.c
index b0fe7bf..1100a19 100644
--- a/quotaio_v2.c
+++ b/quotaio_v2.c
@@ -275,7 +275,7 @@  static int v2_init_io(struct quota_handle *h)
 		else {
 			struct v2_kern_dqinfo kdqinfo;
 
-			if (do_quotactl(QCMD(Q_V2_GETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0) {
+			if (handle_quota(Q_V2_GETINFO, h, 0, (void *)&kdqinfo) < 0) {
 				/* Temporary check just before fix gets to kernel */
 				if (errno == EPERM)	/* Don't have permission to get information? */
 					return 0;
@@ -403,8 +403,8 @@  static int v2_write_info(struct quota_handle *h)
 			kdqinfo.dqi_blocks = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks;
 			kdqinfo.dqi_free_blk = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk;
 			kdqinfo.dqi_free_entry = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry;
-			if (do_quotactl(QCMD(Q_V2_SETGRACE, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0 ||
-			    do_quotactl(QCMD(Q_V2_SETFLAGS, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0)
+			if (handle_quota(Q_V2_SETGRACE, h, 0, (void *)&kdqinfo) < 0 ||
+			    handle_quota(Q_V2_SETFLAGS, h, 0, (void *)&kdqinfo) < 0)
 					return -1;
 		}
 	}
@@ -441,7 +441,7 @@  static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id)
 		else {
 			struct v2_kern_dqblk kdqblk;
 
-			if (do_quotactl(QCMD(Q_V2_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk) < 0) {
+			if (handle_quota(Q_V2_GETQUOTA, h, id, (void *)&kdqblk) < 0) {
 				free(dquot);
 				return NULL;
 			}
@@ -485,8 +485,7 @@  static int v2_commit_dquot(struct dquot *dquot, int flags)
 			else
 				cmd = Q_V2_SETQUOTA;
 			v2_util2kerndqblk(&kdqblk, &dquot->dq_dqb);
-			if (do_quotactl(QCMD(cmd, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev,
-			     dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0)
+			if (handle_quota(cmd, dquot->dq_h, dquot->dq_id, (void *)&kdqblk) < 0)
 				return -1;
 		}
 		return 0;
diff --git a/quotaio_xfs.c b/quotaio_xfs.c
index 0bf6f34..34fd044 100644
--- a/quotaio_xfs.c
+++ b/quotaio_xfs.c
@@ -128,7 +128,7 @@  static int xfs_init_io(struct quota_handle *h)
 
 	qcmd = QCMD(Q_XFS_GETQSTAT, h->qh_type);
 	memset(&info, 0, sizeof(struct xfs_mem_dqinfo));
-	if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, 0, (void *)&info) < 0)
+	if (handle_quota(qcmd, h, 0, (void *)&info) < 0)
 		return -1;
 	h->qh_info.dqi_bgrace = info.qs_btimelimit;
 	h->qh_info.dqi_igrace = info.qs_itimelimit;
@@ -153,7 +153,7 @@  static int xfs_write_info(struct quota_handle *h)
 	xdqblk.d_itimer = h->qh_info.dqi_igrace;
 	xdqblk.d_fieldmask |= FS_DQ_TIMER_MASK;
 	qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type);
-	if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, 0, (void *)&xdqblk) < 0)
+	if (handle_quota(qcmd, h, 0, (void *)&xdqblk) < 0)
 		return -1;
 	return 0;
 }
diff --git a/quotasys.c b/quotasys.c
index 903816b..1f66302 100644
--- a/quotasys.c
+++ b/quotasys.c
@@ -752,6 +752,7 @@  static int hasvfsmetaquota(const char *dev, struct mntent *mnt, int type, int fl
 
 	if (!do_quotactl(QCMD(Q_GETFMT, type), dev, mnt->mnt_dir, 0, (void *)&fmt))
 		return QF_META;
+
 	return QF_ERROR;
 }
 
@@ -816,8 +817,13 @@  static int hasquota(const char *dev, struct mntent *mnt, int type, int flags)
 	    !strcmp(mnt->mnt_type, MNTTYPE_XFS) ||
 	    !strcmp(mnt->mnt_type, MNTTYPE_EXFS))
 		return hasxfsquota(dev, mnt, type, flags);
+
 	if (!strcmp(mnt->mnt_type, MNTTYPE_OCFS2))
 		return hasvfsmetaquota(dev, mnt, type, flags);
+
+	/* tmpfs has no device, pass null here so quotactl_fd() is called */
+	if (!strcmp(mnt->mnt_type, MNTTYPE_TMPFS))
+		return hasvfsmetaquota(NULL, mnt, type, flags);
 	/*
 	 * For ext4 we check whether it has quota in system files and if not,
 	 * we fall back on checking standard quotas. Furthermore we cannot use
@@ -1384,7 +1390,11 @@  alloc:
 			continue;
 		}
 
-		if (!nfs_fstype(mnt->mnt_type)) {
+		/*
+		 * If devname and mnt->mnt_fsname matches, there is no real
+		 * underlyin device, so skip these checks
+		 */
+		if (!nfs_fstype(mnt->mnt_type) && strcmp(devname, mnt->mnt_fsname)) {
 			if (stat(devname, &st) < 0) {	/* Can't stat mounted device? */
 				errstr(_("Cannot stat() mounted device %s: %s\n"), devname, strerror(errno));
 				free((char *)devname);
@@ -1398,6 +1408,7 @@  alloc:
 			dev = st.st_rdev;
 			for (i = 0; i < mnt_entries_cnt && mnt_entries[i].me_dev != dev; i++);
 		}
+
 		/* Cope with network filesystems or new mountpoint */
 		if (nfs_fstype(mnt->mnt_type) || i == mnt_entries_cnt) {
 			if (stat(mnt->mnt_dir, &st) < 0) {	/* Can't stat mountpoint? We have better ignore it... */
@@ -1570,8 +1581,11 @@  restart:
 	sd = check_dirs + act_checked;
 	for (i = 0; i < mnt_entries_cnt; i++) {
 		if (sd->sd_isdir) {
-			if (sd->sd_dev == mnt_entries[i].me_dev && sd->sd_ino == mnt_entries[i].me_ino)
-				break;
+			if (sd->sd_ino == mnt_entries[i].me_ino)
+				if ((sd->sd_dev == mnt_entries[i].me_dev) ||
+				    (!strcmp(mnt_entries[i].me_type, MNTTYPE_TMPFS)))
+					break;
+
 		}
 		else
 			if (sd->sd_dev == mnt_entries[i].me_dev)