mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/2] fs: add revalidating of dentries
@ 2018-10-17  8:43 Sascha Hauer
  2018-10-17  8:43 ` [PATCH 1/2] fs: implement d_revalidate Sascha Hauer
  2018-10-17  8:43 ` [PATCH 2/2] fs: devfs: implement d_revalidate hook Sascha Hauer
  0 siblings, 2 replies; 3+ messages in thread
From: Sascha Hauer @ 2018-10-17  8:43 UTC (permalink / raw)
  To: Barebox List; +Cc: Ladislav Michl

Currently we do not revalidate dentries. I knew this is not correct for
network filesystems, but as it turned out it is also not correct for
devfs. In devfs files can be created/removed without the fs layer
noticing, so have to check if a dentry is still valid before using it.

Sascha Hauer (2):
  fs: implement d_revalidate
  fs: devfs: implement d_revalidate hook

 fs/devfs.c             | 27 +++++++++++++++++++++++++++
 fs/fs.c                | 37 ++++++++++++++++++++++++++++++++++++-
 include/linux/dcache.h |  3 +++
 3 files changed, 66 insertions(+), 1 deletion(-)

-- 
2.19.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 1/2] fs: implement d_revalidate
  2018-10-17  8:43 [PATCH 0/2] fs: add revalidating of dentries Sascha Hauer
@ 2018-10-17  8:43 ` Sascha Hauer
  2018-10-17  8:43 ` [PATCH 2/2] fs: devfs: implement d_revalidate hook Sascha Hauer
  1 sibling, 0 replies; 3+ messages in thread
From: Sascha Hauer @ 2018-10-17  8:43 UTC (permalink / raw)
  To: Barebox List; +Cc: Ladislav Michl

d_revalidate is useful when filesystems change under the hood of the
fs layer. This can happen with network filesystems or with devfs.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/fs.c                | 37 ++++++++++++++++++++++++++++++++++++-
 include/linux/dcache.h |  3 +++
 2 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/fs/fs.c b/fs/fs.c
index d76d829140..eed0155f0d 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -1141,6 +1141,12 @@ const struct qstr slash_name = QSTR_INIT("/", 1);
 void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
 {
 	dentry->d_op = op;
+
+	if (!op)
+		return;
+
+	if (op->d_revalidate)
+		dentry->d_flags |= DCACHE_OP_REVALIDATE;
 }
 
 /**
@@ -1285,6 +1291,35 @@ void d_invalidate(struct dentry *dentry)
 {
 }
 
+static inline int d_revalidate(struct dentry *dentry, unsigned int flags)
+{
+	if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE))
+		return dentry->d_op->d_revalidate(dentry, flags);
+	else
+		return 1;
+}
+
+/*
+ * This looks up the name in dcache and possibly revalidates the found dentry.
+ * NULL is returned if the dentry does not exist in the cache.
+ */
+static struct dentry *lookup_dcache(const struct qstr *name,
+				    struct dentry *dir,
+				    unsigned int flags)
+{
+	struct dentry *dentry = d_lookup(dir, name);
+	if (dentry) {
+		int error = d_revalidate(dentry, flags);
+		if (unlikely(error <= 0)) {
+			if (!error)
+				d_invalidate(dentry);
+			dput(dentry);
+			return ERR_PTR(error);
+		}
+	}
+	return dentry;
+}
+
 static inline void __d_clear_type_and_inode(struct dentry *dentry)
 {
 	dentry->d_flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
@@ -1496,7 +1531,7 @@ static struct dentry *__lookup_hash(const struct qstr *name,
 	if (!base)
 		return ERR_PTR(-ENOENT);
 
-	dentry = d_lookup(base, name);
+	dentry = lookup_dcache(name, base, flags);
 	if (dentry)
 		return dentry;
 
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 16244129bf..1581ddc701 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -82,6 +82,7 @@ struct dentry {
 };
 
 struct dentry_operations {
+	int (*d_revalidate)(struct dentry *, unsigned int);
 };
 
 struct dentry * d_make_root(struct inode *);
@@ -93,6 +94,8 @@ void d_delete(struct dentry *);
 struct dentry *dget(struct dentry *);
 void dput(struct dentry *);
 
+#define DCACHE_OP_REVALIDATE		0x00000004
+
 #define DCACHE_ENTRY_TYPE		0x00700000
 #define DCACHE_MISS_TYPE		0x00000000 /* Negative dentry (maybe fallthru to nowhere) */
 #define DCACHE_WHITEOUT_TYPE		0x00100000 /* Whiteout dentry (stop pathwalk) */
-- 
2.19.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 2/2] fs: devfs: implement d_revalidate hook
  2018-10-17  8:43 [PATCH 0/2] fs: add revalidating of dentries Sascha Hauer
  2018-10-17  8:43 ` [PATCH 1/2] fs: implement d_revalidate Sascha Hauer
@ 2018-10-17  8:43 ` Sascha Hauer
  1 sibling, 0 replies; 3+ messages in thread
From: Sascha Hauer @ 2018-10-17  8:43 UTC (permalink / raw)
  To: Barebox List; +Cc: Ladislav Michl

The files in devfs can change withouut the fs layer noticing, so we
have to revalidate dentries before using them.

A failure could be triggered with:

ls /dev/nand0.root.ubi; ubiattach /dev/nand0.root; ls /dev/nand0.root.ubi

The first 'ls' would create a dentry for nand0.root.ubi with no inode
associated since it does not yet exist. 'ubiattach' then creates that
file, but the second 'ls' does not show it since the dentry is not
revalidated and thus no inode is added to that dentry. This patch
fixes this and also the opposite case when a file is removed (for
example with ubidetach).

Reported-by: Ladislav Michl <ladis@linux-mips.org>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/devfs.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/fs/devfs.c b/fs/devfs.c
index d2b801036e..717e66c5dc 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -212,6 +212,32 @@ static const struct file_operations devfs_dir_operations;
 static const struct inode_operations devfs_dir_inode_operations;
 static const struct file_operations devfs_file_operations;
 
+static int devfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
+{
+	struct devfs_inode *dinode;
+	struct inode *inode;
+	struct cdev *cdev;
+
+	cdev = cdev_by_name(dentry->name);
+	if (!cdev)
+		return -ENOENT;
+
+	inode = d_inode(dentry);
+	if (!inode)
+		return 0;
+
+	dinode = container_of(inode, struct devfs_inode, inode);
+
+	if (dinode->cdev != cdev)
+		return 0;
+
+	return 1;
+}
+
+static const struct dentry_operations devfs_dentry_operations = {
+	.d_revalidate = devfs_lookup_revalidate,
+};
+
 static struct inode *devfs_get_inode(struct super_block *sb, const struct inode *dir,
                                      umode_t mode)
 {
@@ -290,6 +316,7 @@ static int devfs_probe(struct device_d *dev)
 	struct super_block *sb = &fsdev->sb;
 
 	sb->s_op = &devfs_ops;
+	sb->s_d_op = &devfs_dentry_operations;
 
 	inode = devfs_get_inode(sb, NULL, S_IFDIR);
 	sb->s_root = d_make_root(inode);
-- 
2.19.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2018-10-17  8:44 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-17  8:43 [PATCH 0/2] fs: add revalidating of dentries Sascha Hauer
2018-10-17  8:43 ` [PATCH 1/2] fs: implement d_revalidate Sascha Hauer
2018-10-17  8:43 ` [PATCH 2/2] fs: devfs: implement d_revalidate hook Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox