/* * JFFS -- Journaling Flash File System, Linux implementation. * * Copyright (C) 2000 Axis Communications AB. * * Created by Simon Kagstrom . * * $Id: jffs_proc.c,v 1.5 2001/06/02 14:34:55 dwmw2 Exp $ * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Overview: * This file defines JFFS partition entries in the proc file system. * * TODO: * Create some more proc files for different kinds of info, i.e. statistics * about written and read bytes, number of calls to different routines, * reports about failures. */ #include #include #include #include #include #include #include #include "jffs_fm.h" #include "jffs_proc.h" /* * Structure for a JFFS partition in the system */ struct jffs_partition_dir { struct jffs_control *c; struct proc_dir_entry *part_root; struct proc_dir_entry *part_info; struct proc_dir_entry *part_layout; struct jffs_partition_dir *next; }; /* * Structure for top-level entry in '/proc/fs' directory */ struct proc_dir_entry *jffs_proc_root; /* * Linked list of 'jffs_partition_dirs' to help us track * the mounted JFFS partitions in the system */ static struct jffs_partition_dir *jffs_part_dirs; /* * Read functions for entries */ static int jffs_proc_info_read(char *page, char **start, off_t off, int count, int *eof, void *data); static int jffs_proc_layout_read (char *page, char **start, off_t off, int count, int *eof, void *data); /* * Register a JFFS partition directory (called upon mount) */ int jffs_register_jffs_proc_dir(int mtd, struct jffs_control *c) { struct jffs_partition_dir *part_dir; struct proc_dir_entry *part_info = NULL; struct proc_dir_entry *part_layout = NULL; struct proc_dir_entry *part_root = NULL; char name[10]; sprintf(name, "%d", mtd); /* Allocate structure for local JFFS partition table */ part_dir = (struct jffs_partition_dir *) kmalloc(sizeof (struct jffs_partition_dir), GFP_KERNEL); if (!part_dir) goto out; /* Create entry for this partition */ part_root = proc_mkdir(name, jffs_proc_root); if (!part_root) goto out1; /* Create entry for 'info' file */ part_info = create_proc_entry ("info", 0, part_root); if (!part_info) goto out2; part_info->read_proc = jffs_proc_info_read; part_info->data = (void *) c; /* Create entry for 'layout' file */ part_layout = create_proc_entry ("layout", 0, part_root); if (!part_layout) goto out3; part_layout->read_proc = jffs_proc_layout_read; part_layout->data = (void *) c; /* Fill in structure for table and insert in the list */ part_dir->c = c; part_dir->part_root = part_root; part_dir->part_info = part_info; part_dir->part_layout = part_layout; part_dir->next = jffs_part_dirs; jffs_part_dirs = part_dir; /* Return happy */ return 0; out3: remove_proc_entry("info", part_root); out2: remove_proc_entry(name, jffs_proc_root); out1: kfree(part_dir); out: return -ENOMEM; } /* * Unregister a JFFS partition directory (called at umount) */ int jffs_unregister_jffs_proc_dir(struct jffs_control *c) { struct jffs_partition_dir *part_dir = jffs_part_dirs; struct jffs_partition_dir *prev_part_dir = NULL; while (part_dir) { if (part_dir->c == c) { /* Remove entries for partition */ remove_proc_entry (part_dir->part_info->name, part_dir->part_root); remove_proc_entry (part_dir->part_layout->name, part_dir->part_root); remove_proc_entry (part_dir->part_root->name, jffs_proc_root); /* Remove entry from list */ if (prev_part_dir) prev_part_dir->next = part_dir->next; else jffs_part_dirs = part_dir->next; /* * Check to see if this is the last one * and remove the entry from '/proc/fs' * if it is. */ if (jffs_part_dirs == part_dir->next) remove_proc_entry ("jffs", proc_root_fs); /* Free memory for entry */ kfree(part_dir); /* Return happy */ return 0; } /* Move to next entry */ prev_part_dir = part_dir; part_dir = part_dir->next; } /* Return unhappy */ return -1; } /* * Read a JFFS partition's `info' file */ static int jffs_proc_info_read (char *page, char **start, off_t off, int count, int *eof, void *data) { struct jffs_control *c = (struct jffs_control *) data; int len = 0; /* Get information on the parition */ len += sprintf (page, "partition size: %08lX (%u)\n" "sector size: %08lX (%u)\n" "used size: %08lX (%u)\n" "dirty size: %08lX (%u)\n" "free size: %08lX (%u)\n\n", (unsigned long) c->fmc->flash_size, c->fmc->flash_size, (unsigned long) c->fmc->sector_size, c->fmc->sector_size, (unsigned long) c->fmc->used_size, c->fmc->used_size, (unsigned long) c->fmc->dirty_size, c->fmc->dirty_size, (unsigned long) (c->fmc->flash_size - (c->fmc->used_size + c->fmc->dirty_size)), c->fmc->flash_size - (c->fmc->used_size + c->fmc->dirty_size)); /* We're done */ *eof = 1; /* Return length */ return len; } /* * Read a JFFS partition's `layout' file */ static int jffs_proc_layout_read (char *page, char **start, off_t off, int count, int *eof, void *data) { struct jffs_control *c = (struct jffs_control *) data; struct jffs_fm *fm = NULL; struct jffs_fm *last_fm = NULL; int len = 0; /* Get the first item in the list */ fm = c->fmc->head; /* Print free space */ if (fm && fm->offset) { len += sprintf (page, "00000000 %08lX free\n", (unsigned long) fm->offset); } /* Loop through all of the flash control structures */ while (fm && (len < (off + count))) { if (fm->nodes) { len += sprintf (page + len, "%08lX %08lX ino=%08lX, ver=%08lX\n", (unsigned long) fm->offset, (unsigned long) fm->size, (unsigned long) fm->nodes->node->ino, (unsigned long) fm->nodes->node->version); } else { len += sprintf (page + len, "%08lX %08lX dirty\n", (unsigned long) fm->offset, (unsigned long) fm->size); } last_fm = fm; fm = fm->next; } /* Print free space */ if ((len < (off + count)) && last_fm && (last_fm->offset < c->fmc->flash_size)) { len += sprintf (page + len, "%08lX %08lX free\n", (unsigned long) last_fm->offset + last_fm->size, (unsigned long) (c->fmc->flash_size - (last_fm->offset + last_fm->size))); } /* We're done */ *eof = 1; /* Return length */ return len; }