]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/pstore/inode.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[karo-tx-linux.git] / fs / pstore / inode.c
index 57c0646479f51cc0baa9bd82ba3cbb5689f41696..792a4e5f9226d16fefa0b6fd47061a76c79416ba 100644 (file)
@@ -47,12 +47,8 @@ static LIST_HEAD(allpstore);
 
 struct pstore_private {
        struct list_head list;
-       struct pstore_info *psi;
-       enum pstore_type_id type;
-       u64     id;
-       int     count;
-       ssize_t size;
-       char    data[];
+       struct pstore_record *record;
+       size_t total_size;
 };
 
 struct pstore_ftrace_seq_data {
@@ -63,6 +59,17 @@ struct pstore_ftrace_seq_data {
 
 #define REC_SIZE sizeof(struct pstore_ftrace_record)
 
+static void free_pstore_private(struct pstore_private *private)
+{
+       if (!private)
+               return;
+       if (private->record) {
+               kfree(private->record->buf);
+               kfree(private->record);
+       }
+       kfree(private);
+}
+
 static void *pstore_ftrace_seq_start(struct seq_file *s, loff_t *pos)
 {
        struct pstore_private *ps = s->private;
@@ -72,9 +79,9 @@ static void *pstore_ftrace_seq_start(struct seq_file *s, loff_t *pos)
        if (!data)
                return NULL;
 
-       data->off = ps->size % REC_SIZE;
+       data->off = ps->total_size % REC_SIZE;
        data->off += *pos * REC_SIZE;
-       if (data->off + REC_SIZE > ps->size) {
+       if (data->off + REC_SIZE > ps->total_size) {
                kfree(data);
                return NULL;
        }
@@ -94,7 +101,7 @@ static void *pstore_ftrace_seq_next(struct seq_file *s, void *v, loff_t *pos)
        struct pstore_ftrace_seq_data *data = v;
 
        data->off += REC_SIZE;
-       if (data->off + REC_SIZE > ps->size)
+       if (data->off + REC_SIZE > ps->total_size)
                return NULL;
 
        (*pos)++;
@@ -105,7 +112,9 @@ static int pstore_ftrace_seq_show(struct seq_file *s, void *v)
 {
        struct pstore_private *ps = s->private;
        struct pstore_ftrace_seq_data *data = v;
-       struct pstore_ftrace_record *rec = (void *)(ps->data + data->off);
+       struct pstore_ftrace_record *rec;
+
+       rec = (struct pstore_ftrace_record *)(ps->record->buf + data->off);
 
        seq_printf(s, "CPU:%d ts:%llu %08lx  %08lx  %pf <- %pF\n",
                   pstore_ftrace_decode_cpu(rec),
@@ -125,7 +134,7 @@ static const struct seq_operations pstore_ftrace_seq_ops = {
 
 static int pstore_check_syslog_permissions(struct pstore_private *ps)
 {
-       switch (ps->type) {
+       switch (ps->record->type) {
        case PSTORE_TYPE_DMESG:
        case PSTORE_TYPE_CONSOLE:
                return check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
@@ -141,9 +150,10 @@ static ssize_t pstore_file_read(struct file *file, char __user *userbuf,
        struct seq_file *sf = file->private_data;
        struct pstore_private *ps = sf->private;
 
-       if (ps->type == PSTORE_TYPE_FTRACE)
+       if (ps->record->type == PSTORE_TYPE_FTRACE)
                return seq_read(file, userbuf, count, ppos);
-       return simple_read_from_buffer(userbuf, count, ppos, ps->data, ps->size);
+       return simple_read_from_buffer(userbuf, count, ppos,
+                                      ps->record->buf, ps->total_size);
 }
 
 static int pstore_file_open(struct inode *inode, struct file *file)
@@ -157,7 +167,7 @@ static int pstore_file_open(struct inode *inode, struct file *file)
        if (err)
                return err;
 
-       if (ps->type == PSTORE_TYPE_FTRACE)
+       if (ps->record->type == PSTORE_TYPE_FTRACE)
                sops = &pstore_ftrace_seq_ops;
 
        err = seq_open(file, sops);
@@ -193,20 +203,19 @@ static const struct file_operations pstore_file_operations = {
 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 err;
 
        err = pstore_check_syslog_permissions(p);
        if (err)
                return err;
 
-       if (p->psi->erase) {
-               mutex_lock(&p->psi->read_mutex);
-               p->psi->erase(p->type, p->id, p->count,
-                             d_inode(dentry)->i_ctime, p->psi);
-               mutex_unlock(&p->psi->read_mutex);
-       } else {
+       if (!record->psi->erase)
                return -EPERM;
-       }
+
+       mutex_lock(&record->psi->read_mutex);
+       record->psi->erase(record);
+       mutex_unlock(&record->psi->read_mutex);
 
        return simple_unlink(dir, dentry);
 }
@@ -221,7 +230,7 @@ static void pstore_evict_inode(struct inode *inode)
                spin_lock_irqsave(&allpstore_lock, flags);
                list_del(&p->list);
                spin_unlock_irqrestore(&allpstore_lock, flags);
-               kfree(p);
+               free_pstore_private(p);
        }
 }
 
@@ -302,23 +311,23 @@ bool pstore_is_mounted(void)
  * Load it up with "size" bytes of data from "buf".
  * Set the mtime & ctime to the date that this record was originally stored.
  */
-int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
-                 char *data, bool compressed, size_t size,
-                 struct timespec time, struct pstore_info *psi)
+int pstore_mkfile(struct dentry *root, struct pstore_record *record)
 {
-       struct dentry           *root = pstore_sb->s_root;
        struct dentry           *dentry;
        struct inode            *inode;
        int                     rc = 0;
        char                    name[PSTORE_NAMELEN];
        struct pstore_private   *private, *pos;
        unsigned long           flags;
+       size_t                  size = record->size + record->ecc_notice_size;
+
+       WARN_ON(!inode_is_locked(d_inode(root)));
 
        spin_lock_irqsave(&allpstore_lock, flags);
        list_for_each_entry(pos, &allpstore, list) {
-               if (pos->type == type &&
-                   pos->id == id &&
-                   pos->psi == psi) {
+               if (pos->record->type == record->type &&
+                   pos->record->id == record->id &&
+                   pos->record->psi == record->psi) {
                        rc = -EEXIST;
                        break;
                }
@@ -328,72 +337,74 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
                return rc;
 
        rc = -ENOMEM;
-       inode = pstore_get_inode(pstore_sb);
+       inode = pstore_get_inode(root->d_sb);
        if (!inode)
                goto fail;
        inode->i_mode = S_IFREG | 0444;
        inode->i_fop = &pstore_file_operations;
-       private = kmalloc(sizeof *private + size, GFP_KERNEL);
+       private = kzalloc(sizeof(*private), GFP_KERNEL);
        if (!private)
                goto fail_alloc;
-       private->type = type;
-       private->id = id;
-       private->count = count;
-       private->psi = psi;
+       private->record = record;
 
-       switch (type) {
+       switch (record->type) {
        case PSTORE_TYPE_DMESG:
                scnprintf(name, sizeof(name), "dmesg-%s-%lld%s",
-                         psname, id, compressed ? ".enc.z" : "");
+                         record->psi->name, record->id,
+                         record->compressed ? ".enc.z" : "");
                break;
        case PSTORE_TYPE_CONSOLE:
-               scnprintf(name, sizeof(name), "console-%s-%lld", psname, id);
+               scnprintf(name, sizeof(name), "console-%s-%lld",
+                         record->psi->name, record->id);
                break;
        case PSTORE_TYPE_FTRACE:
-               scnprintf(name, sizeof(name), "ftrace-%s-%lld", psname, id);
+               scnprintf(name, sizeof(name), "ftrace-%s-%lld",
+                         record->psi->name, record->id);
                break;
        case PSTORE_TYPE_MCE:
-               scnprintf(name, sizeof(name), "mce-%s-%lld", psname, id);
+               scnprintf(name, sizeof(name), "mce-%s-%lld",
+                         record->psi->name, record->id);
                break;
        case PSTORE_TYPE_PPC_RTAS:
-               scnprintf(name, sizeof(name), "rtas-%s-%lld", psname, id);
+               scnprintf(name, sizeof(name), "rtas-%s-%lld",
+                         record->psi->name, record->id);
                break;
        case PSTORE_TYPE_PPC_OF:
                scnprintf(name, sizeof(name), "powerpc-ofw-%s-%lld",
-                         psname, id);
+                         record->psi->name, record->id);
                break;
        case PSTORE_TYPE_PPC_COMMON:
                scnprintf(name, sizeof(name), "powerpc-common-%s-%lld",
-                         psname, id);
+                         record->psi->name, record->id);
                break;
        case PSTORE_TYPE_PMSG:
-               scnprintf(name, sizeof(name), "pmsg-%s-%lld", psname, id);
+               scnprintf(name, sizeof(name), "pmsg-%s-%lld",
+                         record->psi->name, record->id);
                break;
        case PSTORE_TYPE_PPC_OPAL:
-               sprintf(name, "powerpc-opal-%s-%lld", psname, id);
+               scnprintf(name, sizeof(name), "powerpc-opal-%s-%lld",
+                         record->psi->name, record->id);
                break;
        case PSTORE_TYPE_UNKNOWN:
-               scnprintf(name, sizeof(name), "unknown-%s-%lld", psname, id);
+               scnprintf(name, sizeof(name), "unknown-%s-%lld",
+                         record->psi->name, record->id);
                break;
        default:
                scnprintf(name, sizeof(name), "type%d-%s-%lld",
-                         type, psname, id);
+                         record->type, record->psi->name, record->id);
                break;
        }
 
-       inode_lock(d_inode(root));
-
        dentry = d_alloc_name(root, name);
        if (!dentry)
-               goto fail_lockedalloc;
+               goto fail_private;
 
-       memcpy(private->data, data, size);
-       inode->i_size = private->size = size;
+       inode->i_size = private->total_size = size;
 
        inode->i_private = private;
 
-       if (time.tv_sec)
-               inode->i_mtime = inode->i_ctime = time;
+       if (record->time.tv_sec)
+               inode->i_mtime = inode->i_ctime = record->time;
 
        d_add(dentry, inode);
 
@@ -401,13 +412,10 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
        list_add(&private->list, &allpstore);
        spin_unlock_irqrestore(&allpstore_lock, flags);
 
-       inode_unlock(d_inode(root));
-
        return 0;
 
-fail_lockedalloc:
-       inode_unlock(d_inode(root));
-       kfree(private);
+fail_private:
+       free_pstore_private(private);
 fail_alloc:
        iput(inode);
 
@@ -415,6 +423,27 @@ fail:
        return rc;
 }
 
+/*
+ * Read all the records from the persistent store. Create
+ * files in our filesystem.  Don't warn about -EEXIST errors
+ * when we are re-scanning the backing store looking to add new
+ * error records.
+ */
+void pstore_get_records(int quiet)
+{
+       struct pstore_info *psi = psinfo;
+       struct dentry *root;
+
+       if (!psi || !pstore_sb)
+               return;
+
+       root = pstore_sb->s_root;
+
+       inode_lock(d_inode(root));
+       pstore_get_backend_records(psi, root, quiet);
+       inode_unlock(d_inode(root));
+}
+
 static int pstore_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct inode *inode;