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