OSDN Git Service

pstore: Refactor pstorefs record list removal
authorKees Cook <keescook@chromium.org>
Tue, 5 May 2020 02:41:30 +0000 (19:41 -0700)
committerKees Cook <keescook@chromium.org>
Tue, 12 May 2020 16:15:29 +0000 (09:15 -0700)
The "unlink" handling should perform list removal (which can also make
sure records don't get double-erased), and the "evict" handling should
be responsible only for memory freeing.

Link: https://lore.kernel.org/lkml/20200506152114.50375-8-keescook@chromium.org/
Signed-off-by: Kees Cook <keescook@chromium.org>
fs/pstore/inode.c

index 92ebcc7..5f08b21 100644 (file)
@@ -177,10 +177,21 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct pstore_private *p = d_inode(dentry)->i_private;
        struct pstore_record *record = p->record;
+       int rc = 0;
 
        if (!record->psi->erase)
                return -EPERM;
 
+       /* Make sure we can't race while removing this file. */
+       mutex_lock(&records_list_lock);
+       if (!list_empty(&p->list))
+               list_del_init(&p->list);
+       else
+               rc = -ENOENT;
+       mutex_unlock(&records_list_lock);
+       if (rc)
+               return rc;
+
        mutex_lock(&record->psi->read_mutex);
        record->psi->erase(record);
        mutex_unlock(&record->psi->read_mutex);
@@ -193,12 +204,7 @@ static void pstore_evict_inode(struct inode *inode)
        struct pstore_private   *p = inode->i_private;
 
        clear_inode(inode);
-       if (p) {
-               mutex_lock(&records_list_lock);
-               list_del(&p->list);
-               mutex_unlock(&records_list_lock);
-               free_pstore_private(p);
-       }
+       free_pstore_private(p);
 }
 
 static const struct inode_operations pstore_dir_inode_operations = {
@@ -417,6 +423,7 @@ static void pstore_kill_sb(struct super_block *sb)
 {
        kill_litter_super(sb);
        pstore_sb = NULL;
+       INIT_LIST_HEAD(&records_list);
 }
 
 static struct file_system_type pstore_fs_type = {