aboutsummaryrefslogtreecommitdiffstats
path: root/fs/pstore/inode.c
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2020-05-04 19:46:53 -0700
committerKees Cook <keescook@chromium.org>2020-05-30 10:34:02 -0700
commit609e28bb139e53621521130f0d4aea27a725d465 (patch)
tree83baf007e546d152d1a474b4e3f4e775ab06c011 /fs/pstore/inode.c
parentpstore: Do not leave timer disabled for next backend (diff)
downloadlinux-dev-609e28bb139e53621521130f0d4aea27a725d465.tar.xz
linux-dev-609e28bb139e53621521130f0d4aea27a725d465.zip
pstore: Remove filesystem records when backend is unregistered
If a backend was unloaded without having first removed all its associated records in pstorefs, subsequent removals would crash while attempting to call into the now missing backend. Add automatic removal from the tree in pstore_unregister(), so that no references to the backend remain. Reported-by: Luis Henriques <lhenriques@suse.com> Link: https://lore.kernel.org/lkml/87o8yrmv69.fsf@suse.com Link: https://lore.kernel.org/lkml/20200506152114.50375-11-keescook@chromium.org/ Signed-off-by: Kees Cook <keescook@chromium.org>
Diffstat (limited to 'fs/pstore/inode.c')
-rw-r--r--fs/pstore/inode.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 0e76e12fa6d1..c331efe8de95 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -36,6 +36,7 @@ static struct super_block *pstore_sb;
struct pstore_private {
struct list_head list;
+ struct dentry *dentry;
struct pstore_record *record;
size_t total_size;
};
@@ -191,6 +192,7 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry)
list_del_init(&p->list);
else
rc = -ENOENT;
+ p->dentry = NULL;
mutex_unlock(&records_list_lock);
if (rc)
return rc;
@@ -306,6 +308,35 @@ static struct dentry *psinfo_lock_root(void)
return root;
}
+int pstore_put_backend_records(struct pstore_info *psi)
+{
+ struct pstore_private *pos, *tmp;
+ struct dentry *root;
+ int rc = 0;
+
+ root = psinfo_lock_root();
+ if (!root)
+ return 0;
+
+ mutex_lock(&records_list_lock);
+ list_for_each_entry_safe(pos, tmp, &records_list, list) {
+ if (pos->record->psi == psi) {
+ list_del_init(&pos->list);
+ rc = simple_unlink(d_inode(root), pos->dentry);
+ if (WARN_ON(rc))
+ break;
+ d_drop(pos->dentry);
+ dput(pos->dentry);
+ pos->dentry = NULL;
+ }
+ }
+ mutex_unlock(&records_list_lock);
+
+ inode_unlock(d_inode(root));
+
+ return rc;
+}
+
/*
* Make a regular file in the root directory of our file system.
* Load it up with "size" bytes of data from "buf".
@@ -352,6 +383,7 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record)
if (!dentry)
goto fail_private;
+ private->dentry = dentry;
private->record = record;
inode->i_size = private->total_size = size;
inode->i_private = private;