]>
Commit | Line | Data |
---|---|---|
37fad6fa | 1 | diff -Nuar -X /home/stevel/dontdiff main.orig/Documentation/filesystems/pramfs.txt main/Documentation/filesystems/pramfs.txt |
2 | --- main.orig/Documentation/filesystems/pramfs.txt 1969-12-31 16:00:00.000000000 -0800 | |
3 | +++ main/Documentation/filesystems/pramfs.txt 2004-03-05 09:25:23.000000000 -0800 | |
4 | @@ -0,0 +1,176 @@ | |
5 | +PRAMFS Overview | |
6 | +=============== | |
7 | + | |
8 | +Many embedded systems have a block of non-volatile RAM seperate from | |
9 | +normal system memory, i.e. of which the kernel maintains no memory page | |
10 | +descriptors. For such systems it would be beneficial to mount a | |
11 | +fast read/write filesystem over this "I/O memory", for storing frequently | |
12 | +accessed data that must survive system reboots and power cycles. An | |
13 | +example usage might be system logs under /var/log, or a user address | |
14 | +book in a cell phone or PDA. | |
15 | + | |
16 | +Linux traditionally had no support for a persistent, non-volatile RAM-based | |
17 | +filesystem, persistent meaning the filesystem survives a system reboot | |
18 | +or power cycle intact. The RAM-based filesystems such as tmpfs and ramfs | |
19 | +have no actual backing store but exist entirely in the page and buffer | |
20 | +caches, hence the filesystem disappears after a system reboot or | |
21 | +power cycle. | |
22 | + | |
23 | +A relatively straight-forward solution is to write a simple block driver | |
24 | +for the non-volatile RAM, and mount over it any disk-based filesystem such | |
25 | +as ext2/ext3, reiserfs, etc. | |
26 | + | |
27 | +But the disk-based fs over non-volatile RAM block driver approach has | |
28 | +some drawbacks: | |
29 | + | |
30 | +1. Disk-based filesystems such as ext2/ext3 were designed for optimum | |
31 | + performance on spinning disk media, so they implement features such | |
32 | + as block groups, which attempts to group inode data into a contiguous | |
33 | + set of data blocks to minimize disk seeking when accessing files. For | |
34 | + RAM there is no such concern; a file's data blocks can be scattered | |
35 | + throughout the media with no access speed penalty at all. So block | |
36 | + groups in a filesystem mounted over RAM just adds unnecessary | |
37 | + complexity. A better approach is to use a filesystem specifically | |
38 | + tailored to RAM media which does away with these disk-based features. | |
39 | + This increases the efficient use of space on the media, i.e. more | |
40 | + space is dedicated to actual file data storage and less to meta-data | |
41 | + needed to maintain that file data. | |
42 | + | |
43 | +2. If the backing-store RAM is comparable in access speed to system memory, | |
44 | + there's really no point in caching the file I/O data in the page | |
45 | + cache. Better to move file data directly between the user buffers | |
46 | + and the backing store RAM, i.e. use direct I/O. This prevents the | |
47 | + unnecessary populating of the page cache with dirty pages. However | |
48 | + direct I/O has to be enabled at every file open. To enable direct | |
49 | + I/O at all times for all regular files requires either that | |
50 | + applications be modified to include the O_DIRECT flag on all file | |
51 | + opens, or that a new filesystem be used that always performs direct | |
52 | + I/O by default. | |
53 | + | |
54 | +The Persistent/Protected RAM Special Filesystem (PRAMFS) is a | |
55 | +full-featured read/write filesystem that has been designed to address | |
56 | +these issues. PRAMFS is targeted to fast I/O memory, and if the memory | |
57 | +is non-volatile, the filesystem will be persistent. | |
58 | + | |
59 | +In PRAMFS, direct I/O is enabled across all files in the filesystem, in | |
60 | +other words the O_DIRECT flag is forced on every open of a PRAMFS file. | |
61 | +Also, file I/O in the PRAMFS is always synchronous. There is no need | |
62 | +to block the current process while the transfer to/from the PRAMFS | |
63 | +is in progress, since one of the requirements of the PRAMFS is that the | |
64 | +filesystem exist in fast RAM. So file I/O in PRAMFS is always direct, | |
65 | +synchronous, and never blocks. | |
66 | + | |
67 | +The data organization in PRAMFS can be thought of as an extremely | |
68 | +simplified version of ext2, such that the ratio of data to meta-data is | |
69 | +very high. | |
70 | + | |
71 | +PRAMFS is also write protected. The page table entries that map the | |
72 | +backing-store RAM are normally marked read-only. Write operations into | |
73 | +the filesystem temporarily mark the affected pages as writeable, the | |
74 | +write operation is carried out with locks held, and then the pte is | |
75 | +marked read-only again. This feature provides some protection against | |
76 | +filesystem corruption caused by errant writes into the RAM due to | |
77 | +kernel bugs for instance. In case there are systems where the write | |
78 | +protection is not possible (for instance the RAM cannot be mapped | |
79 | +with page tables), this feature can be disabled with the CONFIG_PRAMFS_NOWP | |
80 | +config option. | |
81 | + | |
82 | +In summary, PRAMFS is a light-weight, full-featured, and space-efficient | |
83 | +special filesystem that is ideal for systems with a block of fast | |
84 | +non-volatile RAM that need to access data on it using a standard | |
85 | +filesytem interface. | |
86 | + | |
87 | + | |
88 | +Supported mount options | |
89 | +======================= | |
90 | + | |
91 | +The PRAMFS currently requires one mount option, and there are several | |
92 | +optional mount options: | |
93 | + | |
94 | +physaddr= Required. It tells PRAMFS the physical address of the | |
95 | + start of the RAM that makes up the filesystem. The | |
96 | + physical address must be located on a page boundary. | |
97 | + | |
98 | +init= Optional. It is used to initialize the memory to an | |
99 | + empty filesystem. Any data in an existing filesystem | |
100 | + will be lost if this option is given. The parameter to | |
101 | + "init=" is the RAM size in bytes. | |
102 | + | |
103 | +bs= Optional. It is used to specify a block size. It is | |
104 | + ignored if the "init=" option is not specified, since | |
105 | + otherwise the block size is read from the PRAMFS | |
106 | + super-block. The default blocksize is 2048 bytes, | |
107 | + and the allowed block sizes are 512, 1024, 2048, and | |
108 | + 4096. | |
109 | + | |
110 | +bpi= Optional. It is used to specify the bytes per inode | |
111 | + ratio, i.e. For every N bytes in the filesystem, an | |
112 | + inode will be created. This behaves the same as the "-i" | |
113 | + option to mke2fs. It is ignored if the "init=" option is | |
114 | + not specified. | |
115 | + | |
116 | +N= Optional. It is used to specify the number of inodes to | |
117 | + allocate in the inode table. If the option is not | |
118 | + specified, the bytes-per-inode ratio is used the | |
119 | + calculate the number of inodes. If neither the "N=" or | |
120 | + "bpi=" options are specified, the default behavior is to | |
121 | + reserve 5% of the total space in the filesystem for the | |
122 | + inode table. This option behaves the same as the "-N" | |
123 | + option to mke2fs. It is ignored if the "init=" option is | |
124 | + not specified. | |
125 | + | |
126 | +Examples: | |
127 | + | |
128 | +mount -t pramfs -o physaddr=0x20000000,init=0x2F000,bs=1024 none /mnt/pram | |
129 | + | |
130 | +This example locates the filesystem at physical address 0x20000000, and | |
131 | +also requests an empty filesystem be initialized, of total size 0x2f000 | |
132 | +bytes and blocksize 1024. The mount point is /mnt/pram. | |
133 | + | |
134 | +mount -t pramfs -o physaddr=0x20000000 none /mnt/pram | |
135 | + | |
136 | +This example locates the filesystem at physical address 0x20000000 as in | |
137 | +the first example, but uses the intact filesystem that already exists. | |
138 | + | |
139 | + | |
140 | +Current Limitations | |
141 | +=================== | |
142 | + | |
143 | +- The RAM used for PRAMFS must be directly addressable. | |
144 | + | |
145 | +- PRAMFS does not support hard links. | |
146 | + | |
147 | +- PRAMFS supports only private memory mappings. This allows most | |
148 | + executables to run, but programs that attempt shared memory | |
149 | + mappings, such as X apps that use X shared memory, will fail. | |
150 | + | |
151 | +Further Documentation | |
152 | +===================== | |
153 | + | |
154 | +If you are interested in the internal design of PRAMFS, there is | |
155 | +documentation available at the Sourceforge PRAMFS home page at | |
156 | +http://pramfs.sourceforge.net. | |
157 | + | |
158 | +Please send bug reports/comments/feed back to the pramfs development | |
159 | +list at sourceforge: pramfs-devel@lists.sourceforge.net. | |
160 | + | |
161 | + | |
162 | +ChangeLog | |
163 | +========= | |
164 | + | |
165 | +1.0.2: | |
166 | + - kernel 2.6.4. | |
167 | + - use pram_truncate() in pram_delete_inode(). | |
168 | + - dangling pram_lock_inode() removed in pram_truncate_blocks(). | |
169 | + - edits to this README | |
170 | + | |
171 | +1.0.1: | |
172 | + - port to kernel 2.6.3. | |
173 | + - implement direct_IO() method instead of custom file read/write | |
174 | + methods. | |
175 | + - do away with __ioremap_readonly() requirement. | |
176 | + - implement inode truncate() method. | |
177 | + | |
178 | +1.0.0: | |
179 | + - Started ChangeLog (kernel 2.4.22). | |
180 | + | |
181 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/Kconfig main/fs/Kconfig | |
182 | --- main.orig/fs/Kconfig 2004-03-04 17:15:10.000000000 -0800 | |
183 | +++ main/fs/Kconfig 2004-03-04 15:58:57.000000000 -0800 | |
184 | @@ -885,6 +885,27 @@ | |
185 | To compile this as a module, choose M here: the module will be called | |
186 | ramfs. | |
187 | ||
188 | +config PRAMFS | |
189 | + tristate "Persistent and Protected RAM file system support" | |
190 | + help | |
191 | + If your system has a block of fast (comparable in access speed to | |
192 | + system memory) and non-volatile RAM and you wish to mount a | |
193 | + light-weight, full-featured, and space-efficient filesystem over it, | |
194 | + say Y here, and read <file:Documentation/filesystems/pramfs.txt>. | |
195 | + | |
196 | + To compile this as a module, choose M here: the module will be | |
197 | + called pramfs. | |
198 | + | |
199 | +config PRAMFS_NOWP | |
200 | + bool "Disable write protection (default is enabled)" | |
201 | + depends on PRAMFS | |
202 | + help | |
203 | + Say Y here to disable the write protect feature of PRAMFS. | |
204 | + | |
205 | +config ROOT_PRAMFS | |
206 | + bool "Root file system on pramfs" | |
207 | + depends on PRAMFS | |
208 | + | |
209 | endmenu | |
210 | ||
211 | menu "Miscellaneous filesystems" | |
212 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/Makefile main/fs/Makefile | |
213 | --- main.orig/fs/Makefile 2004-03-04 17:15:10.000000000 -0800 | |
214 | +++ main/fs/Makefile 2004-03-04 15:58:57.000000000 -0800 | |
215 | @@ -51,6 +51,7 @@ | |
216 | obj-$(CONFIG_EXT2_FS) += ext2/ | |
217 | obj-$(CONFIG_CRAMFS) += cramfs/ | |
218 | obj-$(CONFIG_RAMFS) += ramfs/ | |
219 | +obj-$(CONFIG_PRAMFS) += pramfs/ | |
220 | obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ | |
221 | obj-$(CONFIG_CODA_FS) += coda/ | |
222 | obj-$(CONFIG_INTERMEZZO_FS) += intermezzo/ | |
223 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/balloc.c main/fs/pramfs/balloc.c | |
224 | --- main.orig/fs/pramfs/balloc.c 1969-12-31 16:00:00.000000000 -0800 | |
225 | +++ main/fs/pramfs/balloc.c 2004-03-04 15:59:03.000000000 -0800 | |
226 | @@ -0,0 +1,163 @@ | |
227 | +/* | |
228 | + * balloc.c | |
229 | + * | |
230 | + * The blocks allocation and deallocation routines. | |
231 | + * | |
232 | + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> | |
233 | + * | |
234 | + * 2003 (c) MontaVista Software, Inc. | |
235 | + * Copyright 2003 Sony Corporation | |
236 | + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. | |
237 | + * | |
238 | + * This software is being distributed under the terms of the GNU General Public | |
239 | + * License version 2. Some or all of the technology encompassed by this | |
240 | + * software may be subject to one or more patents pending as of the date of | |
241 | + * this notice. No additional patent license will be required for GPL | |
242 | + * implementations of the technology. If you want to create a non-GPL | |
243 | + * implementation of the technology encompassed by this software, please | |
244 | + * contact legal@mvista.com for details including licensing terms and fees. | |
245 | + * | |
246 | + * This file is licensed under the terms of the GNU General Public License | |
247 | + * version 2. This program is licensed "as is" without any warranty of any | |
248 | + * kind, whether express or implied. | |
249 | + */ | |
250 | +#include <linux/config.h> | |
251 | +#include <linux/fs.h> | |
252 | +#include <linux/pram_fs.h> | |
253 | +#include <linux/quotaops.h> | |
254 | +#include <asm/bitops.h> | |
255 | + | |
256 | + | |
257 | +/* | |
258 | + * This just marks in-use the blocks that make up the bitmap. | |
259 | + * The bitmap must be writeable before calling. | |
260 | + */ | |
261 | +void pram_init_bitmap(struct super_block * sb) | |
262 | +{ | |
263 | + struct pram_super_block * ps = pram_get_super(sb); | |
264 | + u32* bitmap = pram_get_bitmap(sb); | |
265 | + int blocks = ps->s_bitmap_blocks; | |
266 | + | |
267 | + memset(bitmap, 0, blocks<<sb->s_blocksize_bits); | |
268 | + | |
269 | + while (blocks >= 32) { | |
270 | + *bitmap++ = 0xffffffff; | |
271 | + blocks -= 32; | |
272 | + } | |
273 | + | |
274 | + if (blocks) | |
275 | + *bitmap = (1<<blocks) - 1; | |
276 | +} | |
277 | + | |
278 | + | |
279 | +/* Free absolute blocknr */ | |
280 | +void pram_free_block (struct super_block * sb, int blocknr) | |
281 | +{ | |
282 | + struct pram_super_block * ps; | |
283 | + pram_off_t bitmap_block; | |
284 | + unsigned long flags; | |
285 | + int bitmap_bnr; | |
286 | + void* bitmap; | |
287 | + void* bp; | |
288 | + | |
289 | + lock_super (sb); | |
290 | + | |
291 | + bitmap = pram_get_bitmap(sb); | |
292 | + /* | |
293 | + * find the block within the bitmap that contains the inuse bit | |
294 | + * for the block we need to free. We need to unlock this bitmap | |
295 | + * block to clear the inuse bit. | |
296 | + */ | |
297 | + bitmap_bnr = blocknr >> (3 + sb->s_blocksize_bits); | |
298 | + bitmap_block = pram_get_block_off(sb, bitmap_bnr); | |
299 | + bp = pram_get_block(sb, bitmap_block); | |
300 | + | |
301 | + pram_lock_block(sb, bp); | |
302 | + clear_bit(blocknr, bitmap); // mark the block free | |
303 | + pram_unlock_block(sb, bp); | |
304 | + | |
305 | + ps = pram_get_super(sb); | |
306 | + pram_lock_super(ps); | |
307 | + if (blocknr < ps->s_free_blocknr_hint) | |
308 | + ps->s_free_blocknr_hint = blocknr; | |
309 | + ps->s_free_blocks_count++; | |
310 | + pram_unlock_super(ps); | |
311 | + | |
312 | + unlock_super (sb); | |
313 | +} | |
314 | + | |
315 | + | |
316 | +/* | |
317 | + * allocate a block and return it's absolute blocknr. Zeroes out the | |
318 | + * block if zero set. | |
319 | + */ | |
320 | +int pram_new_block (struct super_block * sb, int* blocknr, int zero) | |
321 | +{ | |
322 | + struct pram_super_block * ps; | |
323 | + pram_off_t bitmap_block; | |
324 | + unsigned long flags; | |
325 | + int bnr, bitmap_bnr, errval; | |
326 | + void* bitmap; | |
327 | + void* bp; | |
328 | + | |
329 | + lock_super (sb); | |
330 | + ps = pram_get_super(sb); | |
331 | + bitmap = pram_get_bitmap(sb); | |
332 | + | |
333 | + if (ps->s_free_blocks_count) { | |
334 | + /* find the oldest unused block */ | |
335 | + bnr = find_next_zero_bit(bitmap, | |
336 | + ps->s_blocks_count, | |
337 | + ps->s_free_blocknr_hint); | |
338 | + | |
339 | + if (bnr < ps->s_bitmap_blocks || bnr >= ps->s_blocks_count) { | |
340 | + pram_err("no free blocks found!\n"); | |
341 | + errval = -ENOSPC; | |
342 | + goto fail; | |
343 | + } | |
344 | + | |
345 | + pram_dbg ("allocating blocknr %d\n", bnr); | |
346 | + pram_lock_super(ps); | |
347 | + ps->s_free_blocks_count--; | |
348 | + ps->s_free_blocknr_hint = | |
349 | + (bnr < ps->s_blocks_count-1) ? bnr+1 : 0; | |
350 | + pram_unlock_super(ps); | |
351 | + } else { | |
352 | + pram_err("all blocks allocated\n"); | |
353 | + errval = -ENOSPC; | |
354 | + goto fail; | |
355 | + } | |
356 | + | |
357 | + /* | |
358 | + * find the block within the bitmap that contains the inuse bit | |
359 | + * for the unused block we just found. We need to unlock it to | |
360 | + * set the inuse bit. | |
361 | + */ | |
362 | + bitmap_bnr = bnr >> (3 + sb->s_blocksize_bits); | |
363 | + bitmap_block = pram_get_block_off(sb, bitmap_bnr); | |
364 | + bp = pram_get_block(sb, bitmap_block); | |
365 | + | |
366 | + pram_lock_block(sb, bp); | |
367 | + set_bit(bnr, bitmap); // mark the new block in use | |
368 | + pram_unlock_block(sb, bp); | |
369 | + | |
370 | + if (zero) { | |
371 | + bp = pram_get_block(sb, pram_get_block_off(sb, bnr)); | |
372 | + pram_lock_block(sb, bp); | |
373 | + memset(bp, 0, sb->s_blocksize); | |
374 | + pram_unlock_block(sb, bp); | |
375 | + } | |
376 | + | |
377 | + *blocknr = bnr; | |
378 | + errval = 0; | |
379 | + fail: | |
380 | + unlock_super (sb); | |
381 | + return errval; | |
382 | +} | |
383 | + | |
384 | + | |
385 | +unsigned long pram_count_free_blocks (struct super_block * sb) | |
386 | +{ | |
387 | + struct pram_super_block * ps = pram_get_super(sb); | |
388 | + return ps->s_free_blocks_count; | |
389 | +} | |
390 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/dir.c main/fs/pramfs/dir.c | |
391 | --- main.orig/fs/pramfs/dir.c 1969-12-31 16:00:00.000000000 -0800 | |
392 | +++ main/fs/pramfs/dir.c 2004-03-04 15:59:03.000000000 -0800 | |
393 | @@ -0,0 +1,225 @@ | |
394 | +/* | |
395 | + * dir.c | |
396 | + * | |
397 | + * File operations for directories. | |
398 | + * | |
399 | + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> | |
400 | + * | |
401 | + * 2003 (c) MontaVista Software, Inc. | |
402 | + * Copyright 2003 Sony Corporation | |
403 | + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. | |
404 | + * | |
405 | + * This software is being distributed under the terms of the GNU General Public | |
406 | + * License version 2. Some or all of the technology encompassed by this | |
407 | + * software may be subject to one or more patents pending as of the date of | |
408 | + * this notice. No additional patent license will be required for GPL | |
409 | + * implementations of the technology. If you want to create a non-GPL | |
410 | + * implementation of the technology encompassed by this software, please | |
411 | + * contact legal@mvista.com for details including licensing terms and fees. | |
412 | + * | |
413 | + * This file is licensed under the terms of the GNU General Public License | |
414 | + * version 2. This program is licensed "as is" without any warranty of any | |
415 | + * kind, whether express or implied. | |
416 | + */ | |
417 | + | |
418 | +#include <linux/fs.h> | |
419 | +#include <linux/pram_fs.h> | |
420 | +#include <linux/pagemap.h> | |
421 | + | |
422 | + | |
423 | +/* | |
424 | + * Parent is locked. | |
425 | + */ | |
426 | +int pram_add_link (struct dentry * dentry, struct inode * inode) | |
427 | +{ | |
428 | + struct inode * dir = dentry->d_parent->d_inode; | |
429 | + struct pram_inode * pidir, * pi, * pitail = NULL; | |
430 | + unsigned long flags; | |
431 | + pram_off_t tail_ino, prev_ino; | |
432 | + const char *name = dentry->d_name.name; | |
433 | + int namelen = dentry->d_name.len > PRAM_NAME_LEN ? | |
434 | + PRAM_NAME_LEN : dentry->d_name.len; | |
435 | + | |
436 | + pidir = pram_get_inode(dir->i_sb, dir->i_ino); | |
437 | + pi = pram_get_inode(dir->i_sb, inode->i_ino); | |
438 | + | |
439 | + dir->i_mtime = dir->i_ctime = CURRENT_TIME; | |
440 | + | |
441 | + tail_ino = pidir->i_type.dir.tail; | |
442 | + if (tail_ino != 0) { | |
443 | + pitail = pram_get_inode(dir->i_sb, tail_ino); | |
444 | + pram_lock_inode(pitail); | |
445 | + pitail->i_d.d_next = inode->i_ino; | |
446 | + pram_unlock_inode(pitail); | |
447 | + | |
448 | + prev_ino = tail_ino; | |
449 | + | |
450 | + pram_lock_inode(pidir); | |
451 | + pidir->i_type.dir.tail = inode->i_ino; | |
452 | + pidir->i_mtime = dir->i_mtime.tv_sec; | |
453 | + pidir->i_ctime = dir->i_ctime.tv_sec; | |
454 | + pram_unlock_inode(pidir); | |
455 | + } else { | |
456 | + // the directory is empty | |
457 | + prev_ino = 0; | |
458 | + | |
459 | + pram_lock_inode(pidir); | |
460 | + pidir->i_type.dir.head = pidir->i_type.dir.tail = inode->i_ino; | |
461 | + pidir->i_mtime = dir->i_mtime.tv_sec; | |
462 | + pidir->i_ctime = dir->i_ctime.tv_sec; | |
463 | + pram_unlock_inode(pidir); | |
464 | + } | |
465 | + | |
466 | + | |
467 | + pram_lock_inode(pi); | |
468 | + pi->i_d.d_prev = prev_ino; | |
469 | + pi->i_d.d_parent = dir->i_ino; | |
470 | + memcpy(pi->i_d.d_name, name, namelen); | |
471 | + pi->i_d.d_name[namelen] = '\0'; | |
472 | + pram_unlock_inode(pi); | |
473 | + return 0; | |
474 | +} | |
475 | + | |
476 | +int pram_remove_link(struct inode * inode) | |
477 | +{ | |
478 | + struct super_block * sb = inode->i_sb; | |
479 | + struct pram_inode * prev = NULL; | |
480 | + struct pram_inode * next = NULL; | |
481 | + struct pram_inode * pidir, * pi; | |
482 | + unsigned long flags; | |
483 | + | |
484 | + pi = pram_get_inode(sb, inode->i_ino); | |
485 | + pidir = pram_get_inode(sb, pi->i_d.d_parent); | |
486 | + if (!pidir) | |
487 | + return -EACCES; | |
488 | + | |
489 | + if (inode->i_ino == pidir->i_type.dir.head) { | |
490 | + // first inode in directory | |
491 | + next = pram_get_inode(sb, pi->i_d.d_next); | |
492 | + | |
493 | + if (next) { | |
494 | + pram_lock_inode(next); | |
495 | + next->i_d.d_prev = 0; | |
496 | + pram_unlock_inode(next); | |
497 | + | |
498 | + pram_lock_inode(pidir); | |
499 | + pidir->i_type.dir.head = pi->i_d.d_next; | |
500 | + } else { | |
501 | + pram_lock_inode(pidir); | |
502 | + pidir->i_type.dir.head = pidir->i_type.dir.tail = 0; | |
503 | + } | |
504 | + pram_unlock_inode(pidir); | |
505 | + } else if (inode->i_ino == pidir->i_type.dir.tail) { | |
506 | + // last inode in directory | |
507 | + prev = pram_get_inode(sb, pi->i_d.d_prev); | |
508 | + | |
509 | + pram_lock_inode(prev); | |
510 | + prev->i_d.d_next = 0; | |
511 | + pram_unlock_inode(prev); | |
512 | + | |
513 | + pram_lock_inode(pidir); | |
514 | + pidir->i_type.dir.tail = pi->i_d.d_prev; | |
515 | + pram_unlock_inode(pidir); | |
516 | + } else { | |
517 | + // somewhere in the middle | |
518 | + prev = pram_get_inode(sb, pi->i_d.d_prev); | |
519 | + next = pram_get_inode(sb, pi->i_d.d_next); | |
520 | + | |
521 | + if (prev && next) { | |
522 | + pram_lock_inode(prev); | |
523 | + prev->i_d.d_next = pi->i_d.d_next; | |
524 | + pram_unlock_inode(prev); | |
525 | + | |
526 | + pram_lock_inode(next); | |
527 | + next->i_d.d_prev = pi->i_d.d_prev; | |
528 | + pram_unlock_inode(next); | |
529 | + } | |
530 | + } | |
531 | + | |
532 | + pram_lock_inode(pi); | |
533 | + pi->i_d.d_next = pi->i_d.d_prev = pi->i_d.d_parent = 0; | |
534 | + pram_unlock_inode(pi); | |
535 | + | |
536 | + return 0; | |
537 | +} | |
538 | + | |
539 | +#define S_SHIFT 12 | |
540 | +static unsigned int dtype_by_mode[S_IFMT >> S_SHIFT] = { | |
541 | + [S_IFREG >> S_SHIFT] DT_REG, | |
542 | + [S_IFDIR >> S_SHIFT] DT_DIR, | |
543 | + [S_IFCHR >> S_SHIFT] DT_CHR, | |
544 | + [S_IFBLK >> S_SHIFT] DT_BLK, | |
545 | + [S_IFIFO >> S_SHIFT] DT_FIFO, | |
546 | + [S_IFSOCK >> S_SHIFT] DT_SOCK, | |
547 | + [S_IFLNK >> S_SHIFT] DT_LNK, | |
548 | +}; | |
549 | + | |
550 | +static int | |
551 | +pram_readdir (struct file * filp, void * dirent, filldir_t filldir) | |
552 | +{ | |
553 | + struct inode *inode = filp->f_dentry->d_inode; | |
554 | + struct super_block * sb = inode->i_sb; | |
555 | + struct pram_inode * pi; | |
556 | + int namelen, ret=0; | |
557 | + char *name; | |
558 | + ino_t ino; | |
559 | + | |
560 | + if (filp->f_pos >> 32) | |
561 | + return 0; | |
562 | + | |
563 | + pi = pram_get_inode(sb, inode->i_ino); | |
564 | + | |
565 | + switch ((unsigned long)filp->f_pos) { | |
566 | + case 0: | |
567 | + ret = filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR); | |
568 | + filp->f_pos++; | |
569 | + return ret; | |
570 | + case 1: | |
571 | + ret = filldir(dirent, "..", 2, 1, pi->i_d.d_parent, DT_DIR); | |
572 | + ino = pi->i_type.dir.head; | |
573 | + filp->f_pos = ino ? ino : 2; | |
574 | + return ret; | |
575 | + case 2: | |
576 | + ino = pi->i_type.dir.head; | |
577 | + if (ino) { | |
578 | + filp->f_pos = ino; | |
579 | + pi = pram_get_inode(sb, ino); | |
580 | + break; | |
581 | + } else { | |
582 | + /* the directory is empty */ | |
583 | + filp->f_pos = 2; | |
584 | + return 0; | |
585 | + } | |
586 | + case 3: | |
587 | + return 0; | |
588 | + default: | |
589 | + ino = filp->f_pos; | |
590 | + pi = pram_get_inode(sb, ino); | |
591 | + break; | |
592 | + } | |
593 | + | |
594 | + while (pi && !pi->i_links_count) { | |
595 | + ino = filp->f_pos = pi->i_d.d_next; | |
596 | + pi = pram_get_inode(sb, ino); | |
597 | + } | |
598 | + | |
599 | + if (pi) { | |
600 | + name = pi->i_d.d_name; | |
601 | + namelen = strlen(name); | |
602 | + | |
603 | + ret = filldir(dirent, name, namelen, | |
604 | + filp->f_pos, ino, | |
605 | + dtype_by_mode[(pi->i_mode & S_IFMT)>>S_SHIFT]); | |
606 | + filp->f_pos = pi->i_d.d_next ? pi->i_d.d_next : 3; | |
607 | + } else | |
608 | + filp->f_pos = 3; | |
609 | + | |
610 | + return ret; | |
611 | +} | |
612 | + | |
613 | +struct file_operations pram_dir_operations = { | |
614 | + read: generic_read_dir, | |
615 | + readdir: pram_readdir, | |
616 | + ioctl: pram_ioctl, | |
617 | + fsync: pram_sync_file, | |
618 | +}; | |
619 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/file.c main/fs/pramfs/file.c | |
620 | --- main.orig/fs/pramfs/file.c 1969-12-31 16:00:00.000000000 -0800 | |
621 | +++ main/fs/pramfs/file.c 2004-03-04 15:59:03.000000000 -0800 | |
622 | @@ -0,0 +1,143 @@ | |
623 | +/* | |
624 | + * file.c | |
625 | + * | |
626 | + * File operations for regular files. | |
627 | + * | |
628 | + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> | |
629 | + * | |
630 | + * 2003 (c) MontaVista Software, Inc. | |
631 | + * Copyright 2003 Sony Corporation | |
632 | + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. | |
633 | + * | |
634 | + * This software is being distributed under the terms of the GNU General Public | |
635 | + * License version 2. Some or all of the technology encompassed by this | |
636 | + * software may be subject to one or more patents pending as of the date of | |
637 | + * this notice. No additional patent license will be required for GPL | |
638 | + * implementations of the technology. If you want to create a non-GPL | |
639 | + * implementation of the technology encompassed by this software, please | |
640 | + * contact legal@mvista.com for details including licensing terms and fees. | |
641 | + * | |
642 | + * This file is licensed under the terms of the GNU General Public License | |
643 | + * version 2. This program is licensed "as is" without any warranty of any | |
644 | + * kind, whether express or implied. | |
645 | + */ | |
646 | +#include <linux/fs.h> | |
647 | +#include <linux/pram_fs.h> | |
648 | +#include <linux/sched.h> | |
649 | +#include <linux/slab.h> | |
650 | +#include <linux/uio.h> | |
651 | +#include <asm/uaccess.h> | |
652 | + | |
653 | +static int pram_open_file(struct inode * inode, struct file * filp) | |
654 | +{ | |
655 | + filp->f_flags |= O_DIRECT; | |
656 | + return generic_file_open(inode, filp); | |
657 | +} | |
658 | + | |
659 | +/* | |
660 | + * Called when an inode is released. Note that this is different | |
661 | + * from pram_open_file: open gets called at every open, but release | |
662 | + * gets called only when /all/ the files are closed. | |
663 | + */ | |
664 | +static int pram_release_file (struct inode * inode, struct file * filp) | |
665 | +{ | |
666 | + return 0; | |
667 | +} | |
668 | + | |
669 | +int pram_direct_IO(int rw, struct kiocb *iocb, | |
670 | + const struct iovec *iov, | |
671 | + loff_t offset, unsigned long nr_segs) | |
672 | +{ | |
673 | + struct file *file = iocb->ki_filp; | |
674 | + struct inode *inode = file->f_mapping->host; | |
675 | + struct super_block * sb = inode->i_sb; | |
676 | + int progress = 0, retval = 0; | |
677 | + struct pram_inode * pi; | |
678 | + void * tmp = NULL; | |
679 | + unsigned long blocknr, blockoff, flags; | |
680 | + int num_blocks, blocksize_mask, blocksize, blocksize_bits; | |
681 | + char __user *buf = iov->iov_base; | |
682 | + size_t length = iov->iov_len; | |
683 | + | |
684 | + if (length < 0) | |
685 | + return -EINVAL; | |
686 | + if ((rw == READ) && (offset + length > inode->i_size)) | |
687 | + length = inode->i_size - offset; | |
688 | + if (!length) | |
689 | + goto out; | |
690 | + | |
691 | + blocksize_bits = inode->i_sb->s_blocksize_bits; | |
692 | + blocksize = 1 << blocksize_bits; | |
693 | + blocksize_mask = blocksize - 1; | |
694 | + | |
695 | + /* find starting block number to access */ | |
696 | + blocknr = offset >> blocksize_bits; | |
697 | + /* find starting offset within starting block */ | |
698 | + blockoff = offset & blocksize_mask; | |
699 | + /* find number of blocks to access */ | |
700 | + num_blocks = (blockoff + length + blocksize_mask) >> blocksize_bits; | |
701 | + | |
702 | + if (rw == WRITE) { | |
703 | + // prepare a temporary buffer to hold a user data block | |
704 | + // for writing. | |
705 | + tmp = kmalloc(blocksize, GFP_KERNEL); | |
706 | + if (!tmp) | |
707 | + return -ENOMEM; | |
708 | + /* now allocate the data blocks we'll need */ | |
709 | + retval = pram_alloc_blocks(inode, blocknr, num_blocks); | |
710 | + if (retval) | |
711 | + goto fail; | |
712 | + } | |
713 | + | |
714 | + pi = pram_get_inode(inode->i_sb, inode->i_ino); | |
715 | + | |
716 | + while (length) { | |
717 | + int count; | |
718 | + pram_off_t block = pram_find_data_block(inode, blocknr++); | |
719 | + u8* bp = (u8*)pram_get_block(sb, block); | |
720 | + if (!bp) | |
721 | + goto fail; | |
722 | + | |
723 | + count = blockoff + length > blocksize ? | |
724 | + blocksize - blockoff : length; | |
725 | + | |
726 | + if (rw == READ) { | |
727 | + copy_to_user(buf, &bp[blockoff], count); | |
728 | + } else { | |
729 | + copy_from_user(tmp, buf, count); | |
730 | + | |
731 | + pram_lock_block(inode->i_sb, bp); | |
732 | + memcpy(&bp[blockoff], tmp, count); | |
733 | + pram_unlock_block(inode->i_sb, bp); | |
734 | + } | |
735 | + | |
736 | + progress += count; | |
737 | + buf += count; | |
738 | + length -= count; | |
739 | + blockoff = 0; | |
740 | + } | |
741 | + | |
742 | + retval = progress; | |
743 | + fail: | |
744 | + if (tmp) | |
745 | + kfree(tmp); | |
746 | + out: | |
747 | + return retval; | |
748 | +} | |
749 | + | |
750 | + | |
751 | + | |
752 | +struct file_operations pram_file_operations = { | |
753 | + llseek: generic_file_llseek, | |
754 | + read: generic_file_read, | |
755 | + write: generic_file_write, | |
756 | + ioctl: pram_ioctl, | |
757 | + mmap: generic_file_mmap, | |
758 | + open: pram_open_file, | |
759 | + release: pram_release_file, | |
760 | + fsync: pram_sync_file, | |
761 | +}; | |
762 | + | |
763 | +struct inode_operations pram_file_inode_operations = { | |
764 | + truncate: pram_truncate, | |
765 | +}; | |
766 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/fsync.c main/fs/pramfs/fsync.c | |
767 | --- main.orig/fs/pramfs/fsync.c 1969-12-31 16:00:00.000000000 -0800 | |
768 | +++ main/fs/pramfs/fsync.c 2004-03-04 15:59:03.000000000 -0800 | |
769 | @@ -0,0 +1,37 @@ | |
770 | +/* | |
771 | + * fsync.c | |
772 | + * | |
773 | + * fsync operation for directory and regular files. | |
774 | + * | |
775 | + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> | |
776 | + * | |
777 | + * 2003 (c) MontaVista Software, Inc. | |
778 | + * Copyright 2003 Sony Corporation | |
779 | + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. | |
780 | + * | |
781 | + * This software is being distributed under the terms of the GNU General Public | |
782 | + * License version 2. Some or all of the technology encompassed by this | |
783 | + * software may be subject to one or more patents pending as of the date of | |
784 | + * this notice. No additional patent license will be required for GPL | |
785 | + * implementations of the technology. If you want to create a non-GPL | |
786 | + * implementation of the technology encompassed by this software, please | |
787 | + * contact legal@mvista.com for details including licensing terms and fees. | |
788 | + * | |
789 | + * This file is licensed under the terms of the GNU General Public License | |
790 | + * version 2. This program is licensed "as is" without any warranty of any | |
791 | + * kind, whether express or implied. | |
792 | + */ | |
793 | +#include <linux/fs.h> | |
794 | +#include <linux/pram_fs.h> | |
795 | + | |
796 | +/* | |
797 | + * File may be NULL when we are called. Perhaps we shouldn't | |
798 | + * even pass file to fsync ? | |
799 | + */ | |
800 | + | |
801 | +int pram_sync_file(struct file * file, struct dentry *dentry, int datasync) | |
802 | +{ | |
803 | + // FIXME: check | |
804 | + return 0; | |
805 | +} | |
806 | + | |
807 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/inode.c main/fs/pramfs/inode.c | |
808 | --- main.orig/fs/pramfs/inode.c 1969-12-31 16:00:00.000000000 -0800 | |
809 | +++ main/fs/pramfs/inode.c 2004-03-04 16:45:11.000000000 -0800 | |
810 | @@ -0,0 +1,649 @@ | |
811 | +/* | |
812 | + * inode.c | |
813 | + * | |
814 | + * Inode methods (allocate/free/read/write). | |
815 | + * | |
816 | + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> | |
817 | + * | |
818 | + * 2003 (c) MontaVista Software, Inc. | |
819 | + * Copyright 2003 Sony Corporation | |
820 | + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. | |
821 | + * | |
822 | + * This software is being distributed under the terms of the GNU General Public | |
823 | + * License version 2. Some or all of the technology encompassed by this | |
824 | + * software may be subject to one or more patents pending as of the date of | |
825 | + * this notice. No additional patent license will be required for GPL | |
826 | + * implementations of the technology. If you want to create a non-GPL | |
827 | + * implementation of the technology encompassed by this software, please | |
828 | + * contact legal@mvista.com for details including licensing terms and fees. | |
829 | + * | |
830 | + * This file is licensed under the terms of the GNU General Public License | |
831 | + * version 2. This program is licensed "as is" without any warranty of any | |
832 | + * kind, whether express or implied. | |
833 | + */ | |
834 | +#include <linux/fs.h> | |
835 | +#include <linux/pram_fs.h> | |
836 | +#include <linux/smp_lock.h> | |
837 | +#include <linux/sched.h> | |
838 | +#include <linux/highuid.h> | |
839 | +#include <linux/quotaops.h> | |
840 | +#include <linux/module.h> | |
841 | +#include <linux/buffer_head.h> | |
842 | +#include <linux/mpage.h> | |
843 | +#include <linux/backing-dev.h> | |
844 | + | |
845 | + | |
846 | +static struct backing_dev_info pram_backing_dev_info = { | |
847 | + .ra_pages = 0, /* No readahead */ | |
848 | + .memory_backed = 1, /* Does not contribute to dirty memory */ | |
849 | +}; | |
850 | + | |
851 | +/* | |
852 | + * allocate a data block for inode and return it's absolute blocknr. | |
853 | + * Zeroes out the block if zero set. Increments inode->i_blocks. | |
854 | + */ | |
855 | +static int | |
856 | +pram_new_data_block (struct inode * inode, int* blocknr, int zero) | |
857 | +{ | |
858 | + unsigned long flags; | |
859 | + int errval = pram_new_block(inode->i_sb, blocknr, zero); | |
860 | + | |
861 | + if (!errval) { | |
862 | + struct pram_inode * pi = pram_get_inode(inode->i_sb, | |
863 | + inode->i_ino); | |
864 | + inode->i_blocks++; | |
865 | + pram_lock_inode(pi); | |
866 | + pi->i_blocks = inode->i_blocks; | |
867 | + pram_unlock_inode(pi); | |
868 | + } | |
869 | + | |
870 | + return errval; | |
871 | +} | |
872 | + | |
873 | +/* | |
874 | + * find the offset to the block represented by the given inode's file | |
875 | + * relative block number. | |
876 | + */ | |
877 | +pram_off_t pram_find_data_block(struct inode * inode, int file_blocknr) | |
878 | +{ | |
879 | + struct super_block * sb = inode->i_sb; | |
880 | + struct pram_inode * pi; | |
881 | + pram_off_t * row; /* ptr to row block */ | |
882 | + pram_off_t * col; /* ptr to column blocks */ | |
883 | + pram_off_t bp = 0; | |
884 | + int i_row, i_col; | |
885 | + int N = sb->s_blocksize >> 2; // num block ptrs per block | |
886 | + int Nbits = sb->s_blocksize_bits - 2; | |
887 | + | |
888 | + pi = pram_get_inode(sb, inode->i_ino); | |
889 | + | |
890 | + i_row = file_blocknr >> Nbits; | |
891 | + i_col = file_blocknr & (N-1); | |
892 | + | |
893 | + row = pram_get_block(sb, pi->i_type.reg.row_block); | |
894 | + if (row) { | |
895 | + col = pram_get_block(sb, row[i_row]); | |
896 | + if (col) | |
897 | + bp = col[i_col]; | |
898 | + } | |
899 | + | |
900 | + return bp; | |
901 | +} | |
902 | + | |
903 | + | |
904 | +/* | |
905 | + * Free data blocks from inode starting at first_trunc_block. | |
906 | + */ | |
907 | +static void | |
908 | +pram_truncate_blocks(struct inode * inode, int first_trunc_block) | |
909 | +{ | |
910 | + struct super_block * sb = inode->i_sb; | |
911 | + struct pram_inode * pi = pram_get_inode(sb, inode->i_ino); | |
912 | + int N = sb->s_blocksize >> 2; // num block ptrs per block | |
913 | + int Nbits = sb->s_blocksize_bits - 2; | |
914 | + int first_row_index, last_row_index; | |
915 | + int i, j, first_blocknr, last_blocknr, blocknr; | |
916 | + unsigned long flags; | |
917 | + pram_off_t * row; /* ptr to row block */ | |
918 | + pram_off_t * col; /* ptr to column blocks */ | |
919 | + | |
920 | + if (first_trunc_block >= inode->i_blocks || | |
921 | + !inode->i_blocks || !pi->i_type.reg.row_block) { | |
922 | + return; | |
923 | + } | |
924 | + | |
925 | + first_blocknr = first_trunc_block; | |
926 | + last_blocknr = inode->i_blocks - 1; | |
927 | + first_row_index = first_blocknr >> Nbits; | |
928 | + last_row_index = last_blocknr >> Nbits; | |
929 | + | |
930 | + row = pram_get_block(sb, pi->i_type.reg.row_block); | |
931 | + | |
932 | + for (i=first_row_index; i <= last_row_index; i++) { | |
933 | + int first_col_index = (i == first_row_index) ? | |
934 | + first_blocknr & (N-1) : 0; | |
935 | + int last_col_index = (i == last_row_index) ? | |
936 | + last_blocknr & (N-1) : N-1; | |
937 | + | |
938 | + col = pram_get_block(sb, row[i]); | |
939 | + for (j=first_col_index; j <= last_col_index; j++) { | |
940 | + blocknr = pram_get_blocknr(sb, col[j]); | |
941 | + pram_free_block(sb, blocknr); | |
942 | + pram_lock_block(sb, col); | |
943 | + col[j] = 0; | |
944 | + pram_unlock_block(sb, col); | |
945 | + } | |
946 | + | |
947 | + if (first_col_index == 0) { | |
948 | + blocknr = pram_get_blocknr(sb, row[i]); | |
949 | + pram_free_block(sb, blocknr); | |
950 | + pram_lock_block(sb, row); | |
951 | + row[i] = 0; | |
952 | + pram_unlock_block(sb, row); | |
953 | + } | |
954 | + } | |
955 | + | |
956 | + inode->i_blocks -= (last_blocknr - first_blocknr + 1); | |
957 | + | |
958 | + if (first_row_index == 0) { | |
959 | + blocknr = pram_get_blocknr(sb, pi->i_type.reg.row_block); | |
960 | + pram_free_block(sb, blocknr); | |
961 | + pram_lock_inode(pi); | |
962 | + pi->i_type.reg.row_block = 0; | |
963 | + pram_unlock_inode(pi); | |
964 | + } | |
965 | + pram_lock_inode(pi); | |
966 | + pi->i_blocks = inode->i_blocks; | |
967 | + pram_unlock_inode(pi); | |
968 | +} | |
969 | + | |
970 | +/* | |
971 | + * Allocate num data blocks for inode, starting at given file-relative | |
972 | + * block number. Any unallocated file blocks before file_blocknr | |
973 | + * are allocated. All blocks except the last are zeroed out. | |
974 | + */ | |
975 | +int pram_alloc_blocks(struct inode * inode, int file_blocknr, int num) | |
976 | +{ | |
977 | + struct super_block * sb = inode->i_sb; | |
978 | + struct pram_inode * pi = pram_get_inode(sb, inode->i_ino); | |
979 | + int N = sb->s_blocksize >> 2; // num block ptrs per block | |
980 | + int Nbits = sb->s_blocksize_bits - 2; | |
981 | + int first_file_blocknr; | |
982 | + int last_file_blocknr; | |
983 | + int first_row_index, last_row_index; | |
984 | + int i, j, blocknr, errval; | |
985 | + unsigned long flags; | |
986 | + pram_off_t * row; | |
987 | + pram_off_t * col; | |
988 | + | |
989 | + if (!pi->i_type.reg.row_block) { | |
990 | + /* alloc the 2nd order array block */ | |
991 | + errval = pram_new_block(sb, &blocknr, 1); | |
992 | + if (errval) { | |
993 | + pram_err("failed to alloc 2nd order array block\n"); | |
994 | + goto fail; | |
995 | + } | |
996 | + pram_lock_inode(pi); | |
997 | + pi->i_type.reg.row_block = pram_get_block_off(sb, blocknr); | |
998 | + pram_unlock_inode(pi); | |
999 | + } | |
1000 | + | |
1001 | + row = pram_get_block(sb, pi->i_type.reg.row_block); | |
1002 | + | |
1003 | + first_file_blocknr = (file_blocknr > inode->i_blocks) ? | |
1004 | + inode->i_blocks : file_blocknr; | |
1005 | + last_file_blocknr = file_blocknr + num - 1; | |
1006 | + | |
1007 | + first_row_index = first_file_blocknr >> Nbits; | |
1008 | + last_row_index = last_file_blocknr >> Nbits; | |
1009 | + | |
1010 | + for (i=first_row_index; i<=last_row_index; i++) { | |
1011 | + int first_col_index, last_col_index; | |
1012 | + /* | |
1013 | + * we are starting a new row, so make sure | |
1014 | + * there is a block allocated for the row. | |
1015 | + */ | |
1016 | + if (!row[i]) { | |
1017 | + /* allocate the row block */ | |
1018 | + errval = pram_new_block(sb, &blocknr, 1); | |
1019 | + if (errval) { | |
1020 | + pram_err("failed to alloc row block\n"); | |
1021 | + goto fail; | |
1022 | + } | |
1023 | + pram_lock_block(sb, row); | |
1024 | + row[i] = pram_get_block_off(sb, blocknr); | |
1025 | + pram_unlock_block(sb, row); | |
1026 | + } | |
1027 | + col = pram_get_block(sb, row[i]); | |
1028 | + | |
1029 | + first_col_index = (i == first_row_index) ? | |
1030 | + first_file_blocknr & (N-1) : 0; | |
1031 | + | |
1032 | + last_col_index = (i == last_row_index) ? | |
1033 | + last_file_blocknr & (N-1) : N-1; | |
1034 | + | |
1035 | + for (j=first_col_index; j<=last_col_index; j++) { | |
1036 | + int last_block = | |
1037 | + (i==last_row_index) && (j==last_col_index); | |
1038 | + if (!col[j]) { | |
1039 | + errval = pram_new_data_block(inode, | |
1040 | + &blocknr, | |
1041 | + !last_block); | |
1042 | + if (errval) { | |
1043 | + pram_err("failed to alloc " | |
1044 | + "data block\n"); | |
1045 | + goto fail; | |
1046 | + } | |
1047 | + pram_lock_block(sb, col); | |
1048 | + col[j] = pram_get_block_off(sb, blocknr); | |
1049 | + pram_unlock_block(sb, col); | |
1050 | + } | |
1051 | + } | |
1052 | + } | |
1053 | + | |
1054 | + errval = 0; | |
1055 | + fail: | |
1056 | + return errval; | |
1057 | +} | |
1058 | + | |
1059 | + | |
1060 | +static int | |
1061 | +pram_fill_inode(struct inode * inode, struct pram_inode * pi) | |
1062 | +{ | |
1063 | + int ret = -EIO; | |
1064 | + | |
1065 | + if (pram_calc_checksum((u32*)pi, PRAM_INODE_SIZE>>2)) { | |
1066 | + pram_err("checksum error in inode %08x\n", | |
1067 | + (u32)inode->i_ino); | |
1068 | + goto bad_inode; | |
1069 | + } | |
1070 | + | |
1071 | + inode->i_mode = pi->i_mode; | |
1072 | + inode->i_uid = pi->i_uid; | |
1073 | + inode->i_gid = pi->i_gid; | |
1074 | + inode->i_nlink = pi->i_links_count; | |
1075 | + inode->i_size = pi->i_size; | |
1076 | + inode->i_atime.tv_sec = pi->i_atime; | |
1077 | + inode->i_ctime.tv_sec = pi->i_ctime; | |
1078 | + inode->i_mtime.tv_sec = pi->i_mtime; | |
1079 | + inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec = | |
1080 | + inode->i_ctime.tv_nsec = 0; | |
1081 | + | |
1082 | + /* check if the inode is active. */ | |
1083 | + if (inode->i_nlink == 0 && (inode->i_mode == 0 || pi->i_dtime)) { | |
1084 | + /* this inode is deleted */ | |
1085 | + ret = -EINVAL; | |
1086 | + goto bad_inode; | |
1087 | + } | |
1088 | + | |
1089 | + inode->i_blocks = pi->i_blocks; | |
1090 | + inode->i_blksize = inode->i_sb->s_blocksize; | |
1091 | + inode->i_ino = pram_get_inodenr(inode->i_sb, pi); | |
1092 | + inode->i_mapping->a_ops = &pram_aops; | |
1093 | + inode->i_mapping->backing_dev_info = &pram_backing_dev_info; | |
1094 | + | |
1095 | + insert_inode_hash(inode); | |
1096 | + switch (inode->i_mode & S_IFMT) { | |
1097 | + case S_IFREG: | |
1098 | + inode->i_op = &pram_file_inode_operations; | |
1099 | + inode->i_fop = &pram_file_operations; | |
1100 | + break; | |
1101 | + case S_IFDIR: | |
1102 | + inode->i_op = &pram_dir_inode_operations; | |
1103 | + inode->i_fop = &pram_dir_operations; | |
1104 | + break; | |
1105 | + case S_IFLNK: | |
1106 | + inode->i_op = &pram_symlink_inode_operations; | |
1107 | + break; | |
1108 | + default: | |
1109 | + inode->i_size = 0; | |
1110 | + init_special_inode(inode, inode->i_mode, | |
1111 | + pi->i_type.dev.rdev); | |
1112 | + break; | |
1113 | + } | |
1114 | + | |
1115 | + return 0; | |
1116 | + | |
1117 | + bad_inode: | |
1118 | + make_bad_inode(inode); | |
1119 | + return ret; | |
1120 | +} | |
1121 | + | |
1122 | +static int pram_update_inode(struct inode * inode) | |
1123 | +{ | |
1124 | + struct pram_inode * pi; | |
1125 | + unsigned long flags; | |
1126 | + int retval = 0; | |
1127 | + | |
1128 | + pi = pram_get_inode(inode->i_sb, inode->i_ino); | |
1129 | + | |
1130 | + pram_lock_inode(pi); | |
1131 | + pi->i_mode = inode->i_mode; | |
1132 | + pi->i_uid = inode->i_uid; | |
1133 | + pi->i_gid = inode->i_gid; | |
1134 | + pi->i_links_count = inode->i_nlink; | |
1135 | + pi->i_size = inode->i_size; | |
1136 | + pi->i_blocks = inode->i_blocks; | |
1137 | + pi->i_atime = inode->i_atime.tv_sec; | |
1138 | + pi->i_ctime = inode->i_ctime.tv_sec; | |
1139 | + pi->i_mtime = inode->i_mtime.tv_sec; | |
1140 | + | |
1141 | + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) | |
1142 | + pi->i_type.dev.rdev = inode->i_rdev; | |
1143 | + | |
1144 | + pram_unlock_inode(pi); | |
1145 | + return retval; | |
1146 | +} | |
1147 | + | |
1148 | +/* | |
1149 | + * NOTE! When we get the inode, we're the only people | |
1150 | + * that have access to it, and as such there are no | |
1151 | + * race conditions we have to worry about. The inode | |
1152 | + * is not on the hash-lists, and it cannot be reached | |
1153 | + * through the filesystem because the directory entry | |
1154 | + * has been deleted earlier. | |
1155 | + */ | |
1156 | +static void pram_free_inode (struct inode * inode) | |
1157 | +{ | |
1158 | + struct super_block * sb = inode->i_sb; | |
1159 | + struct pram_super_block * ps; | |
1160 | + struct pram_inode * pi; | |
1161 | + unsigned long flags, inode_nr; | |
1162 | + | |
1163 | + /* | |
1164 | + * Note: we must free any quota before locking the superblock, | |
1165 | + * as writing the quota to disk may need the lock as well. | |
1166 | + */ | |
1167 | + if (!is_bad_inode(inode)) { | |
1168 | + /* Quota is already initialized in iput() */ | |
1169 | + DQUOT_FREE_INODE(inode); | |
1170 | + DQUOT_DROP(inode); | |
1171 | + } | |
1172 | + | |
1173 | + lock_super (sb); | |
1174 | + clear_inode (inode); | |
1175 | + | |
1176 | + inode_nr = (inode->i_ino - PRAM_ROOT_INO) >> PRAM_INODE_BITS; | |
1177 | + | |
1178 | + pi = pram_get_inode(sb, inode->i_ino); | |
1179 | + pram_lock_inode(pi); | |
1180 | + pi->i_dtime = get_seconds(); | |
1181 | + pi->i_type.reg.row_block = 0; | |
1182 | + pram_unlock_inode(pi); | |
1183 | + | |
1184 | + // increment s_free_inodes_count | |
1185 | + ps = pram_get_super(sb); | |
1186 | + pram_lock_super(ps); | |
1187 | + if (inode_nr < ps->s_free_inode_hint) | |
1188 | + ps->s_free_inode_hint = inode_nr; | |
1189 | + ps->s_free_inodes_count++; | |
1190 | + if (ps->s_free_inodes_count == ps->s_inodes_count - 1) { | |
1191 | + // filesystem is empty | |
1192 | + pram_dbg ("fs is empty!\n"); | |
1193 | + ps->s_free_inode_hint = 1; | |
1194 | + } | |
1195 | + pram_unlock_super(ps); | |
1196 | + | |
1197 | + unlock_super (sb); | |
1198 | +} | |
1199 | + | |
1200 | + | |
1201 | +struct inode * | |
1202 | +pram_fill_new_inode(struct super_block *sb, | |
1203 | + struct pram_inode * pi) | |
1204 | +{ | |
1205 | + struct inode * inode = new_inode(sb); | |
1206 | + | |
1207 | + if (inode) | |
1208 | + pram_fill_inode(inode, pi); | |
1209 | + | |
1210 | + return inode; | |
1211 | +} | |
1212 | + | |
1213 | + | |
1214 | +/* | |
1215 | + * Called at each iput() | |
1216 | + */ | |
1217 | +void pram_put_inode (struct inode * inode) | |
1218 | +{ | |
1219 | + // nothing to do | |
1220 | +} | |
1221 | + | |
1222 | +/* | |
1223 | + * Called at the last iput() if i_nlink is zero. | |
1224 | + */ | |
1225 | +void pram_delete_inode (struct inode * inode) | |
1226 | +{ | |
1227 | + lock_kernel(); | |
1228 | + | |
1229 | + if (is_bad_inode(inode)) | |
1230 | + goto no_delete; | |
1231 | + | |
1232 | + // unlink from chain in the inode's directory | |
1233 | + pram_remove_link(inode); | |
1234 | + inode->i_size = 0; | |
1235 | + if (inode->i_blocks) | |
1236 | + pram_truncate(inode); | |
1237 | + pram_free_inode(inode); | |
1238 | + | |
1239 | + unlock_kernel(); | |
1240 | + return; | |
1241 | + no_delete: | |
1242 | + unlock_kernel(); | |
1243 | + clear_inode(inode); /* We must guarantee clearing of inode... */ | |
1244 | +} | |
1245 | + | |
1246 | + | |
1247 | +struct inode * pram_new_inode (const struct inode * dir, int mode) | |
1248 | +{ | |
1249 | + struct super_block * sb; | |
1250 | + struct pram_super_block * ps; | |
1251 | + struct inode * inode; | |
1252 | + struct pram_inode * pi = NULL; | |
1253 | + unsigned long flags; | |
1254 | + int i, errval; | |
1255 | + ino_t ino=0; | |
1256 | + | |
1257 | + sb = dir->i_sb; | |
1258 | + inode = new_inode(sb); | |
1259 | + if (!inode) | |
1260 | + return ERR_PTR(-ENOMEM); | |
1261 | + | |
1262 | + lock_super (sb); | |
1263 | + ps = pram_get_super(sb); | |
1264 | + | |
1265 | + if (ps->s_free_inodes_count) { | |
1266 | + /* find the oldest unused pram inode */ | |
1267 | + for (i=ps->s_free_inode_hint; i < ps->s_inodes_count; i++) { | |
1268 | + ino = PRAM_ROOT_INO + (i << PRAM_INODE_BITS); | |
1269 | + pi = pram_get_inode(sb, ino); | |
1270 | + /* check if the inode is active. */ | |
1271 | + if (pi->i_links_count == 0 && (pi->i_mode == 0 || | |
1272 | + pi->i_dtime)) { | |
1273 | + /* this inode is deleted */ | |
1274 | + break; | |
1275 | + } | |
1276 | + } | |
1277 | + | |
1278 | + if (i >= ps->s_inodes_count) { | |
1279 | + pram_err("s_free_inodes_count!=0 but none free!?\n"); | |
1280 | + errval = -ENOSPC; | |
1281 | + goto fail; | |
1282 | + } | |
1283 | + | |
1284 | + pram_dbg ("allocating inode %lu\n", ino); | |
1285 | + pram_lock_super(ps); | |
1286 | + ps->s_free_inodes_count--; | |
1287 | + ps->s_free_inode_hint = (i < ps->s_inodes_count-1) ? i+1 : 0; | |
1288 | + pram_unlock_super(ps); | |
1289 | + } else { | |
1290 | + pram_err("no space left to create new inode!\n"); | |
1291 | + errval = -ENOSPC; | |
1292 | + goto fail; | |
1293 | + } | |
1294 | + | |
1295 | + // chosen inode is in ino | |
1296 | + | |
1297 | + inode->i_ino = ino; | |
1298 | + inode->i_uid = current->fsuid; | |
1299 | + | |
1300 | + if (dir->i_mode & S_ISGID) { | |
1301 | + inode->i_gid = dir->i_gid; | |
1302 | + if (S_ISDIR(mode)) | |
1303 | + mode |= S_ISGID; | |
1304 | + } else | |
1305 | + inode->i_gid = current->fsgid; | |
1306 | + inode->i_mode = mode; | |
1307 | + | |
1308 | + inode->i_blksize = sb->s_blocksize; | |
1309 | + inode->i_blocks = inode->i_size = 0; | |
1310 | + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | |
1311 | + | |
1312 | + pram_lock_inode(pi); | |
1313 | + pi->i_d.d_next = 0; | |
1314 | + pi->i_d.d_prev = 0; | |
1315 | + pram_unlock_inode(pi); | |
1316 | + | |
1317 | + insert_inode_hash(inode); | |
1318 | + pram_write_inode(inode, 0); | |
1319 | + | |
1320 | + unlock_super (sb); | |
1321 | + | |
1322 | + if(DQUOT_ALLOC_INODE(inode)) { | |
1323 | + DQUOT_DROP(inode); | |
1324 | + inode->i_flags |= S_NOQUOTA; | |
1325 | + inode->i_nlink = 0; | |
1326 | + iput(inode); | |
1327 | + return ERR_PTR(-EDQUOT); | |
1328 | + } | |
1329 | + return inode; | |
1330 | + | |
1331 | +fail: | |
1332 | + unlock_super(sb); | |
1333 | + make_bad_inode(inode); | |
1334 | + iput(inode); | |
1335 | + return ERR_PTR(errval); | |
1336 | +} | |
1337 | + | |
1338 | + | |
1339 | +void pram_read_inode (struct inode * inode) | |
1340 | +{ | |
1341 | + struct pram_inode * pi; | |
1342 | + | |
1343 | + pi = pram_get_inode(inode->i_sb, inode->i_ino); | |
1344 | + pram_fill_inode(inode, pi); | |
1345 | +} | |
1346 | + | |
1347 | +void pram_truncate (struct inode * inode) | |
1348 | +{ | |
1349 | + int blocksize, blocksize_bits; | |
1350 | + int blocknr; | |
1351 | + | |
1352 | + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | |
1353 | + S_ISLNK(inode->i_mode))) | |
1354 | + return; | |
1355 | + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | |
1356 | + return; | |
1357 | + | |
1358 | + blocksize_bits = inode->i_sb->s_blocksize_bits; | |
1359 | + blocksize = 1 << blocksize_bits; | |
1360 | + blocknr = (inode->i_size + blocksize-1) >> blocksize_bits; | |
1361 | + | |
1362 | + lock_kernel(); | |
1363 | + pram_truncate_blocks(inode, blocknr); | |
1364 | + inode->i_mtime = inode->i_ctime = CURRENT_TIME; | |
1365 | + pram_update_inode(inode); | |
1366 | + unlock_kernel(); | |
1367 | +} | |
1368 | + | |
1369 | + | |
1370 | +void pram_write_inode (struct inode * inode, int wait) | |
1371 | +{ | |
1372 | + lock_kernel(); | |
1373 | + pram_update_inode(inode); | |
1374 | + unlock_kernel(); | |
1375 | +} | |
1376 | + | |
1377 | +/* | |
1378 | + * dirty_inode() is called from __mark_inode_dirty() | |
1379 | + */ | |
1380 | +void pram_dirty_inode(struct inode * inode) | |
1381 | +{ | |
1382 | + pram_write_inode(inode, 0); | |
1383 | +} | |
1384 | + | |
1385 | + | |
1386 | +static int pram_get_and_update_block(struct inode *inode, sector_t iblock, | |
1387 | + struct buffer_head *bh, int create) | |
1388 | +{ | |
1389 | + struct super_block * sb = inode->i_sb; | |
1390 | + unsigned int blocksize = 1 << inode->i_blkbits; | |
1391 | + int err = -EIO; | |
1392 | + unsigned long flags; | |
1393 | + pram_off_t block; | |
1394 | + void* bp; | |
1395 | + | |
1396 | + lock_kernel(); | |
1397 | + | |
1398 | + block = pram_find_data_block(inode, iblock); | |
1399 | + | |
1400 | + if (!block) { | |
1401 | + if (!create) | |
1402 | + goto out; | |
1403 | + | |
1404 | + err = pram_alloc_blocks(inode, iblock, 1); | |
1405 | + if (err) | |
1406 | + goto out; | |
1407 | + block = pram_find_data_block(inode, iblock); | |
1408 | + if (!block) { | |
1409 | + err = -EIO; | |
1410 | + goto out; | |
1411 | + } | |
1412 | + set_buffer_new(bh); | |
1413 | + } | |
1414 | + | |
1415 | + bh->b_blocknr = block; | |
1416 | + set_buffer_mapped(bh); | |
1417 | + | |
1418 | + /* now update the buffer synchronously */ | |
1419 | + bp = pram_get_block(sb, block); | |
1420 | + if (buffer_new(bh)) { | |
1421 | + pram_lock_block(sb, bp); | |
1422 | + memset(bp, 0, blocksize); | |
1423 | + pram_unlock_block(sb, bp); | |
1424 | + memset(bh->b_data, 0, blocksize); | |
1425 | + } else { | |
1426 | + memcpy(bh->b_data, bp, blocksize); | |
1427 | + } | |
1428 | + | |
1429 | + set_buffer_uptodate(bh); | |
1430 | + err = 0; | |
1431 | + | |
1432 | + out: | |
1433 | + unlock_kernel(); | |
1434 | + return err; | |
1435 | +} | |
1436 | + | |
1437 | +#if 0 | |
1438 | +static int pram_writepage(struct page *page) | |
1439 | +{ | |
1440 | + return 0; | |
1441 | +} | |
1442 | + | |
1443 | +static int pram_bmap(struct address_space *mapping, long block) | |
1444 | +{ | |
1445 | + return 0; | |
1446 | +} | |
1447 | +#endif | |
1448 | + | |
1449 | +static int pram_readpage(struct file *file, struct page *page) | |
1450 | +{ | |
1451 | + return block_read_full_page(page, pram_get_and_update_block); | |
1452 | +} | |
1453 | + | |
1454 | +struct address_space_operations pram_aops = { | |
1455 | + readpage: pram_readpage, | |
1456 | +// writepage: pram_writepage, | |
1457 | +// bmap: pram_bmap, | |
1458 | + direct_IO: pram_direct_IO, | |
1459 | +}; | |
1460 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/ioctl.c main/fs/pramfs/ioctl.c | |
1461 | --- main.orig/fs/pramfs/ioctl.c 1969-12-31 16:00:00.000000000 -0800 | |
1462 | +++ main/fs/pramfs/ioctl.c 2004-03-04 15:59:03.000000000 -0800 | |
1463 | @@ -0,0 +1,35 @@ | |
1464 | +/* | |
1465 | + * ioctl.c | |
1466 | + * | |
1467 | + * Ioctl method for directory and regular files. | |
1468 | + * | |
1469 | + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> | |
1470 | + * | |
1471 | + * 2003 (c) MontaVista Software, Inc. | |
1472 | + * Copyright 2003 Sony Corporation | |
1473 | + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. | |
1474 | + * | |
1475 | + * This software is being distributed under the terms of the GNU General Public | |
1476 | + * License version 2. Some or all of the technology encompassed by this | |
1477 | + * software may be subject to one or more patents pending as of the date of | |
1478 | + * this notice. No additional patent license will be required for GPL | |
1479 | + * implementations of the technology. If you want to create a non-GPL | |
1480 | + * implementation of the technology encompassed by this software, please | |
1481 | + * contact legal@mvista.com for details including licensing terms and fees. | |
1482 | + * | |
1483 | + * This file is licensed under the terms of the GNU General Public License | |
1484 | + * version 2. This program is licensed "as is" without any warranty of any | |
1485 | + * kind, whether express or implied. | |
1486 | + */ | |
1487 | +#include <linux/fs.h> | |
1488 | +#include <linux/pram_fs.h> | |
1489 | +#include <linux/sched.h> | |
1490 | +#include <asm/uaccess.h> | |
1491 | + | |
1492 | + | |
1493 | +int pram_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, | |
1494 | + unsigned long arg) | |
1495 | +{ | |
1496 | + // FIXME: need any special ioctl's? | |
1497 | + return 0; | |
1498 | +} | |
1499 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/Makefile main/fs/pramfs/Makefile | |
1500 | --- main.orig/fs/pramfs/Makefile 1969-12-31 16:00:00.000000000 -0800 | |
1501 | +++ main/fs/pramfs/Makefile 2004-03-04 15:59:03.000000000 -0800 | |
1502 | @@ -0,0 +1,11 @@ | |
1503 | +# | |
1504 | +# Makefile for the linux pram-filesystem routines. | |
1505 | +# | |
1506 | + | |
1507 | +obj-$(CONFIG_PRAMFS) += pramfs.o | |
1508 | + | |
1509 | +pramfs-objs := balloc.o dir.o file.o fsync.o inode.o ioctl.o namei.o \ | |
1510 | + super.o symlink.o | |
1511 | +ifndef CONFIG_PRAMFS_NOWP | |
1512 | +pramfs-objs += wprotect.o | |
1513 | +endif | |
1514 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/namei.c main/fs/pramfs/namei.c | |
1515 | --- main.orig/fs/pramfs/namei.c 1969-12-31 16:00:00.000000000 -0800 | |
1516 | +++ main/fs/pramfs/namei.c 2004-03-04 15:59:03.000000000 -0800 | |
1517 | @@ -0,0 +1,331 @@ | |
1518 | +/* | |
1519 | + * namei.c | |
1520 | + * | |
1521 | + * Inode operations for directories. | |
1522 | + * | |
1523 | + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> | |
1524 | + * | |
1525 | + * 2003 (c) MontaVista Software, Inc. | |
1526 | + * Copyright 2003 Sony Corporation | |
1527 | + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. | |
1528 | + * | |
1529 | + * This software is being distributed under the terms of the GNU General Public | |
1530 | + * License version 2. Some or all of the technology encompassed by this | |
1531 | + * software may be subject to one or more patents pending as of the date of | |
1532 | + * this notice. No additional patent license will be required for GPL | |
1533 | + * implementations of the technology. If you want to create a non-GPL | |
1534 | + * implementation of the technology encompassed by this software, please | |
1535 | + * contact legal@mvista.com for details including licensing terms and fees. | |
1536 | + * | |
1537 | + * This file is licensed under the terms of the GNU General Public License | |
1538 | + * version 2. This program is licensed "as is" without any warranty of any | |
1539 | + * kind, whether express or implied. | |
1540 | + */ | |
1541 | +#include <linux/fs.h> | |
1542 | +#include <linux/pram_fs.h> | |
1543 | +#include <linux/pagemap.h> | |
1544 | + | |
1545 | + | |
1546 | +/* | |
1547 | + * Couple of helper functions - make the code slightly cleaner. | |
1548 | + */ | |
1549 | + | |
1550 | +static inline void pram_inc_count(struct inode *inode) | |
1551 | +{ | |
1552 | + inode->i_nlink++; | |
1553 | + pram_write_inode(inode, 0); | |
1554 | +} | |
1555 | + | |
1556 | +static inline void pram_dec_count(struct inode *inode) | |
1557 | +{ | |
1558 | + if (inode->i_nlink) { | |
1559 | + inode->i_nlink--; | |
1560 | + pram_write_inode(inode, 0); | |
1561 | + } | |
1562 | +} | |
1563 | + | |
1564 | +static inline int pram_add_nondir(struct inode * dir, | |
1565 | + struct dentry * dentry, | |
1566 | + struct inode * inode) | |
1567 | +{ | |
1568 | + int err = pram_add_link(dentry, inode); | |
1569 | + if (!err) { | |
1570 | + d_instantiate(dentry, inode); | |
1571 | + return 0; | |
1572 | + } | |
1573 | + pram_dec_count(inode); | |
1574 | + iput(inode); | |
1575 | + return err; | |
1576 | +} | |
1577 | + | |
1578 | +/* | |
1579 | + * Methods themselves. | |
1580 | + */ | |
1581 | + | |
1582 | +static ino_t | |
1583 | +pram_inode_by_name(struct inode * dir, | |
1584 | + struct dentry * dentry) | |
1585 | +{ | |
1586 | + struct pram_inode * pi; | |
1587 | + ino_t ino; | |
1588 | + int namelen; | |
1589 | + | |
1590 | + pi = pram_get_inode(dir->i_sb, dir->i_ino); | |
1591 | + ino = pi->i_type.dir.head; | |
1592 | + | |
1593 | + while (ino) { | |
1594 | + pi = pram_get_inode(dir->i_sb, ino); | |
1595 | + | |
1596 | + if (pi->i_links_count) { | |
1597 | + namelen = strlen(pi->i_d.d_name); | |
1598 | + | |
1599 | + if (namelen == dentry->d_name.len && | |
1600 | + !memcmp(dentry->d_name.name, | |
1601 | + pi->i_d.d_name, namelen)) | |
1602 | + break; | |
1603 | + } | |
1604 | + | |
1605 | + ino = pi->i_d.d_next; | |
1606 | + } | |
1607 | + | |
1608 | + return ino; | |
1609 | +} | |
1610 | + | |
1611 | +static struct dentry * | |
1612 | +pram_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) | |
1613 | +{ | |
1614 | + struct inode * inode = NULL; | |
1615 | + ino_t ino; | |
1616 | + | |
1617 | + if (dentry->d_name.len > PRAM_NAME_LEN) | |
1618 | + return ERR_PTR(-ENAMETOOLONG); | |
1619 | + | |
1620 | + ino = pram_inode_by_name(dir, dentry); | |
1621 | + if (ino) { | |
1622 | + struct pram_inode * pi = pram_get_inode(dir->i_sb, ino); | |
1623 | + inode = pram_fill_new_inode(dir->i_sb, pi); | |
1624 | + if (!inode) | |
1625 | + return ERR_PTR(-EACCES); | |
1626 | + } | |
1627 | + | |
1628 | + d_add(dentry, inode); | |
1629 | + return NULL; | |
1630 | +} | |
1631 | + | |
1632 | + | |
1633 | +/* | |
1634 | + * By the time this is called, we already have created | |
1635 | + * the directory cache entry for the new file, but it | |
1636 | + * is so far negative - it has no inode. | |
1637 | + * | |
1638 | + * If the create succeeds, we fill in the inode information | |
1639 | + * with d_instantiate(). | |
1640 | + */ | |
1641 | +static int pram_create (struct inode * dir, struct dentry * dentry, | |
1642 | + int mode, struct nameidata *nd) | |
1643 | +{ | |
1644 | + struct inode * inode = pram_new_inode (dir, mode); | |
1645 | + int err = PTR_ERR(inode); | |
1646 | + if (!IS_ERR(inode)) { | |
1647 | + inode->i_op = &pram_file_inode_operations; | |
1648 | + inode->i_fop = &pram_file_operations; | |
1649 | + inode->i_mapping->a_ops = &pram_aops; | |
1650 | + err = pram_add_nondir(dir, dentry, inode); | |
1651 | + } | |
1652 | + return err; | |
1653 | +} | |
1654 | + | |
1655 | +static int pram_mknod (struct inode * dir, struct dentry *dentry, int mode, | |
1656 | + dev_t rdev) | |
1657 | +{ | |
1658 | + struct inode * inode = pram_new_inode (dir, mode); | |
1659 | + int err = PTR_ERR(inode); | |
1660 | + if (!IS_ERR(inode)) { | |
1661 | + init_special_inode(inode, mode, rdev); | |
1662 | + err = pram_add_nondir(dir, dentry, inode); | |
1663 | + } | |
1664 | + return err; | |
1665 | +} | |
1666 | + | |
1667 | +static int pram_symlink (struct inode * dir, | |
1668 | + struct dentry * dentry, | |
1669 | + const char * symname) | |
1670 | +{ | |
1671 | + struct super_block * sb = dir->i_sb; | |
1672 | + int err = -ENAMETOOLONG; | |
1673 | + unsigned len = strlen(symname); | |
1674 | + struct inode * inode; | |
1675 | + | |
1676 | + if (len+1 > sb->s_blocksize) | |
1677 | + goto out; | |
1678 | + | |
1679 | + inode = pram_new_inode (dir, S_IFLNK | S_IRWXUGO); | |
1680 | + err = PTR_ERR(inode); | |
1681 | + if (IS_ERR(inode)) | |
1682 | + goto out; | |
1683 | + | |
1684 | + inode->i_op = &pram_symlink_inode_operations; | |
1685 | + inode->i_mapping->a_ops = &pram_aops; | |
1686 | + err = pram_block_symlink(inode, symname, len); | |
1687 | + if (err) | |
1688 | + goto out_fail; | |
1689 | + | |
1690 | + inode->i_size = len; | |
1691 | + pram_write_inode(inode, 0); | |
1692 | + | |
1693 | + err = pram_add_nondir(dir, dentry, inode); | |
1694 | +out: | |
1695 | + return err; | |
1696 | + | |
1697 | +out_fail: | |
1698 | + pram_dec_count(inode); | |
1699 | + iput (inode); | |
1700 | + goto out; | |
1701 | +} | |
1702 | + | |
1703 | +static int pram_link (struct dentry * dest_dentry, | |
1704 | + struct inode * dir, | |
1705 | + struct dentry * dentry) | |
1706 | +{ | |
1707 | + pram_dbg ("hard links not supported\n"); | |
1708 | + return -ENOSYS; | |
1709 | +} | |
1710 | + | |
1711 | +static int pram_unlink(struct inode * dir, struct dentry *dentry) | |
1712 | +{ | |
1713 | + struct inode * inode = dentry->d_inode; | |
1714 | + inode->i_ctime = dir->i_ctime; | |
1715 | + pram_dec_count(inode); | |
1716 | + | |
1717 | + return 0; | |
1718 | +} | |
1719 | + | |
1720 | +static int pram_mkdir(struct inode * dir, struct dentry * dentry, int mode) | |
1721 | +{ | |
1722 | + struct inode * inode; | |
1723 | + struct pram_inode * pi; | |
1724 | + unsigned long flags; | |
1725 | + int err = -EMLINK; | |
1726 | + | |
1727 | + if (dir->i_nlink >= PRAM_LINK_MAX) | |
1728 | + goto out; | |
1729 | + | |
1730 | + pram_inc_count(dir); | |
1731 | + | |
1732 | + inode = pram_new_inode (dir, S_IFDIR | mode); | |
1733 | + err = PTR_ERR(inode); | |
1734 | + if (IS_ERR(inode)) | |
1735 | + goto out_dir; | |
1736 | + | |
1737 | + inode->i_op = &pram_dir_inode_operations; | |
1738 | + inode->i_fop = &pram_dir_operations; | |
1739 | + inode->i_mapping->a_ops = &pram_aops; | |
1740 | + | |
1741 | + pram_inc_count(inode); | |
1742 | + | |
1743 | + // make the new directory empty | |
1744 | + pi = pram_get_inode(dir->i_sb, inode->i_ino); | |
1745 | + pram_lock_inode(pi); | |
1746 | + pi->i_type.dir.head = pi->i_type.dir.tail = 0; | |
1747 | + pram_unlock_inode(pi); | |
1748 | + | |
1749 | + err = pram_add_link(dentry, inode); | |
1750 | + if (err) | |
1751 | + goto out_fail; | |
1752 | + | |
1753 | + d_instantiate(dentry, inode); | |
1754 | +out: | |
1755 | + return err; | |
1756 | + | |
1757 | +out_fail: | |
1758 | + pram_dec_count(inode); | |
1759 | + pram_dec_count(inode); | |
1760 | + iput(inode); | |
1761 | +out_dir: | |
1762 | + pram_dec_count(dir); | |
1763 | + goto out; | |
1764 | +} | |
1765 | + | |
1766 | +static int pram_rmdir (struct inode * dir, struct dentry *dentry) | |
1767 | +{ | |
1768 | + struct inode * inode = dentry->d_inode; | |
1769 | + struct pram_inode * pi; | |
1770 | + int err = -ENOTEMPTY; | |
1771 | + | |
1772 | + if (!inode) | |
1773 | + return -ENOENT; | |
1774 | + | |
1775 | + pi = pram_get_inode(dir->i_sb, inode->i_ino); | |
1776 | + | |
1777 | + // directory to delete is empty? | |
1778 | + if (pi->i_type.dir.tail == 0) { | |
1779 | + inode->i_ctime = dir->i_ctime; | |
1780 | + inode->i_size = 0; | |
1781 | + inode->i_nlink = 0; | |
1782 | + pram_write_inode(inode, 0); | |
1783 | + pram_dec_count(dir); | |
1784 | + err = 0; | |
1785 | + } else { | |
1786 | + pram_dbg("dir not empty\n"); | |
1787 | + } | |
1788 | + | |
1789 | + return err; | |
1790 | +} | |
1791 | + | |
1792 | +static int pram_rename (struct inode * old_dir, | |
1793 | + struct dentry * old_dentry, | |
1794 | + struct inode * new_dir, | |
1795 | + struct dentry * new_dentry) | |
1796 | +{ | |
1797 | + struct inode * old_inode = old_dentry->d_inode; | |
1798 | + struct inode * new_inode = new_dentry->d_inode; | |
1799 | + struct pram_inode * pi_new; | |
1800 | + int err = -ENOENT; | |
1801 | + | |
1802 | + if (new_inode) { | |
1803 | + err = -ENOTEMPTY; | |
1804 | + pi_new = pram_get_inode(new_dir->i_sb, new_inode->i_ino); | |
1805 | + if (S_ISDIR(old_inode->i_mode)) { | |
1806 | + if (pi_new->i_type.dir.tail != 0) | |
1807 | + goto out; | |
1808 | + if (new_inode->i_nlink) | |
1809 | + new_inode->i_nlink--; | |
1810 | + } | |
1811 | + | |
1812 | + new_inode->i_ctime = CURRENT_TIME; | |
1813 | + pram_dec_count(new_inode); | |
1814 | + } else { | |
1815 | + if (S_ISDIR(old_inode->i_mode)) { | |
1816 | + err = -EMLINK; | |
1817 | + if (new_dir->i_nlink >= PRAM_LINK_MAX) | |
1818 | + goto out; | |
1819 | + pram_dec_count(old_dir); | |
1820 | + pram_inc_count(new_dir); | |
1821 | + } | |
1822 | + } | |
1823 | + | |
1824 | + /* unlink the inode from the old directory ... */ | |
1825 | + if ((err = pram_remove_link(old_inode))) { | |
1826 | + goto out; | |
1827 | + } | |
1828 | + /* and link it into the new directory. */ | |
1829 | + if ((err = pram_add_link(new_dentry, old_inode))) { | |
1830 | + goto out; | |
1831 | + } | |
1832 | + | |
1833 | + err = 0; | |
1834 | + out: | |
1835 | + return err; | |
1836 | +} | |
1837 | + | |
1838 | +struct inode_operations pram_dir_inode_operations = { | |
1839 | + create: pram_create, | |
1840 | + lookup: pram_lookup, | |
1841 | + link: pram_link, | |
1842 | + unlink: pram_unlink, | |
1843 | + symlink: pram_symlink, | |
1844 | + mkdir: pram_mkdir, | |
1845 | + rmdir: pram_rmdir, | |
1846 | + mknod: pram_mknod, | |
1847 | + rename: pram_rename, | |
1848 | +}; | |
1849 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/super.c main/fs/pramfs/super.c | |
1850 | --- main.orig/fs/pramfs/super.c 1969-12-31 16:00:00.000000000 -0800 | |
1851 | +++ main/fs/pramfs/super.c 2004-03-04 15:59:03.000000000 -0800 | |
1852 | @@ -0,0 +1,393 @@ | |
1853 | +/* | |
1854 | + * super.c | |
1855 | + * | |
1856 | + * Super block operations. | |
1857 | + * | |
1858 | + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> | |
1859 | + * | |
1860 | + * 2003 (c) MontaVista Software, Inc. | |
1861 | + * Copyright 2003 Sony Corporation | |
1862 | + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. | |
1863 | + * | |
1864 | + * This software is being distributed under the terms of the GNU General Public | |
1865 | + * License version 2. Some or all of the technology encompassed by this | |
1866 | + * software may be subject to one or more patents pending as of the date of | |
1867 | + * this notice. No additional patent license will be required for GPL | |
1868 | + * implementations of the technology. If you want to create a non-GPL | |
1869 | + * implementation of the technology encompassed by this software, please | |
1870 | + * contact legal@mvista.com for details including licensing terms and fees. | |
1871 | + * | |
1872 | + * This file is licensed under the terms of the GNU General Public License | |
1873 | + * version 2. This program is licensed "as is" without any warranty of any | |
1874 | + * kind, whether express or implied. | |
1875 | + */ | |
1876 | +#include <linux/config.h> | |
1877 | +#include <linux/module.h> | |
1878 | +#include <linux/string.h> | |
1879 | +#include <linux/slab.h> | |
1880 | +#include <linux/init.h> | |
1881 | +#include <linux/blkdev.h> | |
1882 | +#include <linux/parser.h> | |
1883 | +#include <linux/vfs.h> | |
1884 | +#include <linux/pram_fs.h> | |
1885 | +#include <asm/uaccess.h> | |
1886 | + | |
1887 | +MODULE_AUTHOR("Steve Longerbeam, stevel@mvista.com"); | |
1888 | +MODULE_DESCRIPTION("Protected/Persistent RAM Filesystem"); | |
1889 | +MODULE_LICENSE("GPL"); | |
1890 | + | |
1891 | +static struct super_operations pram_sops; | |
1892 | + | |
1893 | +#ifndef MODULE | |
1894 | +extern struct list_head super_blocks; | |
1895 | + | |
1896 | +struct super_block * find_pramfs_super(void) | |
1897 | +{ | |
1898 | + struct list_head *p; | |
1899 | + list_for_each(p, &super_blocks) { | |
1900 | + struct super_block * s = sb_entry(p); | |
1901 | + if (s->s_magic == PRAM_SUPER_MAGIC) | |
1902 | + return s; | |
1903 | + } | |
1904 | + return NULL; | |
1905 | +} | |
1906 | +EXPORT_SYMBOL(find_pramfs_super); | |
1907 | +#endif | |
1908 | + | |
1909 | +static void pram_set_blocksize(struct super_block * sb, unsigned long size) | |
1910 | +{ | |
1911 | + int bits; | |
1912 | + for (bits = 9, size >>= 9; size >>= 1; bits++) | |
1913 | + ; | |
1914 | + if (bits > 12) | |
1915 | + bits = 12; | |
1916 | + sb->s_blocksize_bits = bits; | |
1917 | + sb->s_blocksize = (1<<bits); | |
1918 | +} | |
1919 | + | |
1920 | +static inline void * pram_ioremap(unsigned long phys_addr, size_t size, | |
1921 | + unsigned long flags) | |
1922 | +{ | |
c9d1c54c | 1923 | + void * retval = __ioremap(phys_addr, size, flags); |
37fad6fa | 1924 | +#ifndef CONFIG_PRAMFS_NOWP |
1925 | + if (retval) { | |
1926 | + spin_lock(&init_mm.page_table_lock); | |
1927 | + pram_writeable(retval, size, 0); | |
1928 | + spin_unlock(&init_mm.page_table_lock); | |
1929 | + } | |
1930 | +#endif | |
1931 | + return retval; | |
1932 | +} | |
1933 | + | |
1934 | + | |
1935 | +static int pram_fill_super (struct super_block * sb, void * data, int silent) | |
1936 | +{ | |
1937 | + char *p; | |
1938 | + struct pram_super_block * super; | |
1939 | + struct pram_inode * root_i; | |
1940 | + struct pram_sb_info * sbi=NULL; | |
1941 | + pram_off_t root_offset; | |
1942 | + unsigned long flags; | |
1943 | + unsigned long maxsize, blocksize; | |
1944 | + int retval = -EINVAL; | |
1945 | + | |
1946 | + /* | |
1947 | + * The physical location of the pram image is specified as | |
1948 | + * a mount parameter. This parameter is mandatory for obvious | |
1949 | + * reasons. Some validation is made on the phys address but this | |
1950 | + * is not exhaustive and we count on the fact that someone using | |
1951 | + * this feature is supposed to know what he/she's doing. | |
1952 | + */ | |
1953 | + if (!data || !(p = strstr((char *)data, "physaddr="))) { | |
1954 | + pram_err("unknown physical address for pramfs image\n"); | |
1955 | + goto out; | |
1956 | + } | |
1957 | + | |
1958 | + sbi = kmalloc(sizeof(*sbi), GFP_KERNEL); | |
1959 | + if (!sbi) | |
1960 | + return -ENOMEM; | |
1961 | + sb->s_fs_info = sbi; | |
1962 | + memset(sbi, 0, sizeof(*sbi)); | |
1963 | + | |
1964 | + sbi->phys_addr = simple_strtoul(p + 9, NULL, 0); | |
1965 | + if (sbi->phys_addr & (PAGE_SIZE-1)) { | |
1966 | + pram_err("physical address 0x%lx for pramfs isn't " | |
1967 | + "aligned to a page boundary\n", | |
1968 | + sbi->phys_addr); | |
1969 | + goto out; | |
1970 | + } | |
1971 | + | |
1972 | + if (sbi->phys_addr == 0) { | |
1973 | + pram_err("physical address for pramfs image can't be 0\n"); | |
1974 | + goto out; | |
1975 | + } | |
1976 | + | |
1977 | + if ((p = strstr((char *)data, "init="))) { | |
1978 | + unsigned long bpi, num_inodes, bitmap_size; | |
1979 | + unsigned long num_blocks; | |
1980 | + pram_off_t bitmap_start; | |
1981 | + | |
1982 | + maxsize = simple_strtoul(p + 5, NULL, 0); | |
1983 | + pram_info("creating an empty pramfs of size %lu\n", maxsize); | |
1984 | + | |
1985 | + sbi->virt_addr = pram_ioremap(sbi->phys_addr, maxsize, 0); | |
1986 | + if (!sbi->virt_addr) { | |
1987 | + pram_err("ioremap of the pramfs image failed\n"); | |
1988 | + goto out; | |
1989 | + } | |
1990 | + | |
1991 | + if ((p = strstr((char *)data, "bs="))) | |
1992 | + blocksize = simple_strtoul(p + 3, NULL, 0); | |
1993 | + else | |
1994 | + blocksize = PRAM_DEF_BLOCK_SIZE; | |
1995 | + | |
1996 | + pram_set_blocksize(sb, blocksize); | |
1997 | + blocksize = sb->s_blocksize; | |
1998 | + | |
1999 | + if ((p = strstr((char *)data, "bpi="))) | |
2000 | + bpi = simple_strtoul(p + 4, NULL, 0); | |
2001 | + else { | |
2002 | + /* default is that 5% of the filesystem is | |
2003 | + devoted to the inode table */ | |
2004 | + bpi = 20 * PRAM_INODE_SIZE; | |
2005 | + } | |
2006 | + | |
2007 | + if ((p = strstr((char *)data, "N="))) | |
2008 | + num_inodes = simple_strtoul(p + 2, NULL, 0); | |
2009 | + else | |
2010 | + num_inodes = maxsize / bpi; | |
2011 | + | |
2012 | + /* up num_inodes such that the end of the inode table | |
2013 | + (and start of bitmap) is on a block boundary */ | |
2014 | + bitmap_start = PRAM_SB_SIZE + (num_inodes<<PRAM_INODE_BITS); | |
2015 | + if (bitmap_start & (blocksize - 1)) | |
2016 | + bitmap_start = (bitmap_start + blocksize) & | |
2017 | + ~(blocksize-1); | |
2018 | + num_inodes = (bitmap_start - PRAM_SB_SIZE) >> PRAM_INODE_BITS; | |
2019 | + | |
2020 | + num_blocks = (maxsize - bitmap_start) >> sb->s_blocksize_bits; | |
2021 | + | |
2022 | + /* calc the data blocks in-use bitmap size in bytes */ | |
2023 | + if (num_blocks & 7) | |
2024 | + bitmap_size = ((num_blocks + 8) & ~7) >> 3; | |
2025 | + else | |
2026 | + bitmap_size = num_blocks >> 3; | |
2027 | + /* round it up to the nearest blocksize boundary */ | |
2028 | + if (bitmap_size & (blocksize - 1)) | |
2029 | + bitmap_size = (bitmap_size + blocksize) & | |
2030 | + ~(blocksize-1); | |
2031 | + | |
2032 | + pram_info("blocksize %lu, num inodes %lu, num blocks %lu\n", | |
2033 | + blocksize, num_inodes, num_blocks); | |
2034 | + pram_dbg("bitmap start 0x%08x, bitmap size %lu\n", | |
2035 | + (unsigned long)bitmap_start, bitmap_size); | |
2036 | + pram_dbg("max name length %d\n", PRAM_NAME_LEN); | |
2037 | + | |
2038 | + super = pram_get_super(sb); | |
2039 | + pram_lock_range(super, bitmap_start + bitmap_size); | |
2040 | + | |
2041 | + /* clear out super-block and inode table */ | |
2042 | + memset(super, 0, bitmap_start); | |
2043 | + super->s_size = maxsize; | |
2044 | + super->s_blocksize = blocksize; | |
2045 | + super->s_inodes_count = num_inodes; | |
2046 | + super->s_blocks_count = num_blocks; | |
2047 | + super->s_free_inodes_count = num_inodes - 1; | |
2048 | + super->s_bitmap_blocks = bitmap_size >> sb->s_blocksize_bits; | |
2049 | + super->s_free_blocks_count = | |
2050 | + num_blocks - super->s_bitmap_blocks; | |
2051 | + super->s_free_inode_hint = 1; | |
2052 | + super->s_bitmap_start = bitmap_start; | |
2053 | + super->s_magic = PRAM_SUPER_MAGIC; | |
2054 | + pram_sync_super(super); | |
2055 | + | |
2056 | + root_i = pram_get_inode(sb, PRAM_ROOT_INO); | |
2057 | + root_i->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; | |
2058 | + root_i->i_links_count = 2; | |
2059 | + root_i->i_d.d_parent = PRAM_ROOT_INO; | |
2060 | + pram_sync_inode(root_i); | |
2061 | + | |
2062 | + pram_init_bitmap(sb); | |
2063 | + | |
2064 | + pram_unlock_range(super, bitmap_start + bitmap_size); | |
2065 | + | |
2066 | + goto setup_sb; | |
2067 | + } | |
2068 | + | |
2069 | + pram_info("checking physical address 0x%lx for pramfs image\n", | |
2070 | + sbi->phys_addr); | |
2071 | + | |
2072 | + /* Map only one page for now. Will remap it when fs size is known. */ | |
2073 | + sbi->virt_addr = pram_ioremap(sbi->phys_addr, PAGE_SIZE, 0); | |
2074 | + if (!sbi->virt_addr) { | |
2075 | + pram_err("ioremap of the pramfs image failed\n"); | |
2076 | + goto out; | |
2077 | + } | |
2078 | + | |
2079 | + super = pram_get_super(sb); | |
2080 | + | |
2081 | + /* Do sanity checks on the superblock */ | |
2082 | + if (super->s_magic != PRAM_SUPER_MAGIC) { | |
2083 | + pram_err("wrong magic\n"); | |
2084 | + goto out; | |
2085 | + } | |
2086 | + /* Read the superblock */ | |
2087 | + if (pram_calc_checksum((u32*)super, PRAM_SB_SIZE>>2)) { | |
2088 | + pram_err("checksum error in super block!\n"); | |
2089 | + goto out; | |
2090 | + } | |
2091 | + | |
2092 | + /* get feature flags first */ | |
2093 | + // FIXME: implement fs features? | |
2094 | +#if 0 | |
2095 | + if (super->s_features & ~PRAM_SUPPORTED_FLAGS) { | |
2096 | + pram_err("unsupported filesystem features\n"); | |
2097 | + goto out; | |
2098 | + } | |
2099 | +#endif | |
2100 | + | |
2101 | + blocksize = super->s_blocksize; | |
2102 | + pram_set_blocksize(sb, blocksize); | |
2103 | + | |
2104 | + maxsize = super->s_size; | |
2105 | + pram_info("pramfs image appears to be %lu KB in size\n", maxsize>>10); | |
2106 | + pram_info("blocksize %lu\n", blocksize); | |
2107 | + | |
2108 | + /* Read the root inode */ | |
2109 | + root_i = pram_get_inode(sb, PRAM_ROOT_INO); | |
2110 | + | |
2111 | + if (pram_calc_checksum((u32*)root_i, PRAM_INODE_SIZE>>2)) { | |
2112 | + pram_err("checksum error in root inode!\n"); | |
2113 | + goto out; | |
2114 | + } | |
2115 | + | |
2116 | + /* Check that the root inode is in a sane state */ | |
2117 | + if (root_i->i_d.d_next) { | |
2118 | + pram_err("root->next not NULL??!!\n"); | |
2119 | + goto out; | |
2120 | + } | |
2121 | + | |
2122 | + if (!S_ISDIR(root_i->i_mode)) { | |
2123 | + pram_err("root is not a directory!\n"); | |
2124 | + goto out; | |
2125 | + } | |
2126 | + | |
2127 | + root_offset = root_i->i_type.dir.head; | |
2128 | + if (root_offset == 0) | |
2129 | + pram_info("empty filesystem\n"); | |
2130 | + | |
2131 | + /* Remap the whole filesystem now */ | |
2132 | + iounmap(sbi->virt_addr); | |
2133 | + sbi->virt_addr = pram_ioremap(sbi->phys_addr, maxsize, 0); | |
2134 | + if (!sbi->virt_addr) { | |
2135 | + pram_err("ioremap of the pramfs image failed\n"); | |
2136 | + goto out; | |
2137 | + } | |
2138 | + super = pram_get_super(sb); | |
2139 | + | |
2140 | + /* Set it all up.. */ | |
2141 | + setup_sb: | |
2142 | + sbi->maxsize = maxsize; | |
2143 | + sb->s_magic = sbi->magic = super->s_magic; | |
2144 | + sbi->features = super->s_features; | |
2145 | + | |
2146 | + sb->s_op = &pram_sops; | |
2147 | + sb->s_root = d_alloc_root(pram_fill_new_inode(sb, root_i)); | |
2148 | + | |
2149 | + retval = 0; | |
2150 | + out: | |
2151 | + if (retval && sbi->virt_addr) | |
2152 | + iounmap(sbi->virt_addr); | |
2153 | + | |
2154 | + return retval; | |
2155 | +} | |
2156 | + | |
2157 | +//static void pram_write_super (struct super_block * sb) | |
2158 | +//{ | |
2159 | +//} | |
2160 | + | |
2161 | +int pram_statfs (struct super_block * sb, struct kstatfs * buf) | |
2162 | +{ | |
2163 | + struct pram_super_block * ps = pram_get_super(sb); | |
2164 | + | |
2165 | + buf->f_type = PRAM_SUPER_MAGIC; | |
2166 | + buf->f_bsize = sb->s_blocksize; | |
2167 | + buf->f_blocks = ps->s_blocks_count; | |
2168 | + buf->f_bfree = buf->f_bavail = ps->s_free_blocks_count; | |
2169 | + buf->f_files = ps->s_inodes_count; | |
2170 | + buf->f_ffree = ps->s_free_inodes_count; | |
2171 | + buf->f_namelen = PRAM_NAME_LEN; | |
2172 | + return 0; | |
2173 | +} | |
2174 | + | |
2175 | +int pram_remount (struct super_block * sb, int * mntflags, char * data) | |
2176 | +{ | |
2177 | + struct pram_super_block * ps; | |
2178 | + unsigned long flags; | |
2179 | + | |
2180 | + if ((*mntflags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { | |
2181 | + ps = pram_get_super(sb); | |
2182 | + pram_lock_super(ps); | |
2183 | + ps->s_mtime = get_seconds(); // update mount time | |
2184 | + pram_unlock_super(ps); | |
2185 | + } | |
2186 | + return 0; | |
2187 | +} | |
2188 | + | |
2189 | +void pram_put_super (struct super_block * sb) | |
2190 | +{ | |
2191 | + struct pram_sb_info * sbi = (struct pram_sb_info *)sb->s_fs_info; | |
2192 | + | |
2193 | + /* It's unmount time, so unmap the pramfs memory */ | |
2194 | + if (sbi->virt_addr) { | |
2195 | + iounmap(sbi->virt_addr); | |
2196 | + sbi->virt_addr = NULL; | |
2197 | + } | |
2198 | + | |
2199 | + sb->s_fs_info = NULL; | |
2200 | + kfree(sbi); | |
2201 | +} | |
2202 | + | |
2203 | +/* | |
2204 | + * the super block writes are all done "on the fly", so the | |
2205 | + * super block is never in a "dirty" state, so there's no need | |
2206 | + * for write_super. | |
2207 | + */ | |
2208 | +static struct super_operations pram_sops = { | |
2209 | + read_inode: pram_read_inode, | |
2210 | + write_inode: pram_write_inode, | |
2211 | + dirty_inode: pram_dirty_inode, | |
2212 | + put_inode: pram_put_inode, | |
2213 | + delete_inode: pram_delete_inode, | |
2214 | + put_super: pram_put_super, | |
2215 | + //write_super: pram_write_super, | |
2216 | + statfs: pram_statfs, | |
2217 | + remount_fs: pram_remount, | |
2218 | +}; | |
2219 | + | |
2220 | +static struct super_block *pram_get_sb(struct file_system_type *fs_type, | |
2221 | + int flags, const char *dev_name, | |
2222 | + void *data) | |
2223 | +{ | |
2224 | + return get_sb_single(fs_type, flags, data, pram_fill_super); | |
2225 | +} | |
2226 | + | |
2227 | +static struct file_system_type pram_fs_type = { | |
2228 | + .owner = THIS_MODULE, | |
2229 | + .name = "pramfs", | |
2230 | + .get_sb = pram_get_sb, | |
2231 | + .kill_sb = kill_anon_super, | |
2232 | +}; | |
2233 | + | |
2234 | +static int __init init_pram_fs(void) | |
2235 | +{ | |
2236 | + return register_filesystem(&pram_fs_type); | |
2237 | +} | |
2238 | + | |
2239 | +static void __exit exit_pram_fs(void) | |
2240 | +{ | |
2241 | + unregister_filesystem(&pram_fs_type); | |
2242 | +} | |
2243 | + | |
2244 | +module_init(init_pram_fs) | |
2245 | +module_exit(exit_pram_fs) | |
2246 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/symlink.c main/fs/pramfs/symlink.c | |
2247 | --- main.orig/fs/pramfs/symlink.c 1969-12-31 16:00:00.000000000 -0800 | |
2248 | +++ main/fs/pramfs/symlink.c 2004-03-04 15:59:03.000000000 -0800 | |
2249 | @@ -0,0 +1,76 @@ | |
2250 | +/* | |
2251 | + * symlink.c | |
2252 | + * | |
2253 | + * Symlink methods. | |
2254 | + * | |
2255 | + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> | |
2256 | + * | |
2257 | + * 2003 (c) MontaVista Software, Inc. | |
2258 | + * Copyright 2003 Sony Corporation | |
2259 | + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. | |
2260 | + * | |
2261 | + * This software is being distributed under the terms of the GNU General Public | |
2262 | + * License version 2. Some or all of the technology encompassed by this | |
2263 | + * software may be subject to one or more patents pending as of the date of | |
2264 | + * this notice. No additional patent license will be required for GPL | |
2265 | + * implementations of the technology. If you want to create a non-GPL | |
2266 | + * implementation of the technology encompassed by this software, please | |
2267 | + * contact legal@mvista.com for details including licensing terms and fees. | |
2268 | + * | |
2269 | + * This file is licensed under the terms of the GNU General Public License | |
2270 | + * version 2. This program is licensed "as is" without any warranty of any | |
2271 | + * kind, whether express or implied. | |
2272 | + */ | |
2273 | +#include <linux/fs.h> | |
2274 | +#include <linux/pram_fs.h> | |
2275 | + | |
2276 | +int pram_block_symlink(struct inode *inode, const char *symname, int len) | |
2277 | +{ | |
2278 | + struct super_block * sb = inode->i_sb; | |
2279 | + pram_off_t block; | |
2280 | + char* blockp; | |
2281 | + unsigned long flags; | |
2282 | + int err; | |
2283 | + | |
2284 | + err = pram_alloc_blocks (inode, 0, 1); | |
2285 | + if (err) | |
2286 | + return err; | |
2287 | + | |
2288 | + block = pram_find_data_block(inode, 0); | |
2289 | + blockp = pram_get_block(sb, block); | |
2290 | + | |
2291 | + pram_lock_block(sb, blockp); | |
2292 | + memcpy(blockp, symname, len); | |
2293 | + blockp[len] = '\0'; | |
2294 | + pram_unlock_block(sb, blockp); | |
2295 | + return 0; | |
2296 | +} | |
2297 | + | |
2298 | +static int pram_readlink(struct dentry *dentry, char *buffer, int buflen) | |
2299 | +{ | |
2300 | + struct inode * inode = dentry->d_inode; | |
2301 | + struct super_block * sb = inode->i_sb; | |
2302 | + pram_off_t block; | |
2303 | + char* blockp; | |
2304 | + | |
2305 | + block = pram_find_data_block(inode, 0); | |
2306 | + blockp = pram_get_block(sb, block); | |
2307 | + return vfs_readlink(dentry, buffer, buflen, blockp); | |
2308 | +} | |
2309 | + | |
2310 | +static int pram_follow_link(struct dentry *dentry, struct nameidata *nd) | |
2311 | +{ | |
2312 | + struct inode * inode = dentry->d_inode; | |
2313 | + struct super_block * sb = inode->i_sb; | |
2314 | + pram_off_t block; | |
2315 | + char* blockp; | |
2316 | + | |
2317 | + block = pram_find_data_block(inode, 0); | |
2318 | + blockp = pram_get_block(sb, block); | |
2319 | + return vfs_follow_link(nd, blockp); | |
2320 | +} | |
2321 | + | |
2322 | +struct inode_operations pram_symlink_inode_operations = { | |
2323 | + readlink: pram_readlink, | |
2324 | + follow_link: pram_follow_link, | |
2325 | +}; | |
2326 | diff -Nuar -X /home/stevel/dontdiff main.orig/fs/pramfs/wprotect.c main/fs/pramfs/wprotect.c | |
2327 | --- main.orig/fs/pramfs/wprotect.c 1969-12-31 16:00:00.000000000 -0800 | |
2328 | +++ main/fs/pramfs/wprotect.c 2004-03-04 15:59:03.000000000 -0800 | |
2329 | @@ -0,0 +1,80 @@ | |
2330 | +/* | |
2331 | + * wprotect.c | |
2332 | + * | |
2333 | + * Write protection for the filesystem pages. | |
2334 | + * | |
2335 | + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> | |
2336 | + * | |
2337 | + * 2003 (c) MontaVista Software, Inc. | |
2338 | + * Copyright 2003 Sony Corporation | |
2339 | + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. | |
2340 | + * | |
2341 | + * This software is being distributed under the terms of the GNU General Public | |
2342 | + * License version 2. Some or all of the technology encompassed by this | |
2343 | + * software may be subject to one or more patents pending as of the date of | |
2344 | + * this notice. No additional patent license will be required for GPL | |
2345 | + * implementations of the technology. If you want to create a non-GPL | |
2346 | + * implementation of the technology encompassed by this software, please | |
2347 | + * contact legal@mvista.com for details including licensing terms and fees. | |
2348 | + * | |
2349 | + * This file is licensed under the terms of the GNU General Public License | |
2350 | + * version 2. This program is licensed "as is" without any warranty of any | |
2351 | + * kind, whether express or implied. | |
2352 | + */ | |
2353 | +#include <linux/config.h> | |
2354 | +#include <linux/module.h> | |
2355 | +#include <linux/fs.h> | |
2356 | +#include <linux/pram_fs.h> | |
2357 | +#include <linux/mm.h> | |
2358 | +#include <asm/pgtable.h> | |
2359 | +#include <asm/pgalloc.h> | |
2360 | + | |
2361 | +// init_mm.page_table_lock must be held before calling! | |
2362 | +static void pram_page_writeable(unsigned long addr, int rw) | |
2363 | +{ | |
2364 | + pgd_t *pgdp; | |
2365 | + pmd_t *pmdp; | |
2366 | + pte_t *ptep; | |
2367 | + | |
2368 | + pgdp = pgd_offset_k(addr); | |
2369 | + if (!pgd_none(*pgdp)) { | |
2370 | + pmdp = pmd_offset(pgdp, addr); | |
2371 | + if (!pmd_none(*pmdp)) { | |
2372 | + pte_t pte; | |
2373 | + ptep = pte_offset_kernel(pmdp, addr); | |
2374 | + pte = *ptep; | |
2375 | + if (pte_present(pte)) { | |
2376 | + pte = rw ? pte_mkwrite(pte) : | |
2377 | + pte_wrprotect(pte); | |
2378 | + set_pte(ptep, pte); | |
2379 | + } | |
2380 | + } | |
2381 | + } | |
2382 | +} | |
2383 | + | |
2384 | + | |
2385 | +// init_mm.page_table_lock must be held before calling! | |
2386 | +void pram_writeable(void * vaddr, unsigned long size, int rw) | |
2387 | +{ | |
2388 | + unsigned long addr = (unsigned long)vaddr & PAGE_MASK; | |
2389 | + unsigned long end = (unsigned long)vaddr + size; | |
2390 | + unsigned long start = addr; | |
2391 | + | |
2392 | + do { | |
2393 | + pram_page_writeable(addr, rw); | |
2394 | + addr += PAGE_SIZE; | |
2395 | + } while (addr && (addr < end)); | |
2396 | + | |
2397 | + | |
2398 | + /* | |
2399 | + * NOTE: we will always flush just one page (one TLB | |
2400 | + * entry) except possibly in one case: when a new | |
2401 | + * filesystem is initialized at mount time, when pram_read_super | |
2402 | + * calls pram_lock_range to make the super block, inode | |
2403 | + * table, and bitmap writeable. | |
2404 | + */ | |
2405 | + if (end <= start + PAGE_SIZE) | |
2406 | + flush_tlb_kernel_page(start); | |
2407 | + else | |
2408 | + flush_tlb_kernel_range(start, end); | |
2409 | +} | |
2410 | diff -Nuar -X /home/stevel/dontdiff main.orig/include/linux/pram_fs.h main/include/linux/pram_fs.h | |
2411 | --- main.orig/include/linux/pram_fs.h 1969-12-31 16:00:00.000000000 -0800 | |
2412 | +++ main/include/linux/pram_fs.h 2004-03-04 15:59:35.000000000 -0800 | |
2413 | @@ -0,0 +1,378 @@ | |
2414 | +/* | |
2415 | + * pram_fs.h | |
2416 | + * | |
2417 | + * Definitions for the PRAMFS filesystem. | |
2418 | + * | |
2419 | + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> | |
2420 | + * | |
2421 | + * 2003 (c) MontaVista Software, Inc. | |
2422 | + * Copyright 2003 Sony Corporation | |
2423 | + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. | |
2424 | + * | |
2425 | + * This software is being distributed under the terms of the GNU General Public | |
2426 | + * License version 2. Some or all of the technology encompassed by this | |
2427 | + * software may be subject to one or more patents pending as of the date of | |
2428 | + * this notice. No additional patent license will be required for GPL | |
2429 | + * implementations of the technology. If you want to create a non-GPL | |
2430 | + * implementation of the technology encompassed by this software, please | |
2431 | + * contact legal@mvista.com for details including licensing terms and fees. | |
2432 | + * | |
2433 | + * This file is licensed under the terms of the GNU General Public License | |
2434 | + * version 2. This program is licensed "as is" without any warranty of any | |
2435 | + * kind, whether express or implied. | |
2436 | + */ | |
2437 | +#ifndef _LINUX_PRAM_FS_H | |
2438 | +#define _LINUX_PRAM_FS_H | |
2439 | + | |
2440 | +#include <linux/types.h> | |
2441 | +#include <linux/pram_fs_sb.h> | |
2442 | + | |
2443 | +#ifdef __KERNEL__ | |
2444 | +#include <linux/sched.h> | |
2445 | +#endif | |
2446 | + | |
2447 | +/* | |
2448 | + * The PRAM filesystem constants/structures | |
2449 | + */ | |
2450 | + | |
2451 | +/* | |
2452 | + * Define PRAMFS_DEBUG to produce debug messages | |
2453 | + */ | |
2454 | +#undef PRAMFS_DEBUG | |
2455 | + | |
2456 | +/* | |
2457 | + * The PRAM filesystem version | |
2458 | + */ | |
2459 | +#define PRAMFS_DATE "2003/06/15" | |
2460 | +#define PRAMFS_VERSION "0.1b" | |
2461 | + | |
2462 | +/* | |
2463 | + * Debug code | |
2464 | + */ | |
2465 | +#ifdef __KERNEL__ | |
2466 | +#define PFX "pramfs" | |
2467 | +#ifdef PRAMFS_DEBUG | |
2468 | +#define pram_dbg(format, arg...) \ | |
2469 | + printk(KERN_DEBUG PFX ": " format , ## arg) | |
2470 | +#else | |
2471 | +#define pram_dbg(format, arg...) do {} while (0) | |
2472 | +#endif | |
2473 | +#define pram_err(format, arg...) \ | |
2474 | + printk(KERN_ERR PFX ": " format , ## arg) | |
2475 | +#define pram_info(format, arg...) \ | |
2476 | + printk(KERN_INFO PFX ": " format , ## arg) | |
2477 | +#define pram_warn(format, arg...) \ | |
2478 | + printk(KERN_WARNING PFX ": " format , ## arg) | |
2479 | +#endif | |
2480 | + | |
2481 | +/* | |
2482 | + * The PRAM file system magic number | |
2483 | + */ | |
2484 | +#define PRAM_SUPER_MAGIC 0xEFFA | |
2485 | + | |
2486 | +/* | |
2487 | + * Maximal count of links to a file | |
2488 | + */ | |
2489 | +#define PRAM_LINK_MAX 32000 | |
2490 | + | |
2491 | +typedef unsigned long pram_off_t; | |
2492 | + | |
2493 | +#define PRAM_MIN_BLOCK_SIZE 512 | |
2494 | +#define PRAM_MAX_BLOCK_SIZE 4096 | |
2495 | +#define PRAM_DEF_BLOCK_SIZE 2048 | |
2496 | + | |
2497 | +#define PRAM_INODE_SIZE 128 // must be power of two | |
2498 | +#define PRAM_INODE_BITS 7 | |
2499 | + | |
2500 | +/* | |
2501 | + * Structure of a directory entry in PRAMFS. | |
2502 | + * Offsets are to the inode that holds the referenced dentry. | |
2503 | + */ | |
2504 | +struct pram_dentry { | |
2505 | + pram_off_t d_next; /* next dentry in this directory */ | |
2506 | + pram_off_t d_prev; /* previous dentry in this directory */ | |
2507 | + pram_off_t d_parent; /* parent directory */ | |
2508 | + char d_name[0]; | |
2509 | +}; | |
2510 | + | |
2511 | + | |
2512 | +/* | |
2513 | + * Structure of an inode in PRAMFS | |
2514 | + */ | |
2515 | +struct pram_inode { | |
2516 | + __u32 i_sum; /* checksum of this inode */ | |
2517 | + __u32 i_uid; /* Owner Uid */ | |
2518 | + __u32 i_gid; /* Group Id */ | |
2519 | + __u16 i_mode; /* File mode */ | |
2520 | + __u16 i_links_count; /* Links count */ | |
2521 | + __u32 i_blocks; /* Blocks count */ | |
2522 | + __u32 i_size; /* Size of data in bytes */ | |
2523 | + __u32 i_atime; /* Access time */ | |
2524 | + __u32 i_ctime; /* Creation time */ | |
2525 | + __u32 i_mtime; /* Modification time */ | |
2526 | + __u32 i_dtime; /* Deletion Time */ | |
2527 | + | |
2528 | + union { | |
2529 | + struct { | |
2530 | + /* | |
2531 | + * ptr to row block of 2D block pointer array, | |
2532 | + * file block #'s 0 to (blocksize/4)^2 - 1. | |
2533 | + */ | |
2534 | + pram_off_t row_block; | |
2535 | + } reg; // regular file or symlink inode | |
2536 | + struct { | |
2537 | + pram_off_t head; /* first entry in this directory */ | |
2538 | + pram_off_t tail; /* last entry in this directory */ | |
2539 | + } dir; | |
2540 | + struct { | |
2541 | + __u32 rdev; /* major/minor # */ | |
2542 | + } dev; // device inode | |
2543 | + } i_type; | |
2544 | + | |
2545 | + struct pram_dentry i_d; | |
2546 | +}; | |
2547 | + | |
2548 | +#define PRAM_NAME_LEN \ | |
2549 | + (PRAM_INODE_SIZE - offsetof(struct pram_inode, i_d.d_name) - 1) | |
2550 | + | |
2551 | + | |
2552 | +/* | |
2553 | + * Behaviour when detecting errors | |
2554 | + */ | |
2555 | +#define PRAM_ERRORS_CONTINUE 1 /* Continue execution */ | |
2556 | +#define PRAM_ERRORS_RO 2 /* Remount fs read-only */ | |
2557 | +#define PRAM_ERRORS_PANIC 3 /* Panic */ | |
2558 | +#define PRAM_ERRORS_DEFAULT PRAM_ERRORS_CONTINUE | |
2559 | + | |
2560 | +#define PRAM_SB_SIZE 128 // must be power of two | |
2561 | +#define PRAM_SB_BITS 7 | |
2562 | + | |
2563 | +/* | |
2564 | + * Structure of the super block in PRAMFS | |
2565 | + */ | |
2566 | +struct pram_super_block { | |
2567 | + __u32 s_size; /* total size of fs in bytes */ | |
2568 | + __u32 s_blocksize; /* blocksize in bytes */ | |
2569 | + __u32 s_features; /* feature flags */ | |
2570 | + __u32 s_inodes_count; /* total inodes count (used or free) */ | |
2571 | + __u32 s_free_inodes_count;/* free inodes count */ | |
2572 | + __u32 s_free_inode_hint; /* start hint for locating free inodes */ | |
2573 | + __u32 s_blocks_count; /* total data blocks count (used or free) */ | |
2574 | + __u32 s_free_blocks_count;/* free data blocks count */ | |
2575 | + __u32 s_free_blocknr_hint;/* free data blocks count */ | |
2576 | + pram_off_t s_bitmap_start; /* data block in-use bitmap location */ | |
2577 | + __u32 s_bitmap_blocks;/* size of bitmap in number of blocks */ | |
2578 | + __u32 s_mtime; /* Mount time */ | |
2579 | + __u32 s_wtime; /* Write time */ | |
2580 | + __u32 s_rev_level; /* Revision level */ | |
2581 | + __u16 s_magic; /* Magic signature */ | |
2582 | + __u16 s_state; /* File system state */ | |
2583 | + __u16 s_errors; /* Behaviour when detecting errors */ | |
2584 | + char s_volume_name[16]; /* volume name */ | |
2585 | + __u32 s_sum; /* checksum of this sb, including padding */ | |
2586 | +}; | |
2587 | + | |
2588 | +/* The root inode follows immediately after the super block */ | |
2589 | +#define PRAM_ROOT_INO PRAM_SB_SIZE | |
2590 | + | |
2591 | +#ifdef __KERNEL__ | |
2592 | + | |
2593 | +/* Function Prototypes */ | |
2594 | + | |
2595 | +/* balloc.c */ | |
2596 | +extern void pram_init_bitmap(struct super_block * sb); | |
2597 | +extern void pram_free_block (struct super_block * sb, int blocknr); | |
2598 | +extern int pram_new_block (struct super_block * sb, int* blocknr, int zero); | |
2599 | +extern unsigned long pram_count_free_blocks (struct super_block * sb); | |
2600 | + | |
2601 | +/* dir.c */ | |
2602 | +extern int pram_add_link (struct dentry * dentry, struct inode *inode); | |
2603 | +extern int pram_remove_link(struct inode * inode); | |
2604 | + | |
2605 | +/* file.c */ | |
2606 | +extern int pram_direct_IO(int rw, struct kiocb *iocb, | |
2607 | + const struct iovec *iov, | |
2608 | + loff_t offset, unsigned long nr_segs); | |
2609 | + | |
2610 | +/* fsync.c */ | |
2611 | +extern int pram_sync_file (struct file *, struct dentry *, int); | |
2612 | +extern int pram_fsync_inode (struct inode *, int); | |
2613 | + | |
2614 | +/* inode.c */ | |
2615 | +extern int pram_alloc_blocks(struct inode * inode, int file_blocknr, int num); | |
2616 | +extern pram_off_t pram_find_data_block(struct inode * inode, | |
2617 | + int file_blocknr); | |
2618 | +extern struct inode * pram_fill_new_inode(struct super_block *sb, | |
2619 | + struct pram_inode * raw_inode); | |
2620 | +extern void pram_put_inode (struct inode * inode); | |
2621 | +extern void pram_delete_inode (struct inode * inode); | |
2622 | +extern struct inode * pram_new_inode (const struct inode * dir, int mode); | |
2623 | +extern void pram_read_inode (struct inode * inode); | |
2624 | +extern void pram_truncate (struct inode * inode); | |
2625 | +extern void pram_write_inode (struct inode * inode, int wait); | |
2626 | +extern void pram_dirty_inode(struct inode * inode); | |
2627 | + | |
2628 | +/* ioctl.c */ | |
2629 | +extern int pram_ioctl (struct inode *, struct file *, unsigned int, | |
2630 | + unsigned long); | |
2631 | + | |
2632 | +/* super.c */ | |
2633 | +extern struct super_block * find_pramfs_super(void); | |
2634 | +extern struct super_block * pram_read_super (struct super_block * sb, | |
2635 | + void * data, | |
2636 | + int silent); | |
2637 | +extern int pram_statfs (struct super_block * sb, struct kstatfs * buf); | |
2638 | +extern int pram_remount (struct super_block * sb, int * flags, char * data); | |
2639 | + | |
2640 | +/* symlink.c */ | |
2641 | +extern int pram_block_symlink(struct inode *inode, | |
2642 | + const char *symname, int len); | |
2643 | + | |
2644 | +/* wprotect.c */ | |
2645 | +#ifndef CONFIG_PRAMFS_NOWP | |
2646 | +extern void pram_writeable (void * vaddr, unsigned long size, int rw); | |
2647 | +#endif | |
2648 | + | |
2649 | +/* Inline functions start here */ | |
2650 | + | |
2651 | +static inline u32 pram_calc_checksum(u32* buf, int n) | |
2652 | +{ | |
2653 | + u32 sum = 0; | |
2654 | + while (n--) | |
2655 | + sum += *buf++; | |
2656 | + return sum; | |
2657 | +} | |
2658 | + | |
2659 | +// If this is part of a read-modify-write of the super block, | |
2660 | +// pram_lock_super() before calling! | |
2661 | +static inline struct pram_super_block * | |
2662 | +pram_get_super(struct super_block * sb) | |
2663 | +{ | |
2664 | + struct pram_sb_info * sbi = (struct pram_sb_info *)sb->s_fs_info; | |
2665 | + return (struct pram_super_block *)sbi->virt_addr; | |
2666 | +} | |
2667 | + | |
2668 | +// pram_lock_super() before calling! | |
2669 | +static inline void pram_sync_super(struct pram_super_block * ps) | |
2670 | +{ | |
2671 | + ps->s_wtime = get_seconds(); | |
2672 | + ps->s_sum = 0; | |
2673 | + ps->s_sum = - pram_calc_checksum((u32*)ps, PRAM_SB_SIZE>>2); | |
2674 | +} | |
2675 | + | |
2676 | +// pram_lock_inode() before calling! | |
2677 | +static inline void pram_sync_inode(struct pram_inode * pi) | |
2678 | +{ | |
2679 | + //pi->i_mtime = CURRENT_TIME; | |
2680 | + pi->i_sum = 0; | |
2681 | + pi->i_sum = - pram_calc_checksum((u32*)pi, PRAM_INODE_SIZE>>2); | |
2682 | +} | |
2683 | + | |
2684 | +#ifndef CONFIG_PRAMFS_NOWP | |
2685 | +#define pram_lock_range(p, len) {\ | |
2686 | + spin_lock_irqsave(&init_mm.page_table_lock, flags);\ | |
2687 | + pram_writeable((p), (len), 1);\ | |
2688 | +} | |
2689 | + | |
2690 | +#define pram_unlock_range(p, len) {\ | |
2691 | + pram_writeable((p), (len), 0);\ | |
2692 | + spin_unlock_irqrestore(&init_mm.page_table_lock, flags);\ | |
2693 | +} | |
2694 | +#else | |
2695 | +#define pram_lock_range(p, len) do {} while (0) | |
2696 | +#define pram_unlock_range(p, len) do {} while (0) | |
2697 | +#endif | |
2698 | + | |
2699 | +// write protection for super block | |
2700 | +#define pram_lock_super(ps) \ | |
2701 | + pram_lock_range((ps), PRAM_SB_SIZE) | |
2702 | +#define pram_unlock_super(ps) {\ | |
2703 | + pram_sync_super(ps);\ | |
2704 | + pram_unlock_range((ps), PRAM_SB_SIZE);\ | |
2705 | +} | |
2706 | + | |
2707 | +// write protection for inode metadata | |
2708 | +#define pram_lock_inode(pi) \ | |
2709 | + pram_lock_range((pi), PRAM_INODE_SIZE) | |
2710 | +#define pram_unlock_inode(pi) {\ | |
2711 | + pram_sync_inode(pi);\ | |
2712 | + pram_unlock_range((pi), PRAM_SB_SIZE);\ | |
2713 | +} | |
2714 | + | |
2715 | +// write protection for a data block | |
2716 | +#define pram_lock_block(sb, bp) \ | |
2717 | + pram_lock_range((bp), (sb)->s_blocksize) | |
2718 | +#define pram_unlock_block(sb, bp) \ | |
2719 | + pram_unlock_range((bp), (sb)->s_blocksize) | |
2720 | + | |
2721 | +static inline void * | |
2722 | +pram_get_bitmap(struct super_block * sb) | |
2723 | +{ | |
2724 | + struct pram_super_block * ps = pram_get_super(sb); | |
2725 | + return ((void*)ps + ps->s_bitmap_start); | |
2726 | +} | |
2727 | + | |
2728 | +// If this is part of a read-modify-write of the inode metadata, | |
2729 | +// pram_lock_inode() before calling! | |
2730 | +static inline struct pram_inode * | |
2731 | +pram_get_inode(struct super_block * sb, pram_off_t ino) | |
2732 | +{ | |
2733 | + struct pram_super_block * ps = pram_get_super(sb); | |
2734 | + return ino ? (struct pram_inode *)((void*)ps + ino) : NULL; | |
2735 | +} | |
2736 | + | |
2737 | +static inline ino_t | |
2738 | +pram_get_inodenr(struct super_block * sb, struct pram_inode * pi) | |
2739 | +{ | |
2740 | + struct pram_super_block * ps = pram_get_super(sb); | |
2741 | + return (ino_t)((unsigned long)pi - (unsigned long)ps); | |
2742 | +} | |
2743 | + | |
2744 | +static inline pram_off_t | |
2745 | +pram_get_block_off(struct super_block * sb, unsigned long blocknr) | |
2746 | +{ | |
2747 | + struct pram_super_block * ps = pram_get_super(sb); | |
2748 | + return (pram_off_t)(ps->s_bitmap_start + | |
2749 | + (blocknr << sb->s_blocksize_bits)); | |
2750 | +} | |
2751 | + | |
2752 | +static inline unsigned long | |
2753 | +pram_get_blocknr(struct super_block * sb, pram_off_t block) | |
2754 | +{ | |
2755 | + struct pram_super_block * ps = pram_get_super(sb); | |
2756 | + return (block - ps->s_bitmap_start) >> sb->s_blocksize_bits; | |
2757 | +} | |
2758 | + | |
2759 | +// If this is part of a read-modify-write of the block, | |
2760 | +// pram_lock_block() before calling! | |
2761 | +static inline void * | |
2762 | +pram_get_block(struct super_block * sb, pram_off_t block) | |
2763 | +{ | |
2764 | + struct pram_super_block * ps = pram_get_super(sb); | |
2765 | + return block ? ((void*)ps + block) : NULL; | |
2766 | +} | |
2767 | + | |
2768 | + | |
2769 | +/* | |
2770 | + * Inodes and files operations | |
2771 | + */ | |
2772 | + | |
2773 | +/* dir.c */ | |
2774 | +extern struct file_operations pram_dir_operations; | |
2775 | + | |
2776 | +/* file.c */ | |
2777 | +extern struct inode_operations pram_file_inode_operations; | |
2778 | +extern struct file_operations pram_file_operations; | |
2779 | + | |
2780 | +/* inode.c */ | |
2781 | +extern struct address_space_operations pram_aops; | |
2782 | + | |
2783 | +/* namei.c */ | |
2784 | +extern struct inode_operations pram_dir_inode_operations; | |
2785 | + | |
2786 | +/* symlink.c */ | |
2787 | +extern struct inode_operations pram_symlink_inode_operations; | |
2788 | + | |
2789 | +#endif /* __KERNEL__ */ | |
2790 | + | |
2791 | +#endif /* _LINUX_PRAM_FS_H */ | |
2792 | diff -Nuar -X /home/stevel/dontdiff main.orig/include/linux/pram_fs_sb.h main/include/linux/pram_fs_sb.h | |
2793 | --- main.orig/include/linux/pram_fs_sb.h 1969-12-31 16:00:00.000000000 -0800 | |
2794 | +++ main/include/linux/pram_fs_sb.h 2004-03-04 15:59:35.000000000 -0800 | |
2795 | @@ -0,0 +1,43 @@ | |
2796 | +/* | |
2797 | + * pram_fs_sb.h | |
2798 | + * | |
2799 | + * Definitions for the PRAM filesystem. | |
2800 | + * | |
2801 | + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> | |
2802 | + * | |
2803 | + * 2003 (c) MontaVista Software, Inc. | |
2804 | + * Copyright 2003 Sony Corporation | |
2805 | + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. | |
2806 | + * | |
2807 | + * This software is being distributed under the terms of the GNU General Public | |
2808 | + * License version 2. Some or all of the technology encompassed by this | |
2809 | + * software may be subject to one or more patents pending as of the date of | |
2810 | + * this notice. No additional patent license will be required for GPL | |
2811 | + * implementations of the technology. If you want to create a non-GPL | |
2812 | + * implementation of the technology encompassed by this software, please | |
2813 | + * contact legal@mvista.com for details including licensing terms and fees. | |
2814 | + * | |
2815 | + * This file is licensed under the terms of the GNU General Public License | |
2816 | + * version 2. This program is licensed "as is" without any warranty of any | |
2817 | + * kind, whether express or implied. | |
2818 | + */ | |
2819 | +#ifndef _LINUX_PRAM_FS_SB | |
2820 | +#define _LINUX_PRAM_FS_SB | |
2821 | + | |
2822 | +/* | |
2823 | + * PRAM filesystem super-block data in memory | |
2824 | + */ | |
2825 | +struct pram_sb_info { | |
2826 | + /* | |
2827 | + * base physical and virtual address of PRAMFS (which is also | |
2828 | + * the pointer to the super block) | |
2829 | + */ | |
2830 | + unsigned long phys_addr; | |
2831 | + void * virt_addr; | |
2832 | + | |
2833 | + u32 maxsize; | |
2834 | + u32 features; | |
2835 | + u16 magic; | |
2836 | +}; | |
2837 | + | |
2838 | +#endif /* _LINUX_PRAM_FS_SB */ | |
2839 | diff -Nuar -X /home/stevel/dontdiff main.orig/init/do_mounts.c main/init/do_mounts.c | |
2840 | --- main.orig/init/do_mounts.c 2004-03-04 17:17:14.000000000 -0800 | |
2841 | +++ main/init/do_mounts.c 2004-03-04 15:59:38.000000000 -0800 | |
2842 | @@ -322,6 +322,17 @@ | |
2843 | } | |
2844 | #endif | |
2845 | ||
2846 | +#ifdef CONFIG_ROOT_PRAMFS | |
2847 | +static int __init mount_pramfs_root(void) | |
2848 | +{ | |
2849 | + create_dev("/dev/root", ROOT_DEV, NULL); | |
2850 | + if (do_mount_root("/dev/root", "pramfs", | |
2851 | + root_mountflags, root_mount_data) == 0) | |
2852 | + return 1; | |
2853 | + return 0; | |
2854 | +} | |
2855 | +#endif | |
2856 | + | |
2857 | #if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD) | |
2858 | void __init change_floppy(char *fmt, ...) | |
2859 | { | |
2860 | @@ -363,6 +374,15 @@ | |
2861 | ROOT_DEV = Root_FD0; | |
2862 | } | |
2863 | #endif | |
2864 | +#ifdef CONFIG_ROOT_PRAMFS | |
2865 | + if (ROOT_DEV == MKDEV(0, 0)) { | |
2866 | + if (mount_pramfs_root()) | |
2867 | + return; | |
2868 | + | |
2869 | + printk (KERN_ERR "VFS: Unable to mount PRAMFS root\n"); | |
2870 | + ROOT_DEV = Root_FD0; | |
2871 | + } | |
2872 | +#endif | |
2873 | #ifdef CONFIG_BLK_DEV_FD | |
2874 | if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { | |
2875 | /* rd_doload is 2 for a dual initrd/ramload setup */ |