262 строки
6.5 KiB
C
262 строки
6.5 KiB
C
|
/*
|
||
|
* JFFS -- Journaling Flash File System, Linux implementation.
|
||
|
*
|
||
|
* Copyright (C) 2000 Axis Communications AB.
|
||
|
*
|
||
|
* Created by Simon Kagstrom <simonk@axis.com>.
|
||
|
*
|
||
|
* $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 <linux/errno.h>
|
||
|
#include <linux/fs.h>
|
||
|
#include <linux/jffs.h>
|
||
|
#include <linux/slab.h>
|
||
|
#include <linux/proc_fs.h>
|
||
|
#include <linux/time.h>
|
||
|
#include <linux/types.h>
|
||
|
#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;
|
||
|
}
|