]> git.pld-linux.org Git - packages/kernel.git/blame - pramfs-2.6.4.patch
- now on HEAD
[packages/kernel.git] / pramfs-2.6.4.patch
CommitLineData
37fad6fa 1diff -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+
181diff -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"
212diff -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/
223diff -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+}
390diff -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+};
619diff -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+};
766diff -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+
807diff -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+};
1460diff -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+}
1499diff -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
1514diff -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+};
1849diff -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)
2246diff -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+};
2326diff -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+}
2410diff -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 */
2792diff -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 */
2839diff -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 */
This page took 0.370787 seconds and 4 git commands to generate.