summaryrefslogtreecommitdiff
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-19 12:03:17 +0200
commit45036658e1f7331b1ffc7ebaed93aeb467d79b94 (patch)
treef1e288acc15dfe98bc05274a00537a2fac1e7089
parent89e7c6321de7a9aaa72c42aec7b4764541ee1b75 (diff)
downloadbarebox-stable/v2018.09.tar.gz
fs: devfs: implement d_revalidate hookstable/v2018.09
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>
-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);