cleanup
[linux-2.4.git] / fs / jffs / jffs_proc.c
1 /*
2  * JFFS -- Journaling Flash File System, Linux implementation.
3  *
4  * Copyright (C) 2000  Axis Communications AB.
5  *
6  * Created by Simon Kagstrom <simonk@axis.com>.
7  *
8  * $Id: jffs_proc.c,v 1.5 2001/06/02 14:34:55 dwmw2 Exp $
9  *
10  * This is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  *  Overview:
16  *   This file defines JFFS partition entries in the proc file system.
17  *
18  *  TODO:
19  *   Create some more proc files for different kinds of info, i.e. statistics
20  *   about written and read bytes, number of calls to different routines,
21  *   reports about failures.
22  */
23
24 #include <linux/errno.h>
25 #include <linux/fs.h>
26 #include <linux/jffs.h>
27 #include <linux/slab.h>
28 #include <linux/proc_fs.h>
29 #include <linux/sched.h>
30 #include <linux/types.h>
31 #include "jffs_fm.h"
32 #include "jffs_proc.h"
33
34 /*
35  * Structure for a JFFS partition in the system
36  */
37 struct jffs_partition_dir {
38         struct jffs_control *c;
39         struct proc_dir_entry *part_root;
40         struct proc_dir_entry *part_info;
41         struct proc_dir_entry *part_layout;
42         struct jffs_partition_dir *next;
43 };
44
45 /*
46  * Structure for top-level entry in '/proc/fs' directory
47  */
48 struct proc_dir_entry *jffs_proc_root;
49
50 /*
51  * Linked list of 'jffs_partition_dirs' to help us track
52  * the mounted JFFS partitions in the system
53  */
54 static struct jffs_partition_dir *jffs_part_dirs = 0;
55
56 /*
57  * Read functions for entries
58  */
59 static int jffs_proc_info_read(char *page, char **start, off_t off,
60                 int count, int *eof, void *data);
61 static int jffs_proc_layout_read (char *page, char **start, off_t off,
62                 int count, int *eof, void *data);
63
64
65 /*
66  * Register a JFFS partition directory (called upon mount)
67  */
68 int jffs_register_jffs_proc_dir(kdev_t dev, struct jffs_control *c)
69 {
70         struct jffs_partition_dir *part_dir;
71         struct proc_dir_entry *part_info = 0;
72         struct proc_dir_entry *part_layout = 0;
73         struct proc_dir_entry *part_root = 0;
74
75         /* Allocate structure for local JFFS partition table */
76         if (!(part_dir = (struct jffs_partition_dir *)
77                 kmalloc (sizeof (struct jffs_partition_dir), GFP_KERNEL))) {
78                 return -ENOMEM;
79         }
80
81         /* Create entry for this partition */
82         if ((part_root = create_proc_entry (kdevname(dev),
83                 S_IFDIR | S_IRUGO | S_IXUGO, jffs_proc_root))) {
84                 part_root->read_proc = jffs_proc_info_read;
85                 part_root->data = (void *) c;
86         }
87         else {
88                 kfree (part_dir);
89                 return -ENOMEM;
90         }
91
92         /* Create entry for 'info' file */
93         if ((part_info = create_proc_entry ("info", 0, part_root))) {
94                 part_info->read_proc = jffs_proc_info_read;
95                 part_info->data = (void *) c;
96         }
97         else {
98                 remove_proc_entry (part_root->name, jffs_proc_root);
99                 kfree (part_dir);
100                 return -ENOMEM;
101         }
102
103         /* Create entry for 'layout' file */
104         if ((part_layout = create_proc_entry ("layout", 0, part_root))) {
105                 part_layout->read_proc = jffs_proc_layout_read;
106                 part_layout->data = (void *) c;
107         }
108         else {
109                 remove_proc_entry (part_info->name, part_root);
110                 remove_proc_entry (part_root->name, jffs_proc_root);
111                 kfree (part_dir);
112                 return -ENOMEM;
113         }
114
115         /* Fill in structure for table and insert in the list */
116         part_dir->c = c;
117         part_dir->part_root = part_root;
118         part_dir->part_info = part_info;
119         part_dir->part_layout = part_layout;
120         part_dir->next = jffs_part_dirs;
121         jffs_part_dirs = part_dir;
122
123         /* Return happy */
124         return 0;
125 }
126
127
128 /*
129  * Unregister a JFFS partition directory (called at umount)
130  */
131 int jffs_unregister_jffs_proc_dir(struct jffs_control *c)
132 {
133         struct jffs_partition_dir *part_dir = jffs_part_dirs;
134         struct jffs_partition_dir *prev_part_dir = 0;
135
136         while (part_dir) {
137                 if (part_dir->c == c) {
138                         /* Remove entries for partition */
139                         remove_proc_entry (part_dir->part_info->name,
140                                 part_dir->part_root);
141                         remove_proc_entry (part_dir->part_layout->name,
142                                 part_dir->part_root);
143                         remove_proc_entry (part_dir->part_root->name,
144                                 jffs_proc_root);
145
146                         /* Remove entry from list */
147                         if (prev_part_dir)
148                                 prev_part_dir->next = part_dir->next;
149                         else
150                                 jffs_part_dirs = part_dir->next;
151
152                         /*
153                          * Check to see if this is the last one
154                          * and remove the entry from '/proc/fs'
155                          * if it is.
156                          */
157                         if (jffs_part_dirs == part_dir->next)
158 #if LINUX_VERSION_CODE < 0x020300
159                                 remove_proc_entry ("jffs", &proc_root_fs);
160 #else
161                                 remove_proc_entry ("jffs", proc_root_fs);
162 #endif
163
164                         /* Free memory for entry */
165                         kfree(part_dir);
166
167                         /* Return happy */
168                         return 0;
169                 }
170
171                 /* Move to next entry */
172                 prev_part_dir = part_dir;
173                 part_dir = part_dir->next;
174         }
175
176         /* Return unhappy */
177         return -1;
178 }
179
180
181 /*
182  * Read a JFFS partition's `info' file
183  */
184 static int jffs_proc_info_read (char *page, char **start, off_t off,
185                 int count, int *eof, void *data)
186 {
187         struct jffs_control *c = (struct jffs_control *) data;
188         int len = 0;
189
190         /* Get information on the parition */
191         len += sprintf (page,
192                 "partition size:     %08lX (%u)\n"
193                 "sector size:        %08lX (%u)\n"
194                 "used size:          %08lX (%u)\n"
195                 "dirty size:         %08lX (%u)\n"
196                 "free size:          %08lX (%u)\n\n",
197                 (unsigned long) c->fmc->flash_size, c->fmc->flash_size,
198                 (unsigned long) c->fmc->sector_size, c->fmc->sector_size,
199                 (unsigned long) c->fmc->used_size, c->fmc->used_size,
200                 (unsigned long) c->fmc->dirty_size, c->fmc->dirty_size,
201                 (unsigned long) (c->fmc->flash_size -
202                         (c->fmc->used_size + c->fmc->dirty_size)),
203                 c->fmc->flash_size - (c->fmc->used_size + c->fmc->dirty_size));
204
205         /* We're done */
206         *eof = 1;
207
208         /* Return length */
209         return len;
210 }
211
212
213 /*
214  * Read a JFFS partition's `layout' file
215  */
216 static int jffs_proc_layout_read (char *page, char **start, off_t off,
217                 int count, int *eof, void *data)
218 {
219         struct jffs_control *c = (struct jffs_control *) data;
220         struct jffs_fm *fm = 0;
221         struct jffs_fm *last_fm = 0;
222         int len = 0;
223
224         /* Get the first item in the list */
225         fm = c->fmc->head;
226
227         /* Print free space */
228         if (fm && fm->offset) {
229                 len += sprintf (page, "00000000 %08lX free\n",
230                         (unsigned long) fm->offset);
231         }
232
233         /* Loop through all of the flash control structures */
234         while (fm && (len < (off + count))) {
235                 if (fm->nodes) {
236                         len += sprintf (page + len,
237                                 "%08lX %08lX ino=%08lX, ver=%08lX\n",
238                                 (unsigned long) fm->offset,
239                                 (unsigned long) fm->size,
240                                 (unsigned long) fm->nodes->node->ino,
241                                 (unsigned long) fm->nodes->node->version);
242                 }
243                 else {
244                         len += sprintf (page + len,
245                                 "%08lX %08lX dirty\n",
246                                 (unsigned long) fm->offset,
247                                 (unsigned long) fm->size);
248                 }
249                 last_fm = fm;
250                 fm = fm->next;
251         }
252
253         /* Print free space */
254         if ((len < (off + count)) && last_fm
255             && (last_fm->offset < c->fmc->flash_size)) {
256                 len += sprintf (page + len,
257                                "%08lX %08lX free\n",
258                                (unsigned long) last_fm->offset + 
259                                 last_fm->size,
260                                (unsigned long) (c->fmc->flash_size -
261                                                     (last_fm->offset + last_fm->size)));
262         }
263
264         /* We're done */
265         *eof = 1;
266
267         /* Return length */
268         return len;
269 }