summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2018-10-17 10:35:51 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2018-10-29 12:23:38 +0100
commitb7705a105f62234465bfdd47769e1f9b9d632fd2 (patch)
treead45cc7453d99213a14ea26d7e6fa6c86979ae82 /fs
parent4e601546388e2e2968eed3b96b1ff19c4e421c31 (diff)
downloadbarebox-b7705a105f62234465bfdd47769e1f9b9d632fd2.tar.gz
barebox-b7705a105f62234465bfdd47769e1f9b9d632fd2.tar.xz
fs: devfs: implement d_revalidate hook
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/devfs.c27
1 files changed, 27 insertions, 0 deletions
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);