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 */
jffs_register_jffs_proc_dir(kdev_t dev,struct jffs_control * c)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 */
jffs_unregister_jffs_proc_dir(struct jffs_control * c)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 */
jffs_proc_info_read(char * page,char ** start,off_t off,int count,int * eof,void * data)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 */
jffs_proc_layout_read(char * page,char ** start,off_t off,int count,int * eof,void * data)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 }
270