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
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.
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
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.
27 +But the disk-based fs over non-volatile RAM block driver approach has
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.
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
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.
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.
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
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
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
88 +Supported mount options
89 +=======================
91 +The PRAMFS currently requires one mount option, and there are several
92 +optional mount options:
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.
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.
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
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
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
128 +mount -t pramfs -o physaddr=0x20000000,init=0x2F000,bs=1024 none /mnt/pram
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.
134 +mount -t pramfs -o physaddr=0x20000000 none /mnt/pram
136 +This example locates the filesystem at physical address 0x20000000 as in
137 +the first example, but uses the intact filesystem that already exists.
143 +- The RAM used for PRAMFS must be directly addressable.
145 +- PRAMFS does not support hard links.
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.
151 +Further Documentation
152 +=====================
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.
158 +Please send bug reports/comments/feed back to the pramfs development
159 +list at sourceforge: pramfs-devel@lists.sourceforge.net.
167 + - use pram_truncate() in pram_delete_inode().
168 + - dangling pram_lock_inode() removed in pram_truncate_blocks().
169 + - edits to this README
172 + - port to kernel 2.6.3.
173 + - implement direct_IO() method instead of custom file read/write
175 + - do away with __ioremap_readonly() requirement.
176 + - implement inode truncate() method.
179 + - Started ChangeLog (kernel 2.4.22).
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
185 To compile this as a module, choose M here: the module will be called
189 + tristate "Persistent and Protected RAM file system support"
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>.
196 + To compile this as a module, choose M here: the module will be
200 + bool "Disable write protection (default is enabled)"
203 + Say Y here to disable the write protect feature of PRAMFS.
206 + bool "Root file system on pramfs"
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
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
230 + * The blocks allocation and deallocation routines.
232 + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
234 + * 2003 (c) MontaVista Software, Inc.
235 + * Copyright 2003 Sony Corporation
236 + * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
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.
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.
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>
258 + * This just marks in-use the blocks that make up the bitmap.
259 + * The bitmap must be writeable before calling.
261 +void pram_init_bitmap(struct super_block * sb)
263 + struct pram_super_block * ps = pram_get_super(sb);
264 + u32* bitmap = pram_get_bitmap(sb);
265 + int blocks = ps->s_bitmap_blocks;
267 + memset(bitmap, 0, blocks<<sb->s_blocksize_bits);
269 + while (blocks >= 32) {
270 + *bitmap++ = 0xffffffff;
275 + *bitmap = (1<<blocks) - 1;
279 +/* Free absolute blocknr */
280 +void pram_free_block (struct super_block * sb, int blocknr)
282 + struct pram_super_block * ps;
283 + pram_off_t bitmap_block;
284 + unsigned long flags;
291 + bitmap = pram_get_bitmap(sb);
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.
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);
301 + pram_lock_block(sb, bp);
302 + clear_bit(blocknr, bitmap); // mark the block free
303 + pram_unlock_block(sb, bp);
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);
317 + * allocate a block and return it's absolute blocknr. Zeroes out the
318 + * block if zero set.
320 +int pram_new_block (struct super_block * sb, int* blocknr, int zero)
322 + struct pram_super_block * ps;
323 + pram_off_t bitmap_block;
324 + unsigned long flags;
325 + int bnr, bitmap_bnr, errval;
330 + ps = pram_get_super(sb);
331 + bitmap = pram_get_bitmap(sb);
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);
339 + if (bnr < ps->s_bitmap_blocks || bnr >= ps->s_blocks_count) {
340 + pram_err("no free blocks found!\n");
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);
352 + pram_err("all blocks allocated\n");
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.
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);
366 + pram_lock_block(sb, bp);
367 + set_bit(bnr, bitmap); // mark the new block in use
368 + pram_unlock_block(sb, bp);
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);
385 +unsigned long pram_count_free_blocks (struct super_block * sb)
387 + struct pram_super_block * ps = pram_get_super(sb);
388 + return ps->s_free_blocks_count;
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
397 + * File operations for directories.
399 + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
401 + * 2003 (c) MontaVista Software, Inc.
402 + * Copyright 2003 Sony Corporation
403 + * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
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.
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.
418 +#include <linux/fs.h>
419 +#include <linux/pram_fs.h>
420 +#include <linux/pagemap.h>
424 + * Parent is locked.
426 +int pram_add_link (struct dentry * dentry, struct inode * inode)
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;
436 + pidir = pram_get_inode(dir->i_sb, dir->i_ino);
437 + pi = pram_get_inode(dir->i_sb, inode->i_ino);
439 + dir->i_mtime = dir->i_ctime = CURRENT_TIME;
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);
448 + prev_ino = tail_ino;
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);
456 + // the directory is empty
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);
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);
476 +int pram_remove_link(struct inode * inode)
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;
484 + pi = pram_get_inode(sb, inode->i_ino);
485 + pidir = pram_get_inode(sb, pi->i_d.d_parent);
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);
494 + pram_lock_inode(next);
495 + next->i_d.d_prev = 0;
496 + pram_unlock_inode(next);
498 + pram_lock_inode(pidir);
499 + pidir->i_type.dir.head = pi->i_d.d_next;
501 + pram_lock_inode(pidir);
502 + pidir->i_type.dir.head = pidir->i_type.dir.tail = 0;
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);
509 + pram_lock_inode(prev);
510 + prev->i_d.d_next = 0;
511 + pram_unlock_inode(prev);
513 + pram_lock_inode(pidir);
514 + pidir->i_type.dir.tail = pi->i_d.d_prev;
515 + pram_unlock_inode(pidir);
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);
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);
526 + pram_lock_inode(next);
527 + next->i_d.d_prev = pi->i_d.d_prev;
528 + pram_unlock_inode(next);
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);
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,
551 +pram_readdir (struct file * filp, void * dirent, filldir_t filldir)
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;
560 + if (filp->f_pos >> 32)
563 + pi = pram_get_inode(sb, inode->i_ino);
565 + switch ((unsigned long)filp->f_pos) {
567 + ret = filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR);
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;
576 + ino = pi->i_type.dir.head;
579 + pi = pram_get_inode(sb, ino);
582 + /* the directory is empty */
590 + pi = pram_get_inode(sb, ino);
594 + while (pi && !pi->i_links_count) {
595 + ino = filp->f_pos = pi->i_d.d_next;
596 + pi = pram_get_inode(sb, ino);
600 + name = pi->i_d.d_name;
601 + namelen = strlen(name);
603 + ret = filldir(dirent, name, namelen,
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;
613 +struct file_operations pram_dir_operations = {
614 + read: generic_read_dir,
615 + readdir: pram_readdir,
617 + fsync: pram_sync_file,
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
626 + * File operations for regular files.
628 + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
630 + * 2003 (c) MontaVista Software, Inc.
631 + * Copyright 2003 Sony Corporation
632 + * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
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.
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.
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>
653 +static int pram_open_file(struct inode * inode, struct file * filp)
655 + filp->f_flags |= O_DIRECT;
656 + return generic_file_open(inode, filp);
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.
664 +static int pram_release_file (struct inode * inode, struct file * filp)
669 +int pram_direct_IO(int rw, struct kiocb *iocb,
670 + const struct iovec *iov,
671 + loff_t offset, unsigned long nr_segs)
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;
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;
686 + if ((rw == READ) && (offset + length > inode->i_size))
687 + length = inode->i_size - offset;
691 + blocksize_bits = inode->i_sb->s_blocksize_bits;
692 + blocksize = 1 << blocksize_bits;
693 + blocksize_mask = blocksize - 1;
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;
703 + // prepare a temporary buffer to hold a user data block
705 + tmp = kmalloc(blocksize, GFP_KERNEL);
708 + /* now allocate the data blocks we'll need */
709 + retval = pram_alloc_blocks(inode, blocknr, num_blocks);
714 + pi = pram_get_inode(inode->i_sb, inode->i_ino);
718 + pram_off_t block = pram_find_data_block(inode, blocknr++);
719 + u8* bp = (u8*)pram_get_block(sb, block);
723 + count = blockoff + length > blocksize ?
724 + blocksize - blockoff : length;
727 + copy_to_user(buf, &bp[blockoff], count);
729 + copy_from_user(tmp, buf, count);
731 + pram_lock_block(inode->i_sb, bp);
732 + memcpy(&bp[blockoff], tmp, count);
733 + pram_unlock_block(inode->i_sb, bp);
752 +struct file_operations pram_file_operations = {
753 + llseek: generic_file_llseek,
754 + read: generic_file_read,
755 + write: generic_file_write,
757 + mmap: generic_file_mmap,
758 + open: pram_open_file,
759 + release: pram_release_file,
760 + fsync: pram_sync_file,
763 +struct inode_operations pram_file_inode_operations = {
764 + truncate: pram_truncate,
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
773 + * fsync operation for directory and regular files.
775 + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
777 + * 2003 (c) MontaVista Software, Inc.
778 + * Copyright 2003 Sony Corporation
779 + * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
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.
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.
793 +#include <linux/fs.h>
794 +#include <linux/pram_fs.h>
797 + * File may be NULL when we are called. Perhaps we shouldn't
798 + * even pass file to fsync ?
801 +int pram_sync_file(struct file * file, struct dentry *dentry, int datasync)
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
814 + * Inode methods (allocate/free/read/write).
816 + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
818 + * 2003 (c) MontaVista Software, Inc.
819 + * Copyright 2003 Sony Corporation
820 + * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
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.
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.
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>
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 */
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.
856 +pram_new_data_block (struct inode * inode, int* blocknr, int zero)
858 + unsigned long flags;
859 + int errval = pram_new_block(inode->i_sb, blocknr, zero);
862 + struct pram_inode * pi = pram_get_inode(inode->i_sb,
865 + pram_lock_inode(pi);
866 + pi->i_blocks = inode->i_blocks;
867 + pram_unlock_inode(pi);
874 + * find the offset to the block represented by the given inode's file
875 + * relative block number.
877 +pram_off_t pram_find_data_block(struct inode * inode, int file_blocknr)
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 */
885 + int N = sb->s_blocksize >> 2; // num block ptrs per block
886 + int Nbits = sb->s_blocksize_bits - 2;
888 + pi = pram_get_inode(sb, inode->i_ino);
890 + i_row = file_blocknr >> Nbits;
891 + i_col = file_blocknr & (N-1);
893 + row = pram_get_block(sb, pi->i_type.reg.row_block);
895 + col = pram_get_block(sb, row[i_row]);
905 + * Free data blocks from inode starting at first_trunc_block.
908 +pram_truncate_blocks(struct inode * inode, int first_trunc_block)
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 */
920 + if (first_trunc_block >= inode->i_blocks ||
921 + !inode->i_blocks || !pi->i_type.reg.row_block) {
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;
930 + row = pram_get_block(sb, pi->i_type.reg.row_block);
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;
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);
944 + pram_unlock_block(sb, col);
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);
952 + pram_unlock_block(sb, row);
956 + inode->i_blocks -= (last_blocknr - first_blocknr + 1);
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);
965 + pram_lock_inode(pi);
966 + pi->i_blocks = inode->i_blocks;
967 + pram_unlock_inode(pi);
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.
975 +int pram_alloc_blocks(struct inode * inode, int file_blocknr, int num)
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;
989 + if (!pi->i_type.reg.row_block) {
990 + /* alloc the 2nd order array block */
991 + errval = pram_new_block(sb, &blocknr, 1);
993 + pram_err("failed to alloc 2nd order array block\n");
996 + pram_lock_inode(pi);
997 + pi->i_type.reg.row_block = pram_get_block_off(sb, blocknr);
998 + pram_unlock_inode(pi);
1001 + row = pram_get_block(sb, pi->i_type.reg.row_block);
1003 + first_file_blocknr = (file_blocknr > inode->i_blocks) ?
1004 + inode->i_blocks : file_blocknr;
1005 + last_file_blocknr = file_blocknr + num - 1;
1007 + first_row_index = first_file_blocknr >> Nbits;
1008 + last_row_index = last_file_blocknr >> Nbits;
1010 + for (i=first_row_index; i<=last_row_index; i++) {
1011 + int first_col_index, last_col_index;
1013 + * we are starting a new row, so make sure
1014 + * there is a block allocated for the row.
1017 + /* allocate the row block */
1018 + errval = pram_new_block(sb, &blocknr, 1);
1020 + pram_err("failed to alloc row block\n");
1023 + pram_lock_block(sb, row);
1024 + row[i] = pram_get_block_off(sb, blocknr);
1025 + pram_unlock_block(sb, row);
1027 + col = pram_get_block(sb, row[i]);
1029 + first_col_index = (i == first_row_index) ?
1030 + first_file_blocknr & (N-1) : 0;
1032 + last_col_index = (i == last_row_index) ?
1033 + last_file_blocknr & (N-1) : N-1;
1035 + for (j=first_col_index; j<=last_col_index; j++) {
1037 + (i==last_row_index) && (j==last_col_index);
1039 + errval = pram_new_data_block(inode,
1043 + pram_err("failed to alloc "
1047 + pram_lock_block(sb, col);
1048 + col[j] = pram_get_block_off(sb, blocknr);
1049 + pram_unlock_block(sb, col);
1061 +pram_fill_inode(struct inode * inode, struct pram_inode * pi)
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);
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;
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 */
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;
1095 + insert_inode_hash(inode);
1096 + switch (inode->i_mode & S_IFMT) {
1098 + inode->i_op = &pram_file_inode_operations;
1099 + inode->i_fop = &pram_file_operations;
1102 + inode->i_op = &pram_dir_inode_operations;
1103 + inode->i_fop = &pram_dir_operations;
1106 + inode->i_op = &pram_symlink_inode_operations;
1109 + inode->i_size = 0;
1110 + init_special_inode(inode, inode->i_mode,
1111 + pi->i_type.dev.rdev);
1118 + make_bad_inode(inode);
1122 +static int pram_update_inode(struct inode * inode)
1124 + struct pram_inode * pi;
1125 + unsigned long flags;
1128 + pi = pram_get_inode(inode->i_sb, inode->i_ino);
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;
1141 + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
1142 + pi->i_type.dev.rdev = inode->i_rdev;
1144 + pram_unlock_inode(pi);
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.
1156 +static void pram_free_inode (struct inode * inode)
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;
1164 + * Note: we must free any quota before locking the superblock,
1165 + * as writing the quota to disk may need the lock as well.
1167 + if (!is_bad_inode(inode)) {
1168 + /* Quota is already initialized in iput() */
1169 + DQUOT_FREE_INODE(inode);
1170 + DQUOT_DROP(inode);
1174 + clear_inode (inode);
1176 + inode_nr = (inode->i_ino - PRAM_ROOT_INO) >> PRAM_INODE_BITS;
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);
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;
1195 + pram_unlock_super(ps);
1197 + unlock_super (sb);
1202 +pram_fill_new_inode(struct super_block *sb,
1203 + struct pram_inode * pi)
1205 + struct inode * inode = new_inode(sb);
1208 + pram_fill_inode(inode, pi);
1215 + * Called at each iput()
1217 +void pram_put_inode (struct inode * inode)
1223 + * Called at the last iput() if i_nlink is zero.
1225 +void pram_delete_inode (struct inode * inode)
1229 + if (is_bad_inode(inode))
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);
1243 + clear_inode(inode); /* We must guarantee clearing of inode... */
1247 +struct inode * pram_new_inode (const struct inode * dir, int mode)
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;
1258 + inode = new_inode(sb);
1260 + return ERR_PTR(-ENOMEM);
1263 + ps = pram_get_super(sb);
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 ||
1273 + /* this inode is deleted */
1278 + if (i >= ps->s_inodes_count) {
1279 + pram_err("s_free_inodes_count!=0 but none free!?\n");
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);
1290 + pram_err("no space left to create new inode!\n");
1295 + // chosen inode is in ino
1297 + inode->i_ino = ino;
1298 + inode->i_uid = current->fsuid;
1300 + if (dir->i_mode & S_ISGID) {
1301 + inode->i_gid = dir->i_gid;
1302 + if (S_ISDIR(mode))
1305 + inode->i_gid = current->fsgid;
1306 + inode->i_mode = mode;
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;
1312 + pram_lock_inode(pi);
1313 + pi->i_d.d_next = 0;
1314 + pi->i_d.d_prev = 0;
1315 + pram_unlock_inode(pi);
1317 + insert_inode_hash(inode);
1318 + pram_write_inode(inode, 0);
1320 + unlock_super (sb);
1322 + if(DQUOT_ALLOC_INODE(inode)) {
1323 + DQUOT_DROP(inode);
1324 + inode->i_flags |= S_NOQUOTA;
1325 + inode->i_nlink = 0;
1327 + return ERR_PTR(-EDQUOT);
1333 + make_bad_inode(inode);
1335 + return ERR_PTR(errval);
1339 +void pram_read_inode (struct inode * inode)
1341 + struct pram_inode * pi;
1343 + pi = pram_get_inode(inode->i_sb, inode->i_ino);
1344 + pram_fill_inode(inode, pi);
1347 +void pram_truncate (struct inode * inode)
1349 + int blocksize, blocksize_bits;
1352 + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
1353 + S_ISLNK(inode->i_mode)))
1355 + if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
1358 + blocksize_bits = inode->i_sb->s_blocksize_bits;
1359 + blocksize = 1 << blocksize_bits;
1360 + blocknr = (inode->i_size + blocksize-1) >> blocksize_bits;
1363 + pram_truncate_blocks(inode, blocknr);
1364 + inode->i_mtime = inode->i_ctime = CURRENT_TIME;
1365 + pram_update_inode(inode);
1370 +void pram_write_inode (struct inode * inode, int wait)
1373 + pram_update_inode(inode);
1378 + * dirty_inode() is called from __mark_inode_dirty()
1380 +void pram_dirty_inode(struct inode * inode)
1382 + pram_write_inode(inode, 0);
1386 +static int pram_get_and_update_block(struct inode *inode, sector_t iblock,
1387 + struct buffer_head *bh, int create)
1389 + struct super_block * sb = inode->i_sb;
1390 + unsigned int blocksize = 1 << inode->i_blkbits;
1392 + unsigned long flags;
1398 + block = pram_find_data_block(inode, iblock);
1404 + err = pram_alloc_blocks(inode, iblock, 1);
1407 + block = pram_find_data_block(inode, iblock);
1412 + set_buffer_new(bh);
1415 + bh->b_blocknr = block;
1416 + set_buffer_mapped(bh);
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);
1426 + memcpy(bh->b_data, bp, blocksize);
1429 + set_buffer_uptodate(bh);
1438 +static int pram_writepage(struct page *page)
1443 +static int pram_bmap(struct address_space *mapping, long block)
1449 +static int pram_readpage(struct file *file, struct page *page)
1451 + return block_read_full_page(page, pram_get_and_update_block);
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,
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
1467 + * Ioctl method for directory and regular files.
1469 + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
1471 + * 2003 (c) MontaVista Software, Inc.
1472 + * Copyright 2003 Sony Corporation
1473 + * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
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.
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.
1487 +#include <linux/fs.h>
1488 +#include <linux/pram_fs.h>
1489 +#include <linux/sched.h>
1490 +#include <asm/uaccess.h>
1493 +int pram_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
1494 + unsigned long arg)
1496 + // FIXME: need any special ioctl's?
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
1504 +# Makefile for the linux pram-filesystem routines.
1507 +obj-$(CONFIG_PRAMFS) += pramfs.o
1509 +pramfs-objs := balloc.o dir.o file.o fsync.o inode.o ioctl.o namei.o \
1511 +ifndef CONFIG_PRAMFS_NOWP
1512 +pramfs-objs += wprotect.o
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
1521 + * Inode operations for directories.
1523 + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
1525 + * 2003 (c) MontaVista Software, Inc.
1526 + * Copyright 2003 Sony Corporation
1527 + * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
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.
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.
1541 +#include <linux/fs.h>
1542 +#include <linux/pram_fs.h>
1543 +#include <linux/pagemap.h>
1547 + * Couple of helper functions - make the code slightly cleaner.
1550 +static inline void pram_inc_count(struct inode *inode)
1553 + pram_write_inode(inode, 0);
1556 +static inline void pram_dec_count(struct inode *inode)
1558 + if (inode->i_nlink) {
1560 + pram_write_inode(inode, 0);
1564 +static inline int pram_add_nondir(struct inode * dir,
1565 + struct dentry * dentry,
1566 + struct inode * inode)
1568 + int err = pram_add_link(dentry, inode);
1570 + d_instantiate(dentry, inode);
1573 + pram_dec_count(inode);
1579 + * Methods themselves.
1583 +pram_inode_by_name(struct inode * dir,
1584 + struct dentry * dentry)
1586 + struct pram_inode * pi;
1590 + pi = pram_get_inode(dir->i_sb, dir->i_ino);
1591 + ino = pi->i_type.dir.head;
1594 + pi = pram_get_inode(dir->i_sb, ino);
1596 + if (pi->i_links_count) {
1597 + namelen = strlen(pi->i_d.d_name);
1599 + if (namelen == dentry->d_name.len &&
1600 + !memcmp(dentry->d_name.name,
1601 + pi->i_d.d_name, namelen))
1605 + ino = pi->i_d.d_next;
1611 +static struct dentry *
1612 +pram_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
1614 + struct inode * inode = NULL;
1617 + if (dentry->d_name.len > PRAM_NAME_LEN)
1618 + return ERR_PTR(-ENAMETOOLONG);
1620 + ino = pram_inode_by_name(dir, dentry);
1622 + struct pram_inode * pi = pram_get_inode(dir->i_sb, ino);
1623 + inode = pram_fill_new_inode(dir->i_sb, pi);
1625 + return ERR_PTR(-EACCES);
1628 + d_add(dentry, inode);
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.
1638 + * If the create succeeds, we fill in the inode information
1639 + * with d_instantiate().
1641 +static int pram_create (struct inode * dir, struct dentry * dentry,
1642 + int mode, struct nameidata *nd)
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);
1655 +static int pram_mknod (struct inode * dir, struct dentry *dentry, int mode,
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);
1667 +static int pram_symlink (struct inode * dir,
1668 + struct dentry * dentry,
1669 + const char * symname)
1671 + struct super_block * sb = dir->i_sb;
1672 + int err = -ENAMETOOLONG;
1673 + unsigned len = strlen(symname);
1674 + struct inode * inode;
1676 + if (len+1 > sb->s_blocksize)
1679 + inode = pram_new_inode (dir, S_IFLNK | S_IRWXUGO);
1680 + err = PTR_ERR(inode);
1681 + if (IS_ERR(inode))
1684 + inode->i_op = &pram_symlink_inode_operations;
1685 + inode->i_mapping->a_ops = &pram_aops;
1686 + err = pram_block_symlink(inode, symname, len);
1690 + inode->i_size = len;
1691 + pram_write_inode(inode, 0);
1693 + err = pram_add_nondir(dir, dentry, inode);
1698 + pram_dec_count(inode);
1703 +static int pram_link (struct dentry * dest_dentry,
1704 + struct inode * dir,
1705 + struct dentry * dentry)
1707 + pram_dbg ("hard links not supported\n");
1711 +static int pram_unlink(struct inode * dir, struct dentry *dentry)
1713 + struct inode * inode = dentry->d_inode;
1714 + inode->i_ctime = dir->i_ctime;
1715 + pram_dec_count(inode);
1720 +static int pram_mkdir(struct inode * dir, struct dentry * dentry, int mode)
1722 + struct inode * inode;
1723 + struct pram_inode * pi;
1724 + unsigned long flags;
1725 + int err = -EMLINK;
1727 + if (dir->i_nlink >= PRAM_LINK_MAX)
1730 + pram_inc_count(dir);
1732 + inode = pram_new_inode (dir, S_IFDIR | mode);
1733 + err = PTR_ERR(inode);
1734 + if (IS_ERR(inode))
1737 + inode->i_op = &pram_dir_inode_operations;
1738 + inode->i_fop = &pram_dir_operations;
1739 + inode->i_mapping->a_ops = &pram_aops;
1741 + pram_inc_count(inode);
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);
1749 + err = pram_add_link(dentry, inode);
1753 + d_instantiate(dentry, inode);
1758 + pram_dec_count(inode);
1759 + pram_dec_count(inode);
1762 + pram_dec_count(dir);
1766 +static int pram_rmdir (struct inode * dir, struct dentry *dentry)
1768 + struct inode * inode = dentry->d_inode;
1769 + struct pram_inode * pi;
1770 + int err = -ENOTEMPTY;
1775 + pi = pram_get_inode(dir->i_sb, inode->i_ino);
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);
1786 + pram_dbg("dir not empty\n");
1792 +static int pram_rename (struct inode * old_dir,
1793 + struct dentry * old_dentry,
1794 + struct inode * new_dir,
1795 + struct dentry * new_dentry)
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;
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)
1808 + if (new_inode->i_nlink)
1809 + new_inode->i_nlink--;
1812 + new_inode->i_ctime = CURRENT_TIME;
1813 + pram_dec_count(new_inode);
1815 + if (S_ISDIR(old_inode->i_mode)) {
1817 + if (new_dir->i_nlink >= PRAM_LINK_MAX)
1819 + pram_dec_count(old_dir);
1820 + pram_inc_count(new_dir);
1824 + /* unlink the inode from the old directory ... */
1825 + if ((err = pram_remove_link(old_inode))) {
1828 + /* and link it into the new directory. */
1829 + if ((err = pram_add_link(new_dentry, old_inode))) {
1838 +struct inode_operations pram_dir_inode_operations = {
1839 + create: pram_create,
1840 + lookup: pram_lookup,
1842 + unlink: pram_unlink,
1843 + symlink: pram_symlink,
1844 + mkdir: pram_mkdir,
1845 + rmdir: pram_rmdir,
1846 + mknod: pram_mknod,
1847 + rename: pram_rename,
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
1856 + * Super block operations.
1858 + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
1860 + * 2003 (c) MontaVista Software, Inc.
1861 + * Copyright 2003 Sony Corporation
1862 + * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
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.
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.
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>
1887 +MODULE_AUTHOR("Steve Longerbeam, stevel@mvista.com");
1888 +MODULE_DESCRIPTION("Protected/Persistent RAM Filesystem");
1889 +MODULE_LICENSE("GPL");
1891 +static struct super_operations pram_sops;
1894 +extern struct list_head super_blocks;
1896 +struct super_block * find_pramfs_super(void)
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)
1906 +EXPORT_SYMBOL(find_pramfs_super);
1909 +static void pram_set_blocksize(struct super_block * sb, unsigned long size)
1912 + for (bits = 9, size >>= 9; size >>= 1; bits++)
1916 + sb->s_blocksize_bits = bits;
1917 + sb->s_blocksize = (1<<bits);
1920 +static inline void * pram_ioremap(unsigned long phys_addr, size_t size,
1921 + unsigned long flags)
1923 + void * retval = __ioremap(phys_addr, size, flags);
1924 +#ifndef CONFIG_PRAMFS_NOWP
1926 + spin_lock(&init_mm.page_table_lock);
1927 + pram_writeable(retval, size, 0);
1928 + spin_unlock(&init_mm.page_table_lock);
1935 +static int pram_fill_super (struct super_block * sb, void * data, int silent)
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;
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.
1953 + if (!data || !(p = strstr((char *)data, "physaddr="))) {
1954 + pram_err("unknown physical address for pramfs image\n");
1958 + sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
1961 + sb->s_fs_info = sbi;
1962 + memset(sbi, 0, sizeof(*sbi));
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",
1972 + if (sbi->phys_addr == 0) {
1973 + pram_err("physical address for pramfs image can't be 0\n");
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;
1982 + maxsize = simple_strtoul(p + 5, NULL, 0);
1983 + pram_info("creating an empty pramfs of size %lu\n", maxsize);
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");
1991 + if ((p = strstr((char *)data, "bs=")))
1992 + blocksize = simple_strtoul(p + 3, NULL, 0);
1994 + blocksize = PRAM_DEF_BLOCK_SIZE;
1996 + pram_set_blocksize(sb, blocksize);
1997 + blocksize = sb->s_blocksize;
1999 + if ((p = strstr((char *)data, "bpi=")))
2000 + bpi = simple_strtoul(p + 4, NULL, 0);
2002 + /* default is that 5% of the filesystem is
2003 + devoted to the inode table */
2004 + bpi = 20 * PRAM_INODE_SIZE;
2007 + if ((p = strstr((char *)data, "N=")))
2008 + num_inodes = simple_strtoul(p + 2, NULL, 0);
2010 + num_inodes = maxsize / bpi;
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) &
2018 + num_inodes = (bitmap_start - PRAM_SB_SIZE) >> PRAM_INODE_BITS;
2020 + num_blocks = (maxsize - bitmap_start) >> sb->s_blocksize_bits;
2022 + /* calc the data blocks in-use bitmap size in bytes */
2023 + if (num_blocks & 7)
2024 + bitmap_size = ((num_blocks + 8) & ~7) >> 3;
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) &
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);
2038 + super = pram_get_super(sb);
2039 + pram_lock_range(super, bitmap_start + bitmap_size);
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);
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);
2062 + pram_init_bitmap(sb);
2064 + pram_unlock_range(super, bitmap_start + bitmap_size);
2069 + pram_info("checking physical address 0x%lx for pramfs image\n",
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");
2079 + super = pram_get_super(sb);
2081 + /* Do sanity checks on the superblock */
2082 + if (super->s_magic != PRAM_SUPER_MAGIC) {
2083 + pram_err("wrong magic\n");
2086 + /* Read the superblock */
2087 + if (pram_calc_checksum((u32*)super, PRAM_SB_SIZE>>2)) {
2088 + pram_err("checksum error in super block!\n");
2092 + /* get feature flags first */
2093 + // FIXME: implement fs features?
2095 + if (super->s_features & ~PRAM_SUPPORTED_FLAGS) {
2096 + pram_err("unsupported filesystem features\n");
2101 + blocksize = super->s_blocksize;
2102 + pram_set_blocksize(sb, blocksize);
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);
2108 + /* Read the root inode */
2109 + root_i = pram_get_inode(sb, PRAM_ROOT_INO);
2111 + if (pram_calc_checksum((u32*)root_i, PRAM_INODE_SIZE>>2)) {
2112 + pram_err("checksum error in root inode!\n");
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");
2122 + if (!S_ISDIR(root_i->i_mode)) {
2123 + pram_err("root is not a directory!\n");
2127 + root_offset = root_i->i_type.dir.head;
2128 + if (root_offset == 0)
2129 + pram_info("empty filesystem\n");
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");
2138 + super = pram_get_super(sb);
2140 + /* Set it all up.. */
2142 + sbi->maxsize = maxsize;
2143 + sb->s_magic = sbi->magic = super->s_magic;
2144 + sbi->features = super->s_features;
2146 + sb->s_op = &pram_sops;
2147 + sb->s_root = d_alloc_root(pram_fill_new_inode(sb, root_i));
2151 + if (retval && sbi->virt_addr)
2152 + iounmap(sbi->virt_addr);
2157 +//static void pram_write_super (struct super_block * sb)
2161 +int pram_statfs (struct super_block * sb, struct kstatfs * buf)
2163 + struct pram_super_block * ps = pram_get_super(sb);
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;
2175 +int pram_remount (struct super_block * sb, int * mntflags, char * data)
2177 + struct pram_super_block * ps;
2178 + unsigned long flags;
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);
2189 +void pram_put_super (struct super_block * sb)
2191 + struct pram_sb_info * sbi = (struct pram_sb_info *)sb->s_fs_info;
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;
2199 + sb->s_fs_info = NULL;
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.
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,
2220 +static struct super_block *pram_get_sb(struct file_system_type *fs_type,
2221 + int flags, const char *dev_name,
2224 + return get_sb_single(fs_type, flags, data, pram_fill_super);
2227 +static struct file_system_type pram_fs_type = {
2228 + .owner = THIS_MODULE,
2230 + .get_sb = pram_get_sb,
2231 + .kill_sb = kill_anon_super,
2234 +static int __init init_pram_fs(void)
2236 + return register_filesystem(&pram_fs_type);
2239 +static void __exit exit_pram_fs(void)
2241 + unregister_filesystem(&pram_fs_type);
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
2253 + * Symlink methods.
2255 + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
2257 + * 2003 (c) MontaVista Software, Inc.
2258 + * Copyright 2003 Sony Corporation
2259 + * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
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.
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.
2273 +#include <linux/fs.h>
2274 +#include <linux/pram_fs.h>
2276 +int pram_block_symlink(struct inode *inode, const char *symname, int len)
2278 + struct super_block * sb = inode->i_sb;
2281 + unsigned long flags;
2284 + err = pram_alloc_blocks (inode, 0, 1);
2288 + block = pram_find_data_block(inode, 0);
2289 + blockp = pram_get_block(sb, block);
2291 + pram_lock_block(sb, blockp);
2292 + memcpy(blockp, symname, len);
2293 + blockp[len] = '\0';
2294 + pram_unlock_block(sb, blockp);
2298 +static int pram_readlink(struct dentry *dentry, char *buffer, int buflen)
2300 + struct inode * inode = dentry->d_inode;
2301 + struct super_block * sb = inode->i_sb;
2305 + block = pram_find_data_block(inode, 0);
2306 + blockp = pram_get_block(sb, block);
2307 + return vfs_readlink(dentry, buffer, buflen, blockp);
2310 +static int pram_follow_link(struct dentry *dentry, struct nameidata *nd)
2312 + struct inode * inode = dentry->d_inode;
2313 + struct super_block * sb = inode->i_sb;
2317 + block = pram_find_data_block(inode, 0);
2318 + blockp = pram_get_block(sb, block);
2319 + return vfs_follow_link(nd, blockp);
2322 +struct inode_operations pram_symlink_inode_operations = {
2323 + readlink: pram_readlink,
2324 + follow_link: pram_follow_link,
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
2333 + * Write protection for the filesystem pages.
2335 + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
2337 + * 2003 (c) MontaVista Software, Inc.
2338 + * Copyright 2003 Sony Corporation
2339 + * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
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.
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.
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>
2361 +// init_mm.page_table_lock must be held before calling!
2362 +static void pram_page_writeable(unsigned long addr, int rw)
2368 + pgdp = pgd_offset_k(addr);
2369 + if (!pgd_none(*pgdp)) {
2370 + pmdp = pmd_offset(pgdp, addr);
2371 + if (!pmd_none(*pmdp)) {
2373 + ptep = pte_offset_kernel(pmdp, addr);
2375 + if (pte_present(pte)) {
2376 + pte = rw ? pte_mkwrite(pte) :
2377 + pte_wrprotect(pte);
2378 + set_pte(ptep, pte);
2385 +// init_mm.page_table_lock must be held before calling!
2386 +void pram_writeable(void * vaddr, unsigned long size, int rw)
2388 + unsigned long addr = (unsigned long)vaddr & PAGE_MASK;
2389 + unsigned long end = (unsigned long)vaddr + size;
2390 + unsigned long start = addr;
2393 + pram_page_writeable(addr, rw);
2394 + addr += PAGE_SIZE;
2395 + } while (addr && (addr < end));
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.
2405 + if (end <= start + PAGE_SIZE)
2406 + flush_tlb_kernel_page(start);
2408 + flush_tlb_kernel_range(start, end);
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
2417 + * Definitions for the PRAMFS filesystem.
2419 + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
2421 + * 2003 (c) MontaVista Software, Inc.
2422 + * Copyright 2003 Sony Corporation
2423 + * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
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.
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.
2437 +#ifndef _LINUX_PRAM_FS_H
2438 +#define _LINUX_PRAM_FS_H
2440 +#include <linux/types.h>
2441 +#include <linux/pram_fs_sb.h>
2444 +#include <linux/sched.h>
2448 + * The PRAM filesystem constants/structures
2452 + * Define PRAMFS_DEBUG to produce debug messages
2454 +#undef PRAMFS_DEBUG
2457 + * The PRAM filesystem version
2459 +#define PRAMFS_DATE "2003/06/15"
2460 +#define PRAMFS_VERSION "0.1b"
2466 +#define PFX "pramfs"
2467 +#ifdef PRAMFS_DEBUG
2468 +#define pram_dbg(format, arg...) \
2469 + printk(KERN_DEBUG PFX ": " format , ## arg)
2471 +#define pram_dbg(format, arg...) do {} while (0)
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)
2482 + * The PRAM file system magic number
2484 +#define PRAM_SUPER_MAGIC 0xEFFA
2487 + * Maximal count of links to a file
2489 +#define PRAM_LINK_MAX 32000
2491 +typedef unsigned long pram_off_t;
2493 +#define PRAM_MIN_BLOCK_SIZE 512
2494 +#define PRAM_MAX_BLOCK_SIZE 4096
2495 +#define PRAM_DEF_BLOCK_SIZE 2048
2497 +#define PRAM_INODE_SIZE 128 // must be power of two
2498 +#define PRAM_INODE_BITS 7
2501 + * Structure of a directory entry in PRAMFS.
2502 + * Offsets are to the inode that holds the referenced dentry.
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 */
2513 + * Structure of an inode in PRAMFS
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 */
2531 + * ptr to row block of 2D block pointer array,
2532 + * file block #'s 0 to (blocksize/4)^2 - 1.
2534 + pram_off_t row_block;
2535 + } reg; // regular file or symlink inode
2537 + pram_off_t head; /* first entry in this directory */
2538 + pram_off_t tail; /* last entry in this directory */
2541 + __u32 rdev; /* major/minor # */
2542 + } dev; // device inode
2545 + struct pram_dentry i_d;
2548 +#define PRAM_NAME_LEN \
2549 + (PRAM_INODE_SIZE - offsetof(struct pram_inode, i_d.d_name) - 1)
2553 + * Behaviour when detecting errors
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
2560 +#define PRAM_SB_SIZE 128 // must be power of two
2561 +#define PRAM_SB_BITS 7
2564 + * Structure of the super block in PRAMFS
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 */
2588 +/* The root inode follows immediately after the super block */
2589 +#define PRAM_ROOT_INO PRAM_SB_SIZE
2593 +/* Function Prototypes */
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);
2602 +extern int pram_add_link (struct dentry * dentry, struct inode *inode);
2603 +extern int pram_remove_link(struct inode * inode);
2606 +extern int pram_direct_IO(int rw, struct kiocb *iocb,
2607 + const struct iovec *iov,
2608 + loff_t offset, unsigned long nr_segs);
2611 +extern int pram_sync_file (struct file *, struct dentry *, int);
2612 +extern int pram_fsync_inode (struct inode *, int);
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);
2629 +extern int pram_ioctl (struct inode *, struct file *, unsigned int,
2633 +extern struct super_block * find_pramfs_super(void);
2634 +extern struct super_block * pram_read_super (struct super_block * sb,
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);
2641 +extern int pram_block_symlink(struct inode *inode,
2642 + const char *symname, int len);
2645 +#ifndef CONFIG_PRAMFS_NOWP
2646 +extern void pram_writeable (void * vaddr, unsigned long size, int rw);
2649 +/* Inline functions start here */
2651 +static inline u32 pram_calc_checksum(u32* buf, int n)
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)
2664 + struct pram_sb_info * sbi = (struct pram_sb_info *)sb->s_fs_info;
2665 + return (struct pram_super_block *)sbi->virt_addr;
2668 +// pram_lock_super() before calling!
2669 +static inline void pram_sync_super(struct pram_super_block * ps)
2671 + ps->s_wtime = get_seconds();
2673 + ps->s_sum = - pram_calc_checksum((u32*)ps, PRAM_SB_SIZE>>2);
2676 +// pram_lock_inode() before calling!
2677 +static inline void pram_sync_inode(struct pram_inode * pi)
2679 + //pi->i_mtime = CURRENT_TIME;
2681 + pi->i_sum = - pram_calc_checksum((u32*)pi, PRAM_INODE_SIZE>>2);
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);\
2690 +#define pram_unlock_range(p, len) {\
2691 + pram_writeable((p), (len), 0);\
2692 + spin_unlock_irqrestore(&init_mm.page_table_lock, flags);\
2695 +#define pram_lock_range(p, len) do {} while (0)
2696 +#define pram_unlock_range(p, len) do {} while (0)
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);\
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);\
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)
2721 +static inline void *
2722 +pram_get_bitmap(struct super_block * sb)
2724 + struct pram_super_block * ps = pram_get_super(sb);
2725 + return ((void*)ps + ps->s_bitmap_start);
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)
2733 + struct pram_super_block * ps = pram_get_super(sb);
2734 + return ino ? (struct pram_inode *)((void*)ps + ino) : NULL;
2737 +static inline ino_t
2738 +pram_get_inodenr(struct super_block * sb, struct pram_inode * pi)
2740 + struct pram_super_block * ps = pram_get_super(sb);
2741 + return (ino_t)((unsigned long)pi - (unsigned long)ps);
2744 +static inline pram_off_t
2745 +pram_get_block_off(struct super_block * sb, unsigned long blocknr)
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));
2752 +static inline unsigned long
2753 +pram_get_blocknr(struct super_block * sb, pram_off_t block)
2755 + struct pram_super_block * ps = pram_get_super(sb);
2756 + return (block - ps->s_bitmap_start) >> sb->s_blocksize_bits;
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)
2764 + struct pram_super_block * ps = pram_get_super(sb);
2765 + return block ? ((void*)ps + block) : NULL;
2770 + * Inodes and files operations
2774 +extern struct file_operations pram_dir_operations;
2777 +extern struct inode_operations pram_file_inode_operations;
2778 +extern struct file_operations pram_file_operations;
2781 +extern struct address_space_operations pram_aops;
2784 +extern struct inode_operations pram_dir_inode_operations;
2787 +extern struct inode_operations pram_symlink_inode_operations;
2789 +#endif /* __KERNEL__ */
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
2799 + * Definitions for the PRAM filesystem.
2801 + * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com>
2803 + * 2003 (c) MontaVista Software, Inc.
2804 + * Copyright 2003 Sony Corporation
2805 + * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
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.
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.
2819 +#ifndef _LINUX_PRAM_FS_SB
2820 +#define _LINUX_PRAM_FS_SB
2823 + * PRAM filesystem super-block data in memory
2825 +struct pram_sb_info {
2827 + * base physical and virtual address of PRAMFS (which is also
2828 + * the pointer to the super block)
2830 + unsigned long phys_addr;
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 @@
2846 +#ifdef CONFIG_ROOT_PRAMFS
2847 +static int __init mount_pramfs_root(void)
2849 + create_dev("/dev/root", ROOT_DEV, NULL);
2850 + if (do_mount_root("/dev/root", "pramfs",
2851 + root_mountflags, root_mount_data) == 0)
2857 #if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD)
2858 void __init change_floppy(char *fmt, ...)
2860 @@ -363,6 +374,15 @@
2861 ROOT_DEV = Root_FD0;
2864 +#ifdef CONFIG_ROOT_PRAMFS
2865 + if (ROOT_DEV == MKDEV(0, 0)) {
2866 + if (mount_pramfs_root())
2869 + printk (KERN_ERR "VFS: Unable to mount PRAMFS root\n");
2870 + ROOT_DEV = Root_FD0;
2873 #ifdef CONFIG_BLK_DEV_FD
2874 if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
2875 /* rd_doload is 2 for a dual initrd/ramload setup */