Dump Management
Hi, what's the standard way to manage the core dump and therefore the post-mortem debug? For my experience it could be useful to have a mechanism to have little dump image (only some information) to store it in flash and maybe to have an hook (or something like this) for each application to customize the dump information. What do you think about it? Regards, -- Marco Stornelli Embedded Software Engineer CoRiTeL - Consorzio di Ricerca sulle Telecomunicazioni http://www.coritel.it [EMAIL PROTECTED] +39 06 72582838 -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: prevalence of C++ in embedded linux?
Bernd Petrovitsch ha scritto: On Tue, 2008-07-29 at 09:51 +0200, Alexander Neundorf wrote: On Tuesday 29 July 2008 09:40:20 Marco Stornelli wrote: Robert P. J. Day ha scritto: just curious -- how many folks are working in C++ in their embedded linux work? Not if it's in anyway avoidable. [] Like Linus Torvals said ...C++ is an horrible language :) If you avoid RTTI and exceptions and if you are handle templates and multiple inheritance carefully I see nothing which speaks against using it for embedded and real-time software. That's the main reason for *not* using C++ in the embedded world in the first place. Tell people that they may use C++ and see them happy. Then tell them that you better not use templates, RTTI, exceptions and multiple inheritance if you want to boot from small space. Yes, one *can* use the above features and get small features. But most people simply can't - if only that they use some tool/lib written in C++ (and coming from the normal world) which simply uses them without thinking about space and wonder why the device won't run with only 128MB flash and run in 16MB RAM. BTW why should I use C++ if I don't use any fancy features? Bernd I quite agree with you -- Marco Stornelli Embedded Software Engineer CoRiTeL - Consorzio di Ricerca sulle Telecomunicazioni http://www.coritel.it [EMAIL PROTECTED] +39 06 72582838 -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: embedded rootfs utility
On Tue, Jul 29, 2008 at 10:18:37PM -0400, Behan Webster wrote: A quick announcement of the release of elbs, or the Embedded Linux Build System (it seemed like a good name at the time I started writing it...) So far it's just a few utilities that I wrote to make a few of my own projects easier. However, most notably it contains a utility called elbs-rootfs which makes it easy to create an embedded rootfs for any architecture supported by the Debian projecy (or Ubuntu Linux). The idea is to get a rootfs up and working quickly via nfs (or a flash drive) which allows you to install any debian package and/or to do native development. This is (not yet) meant as a tool to make your final rootfs fit on a small flash partition. Very interesting, where can I found it? Can you give me a site to download it? -- Marco Stornelli Embedded Software Engineer CoRiTeL - Consorzio di Ricerca sulle Telecomunicazioni http://www.coritel.it [EMAIL PROTECTED] +39 06 72582838 -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
PRAMFS with XIP support
Hi all, I enjoyed to make a porting of pramfs to the kernel 2.6.26.5. In addition, I made a patch to add execute-in-place support. You can download the patches from the project site under tracker/patches. If you have comments and/or suggestions you can write to me an email :). Thanks. Regards, -- Marco Stornelli Embedded Software Engineer CoRiTeL - Consorzio di Ricerca sulle Telecomunicazioni http://www.coritel.it [EMAIL PROTECTED] +39 06 72582838 -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: PRAMFS with XIP support
Hi Mike, I am not the PRAMFS mantainer, and I think he is in charge to do that (right?), I sent an email to Steve Longerbeam and to MontaVista support, but I haven't received any response. However, if you think it could be useful to submit it to lkml I could do it. Regards. Mike Frysinger ha scritto: On Tue, Oct 7, 2008 at 05:14, Marco Stornelli wrote: I enjoyed to make a porting of pramfs to the kernel 2.6.26.5. In addition, I made a patch to add execute-in-place support. You can download the patches from the project site under tracker/patches. If you have comments and/or suggestions you can write to me an email :). why not submit it for inclusion to lkml ? -mike -- Marco Stornelli Embedded Software Engineer CoRiTeL - Consorzio di Ricerca sulle Telecomunicazioni http://www.coritel.it [EMAIL PROTECTED] +39 06 72582838 -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: UIO - interrupt performance
I quite agree with Ben and Christian. I think UIO drivers are usable for simple devices, I think they aren't mature (will it ever be?) to use it with complicated devices or with strict requirement. Regards, Douglas, Jim (Jim) ha scritto: We are contemplating porting a large number of device drivers to Linux. The pragmatic solution is to keep them in user mode (using the UIO framework) where possible ... they are written in C++ for a start. The obvious disadvantages of user mode device drivers are security / isolation. The main benefit is ease of development. Do you know what the *technical* disadvantages of this approach might be? I am most concerned about possible impact on interrupt handling. For example, I assume the context switching overhead is higher, and that interrupt latency is more difficult to predict? --jim douglas Avaya UK, Registered in England and Wales under Registered Number 3049861, Registered Address: Avaya House, Cathedral Hill, Guildford, Surrey, GU2 7YL. -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html -- Marco Stornelli Embedded Software Engineer CoRiTeL - Consorzio di Ricerca sulle Telecomunicazioni http://www.coritel.it [EMAIL PROTECTED] +39 06 72582838 -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: UIO - interrupt performance
No I don't think you can decide kernel or user space, indeed you can read my previous posts, I quite agree with you, I meant the same to Bill Gatliff. Ben Nizette ha scritto: On Tue, 2008-10-21 at 11:30 +0200, Marco Stornelli wrote: I could agree, but the facto due to UIO license condition, a company often uses UIO drivers, regardless performance, debug, etc, only as not to public the code under GPL. It sounds to me like you think that driver authors can sit down and decide whether they want to implement their driver in userspace or kernel space. For 99% of drivers that's simply not true. You *cannot* write userspace drivers for most hardware, the hooks just aren't available. UIO is Userspace I/O, not a set of general hooks for userspace drivers. If people want drivers not under the GPL then they can distribute a binary-only module (though thank $DEITY there aren't many of those left). Userspace I/O exists to provide good performance interfacing to a family of devices - those which exist just to shuffle data around and have an interrupt to tell you when they're done. Do you have any example of a userspace i/o driver which exists to get around licencing constraints? --Ben. -- Marco Stornelli Embedded Software Engineer CoRiTeL - Consorzio di Ricerca sulle Telecomunicazioni http://www.coritel.it [EMAIL PROTECTED] +39 06 72582838 -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] uio: add ioctl callback
Read the file SubmittingPatches in your kernel documentation folder before sending a patch. In addition, check the patch with checkpatch script. You can find the script in the script kernel folder. Send the patch with the right destination. You can know the names (and emails) of the maintainers in the MAINTAINER file in the kernel source. Regards, Marco Neil Armstrong wrote: Add an ioctl callback to the UIO device class. This can be useful when status and data are needed after an interrupt occurs. Changes : - Add an uio_ioctl method - Add en ioctl entry in uio_info Neil Armstrong [EMAIL PROTECTED] Index: drivers/uio/uio.c === --- drivers/uio/uio.c(revision 80) +++ drivers/uio/uio.c(working copy) @@ -378,6 +378,17 @@ return 0; } +static int uio_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg) +{ +struct uio_listener *listener = filep-private_data; +struct uio_device *idev = listener-dev; + +if (idev-info-ioctl) +return idev-info-ioctl(idev-info, cmd, arg); + +return -ENOSYS; +} + static ssize_t uio_read(struct file *filep, char __user *buf, size_t count, loff_t *ppos) { @@ -575,6 +586,7 @@ .mmap= uio_mmap, .poll= uio_poll, .fasync= uio_fasync, + .ioctl = uio_ioctl, }; static int uio_major_init(void) Index: include/linux/uio_driver.h === --- include/linux/uio_driver.h(revision 80) +++ include/linux/uio_driver.h(working copy) @@ -68,6 +68,7 @@ int (*open)(struct uio_info *info, struct inode *inode); int (*release)(struct uio_info *info, struct inode *inode); int (*irqcontrol)(struct uio_info *info, s32 irq_on); +int (*ioctl)(struct uio_info *info, unsigned int cmd, unsigned long arg); }; extern int __must_check -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Linux SBC recommendations
Hi Greg, I suggest you this board: http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4102 It's very cheaper, sometimes ago I bought it for 65 Euro. However it hasn't got an host USB port, but only a device one. Regards, Marco Greg Lee ha scritto: I'm in the process of selecting a single-board computer (SBC) for a project and I'd like to hear what others are using sucessfully. My requirements for the SBC are: 1) Low cost ($100) 2) Runs Linux 3) Has an Ethernet and USB host connection 4) Has sufficient storage capacity to run an small HTTP server such as mini httpd and a few MB left over for custom applications 5) Mechanical packaging suitable for a server room environment 6) Processing capacity requirement is not very large, low-power processor okay I previously assumed that I would use the Gumstix Vertex-Pro boards, but cost is a limiting factor on this project and precludes using these boards. What low-cost SBCs has the Linux Embedded community used with success? Greg -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 13/14] Pramfs: Write Protection
2009/6/18 Paul Mundt let...@linux-sh.org: On Wed, Jun 17, 2009 at 06:58:00PM +0200, Marco wrote: Jared Hulbert wrote: Why not just fix flush_tlb_range()? If an arch has a flush_tlb_kernel_page() that works then it stands to reason that the flush_tlb_kernel_range() shouldn't work with minimal effort, no? flush_tlb_kernel_page() is a new one to me, it doesn't have any mention in Documentation/cachetlb.txt anyways. Many of the flush_tlb_kernel_range() implementations do ranged checks with tunables to determine whether it is more expensive to selectively flush vs just blowing the entire TLB away. Likewise, there is no reason why those 4 architectures can not just shove that if (end = start + PAGE_SIZE) check in the beginning of their flush_tlb_kernel_range() and fall back on flush_tlb_kernel_page() for those cases. Hiding this in generic code is definitely not the way to go. Ok I'll change that function at arch level and I'll remove the ifdef, I'll call only flush_tlb_kernel_page(), but I'd like to know what is the opinion of the arch maintainers to do that. (Who is the maintainer of H8300 arch?) No, you should call flush_tlb_kernel_range() and just fix up the flush_tlb_kernel_range() calls to wrap in to flush_tlb_kernel_page(). As far as the kernel is concerned, flush_tlb_kernel_page() is not a standard interface, as it has no mention in Documentation/cachetlb.txt. flush_tlb_page() and flush_tlb_kernel_range() on the other hand are both standard interfaces. Oops, my fault. I meant flush_tlb_kernel_range not the page version, sorry. I agree with you. H8300 is a nommu platform, so it has no TLB to flush. Yoshinori Sato is the maintainer. Consult the MAINTAINERS file, that's what it is there for. I know the MAINTAINERS file but for h8300 there isn't an exactly indication (/arch/h8300 as for the other archs). Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 00/14] Pramfs: Persistent and protected ram filesystem
2009/6/17 Chris Friesen cfrie...@nortel.com: Marco wrote: This is a second attempt at mainlining Pramfs. The first attempt was back in early 2004 by MontaVista. Since then the kernel code has almost been completely rewritten. So my first item on the list was porting the code on a recent kernel version. After that I added the XIP support. Now some FAQs: What is the goal of this filesystem? Many embedded systems have a block of non-volatile RAM separate from normal system memory, i.e. of which the kernel maintains no memory page descriptors. For such systems it would be beneficial to mount a fast read/write filesystem over this I/O memory, for storing frequently accessed data that must survive system reboots and power cycles. An example usage might be system logs under /var/log, or a user address book in a cell phone or PDA. Nice to see something like this submitted to mainline. We use something similar to provide persistent storage for crash recovery debug data for boards which don't have local storage. In many cases kdump can provide good information, but it's not sufficient for flight recorder type data if the kernel gets rebooted by a hardware mechanism (watchdog, for instance) that doesn't give a pre-interrupt. I'm very happy that this fs has the approval of the kernel community. :) I'm a bit concerned about your PTE modifications on every write though...we do things like log every exception and scheduler operation to persistent memory, and I think the overhead of changing the protection on every write would be a killer. Instead, we make extensive use of checksums at various different levels so that the recovery app can determine which data is valid. It's a trade-off between security and performance. Checksum it's a good way to understand if a data is valid or not (indeed it's used in this fs), but with this schema you can prevent the system to do something wrong. This option, however, can be enabled/disabled via kconfig. Also, I'd like to ensure that direct memory access to the memory area would be available. What do you exactly mean with this? Can you explain to me a bit deeper? There are some things (like the sched/exception logging mentioned above) where we want to make accesses as fast as possible. Chris Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 06/14] Pramfs: Include files
2009/6/21 Arnd Bergmann a...@arndb.de: On Sunday 21 June 2009, Marco wrote: I was thinking about your comment and I think I'll use __kernel_off_t for the exported headers. I know that it will differ between 32 and 64 bit architectures, but for this kind of fs there isn't any compatibility problem at layout level. You cannot remove a chip of RAM from a board 32bit little endian and attach it to a board with a cpu 64bit big endian, the memory isn't a disk. Indeed, I see that tmpfs uses simply unsigned long in the exported header file without any problems to little or big endian. It's still a problem. You might be creating a file system image for an embedded board with a different endianess. It's not possible to create an image with pramfs, it's like tmpfs. Or even on the same machine, you could be looking at the file system contents with a 32 bit process running on a 64 bit kernel. Arnd Yes, indeed the most important thing is to be sure that a 64bit kernel works well. I'll try to test it in this environment. If there are 64bit guys to help me to test it, it'd be great. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: I:Re: [PATCH 06/14] Pramfs: Include files
On Tue, 23 June 2009 19:38:33 +0200, Marco wrote: dd? You haven't got any device file to have a dump. I think we're going a bit out of scope. I had some doubt to support rootfs in pram and after some feedback and the comments of this review I think I'll remove it from the next release (to understand some aspects of this fs with the kernel community was my main goal for this review). I agree to use the native endian. As I said the important thing is that if an user want to use it in a 64bit environment then the fs must work well and then it must be designed to support even this situation, I think it's obvious. Glancing at the discussion with Pawel, I see two paths to follow. One is to turn pramfs into a full-features all-round general-purpose filesystem with mkfs, fsck, xattr and any number of additional features. That way lies doom, as you would compete against ext2+xip and have little new to offer. The other path is to make/keep pramfs as simple as possible for comparatively specialized purposes, like flight recorder data and dump information. Main selling point here is the amount of vulnerable code in the total package. ext2 + block layer + vfs helpers is relatively large and many things may go wrong in a panic situation. So I agree with you that many things expected from general purpose filesystems simply don't apply to pramfs. Moving mkfs into the kernel is a fair tradeoff, when the required code is small. Endianness is a different case imo. dd may not work, but a jtag probe will happily get you the dump to your development machine. I quite agree, but I'd like to say that it was _not_ my intention to submit a general-purpose fs comparable with ext2 or ext3. And even within the same box you can have more than one architecture and endianness. http://www.top500.org/system/9707 will show you one such beast, which happens to have the top bragging rights at the moment. I don't want to endorse such strange beasts, but there is no good reason not to support reading the ppc-written fs from the opteron. In fact, there is no reason full stop. Jörn MmmJtag dump makes more sense, ok in the next release I rework the layout to have an independent endianess layout. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 06/14] Pramfs: Include files
2009/6/23 Arnd Bergmann a...@arndb.de: On Tuesday 23 June 2009, David Woodhouse wrote: And dd on /dev/mem would work, surely? Actually, reading from /dev/mem is only valid on real RAM. If the nvram is part of an IO memory mapping, you have to do mmap()+memcpy() rather than read(). So dd won't do it, but it's still easy to read from user space. For security reasons pram reserve the region of memory with reserve_mem_region_exclusive(). I'd definitely recommend making it fixed-endian. Not doing so for JFFS2 was a mistake I frequently regretted. Right. Arnd -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 00/14] Pramfs: Persistent and protected ram filesystem
2009/6/24 Pavel Machek pa...@ucw.cz: On Wed 2009-06-24 19:38:37, Marco wrote: Pavel Machek wrote: On Mon 2009-06-22 14:50:01, Tim Bird wrote: Pavel Machek wrote: block of fast non-volatile RAM that need to access data on it using a standard filesytem interface. Turns a block of fast RAM into 13MB/sec disk. Hmm. I believe you are better with ext2. Not if you want the RAM-based filesystem to persist over a kernel invocation. Yes, you'll need to code Persistent, RAM-based _block_device_. First of all I have to say that I'd like to update the site and make it clearer but at the moment it's not possible because I'm not the admin and I've already asked to the sourceforge support to have this possibility. About the comments: sincerely I don't understand the comments. We have *already* a fs that takes care to remap a piace of ram (ram, sram, nvram, etc.), takes care of caching problems, takes care of write Well, it looks pramfs design is confused. 13MB/sec shows that caching _is_ useful for pramfs. So...? caching problems means to avoid filesystem corruption, so dirty pages in the page cache are not allowed to be written back to the backing-store RAM. It's clear that there is a performance penalty. This penalty should be reduced by the access speed of the RAM, however the performance are not important for this special fs as Tim Bird said, so this question is not relevant for me. If this issue is not clear enough on the web site, I hope I can update the information in the future. You are talked about journaling. This schema works well for a disk, but what about a piece of ram? What about a crazy kernel that write in that area for a bug? Do you remember for example the e1000e bug? It's not I believe you need both journaling *and* write protection. How do you handle power fault while writing data? Pavel Ah now the write protection is a needed feature, in your previous comment you talked about why not use ext2/3... Marco Just for your information I tried the same test with pc in a virtual machine with 32MB of RAM: Version 1.03e --Sequential Output-- --Sequential Input- --Random- -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Machine Size:chnk K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP hostname 15M:1k 14156 99 128779 100 92240 100 11669 100 166242 99 80058 82 --Sequential Create-- Random Create -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 4 2842 99 133506 104 45088 101 2787 99 79581 101 58212 102 These data are the proof of the importance of the environment, workload and so on when we talk about benchmark. Your consideration are really superficial. Unfortunately, your numbers are meaningless. I don't think so. Pavel (PCs should have cca 3GB/sec RAM transfer rates; and you demosstrated cca 166MB/sec read rate; disk is 80MB/sec, so that's too slow. If you want to prove your filesystem the filesystem is reasonably fast, compare it with ext2 on ramdisk.) This is the point. I don't want compare it with ext2 from performance point of view. This comparison makes no sense for me. I've done this test to prove that if you change environment you can change in a purposeful way the results. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 00/14] Pramfs: Persistent and protected ram filesystem
Pavel Machek wrote: Ah now the write protection is a needed feature, in your previous comment you talked about why not use ext2/3... Marco Just for your information I tried the same test with pc in a virtual machine with 32MB of RAM: Version 1.03e --Sequential Output-- --Sequential Input- --Random- -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Machine Size:chnk K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP hostname 15M:1k 14156 99 128779 100 92240 100 11669 100 166242 99 80058 82 --Sequential Create-- Random Create -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 4 2842 99 133506 104 45088 101 2787 99 79581 101 58212 102 These data are the proof of the importance of the environment, workload and so on when we talk about benchmark. Your consideration are really superficial. Unfortunately, your numbers are meaningless. I don't think so. (PCs should have cca 3GB/sec RAM transfer rates; and you demosstrated cca 166MB/sec read rate; disk is 80MB/sec, so that's too slow. If you want to prove your filesystem the filesystem is reasonably fast, compare it with ext2 on ramdisk.) This is the point. I don't want compare it with ext2 from performance point of view. This comparison makes no sense for me. I've done this test to prove that if you change environment you can change in a purposeful way the results. Yes, IOW you demonstrated that the numbers are machine-dependend and really meaningless. ext2 comparison would tell you how much pramfs sucks (or not). Pavel If you knew that the results were machine-dependent I don't understand why you were so upset by my previous benchmark. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 00/14] Pramfs: Persistent and protected ram filesystem
Pavel Machek wrote: Ah now the write protection is a needed feature, in your previous comment you talked about why not use ext2/3... Marco Just for your information I tried the same test with pc in a virtual machine with 32MB of RAM: Version 1.03e --Sequential Output-- --Sequential Input- --Random- -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Machine Size:chnk K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP hostname 15M:1k 14156 99 128779 100 92240 100 11669 100 166242 99 80058 82 --Sequential Create-- Random Create -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 4 2842 99 133506 104 45088 101 2787 99 79581 101 58212 102 These data are the proof of the importance of the environment, workload and so on when we talk about benchmark. Your consideration are really superficial. Unfortunately, your numbers are meaningless. I don't think so. (PCs should have cca 3GB/sec RAM transfer rates; and you demosstrated cca 166MB/sec read rate; disk is 80MB/sec, so that's too slow. If you want to prove your filesystem the filesystem is reasonably fast, compare it with ext2 on ramdisk.) This is the point. I don't want compare it with ext2 from performance point of view. This comparison makes no sense for me. I've done this test to prove that if you change environment you can change in a purposeful way the results. Yes, IOW you demonstrated that the numbers are machine-dependend and really meaningless. ext2 comparison would tell you how much pramfs sucks (or not). Pavel Here the test with ext2 (same environment): Version 1.03e --Sequential Output-- --Sequential Input- --Random- -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Machine Size:chnk K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP hostname 15M:1k 10262 83 40847 82 38574 82 9866 92 62252 98 25204 81 --Sequential Create-- Random Create -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 1 19859 98 44804 61 68830 100 13566 99 157129 100 30431 98 Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: New fast(?)-boot results on ARM
Dirk Behme wrote: Sascha Hauer wrote: On Fri, Aug 14, 2009 at 07:02:28PM +0200, Robert Schwebel wrote: Hi, On Thu, Aug 13, 2009 at 05:33:26PM +0200, Robert Schwebel wrote: On Thu, Aug 13, 2009 at 08:28:26AM -0700, Arjan van de Ven wrote: That's bad :-) So there is no room for improvement any more in our ARM boot sequences ... on x86 we're doing pretty well ;-) On i.MX27 (400 MHz ARM926EJ-S) we currently need 7 s, measured from power-on through the kernel up to starting init. This is with - no delay in u-boot-v2 - rootfs on NAND (UBIFS) - quiet - precalculated loops-per-jiffy - zImage kernel instead of uImage Here's a little video of our demo system booting: http://www.youtube.com/watch?v=xDbUnNsj0cI As you can see there, it needs about 15 s from the release of the reset button up to the moment where the application shows it's Qt 4.5.2 based GUI (which is when we fade over from the initial framebuffer to the final one, in order to hide the qt application startup noise). And below is the boot log (after turning quiet off again). The numbers are the timestamp and the delta to the last timestamp, measured on the controlling PC by looking at the serial console output. The ptx_ts script starts when the regexp was found, so the numbers start basically in the moment when u-boot-v2 has initialized the system up to the point where we can see something. Result: - 2.4 s up from u-boot to the end of Uncompressing Linux - 300 ms until ubifs initialization starts - 3.7 s for ubifs, until mounted root So we basically have 7 s for the kernel. The rest is userspace, which hasn't seen much optimization yet, other than trying to start the GUI application as early as possible, while doing all other init stuff in parallel. Adding quiet brings us another 300 ms. That's factor 70 away from the 110 ms boot time Tim has talked about some days ago (and he measured on an ARM cpu which had almost half the speed of this one), and I'm wondering what we can do to improve the boot time. Robert r...@thebe:~$ microcom | ptx_ts U-Boot 2.0.0-rc9 [ 13.522625] 0.043189 [ 13.546627] 0.024002 OSELAS(R)-phyCORE-trunk (PTXdist-1.99.svn/2009-08-06T08:37:25+0200) [ 13.558613] 0.011986 [ 13.690643] 0.132030_ ___ _ [ 13.690731] 0.88 _ __ | |__ _ _ / ___/ _ \| _ \| | [ 13.698595] 0.007864 | '_ \| '_ \| | | | | | | | | |_) | _| [ 13.698654] 0.59 | |_) | | | | |_| | |__| |_| | _ | |___ [ 13.702581] 0.003927 | .__/|_| |_|\__, |\\___/|_| \_\_| [ 13.706573] 0.003992 |_| |___/ [ 13.706622] 0.49 [ 13.725043] 0.018421 [ 14.742608] 1.017565 I made some changes suggested in this thread: - enable MMU in the bootloader - use assembler optimized memcpy/memset in the bootloader - start an uncompressed image - disable IP autoconfiguration in the Kernel - use lpj= command line parameter - use static device nodes instead of udev - skip some init scripts - made the kernel smaller (I do not have both configs handy, so I do not know what exactly I changed) Already looks much better: [ 0.05] 0.05 U-Boot 2.0.0-rc10-00241-g3f10fe9-dirty (Aug 18 2009 - 13:29:25) [ 0.26] 0.21 [ 0.41] 0.15 Board: Phytec phyCORE-i.MX27 [ 0.54] 0.13 cfi_probe: cfi_flash base: 0xc000 size: 0x0200 [ 0.67] 0.13 NAND device: Manufacturer ID: 0x20, Chip ID: 0x36 (ST Micro NAND 64MiB 1,8V 8-bit) [ 0.80] 0.13 im...@imxfb0: i.MX Framebuffer driver [ 0.92] 0.12 dma_alloc: 0xa6f56e40 0x1000 [ 0.000105] 0.13 dma_alloc: 0xa6f57088 0x1000 [ 0.000118] 0.13 dev_protect: currently broken [ 0.000129] 0.11 Using environment in NOR Flash [ 0.000141] 0.12 initialising PLLs [ 0.128972] 0.128831 Malloc space: 0xa6f0 - 0xa7f0 (size 16 MB) [ 0.128995] 0.23 Stack space : 0xa6ef8000 - 0xa6f0 (size 32 kB) [ 0.129008] 0.13 running /env/bin/init... [ 0.224963] 0.095955 [ 0.224984] 0.21 Hit any key to stop autoboot: 0 [ 0.224999] 0.15 copy [ 0.592964] 0.367965 done [ 0.652010] 0.059046 Linux version 2.6.31-rc4-4-g05786f8-dirty (s...@octopus) (gcc version 4.3.2 (OSELAS.Toolchain-1.99.3) ) #206 PREEMPT Tue Aug 18 14:08:51 CEST 2009 So, this are ~0.6 s in boot loader and kernel copy until kernel starts, correct? What's the size of the uncompressed kernel copied here? Best regards Dirk Btw.: I tried to summarize some hints given in this thread in http://elinux.org/Boot_Time#Boot_time_check_list Please feel free to add and correct stuff! It's a good documentation, good work. From 14s to 5s I think it's a very good result. In reference to the previous response of Robert, I think that it's a good thing to use a vanilla kernel and avoid strange and specific or not mature solutions, but it needs to use the right tool for
Re: [PATCH 1/5] printk: introduce CONFIG_PRINTK_VERBOSITY
Marc Andre Tanner ha scritto: Introduce a config option which allows to selectively compile out printk messages based on a specified verbosity level. Signed-off-by: Marc Andre Tanner m...@brain-dump.org --- init/Kconfig | 29 + 1 files changed, 29 insertions(+), 0 deletions(-) diff --git a/init/Kconfig b/init/Kconfig index 3f7e609..549ed95 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -833,6 +833,35 @@ config PRINTK very difficult to diagnose system problems, saying N here is strongly discouraged. +config PRINTK_VERBOSITY + int Printk compile time verbosity + depends on EMBEDDED PRINTK + range 0 7 + default 0 + help + + Select the maximum printk verbosity level to be compiled into + the kernel. + + Messages above the specified verbosity level are removed from + the kernel at compile time. This reduces the kernel image size + at the cost of a calmer kernel. + + Possible verbosity levels are listed below. Note that messages + without an explicit loglevel will be classified as KERN_WARNING. + +0 Disable this feature and compile all messages in. + +1 KERN_ALERT/* action must be taken immediately */ +2 KERN_CRIT /* critical conditions */ +3 KERN_ERR /* error conditions */ +4 KERN_WARNING /* warning conditions*/ +5 KERN_NOTICE /* normal but significant condition */ +6 KERN_INFO /* informational */ +7 KERN_DEBUG/* debug-level messages */ + + If unsure, just move on and leave this option alone. + config BUG bool BUG() support if EMBEDDED default y If there are some problems to handle KERN_CONT you should say something here. You should even add in cc: the kernel ML, however it seems a good work. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 5/5] printk: provide a filtering macro for printk
2009/9/2 Marc Andre Tanner m...@brain-dump.org: On Wed, Sep 02, 2009 at 06:44:19PM +0200, Marco Stornelli wrote: Marc Andre Tanner ha scritto: +#define printk(fmt, ...) ( \ Shouldn't it be an and? Don't think so. If the expression isn't constant we are unable to filter it and therefore printk is called anyway. However if the expression is constant the second part of the condition is evaluated and we filter based on the verbosity level. Yes, you're right. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH, RFC] panic-note: Annotation from user space for panics
Sincerely, I don't understand why we should involve the kernel to gather this kind of information when we can use other (user-space) tools, only to have all in a single report maybe? I think it's a bit weak reason to include this additional behavior in the kernel. David VomLehn ha scritto: Allows annotation of panics to include platform information. It's no big deal to collect information, but way helpful when you are collecting failure reports from a eventual base of millions of systems deployed in other people's homes. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH, RFC] panic-note: Annotation from user space for panics
I think in general the procedure should be: at startup or event (for example acquired IP address from DHCP) user applications write in flash (better in persistent ram) a log with a tag or a timestamp or something like this, when there is a kernel panic, it is captured in a file stored together the log and when possible the system should send all via network for example. Are there problems that I can't see to follow this approach? When David says ...so this looks much more like a real file than a sysctl file I quite agree, it seems a normal application/system log indeed. Marco Artem Bityutskiy wrote: On Fri, 2009-11-13 at 09:10 +0100, Simon Kagstrom wrote: On Thu, 12 Nov 2009 16:56:49 -0500 David VomLehn dvoml...@cisco.com wrote: Good question. Some more detail on our application might help. In some situations, we may have no disk and only enough flash for the bootloader. The kernel is downloaded over the network. When we get to user space, we initialize a number of things dynamically. For example, we dynamically compute some MAC address, and most of the IP addresses are obtained with DHCP. This are very useful to have for panic analysis. Since there is neither flash nor disk, user space has no place to store this information, should the kernel panic. When we come back up, we will get different MAC and IP addresses. Storing them in memory is our only hope. Fortunately, there is a section of RAM that the bootloader promises not to overwrite. On a panic, we capture the messages written on the console and store them in the protected area. If the information from the /proc file is written as part of the panic, we will capture it, too. Can't you solve this completely from userspace using phram and mtdoops instead? I.e., setup two phram areas modprobe phram 4...@start-of-your-area,4...@start-of-your-area+4k# Can't remember the exact syntax! you'll then get /dev/mtdX and /dev/mtdX+1 for these two. You can then do modprobe mtdoops mtddev=/dev/mtdX+1 dump_oops=0 to load mtdoops to catch the panic in the second area, and just write your userspace messages to /dev/mtdX. This might work for them, not sure, but not for us. We store panics on flash, and later they are automatically sent to the panic collection system via the network. And the complications are: 1. There may be many panics before the device has network access and has a chance to send the panics. 2. User can re-flash the device with different SW inbetween. So we really need to print some user-space supplied information during the panic, and then we store it on flash with mtdoops, and the later, when the device has network access we send whole bunch of oopses via the network. One thing probably have to be fixed though: I don't think phram has a panic_write, which will be needed by mtdoops to catch the panic - this should be trivial to add though since it's plain RAM. -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH, RFC] panic-note: Annotation from user space for panics
Artem Bityutskiy wrote: On Tue, 2009-11-17 at 13:45 +0100, Marco Stornelli wrote: 2009/11/17 Artem Bityutskiy dedeki...@gmail.com: We need to store this information of NAND flash. Implementing logs on NAND flash is about handling bad blocks, choosing format of records, and may be even handling wear-levelling. This is not that simple. And then I have match oops to the userspace environment prints, using I guess timestamps, which is also about complications in userspace. Indeed my suggestion was to use a persistent ram, not difficult to use. This patch solves the problem gracefully, and I'd rather demand you to point what is the technical problem with the patches. Simply because I think that we should avoid to include in the kernel things we can do in a simply way at user space level. If it is much easier to have in the kernel, then this argument does not work, IMHO. I think this patch is well done but it's one of the patches that are solutions for embedded only, but it's only my opinion. Also IMHO, but having embedded-only things is not bad at all. In the past other patches are not accepted in main line for this, maybe you'll be luckier. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
How to store kernel pranic/oops
Hi, I know the open project proposal 2010 is closed, but it's just to start a discussion. It would be nice to save oops/panic automatically in a structure/file in ram. At the moment there are two way to save information: mtdoops (save the information in flash), with kdump/kexec (we can extract the dmesg from vmcore file). With these tools there are some drawbacks: 1) There are embedded systems without a flash where to save the information; 2) we could consider this kind of logs too volatile for a flash, I mean there's no reason to store it for a long time, it's important to recover and read them as soon as possible, at next boot for example. 3) kdump requires a lot of ram and resources for embedded systems. 4) kexec is available only for some archs. It would be nice to have a ramoops to save in a circular buffer in a persistent ram this kind of information. Any comments? Is there already anything similar out-of-tree? Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Re: How to store kernel panic/oops
David Woodhouse wrote: Can't it be done with what's in the tree already? Just create an MTD device using phram or something else, then point mtdoops at it Yes of course, if possible we shouldn't reinvent the wheel but I wondered if there was something more specific. To add mtdoops (more or less 1k) we have to add mtd subsys (more or less 14k) to the kernel to achieve this and it's all overhead. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH V2 6/8] lzma: Make lzma ... thunderbird ok
Il 07/01/2010 08:43, Hein_Tibosch ha scritto: On 7-1-2010 08:37, Phillip Lougher wrote: Sorry, I was worried it might do that - the curse of Thunderbird. I normally use a really dumb client like mailx to send patches, but I obviously didn't have the email thread under mailx to do that. Thunderbird: not a real curse for patches. Try the following: Tools - Options - Advanced - General - Config Editor mailnews.send_plaintext_flowed user boolean false mailnews.display.disable_flowed_support user boolean true mailnews.wraplength user integer 512 And see this patch below: --- diff --git a/thunderbird b/thunderbird +++ --- if (using_thunderbird) { you can send patches safely } --- Hein And with pasteCode and Toggle Word Wrap extensions it is even more easier ;) Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: mount ramdisk rootfs /etc directory to jffs2 filesystem.
2010/1/20 Johnny Hung johnny.hack...@gmail.com: 2010/1/19 Matthias Kaehlcke matth...@kaehlcke.net: El Tue, Jan 19, 2010 at 02:17:22PM +0100 Ricard Wanderlof ha dit: I consider to use ramdisk as rootfs because worry about wrong operation in rootfs (is use jffs2 rootfs) and it will cause system boot up failed. Another query, does the syslogd/klogd log files also store in jffs2 rootfs? Write to jffs2 frequently will reduce flash life cycle. BRs, H. Johnny -- In general a good splitting for rootfs could be: squashfs for rootfs, tmpfs for volatile data (/tmp), ubifs (with a flash partition) for strong permanent data (/etc, ) and pramfs for light permanent data (/var/log, .). I think you should split your rootfs. Ramdisk is an old approach with some drawbacks. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: mount ramdisk rootfs /etc directory to jffs2 filesystem.
2010/1/20 Matthias Kaehlcke matth...@kaehlcke.net: El Wed, Jan 20, 2010 at 08:57:44AM +0100 Marco Stornelli ha dit: 2010/1/20 Johnny Hung johnny.hack...@gmail.com: 2010/1/19 Matthias Kaehlcke matth...@kaehlcke.net: El Tue, Jan 19, 2010 at 02:17:22PM +0100 Ricard Wanderlof ha dit: I consider to use ramdisk as rootfs because worry about wrong operation in rootfs (is use jffs2 rootfs) and it will cause system boot up failed. Another query, does the syslogd/klogd log files also store in jffs2 rootfs? Write to jffs2 frequently will reduce flash life cycle. BRs, H. Johnny -- In general a good splitting for rootfs could be: squashfs for rootfs, tmpfs for volatile data (/tmp), ubifs (with a flash partition) for strong permanent data (/etc, ) and pramfs for light permanent data (/var/log, .). if ubifs is a good choice depends on the size of the partition, iirc it has a significant overhead for very small partitions. once using ubi it could be interesting to set up the read-only rootfs partition upon ubi in order to spread the wear out over a maximum of blocks. I don't know the size constraints of Johnny, so it can be useful to use jffs2. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH]: Ram oops/panic logger
Ramoops, like mtdoops, can log oops/panic information but in RAM. It can be used with persistent RAM for systems without flash support. In addition, for this systems, with this driver, it's no more needed add to the kernel the mtd subsystem with advantage in footprint. Signed-off-by: Marco Stornelli marco.storne...@gmail.com -- diff -Nuar linux-2.6.33-orig/drivers/char/Kconfig linux-2.6.33/drivers/char/Kconfig --- linux-2.6.33-orig/drivers/char/Kconfig 2010-02-24 19:52:17.0 +0100 +++ linux-2.6.33/drivers/char/Kconfig 2010-02-28 10:47:29.0 +0100 @@ -1105,5 +1105,12 @@ source drivers/s390/char/Kconfig +config RAMOOPS + tristate Log panic/oops to a RAM buffer + default n + help + This enables panic and oops messages to be logged to a circular + buffer in RAM where it can be read back at some later point. + endmenu diff -Nuar linux-2.6.33-orig/drivers/char/Makefile linux-2.6.33/drivers/char/Makefile --- linux-2.6.33-orig/drivers/char/Makefile 2010-02-24 19:52:17.0 +0100 +++ linux-2.6.33/drivers/char/Makefile 2010-02-28 10:49:17.0 +0100 @@ -107,6 +107,7 @@ obj-$(CONFIG_TCG_TPM) += tpm/ obj-$(CONFIG_PS3_FLASH)+= ps3flash.o +obj-$(CONFIG_RAMOOPS) += ramoops.o obj-$(CONFIG_JS_RTC) += js-rtc.o js-rtc-y = rtc.o diff -Nuar linux-2.6.33-orig/drivers/char/ramoops.c linux-2.6.33/drivers/char/ramoops.c --- linux-2.6.33-orig/drivers/char/ramoops.c1970-01-01 01:00:00.0 +0100 +++ linux-2.6.33/drivers/char/ramoops.c 2010-03-06 13:36:31.0 +0100 @@ -0,0 +1,163 @@ +/* + * RAM Oops/Panic logger + * + * Copyright (C) 2009 Marco Stornelli marco.storne...@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include linux/kernel.h +#include linux/module.h +#include linux/kmsg_dump.h +#include linux/time.h +#include linux/io.h +#include linux/ioport.h + +#define RAMOOPS_KERNMSG_HDR +#define RAMOOPS_HEADER_SIZE (5 + sizeof(struct timeval)) + +#define RECORD_SIZE 4096 + +static ulong mem_address; +module_param(mem_address, ulong, 0600); +MODULE_PARM_DESC(mem_address, + start of reserved RAM used to store oops/panic logs); + +static ulong mem_size; +module_param(mem_size, ulong, 0600); +MODULE_PARM_DESC(mem_size, + size of reserved RAM used to store oops/panic logs); + +static int dump_oops = 1; +module_param(dump_oops, int, 0600); +MODULE_PARM_DESC(dump_oops, + set to 1 to dump oopses, 0 to only dump panics (default 1)); + +static struct ramoops_context { + struct kmsg_dumper dump; + void *virt_addr; + phys_addr_t phys_addr; + unsigned long size; + int count; + int max_count; +} oops_cxt; + +static void ramoops_do_dump(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason, const char *s1, unsigned long l1, + const char *s2, unsigned long l2) +{ + struct ramoops_context *cxt = container_of(dumper, + struct ramoops_context, dump); + unsigned long s1_start, s2_start; + unsigned long l1_cpy, l2_cpy; + int res; + char *buf; + struct timeval timestamp; + + /* Only dump oopses if dump_oops is set */ + if (reason == KMSG_DUMP_OOPS !dump_oops) + return; + + buf = (char *)(cxt-virt_addr + (cxt-count * RECORD_SIZE)); + memset(buf, '\0', RECORD_SIZE); + res = sprintf(buf, %s, RAMOOPS_KERNMSG_HDR); + buf += res; + do_gettimeofday(timestamp); + res = sprintf(buf, %lu.%lu\n, (long)timestamp.tv_sec, (long)timestamp.tv_usec); + buf += res; + + l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE)); + l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE) - l2_cpy); + + s2_start = l2 - l2_cpy; + s1_start = l1 - l1_cpy; + + memcpy(buf, s1 + s1_start, l1_cpy); + memcpy(buf + l1_cpy, s2 + s2_start, l2_cpy); + + cxt-count = (cxt-count + 1) % cxt-max_count; +} + +static int __init ramoops_init(void) +{ + struct ramoops_context *cxt = oops_cxt; + int err = -EINVAL; + + if (!mem_size) { + printk(KERN_ERR Invalid size specification); + goto fail3; + } + + rounddown_pow_of_two(mem_size
Re: [PATCH v2] char drivers: Ram oops/panic logger
2010/3/10 Yuasa Yoichi yu...@linux-mips.org: Hi, 2010/3/10 Marco Stornelli marco.storne...@gmail.com: Ramoops, like mtdoops, can log oops/panic information but in RAM. What is different from mtdoops + mtd-ram? Yoichi It can be used in a very easy way with persistent RAM for systems without flash support. For this systems, with this driver, it's no more needed add to the kernel the mtd subsystem with advantage in footprint as I said in the description. In addition, you can save flash space and store this information only in RAM. I think it's very useful for embedded systems. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2] char drivers: Ram oops/panic logger
Il 13/03/2010 00:31, Jamie Lokier ha scritto: That'd be fine if the kernel link scripts choose the address, as long as it's consistent between different compiles and similar configurations. That'd be a bit simpler than the admin having to know the memory map well enough to choose an address. -- Jamie I agree, but the bootloader should be aware of it. I mean, usually bootloaders at boot, reset the RAM, so you have to tell to the bootloader that you are using a piece of RAM as persistent RAM, for example U-Boot has got a specific option CONFIG_PRAM. I don't know if all the process can be completely transparent to the admin in all situations. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2] char drivers: Ram oops/panic logger
Il 12/03/2010 23:48, Andrew Morton ha scritto: On Wed, 10 Mar 2010 13:15:25 +0100 Marco Stornelli marco.storne...@gmail.com wrote: 2010/3/10 Yuasa Yoichi yu...@linux-mips.org: 2010/3/10 Marco Stornelli marco.storne...@gmail.com: 2010/3/10 Yuasa Yoichi yu...@linux-mips.org: I meant with the classic use of mtdoops, therefore with a flash partition without use MTD_RAM. Using MTD_RAM, it's more or less the same thing, with the exception of where you want deploy the log. For example: if in your system you have got a nvram you can use it without problem, you need to specify the address of the nvram to the module. Very simple. I think it's a small driver but very useful, feedback from other embedded guys are welcome. Seems sensible to me. If you have a machine whose memory is persistent across reboots then you reserve an arbitrary 4k hunk of memory for collecting oops traces, yes? Yes. What tools are used for displaying that memory on the next boot? How do those tools distinguish between valid oops trace and garbage because it was just powered on? A magic signature? For my test I used the program devmem2 to dump the log. In general, you can read the memory via /dev/mem. There's an header plus a timestamp of the log. The memory is initialized with blank spaces and the size of the record is fixed at 4k, so if a program/script doesn't find the header at next 4k, it means there's garbage and it can stop the read operation. Should the kernel provide the 4k of memory rather than (or in addition to) requiring that the system administrator reserve it and tell the kernel about it? That'd be a matter of creating a linker section which isn't cleared out by the startup code. Yes, it can be an option. My first idea was to write a general driver, with an address in input that it can be related to the reserved RAM as an NVRAM in the system, however it can be a good idea, why not. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2] char drivers: Ram oops/panic logger
2010/3/15 Jamie Lokier ja...@shareable.org: Marco Stornelli wrote: Il 13/03/2010 00:31, Jamie Lokier ha scritto: I agree, but the bootloader should be aware of it. I mean, usually bootloaders at boot, reset the RAM, so you have to tell to the bootloader that you are using a piece of RAM as persistent RAM, for example U-Boot has got a specific option CONFIG_PRAM. I don't know if all the process can be completely transparent to the admin in all situations. Sometimes you can't change the bootloader (they don't always come with source code). Or you could, but you don't want to risk it (there isn't always a way to recover if you break it). Obviously then the feature is only useful when the bootloader doesn't clear all the RAM :-) On slow boards in consumer devices, they sometimes avoid clearing the RAM because that adds measurable boot time. In the embedded world, usually, you can change/write the fw and you know well the memory map, so no problem to know the address to use. In other cases, it can be possible to use a transparent approach, but in my opinion the general approach used by the driver is enough. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3] char drivers: Ram oops/panic logger
From: Marco Stornelli marco.storne...@gmail.com Ramoops, like mtdoops, can log oops/panic information but in RAM. It can be used with persistent RAM for systems without flash support. In addition, for this systems, with this driver, it's no more needed add to the kernel the mtd subsystem with advantage in footprint. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- Changelog: -v1: first draft -v2: fixed compilation warning when using request_mem_region -v3: changed permissions from 0600 to 0400 for size and address of ram buffer. Fixed the lack of 'ramoops:' in some printk. --- linux-2.6.33-orig/drivers/char/Kconfig 2010-02-24 19:52:17.0 +0100 +++ linux-2.6.33/drivers/char/Kconfig 2010-02-28 10:47:29.0 +0100 @@ -1105,5 +1105,12 @@ config DEVPORT source drivers/s390/char/Kconfig +config RAMOOPS + tristate Log panic/oops to a RAM buffer + default n + help + This enables panic and oops messages to be logged to a circular + buffer in RAM where it can be read back at some later point. + endmenu --- linux-2.6.33-orig/drivers/char/Makefile 2010-02-24 19:52:17.0 +0100 +++ linux-2.6.33/drivers/char/Makefile 2010-02-28 10:49:17.0 +0100 @@ -107,6 +107,7 @@ obj-$(CONFIG_HANGCHECK_TIMER) += hangche obj-$(CONFIG_TCG_TPM) += tpm/ obj-$(CONFIG_PS3_FLASH)+= ps3flash.o +obj-$(CONFIG_RAMOOPS) += ramoops.o obj-$(CONFIG_JS_RTC) += js-rtc.o js-rtc-y = rtc.o --- linux-2.6.33-orig/drivers/char/ramoops.c2009-12-16 00:58:07.0 +0100 +++ linux-2.6.33/drivers/char/ramoops.c 2010-03-21 11:06:40.0 +0100 @@ -0,0 +1,162 @@ +/* + * RAM Oops/Panic logger + * + * Copyright (C) 2010 Marco Stornelli marco.storne...@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include linux/kernel.h +#include linux/module.h +#include linux/kmsg_dump.h +#include linux/time.h +#include linux/io.h +#include linux/ioport.h + +#define RAMOOPS_KERNMSG_HDR +#define RAMOOPS_HEADER_SIZE (5 + sizeof(struct timeval)) + +#define RECORD_SIZE 4096 + +static ulong mem_address; +module_param(mem_address, ulong, 0400); +MODULE_PARM_DESC(mem_address, + start of reserved RAM used to store oops/panic logs); + +static ulong mem_size; +module_param(mem_size, ulong, 0400); +MODULE_PARM_DESC(mem_size, + size of reserved RAM used to store oops/panic logs); + +static int dump_oops = 1; +module_param(dump_oops, int, 0600); +MODULE_PARM_DESC(dump_oops, + set to 1 to dump oopses, 0 to only dump panics (default 1)); + +static struct ramoops_context { + struct kmsg_dumper dump; + void *virt_addr; + phys_addr_t phys_addr; + unsigned long size; + int count; + int max_count; +} oops_cxt; + +static void ramoops_do_dump(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason, const char *s1, unsigned long l1, + const char *s2, unsigned long l2) +{ + struct ramoops_context *cxt = container_of(dumper, + struct ramoops_context, dump); + unsigned long s1_start, s2_start; + unsigned long l1_cpy, l2_cpy; + int res; + char *buf; + struct timeval timestamp; + + /* Only dump oopses if dump_oops is set */ + if (reason == KMSG_DUMP_OOPS !dump_oops) + return; + + buf = (char *)(cxt-virt_addr + (cxt-count * RECORD_SIZE)); + memset(buf, '\0', RECORD_SIZE); + res = sprintf(buf, %s, RAMOOPS_KERNMSG_HDR); + buf += res; + do_gettimeofday(timestamp); + res = sprintf(buf, %lu.%lu\n, (long)timestamp.tv_sec, (long)timestamp.tv_usec); + buf += res; + + l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE)); + l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE) - l2_cpy); + + s2_start = l2 - l2_cpy; + s1_start = l1 - l1_cpy; + + memcpy(buf, s1 + s1_start, l1_cpy); + memcpy(buf + l1_cpy, s2 + s2_start, l2_cpy); + + cxt-count = (cxt-count + 1) % cxt-max_count; +} + +static int __init ramoops_init(void) +{ + struct ramoops_context *cxt = oops_cxt; + int err = -EINVAL; + + if (!mem_size) { + printk(KERN_ERR ramoops: invalid size specification); + goto fail3
Re: [PATCH] Pseudo-console for capture and redirection of console output
2010/4/12 David VomLehn dvoml...@cisco.com: Provide functions for capturing console output for storage. The primary user is likely to be embedded systems that don't have the storage for core dumps but do have a need to log kernel panic information for later evaluation. It offers two main areas of functionality: o It can maintain a circular log of console output so that kernel log messages written before panic() was called can be retrieved to be added to the failure log. o A function can be registered to store output from printk() in a persistent location, such as a reserved location in RAM. Then, printk() can be used either directly, to print state information, or indirectly, through standard functions like dump_stack() and show_regs(). During normal operation, we use the circular logging. When we crash, almost the first thing we do is to switch to storing output. This goes in a memory buffer that is preserved over reboots. We then write a detailed crash report using printk() and functions that use printk(). We retrieve the last n lines of the log before the crash and print it, so that gets captured in the log, too. It's very similar to my driver ramoops, have you already seen it? Currently it's in the mm tree, I think it will be included in mainline early. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Can I manage/modify console baud rates from userspace?
02/05/2010 02:02, Paul Smith wrote: I've looked at setserial and it supports a baud_base parameter but that doesn't appear to be what I want (I tried it anyway: changing it didn't work, my console output was still screwed up). Trying to do something like creating customized PXE configs on the server based on the MAC addresses of the blades that are new (or old) would be an absolute nightmare as people swap blades between chassis, add new ones, etc. all the time. Please help me find a better way... :-( It's strange that it's not possible to change the baud rate, but I'm not an expert of tty layer. A naive implementation could be patch the kernel to choose a well-known baud rate for your hw reading a revision register or something like that. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] console logging detour via printk
01/05/2010 20:48, Samo Pogacnik wrote: Dne 01.05.2010 (sob) ob 12:04 +0100 je Alan Cox zapisal(a): while i was searching for effective logging of complete console output produced by the kernel and user phase of the boot process, it turned out that only kernel messages imho get systematically cached and stored into log files (if needed). All userspace processes are on their own to use syslog, which is fine, but there are also many console messages reporting the boot status via init scripts, I came across the bootlogd daemo, which handles the job of redirecting console output into a log file, but i find it problematic to use especialy, when using initial ram disk image. So you want to patch the kernel because you can't work out how to do this in userspace ? The distributions seem to have no problem doing this in user space that I can see. It doesn't seem to be a hard user space problem, and there are a ton of things you want to do with this sort of stuff (like network logging) that you can't do in kernel space. The distros have no problem logging complete console output into log files or over the network, because they simply do not do it at least for the initrd part of the boot process (i'd be glad, if i'm wrong). Mmm...It's an interesting problem. I see in my distro (openSuse) a script called boot.klog that it seems to perform that (even initrd part). In the file boot.msg I can see the initial prints of the kernel and user space scripts. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] console logging detour via printk
Il 02/05/2010 15:29, Samo Pogacnik ha scritto: Dne 02.05.2010 (ned) ob 11:58 +0200 je Marco Stornelli zapisal(a): 01/05/2010 20:48, Samo Pogacnik wrote: Mmm...It's an interesting problem. I see in my distro (openSuse) a script called boot.klog that it seems to perform that (even initrd part). In the file boot.msg I can see the initial prints of the kernel and user space scripts. Thanks for the info. Is this boot.klog script from the initrd image or from the real rootfs? As you can see, i am still suspicious about the initrd part user console messages:) Samo In the initrd there's the script blogd.sh: if test -z $fboot -a -z $quiet -a -z $REDIRECT ; then REDIRECT=$(showconsole 2/dev/null) if test -n $REDIRECT ; then if test $devpts != yes ; then mount -t devpts devpts /dev/pts devpts=yes fi /dev/shm/initrd.msg ln -sf /dev/shm/initrd.msg /var/log/boot.msg mkdir -p /var/run /sbin/blogd $REDIRECT fi fi And in the rootfs the boot.klog script: # Read all kernel messages generated until now and put them in one file. test -s /var/log/boot.msg mv -f /var/log/boot.msg /var/log/boot.omsg echo Creating /var/log/boot.msg if test -x /sbin/klogd ; then # klogd syncs out the file /sbin/klogd -s -o -n -f /var/log/boot.msg test -s /var/log/boot.msg rc_status -v1 -r elif test -x /bin/dmesg ; then /bin/dmesg /var/log/boot.msg /bin/sync test -s /var/log/boot.msg rc_status -v1 -r fi if test -e /dev/shm/initrd.msg ; then cat /dev/shm/initrd.msg /var/log/boot.msg rm -f /dev/shm/initrd.msg fi [ --- cut here --- ] Regards, Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
omap udc driver problem with beagle board
Hi, I'm using the kernel 2.6.34 with the beagle board rev. c4. I have got some problems with the ethernet gadget to use nfs over usb. The problem is with the usb. When the g_ether driver register itself, the omap udc driver returns ENODEV because the kernel didn't call the probe for this driver. Looking at the code, it seems the problem is in board specific management of the usb. There isn't the registration of the platform device to match the omap udc platform driver. It should be done in the omap_usb_init() but in case of beagle board this function is never called, so omap udc driver cannot work. Is it a regression? Is there any workaround? Thanks. Regards, Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: omap udc driver problem with beagle board
2010/5/30 Felipe Balbi m...@felipebalbi.com: On Sun, May 30, 2010 at 11:53:49AM +0200, Marco Stornelli wrote: beagle board uses musb. You shouldn't be relying on the udc controller. Your Kconfig is just wrong. -- balbi Oops, my fault. I see the error in the configuration. Thank you very much for your response. I'll try again. Regards, Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] detour TTY driver - now ttyprintk
2010/8/25 Greg KH gre...@suse.de: On Wed, Aug 25, 2010 at 12:51:52AM +0100, Alan Cox wrote: Seriously, look at how Fedora 14 handles this, why can't you do the same for embedded systems all from userspace, no additional code needed anywhere. thanks, greg k-h -- Samo sometimes ago I gave you some information on the system startup about OpenSuse, have you look at it? It's possible that what Greg said, it's true. Regards, Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] pramfs: Persistent and protected RAM filesystem
Hi all, after a lot of improvement, test, bug fix and new features, it's the moment for third round with the kernel community to submit PRAMFS for mainline. First of all, I have to say thanks to Tim Bird and CELF to actively support the project. Since the last review (June 2009) a lot of things are changed: - removed any reference of BKL - fixed the endianess for the fs layout - added support for extended attributes, ACLs and security labels - moved out any pte manipulations from fs and inserted them in mm - implemented the new truncate convention - fixed problems with 64bit archs ...and much more. Complete story in the ChangeLog inserted in the documentation file. Since the patch is long, you can download and review the patch from the project site: http:\\pramfs.sourceforge.net. The patch version is 1.2.1 for kernel 2.6.36. In addition, in the web site tech page, you can find a lot of information about implementation, technical details, benchemarking and so on. Regards, Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 00/16] pramfs: persistent and protected RAM Filesystem
Hi all, after a lot of improvement, test, bug fix and new features, it's the moment for third round with the kernel community to submit PRAMFS for mainline. Since the last review (June 2009) a lot of things are changed: - removed any reference of BKL - fixed the endianess for the fs layout - added support for extended attributes, ACLs and security labels - moved out any pte manipulations from fs and inserted them in mm - implemented the new truncate convention - fixed problems with 64bit archs ...and much more. Complete story in the ChangeLog inserted in the documentation file. In addition, in the web site tech page (http:\\pramfs.sourceforge.net), you can find a lot of information about implementation, technical details, benchmarking and so on. All the work to mainline this feature is sponsored by the CE Linux Forum. Regards, Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 02/16] pramfs: super block operations
From: Marco Stornelli marco.storne...@gmail.com Super block operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/super.c linux-2.6.36/fs/pramfs/super.c --- linux-2.6.36-orig/fs/pramfs/super.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/super.c 2010-09-25 14:09:47.0 +0200 @@ -0,0 +1,740 @@ +/* + * FILE NAME fs/pramfs/super.c + * + * BRIEF DESCRIPTION + * + * Super block operations. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/module.h +#include linux/string.h +#include linux/slab.h +#include linux/init.h +#include linux/blkdev.h +#include linux/parser.h +#include linux/vfs.h +#include linux/uaccess.h +#include linux/io.h +#include linux/seq_file.h +#include linux/mount.h +#include linux/mm.h +#include linux/ctype.h +#include linux/bitops.h +#include linux/magic.h +#include linux/exportfs.h +#include linux/random.h +#include xattr.h +#include pram.h + +static struct super_operations pram_sops; +static const struct export_operations pram_export_ops; +static struct kmem_cache *pram_inode_cachep; + +#ifdef CONFIG_PRAMFS_TEST +static void *first_pram_super; + +struct pram_super_block *get_pram_super(void) +{ + return (struct pram_super_block *)first_pram_super; +} +EXPORT_SYMBOL(get_pram_super); +#endif + +static void pram_set_blocksize(struct super_block *sb, unsigned long size) +{ + int bits; + + /* + * We've already validated the user input and the value here must be + * between PRAM_MAX_BLOCK_SIZE and PRAM_MIN_BLOCK_SIZE + * and it must be a power of 2. + */ + bits = fls(size) - 1; + sb-s_blocksize_bits = bits; + sb-s_blocksize = (1bits); +} + +static inline void *pram_ioremap(phys_addr_t phys_addr, ssize_t size) +{ + void *retval; + + /* +* NOTE: Userland may not map this resource, we will mark the region so +* /dev/mem and the sysfs MMIO access will not be allowed. This +* restriction depends on STRICT_DEVMEM option. If this option is +* disabled or not available we mark the region only as busy. +*/ + retval = request_mem_region_exclusive(phys_addr, size, pramfs); + if (!retval) + goto fail; + + retval = ioremap_nocache(phys_addr, size); + + if (retval) + wrprotect(retval, size); +fail: + return retval; +} + +static loff_t pram_max_size(int bits) +{ + loff_t res; + res = (1ULL (3*bits - 6)) - 1; + + if (res MAX_LFS_FILESIZE) + res = MAX_LFS_FILESIZE; + + pram_info(Max file size %llu bytes, res); + return res; +} + +enum { + Opt_addr, Opt_bpi, Opt_size, + Opt_num_inodes, Opt_mode, Opt_uid, + Opt_gid, Opt_blocksize, Opt_err +}; + +static const match_table_t tokens = { + {Opt_bpi, physaddr=%x}, + {Opt_bpi, bpi=%u}, + {Opt_size, init=%s}, + {Opt_num_inodes, N=%u}, + {Opt_mode, mode=%o}, + {Opt_uid, uid=%u}, + {Opt_gid, gid=%u}, + {Opt_blocksize, bs=%s}, + {Opt_err, NULL}, +}; + +static phys_addr_t get_phys_addr(void **data) +{ + phys_addr_t phys_addr; + char *options = (char *) *data; + + if (!options || strncmp(options, physaddr=, 9) != 0) + return (phys_addr_t)ULLONG_MAX; + options += 9; + phys_addr = (phys_addr_t)simple_strtoull(options, options, 0); + if (*options *options != ',') { + pram_err(Invalid phys addr specification: %s\n, + (char *) *data); + return (phys_addr_t)ULLONG_MAX; + } + if (phys_addr (PAGE_SIZE - 1)) { + pram_err(physical address 0x%16llx for pramfs isn't + aligned to a page boundary\n, + (u64)phys_addr); + return (phys_addr_t)ULLONG_MAX; + } + if (*options == ',') + options++; + *data = (void *) options; + return phys_addr; +} + +static int pram_parse_options(char *options, struct pram_sb_info *sbi) +{ + char *p, *rest; + substring_t args[MAX_OPT_ARGS]; + int option; + + if (!options) + return 0; + + while ((p = strsep(options, ,)) != NULL) { + int token; + if (!*p) + continue; + + token = match_token(p, tokens, args); + switch (token) { + case Opt_addr: { + /* physaddr managed
[PATCH 06/16] pramfs: inode operations for dirs
From: Marco Stornelli marco.storne...@gmail.com Inode operations for directories. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/namei.c linux-2.6.36/fs/pramfs/namei.c --- linux-2.6.36-orig/fs/pramfs/namei.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/namei.c 2010-09-18 12:00:35.0 +0200 @@ -0,0 +1,363 @@ +/* + * FILE NAME fs/pramfs/namei.c + * + * BRIEF DESCRIPTION + * + * Inode operations for directories. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ +#include linux/fs.h +#include linux/pagemap.h +#include pram.h +#include acl.h +#include xattr.h + +/* + * Couple of helper functions - make the code slightly cleaner. + */ + +static inline void pram_inc_count(struct inode *inode) +{ + inode-i_nlink++; + pram_write_inode(inode, 0); +} + +static inline void pram_dec_count(struct inode *inode) +{ + if (inode-i_nlink) { + inode-i_nlink--; + pram_write_inode(inode, 0); + } +} + +static inline int pram_add_nondir(struct inode *dir, + struct dentry *dentry, + struct inode *inode) +{ + int err = pram_add_link(dentry, inode); + if (!err) { + d_instantiate(dentry, inode); + unlock_new_inode(inode); + return 0; + } + pram_dec_count(inode); + unlock_new_inode(inode); + iput(inode); + return err; +} + +/* + * Methods themselves. + */ + +static ino_t +pram_inode_by_name(struct inode *dir, + struct dentry *dentry) +{ + struct pram_inode *pi; + ino_t ino; + int namelen; + + pi = pram_get_inode(dir-i_sb, dir-i_ino); + ino = be64_to_cpu(pi-i_type.dir.head); + + while (ino) { + pi = pram_get_inode(dir-i_sb, ino); + + if (pi-i_links_count) { + namelen = strlen(pi-i_d.d_name); + + if (namelen == dentry-d_name.len + !memcmp(dentry-d_name.name, + pi-i_d.d_name, namelen)) + break; + } + + ino = be64_to_cpu(pi-i_d.d_next); + } + + return ino; +} + +static struct dentry * +pram_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) +{ + struct inode *inode = NULL; + ino_t ino; + + if (dentry-d_name.len PRAM_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + + ino = pram_inode_by_name(dir, dentry); + if (ino) { + inode = pram_iget(dir-i_sb, ino); + if (!inode) + return ERR_PTR(-EACCES); + } + + d_splice_alias(inode, dentry); + return NULL; +} + + +/* + * By the time this is called, we already have created + * the directory cache entry for the new file, but it + * is so far negative - it has no inode. + * + * If the create succeeds, we fill in the inode information + * with d_instantiate(). + */ +static int pram_create(struct inode *dir, struct dentry *dentry, + int mode, struct nameidata *nd) +{ + struct inode *inode = pram_new_inode(dir, mode); + int err = PTR_ERR(inode); + if (!IS_ERR(inode)) { + + inode-i_op = pram_file_inode_operations; + inode-i_fop = pram_file_operations; + inode-i_mapping-a_ops = pram_aops; + err = pram_add_nondir(dir, dentry, inode); + } + return err; +} + +static int pram_mknod(struct inode *dir, struct dentry *dentry, int mode, + dev_t rdev) +{ + struct inode *inode = pram_new_inode(dir, mode); + int err = PTR_ERR(inode); + if (!IS_ERR(inode)) { + init_special_inode(inode, mode, rdev); + pram_write_inode(inode, 0); /* update rdev */ + err = pram_add_nondir(dir, dentry, inode); + } + return err; +} + +static int pram_symlink(struct inode *dir, + struct dentry *dentry, + const char *symname) +{ + struct super_block *sb = dir-i_sb; + int err = -ENAMETOOLONG; + unsigned len = strlen(symname); + struct inode *inode; + + if (len+1 sb-s_blocksize) + goto out; + + inode = pram_new_inode(dir, S_IFLNK | S_IRWXUGO); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out; + + inode-i_op = pram_symlink_inode_operations; + inode-i_mapping-a_ops = pram_aops
[PATCH 05/16] pramfs: block allocation
From: Marco Stornelli marco.storne...@gmail.com Block allocation operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/balloc.c linux-2.6.36/fs/pramfs/balloc.c --- linux-2.6.36-orig/fs/pramfs/balloc.c1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/balloc.c 2010-09-26 18:05:06.0 +0200 @@ -0,0 +1,155 @@ +/* + * FILE NAME fs/pramfs/balloc.c + * + * BRIEF MODULE DESCRIPTION + * + * The blocks allocation and deallocation routines. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/fs.h +#include linux/bitops.h +#include pram.h + +/* + * This just marks in-use the blocks that make up the bitmap. + * The bitmap must be writeable before calling. + */ +void pram_init_bitmap(struct super_block *sb) +{ + struct pram_super_block *ps = pram_get_super(sb); + u64 *bitmap = pram_get_bitmap(sb); + int blocks = be32_to_cpu(ps-s_bitmap_blocks); + + memset(bitmap, 0, blocks sb-s_blocksize_bits); + + while (blocks = 64) { + *bitmap++ = (u64)ULLONG_MAX; + blocks -= 64; + } + + if (blocks) + *bitmap = cpu_to_le64((1ULL blocks) - 1); +} + + +/* Free absolute blocknr */ +void pram_free_block(struct super_block *sb, unsigned long blocknr) +{ + struct pram_super_block *ps; + u64 bitmap_block; + unsigned long bitmap_bnr; + void *bitmap; + void *bp; + + lock_super(sb); + + bitmap = pram_get_bitmap(sb); + /* +* find the block within the bitmap that contains the inuse bit +* for the block we need to free. We need to unlock this bitmap +* block to clear the inuse bit. +*/ + bitmap_bnr = blocknr (3 + sb-s_blocksize_bits); + bitmap_block = pram_get_block_off(sb, bitmap_bnr); + bp = pram_get_block(sb, bitmap_block); + + pram_memunlock_block(sb, bp); + pram_clear_bit(blocknr, bitmap); /* mark the block free */ + pram_memlock_block(sb, bp); + + ps = pram_get_super(sb); + pram_memunlock_super(ps); + if (blocknr be32_to_cpu(ps-s_free_blocknr_hint)) + ps-s_free_blocknr_hint = cpu_to_be32(blocknr); + be32_add_cpu(ps-s_free_blocks_count, 1); + pram_memlock_super(ps); + + unlock_super(sb); +} + + +/* + * allocate a block and return it's absolute blocknr. Zeroes out the + * block if zero set. + */ +int pram_new_block(struct super_block *sb, unsigned long *blocknr, int zero) +{ + struct pram_super_block *ps; + off_t bitmap_block; + unsigned long bnr, bitmap_bnr; + int errval; + void *bitmap; + void *bp; + + lock_super(sb); + ps = pram_get_super(sb); + bitmap = pram_get_bitmap(sb); + + if (ps-s_free_blocks_count) { + /* find the oldest unused block */ + bnr = pram_find_next_zero_bit(bitmap, +be32_to_cpu(ps-s_blocks_count), +be32_to_cpu(ps-s_free_blocknr_hint)); + + if (bnr be32_to_cpu(ps-s_bitmap_blocks) || + bnr = be32_to_cpu(ps-s_blocks_count)) { + pram_err(no free blocks found!\n); + errval = -ENOSPC; + goto fail; + } + + pram_dbg(allocating blocknr %lu\n, bnr); + pram_memunlock_super(ps); + be32_add_cpu(ps-s_free_blocks_count, -1); + if (bnr (be32_to_cpu(ps-s_blocks_count)-1)) + ps-s_free_blocknr_hint = cpu_to_be32(bnr+1); + else + ps-s_free_blocknr_hint = 0; + pram_memlock_super(ps); + } else { + pram_err(all blocks allocated\n); + errval = -ENOSPC; + goto fail; + } + + /* +* find the block within the bitmap that contains the inuse bit +* for the unused block we just found. We need to unlock it to +* set the inuse bit. +*/ + bitmap_bnr = bnr (3 + sb-s_blocksize_bits); + bitmap_block = pram_get_block_off(sb, bitmap_bnr); + bp = pram_get_block(sb, bitmap_block); + + pram_memunlock_block(sb, bp); + pram_set_bit(bnr, bitmap); /* mark the new block in use */ + pram_memlock_block(sb, bp); + + if (zero) { + bp = pram_get_block(sb, pram_get_block_off(sb, bnr)); + pram_memunlock_block(sb, bp); + memset(bp, 0, sb-s_blocksize
[PATCH 07/16] pramfs: symbolic links
From: Marco Stornelli marco.storne...@gmail.com Symlink operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/symlink.c linux-2.6.36/fs/pramfs/symlink.c --- linux-2.6.36-orig/fs/pramfs/symlink.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/symlink.c2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,78 @@ +/* + * FILE NAME fs/pramfs/symlink.c + * + * BRIEF DESCRIPTION + * + * Symlink operations + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/fs.h +#include pram.h +#include xattr.h + +int pram_block_symlink(struct inode *inode, const char *symname, int len) +{ + struct super_block *sb = inode-i_sb; + u64 block; + char *blockp; + int err; + + err = pram_alloc_blocks(inode, 0, 1); + if (err) + return err; + + block = pram_find_data_block(inode, 0); + blockp = pram_get_block(sb, block); + + pram_memunlock_block(sb, blockp); + memcpy(blockp, symname, len); + blockp[len] = '\0'; + pram_memlock_block(sb, blockp); + return 0; +} + +static int pram_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + struct inode *inode = dentry-d_inode; + struct super_block *sb = inode-i_sb; + u64 block; + char *blockp; + + block = pram_find_data_block(inode, 0); + blockp = pram_get_block(sb, block); + return vfs_readlink(dentry, buffer, buflen, blockp); +} + +static void *pram_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct inode *inode = dentry-d_inode; + struct super_block *sb = inode-i_sb; + off_t block; + int status; + char *blockp; + + block = pram_find_data_block(inode, 0); + blockp = pram_get_block(sb, block); + status = vfs_follow_link(nd, blockp); + return ERR_PTR(status); +} + +struct inode_operations pram_symlink_inode_operations = { + .readlink = pram_readlink, + .follow_link= pram_follow_link, + .setattr= pram_notify_change, +#ifdef CONFIG_PRAMFS_XATTR + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = pram_listxattr, + .removexattr= generic_removexattr, +#endif +}; -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/16] pramfs: dir operations
From: Marco Stornelli marco.storne...@gmail.com File operations for directories. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/dir.c linux-2.6.36/fs/pramfs/dir.c --- linux-2.6.36-orig/fs/pramfs/dir.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/dir.c2010-09-17 19:08:54.0 +0200 @@ -0,0 +1,215 @@ +/* + * FILE NAME fs/pramfs/dir.c + * + * BRIEF DESCRIPTION + * + * File operations for directories. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/fs.h +#include linux/pagemap.h +#include pram.h + +/* + * Parent is locked. + */ +int pram_add_link(struct dentry *dentry, struct inode *inode) +{ + struct inode *dir = dentry-d_parent-d_inode; + struct pram_inode *pidir, *pi, *pitail = NULL; + u64 tail_ino, prev_ino; + + const char *name = dentry-d_name.name; + + int namelen = dentry-d_name.len PRAM_NAME_LEN ? + PRAM_NAME_LEN : dentry-d_name.len; + + pidir = pram_get_inode(dir-i_sb, dir-i_ino); + pi = pram_get_inode(dir-i_sb, inode-i_ino); + + dir-i_mtime = dir-i_ctime = CURRENT_TIME; + + tail_ino = be64_to_cpu(pidir-i_type.dir.tail); + if (tail_ino != 0) { + pitail = pram_get_inode(dir-i_sb, tail_ino); + pram_memunlock_inode(pitail); + pitail-i_d.d_next = cpu_to_be64(inode-i_ino); + pram_memlock_inode(pitail); + + prev_ino = tail_ino; + + pram_memunlock_inode(pidir); + pidir-i_type.dir.tail = cpu_to_be64(inode-i_ino); + pidir-i_mtime = cpu_to_be32(dir-i_mtime.tv_sec); + pidir-i_ctime = cpu_to_be32(dir-i_ctime.tv_sec); + pram_memlock_inode(pidir); + } else { + /* the directory is empty */ + prev_ino = 0; + + pram_memunlock_inode(pidir); + pidir-i_type.dir.tail = cpu_to_be64(inode-i_ino); + pidir-i_type.dir.head = cpu_to_be64(inode-i_ino); + pidir-i_mtime = cpu_to_be32(dir-i_mtime.tv_sec); + pidir-i_ctime = cpu_to_be32(dir-i_ctime.tv_sec); + pram_memlock_inode(pidir); + } + + + pram_memunlock_inode(pi); + pi-i_d.d_prev = cpu_to_be64(prev_ino); + pi-i_d.d_parent = cpu_to_be64(dir-i_ino); + memcpy(pi-i_d.d_name, name, namelen); + pi-i_d.d_name[namelen] = '\0'; + pram_memlock_inode(pi); + return 0; +} + +int pram_remove_link(struct inode *inode) +{ + struct super_block *sb = inode-i_sb; + struct pram_inode *prev = NULL; + struct pram_inode *next = NULL; + struct pram_inode *pidir, *pi; + + pi = pram_get_inode(sb, inode-i_ino); + pidir = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_parent)); + if (!pidir) + return -EACCES; + + if (inode-i_ino == be64_to_cpu(pidir-i_type.dir.head)) { + /* first inode in directory */ + next = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_next)); + + if (next) { + pram_memunlock_inode(next); + next-i_d.d_prev = 0; + pram_memlock_inode(next); + + pram_memunlock_inode(pidir); + pidir-i_type.dir.head = pi-i_d.d_next; + } else { + pram_memunlock_inode(pidir); + pidir-i_type.dir.head = 0; + pidir-i_type.dir.tail = 0; + } + pram_memlock_inode(pidir); + } else if (inode-i_ino == be64_to_cpu(pidir-i_type.dir.tail)) { + /* last inode in directory */ + prev = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_prev)); + + pram_memunlock_inode(prev); + prev-i_d.d_next = 0; + pram_memlock_inode(prev); + + pram_memunlock_inode(pidir); + pidir-i_type.dir.tail = pi-i_d.d_prev; + pram_memlock_inode(pidir); + } else { + /* somewhere in the middle */ + prev = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_prev)); + next = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_next)); + + if (prev next) { + pram_memunlock_inode(prev); + prev-i_d.d_next = pi-i_d.d_next; + pram_memlock_inode(prev); + + pram_memunlock_inode(next); + next-i_d.d_prev = pi-i_d.d_prev
[PATCH 12/16] pramfs: extended attributes
From: Marco Stornelli marco.storne...@gmail.com Extended attributes operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/xattr.c linux-2.6.36/fs/pramfs/xattr.c --- linux-2.6.36-orig/fs/pramfs/xattr.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/xattr.c 2010-09-14 19:45:40.0 +0200 @@ -0,0 +1,1108 @@ +/* + * FILE NAME fs/pramfs/xattr.c + * + * BRIEF DESCRIPTION + * + * Extended attributes operations. + * + * Copyright 2010 Marco Stornelli marco.storne...@gmail.com + * + * based on fs/ext2/xattr.c with the following copyright: + * + * Fix by Harrison Xing harri...@mountainviewdata.com. + * Extended attributes for symlinks and special files added per + * suggestion of Luka Renko luka.re...@hermes.si. + * xattr consolidation Copyright (c) 2004 James Morris jmor...@redhat.com, + * Red Hat Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +/* + * Extended attributes are stored in blocks allocated outside of + * any inode. The i_xattr field is then made to point to this allocated + * block. If all extended attributes of an inode are identical, these + * inodes may share the same extended attribute block. Such situations + * are automatically detected by keeping a cache of recent attribute block + * numbers and hashes over the block's contents in memory. + * + * + * Extended attribute block layout: + * + * +--+ + * | header | + * | entry 1 | | + * | entry 2 | | growing downwards + * | entry 3 | v + * | four null bytes | + * | . . .| + * | value 1 | ^ + * | value 3 | | growing upwards + * | value 2 | | + * +--+ + * + * The block header is followed by multiple entry descriptors. These entry + * descriptors are variable in size, and alligned to PRAM_XATTR_PAD + * byte boundaries. The entry descriptors are sorted by attribute name, + * so that two extended attribute blocks can be compared efficiently. + * + * Attribute values are aligned to the end of the block, stored in + * no specific order. They are also padded to PRAM_XATTR_PAD byte + * boundaries. No additional gaps are left between them. + * + * Locking strategy + * + * pi-i_xattr is protected by PRAM_I(inode)-xattr_sem. + * EA blocks are only changed if they are exclusive to an inode, so + * holding xattr_sem also means that nothing but the EA block's reference + * count will change. Multiple writers to an EA block are synchronized + * by the mutex in each block descriptor. Block descriptors are kept in a + * red black tree and the key is the absolute block number. + */ + +#include linux/module.h +#include linux/init.h +#include linux/mbcache.h +#include linux/rwsem.h +#include linux/security.h +#include pram.h +#include xattr.h +#include acl.h +#include desctree.h + +#define HDR(bp) ((struct pram_xattr_header *)(bp)) +#define ENTRY(ptr) ((struct pram_xattr_entry *)(ptr)) +#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) +#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) +#define GET_DESC(sbi, blocknr) lookup_xblock_desc(sbi, blocknr, pram_xblock_desc_cache, 1) +#define LOOKUP_DESC(sbi, blocknr) lookup_xblock_desc(sbi, blocknr, NULL, 0) + +#ifdef PRAM_XATTR_DEBUG +# define ea_idebug(inode, f...) do { \ + printk(KERN_DEBUG inode %ld: , inode-i_ino); \ + printk(f); \ + printk(\n); \ + } while (0) +# define ea_bdebug(blocknr, f...) do { \ + printk(KERN_DEBUG block %lu: , blocknr); \ + printk(f); \ + printk(\n); \ + } while (0) +#else +# define ea_idebug(f...) +# define ea_bdebug(f...) +#endif + +static int pram_xattr_set2(struct inode *, char *, struct pram_xblock_desc *, struct pram_xattr_header *); + +static int pram_xattr_cache_insert(struct super_block *sb, unsigned long blocknr, u32 xhash); +static struct pram_xblock_desc *pram_xattr_cache_find(struct inode *, +struct pram_xattr_header *); +static void pram_xattr_rehash(struct pram_xattr_header *, + struct pram_xattr_entry *); + +static struct mb_cache *pram_xattr_cache; +static struct kmem_cache *pram_xblock_desc_cache; + +static const struct xattr_handler *pram_xattr_handler_map[] = { + [PRAM_XATTR_INDEX_USER] = pram_xattr_user_handler, +#ifdef CONFIG_PRAMFS_POSIX_ACL + [PRAM_XATTR_INDEX_POSIX_ACL_ACCESS] = pram_xattr_acl_access_handler, + [PRAM_XATTR_INDEX_POSIX_ACL_DEFAULT] = pram_xattr_acl_default_handler, +#endif + [PRAM_XATTR_INDEX_TRUSTED] = pram_xattr_trusted_handler, +#ifdef CONFIG_PRAMFS_SECURITY + [PRAM_XATTR_INDEX_SECURITY] = pram_xattr_security_handler, +#endif +}; + +const
[PATCH 14(16] pramfs: memory protection
From: Marco Stornelli marco.storne...@gmail.com Memory write protection. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/wprotect.c linux-2.6.36/fs/pramfs/wprotect.c --- linux-2.6.36-orig/fs/pramfs/wprotect.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/wprotect.c 2010-09-26 18:04:07.0 +0200 @@ -0,0 +1,31 @@ +/* + * FILE NAME fs/pramfs/wprotect.c + * + * BRIEF DESCRIPTION + * + * Write protection for the filesystem pages. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/module.h +#include linux/fs.h +#include linux/mm.h +#include linux/io.h +#include pram.h + +void pram_writeable(void *vaddr, unsigned long size, int rw) +{ + int ret = 0; + + ret = rw ? write_on_kernel_pte_range((unsigned long)vaddr, size) : + write_off_kernel_pte_range((unsigned long)vaddr, size); + + BUG_ON(ret); +} diff -Nurp linux-2.6.36-orig/include/linux/mm.h linux-2.6.36/include/linux/mm.h --- linux-2.6.36-orig/include/linux/mm.h2010-09-13 01:07:37.0 +0200 +++ linux-2.6.36/include/linux/mm.h 2010-09-14 18:49:52.0 +0200 @@ -811,6 +811,11 @@ int follow_phys(struct vm_area_struct *v unsigned int flags, unsigned long *prot, resource_size_t *phys); int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, void *buf, int len, int write); +int writeable_kernel_pte_range(unsigned long address, unsigned long size, + unsigned int rw); + +#define write_on_kernel_pte_range(addr, size) writeable_kernel_pte_range(addr, size, 1) +#define write_off_kernel_pte_range(addr, size) writeable_kernel_pte_range(addr, size, 0) static inline void unmap_shared_mapping_range(struct address_space *mapping, loff_t const holebegin, loff_t const holelen) diff -Nurp linux-2.6.36-orig/mm/memory.c linux-2.6.36/mm/memory.c --- linux-2.6.36-orig/mm/memory.c 2010-09-13 01:07:37.0 +0200 +++ linux-2.6.36/mm/memory.c2010-09-14 18:49:52.0 +0200 @@ -3587,3 +3587,49 @@ void might_fault(void) } EXPORT_SYMBOL(might_fault); #endif + +int writeable_kernel_pte_range(unsigned long address, unsigned long size, + unsigned int rw) +{ + + unsigned long addr = address PAGE_MASK; + unsigned long end = address + size; + unsigned long start = addr; + int ret = -EINVAL; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *ptep, pte; + + spin_lock_irq(init_mm.page_table_lock); + + do { + pgd = pgd_offset(init_mm, address); + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) + goto out; + + pud = pud_offset(pgd, address); + if (pud_none(*pud) || unlikely(pud_bad(*pud))) + goto out; + + pmd = pmd_offset(pud, address); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + goto out; + + ptep = pte_offset_kernel(pmd, addr); + pte = *ptep; + if (pte_present(pte)) { + pte = rw ? pte_mkwrite(pte) : pte_wrprotect(pte); + *ptep = pte; + } + addr += PAGE_SIZE; + } while (addr (addr end)); + + ret = 0; + +out: + flush_tlb_kernel_range(start, end); + spin_unlock_irq(init_mm.page_table_lock); + return ret; +} +EXPORT_SYMBOL(writeable_kernel_pte_range); -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 16/16] pramfs Makefile and Kconfig
From: Marco Stornelli marco.storne...@gmail.com Makefile and Kconfig. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/Makefile linux-2.6.36/fs/Makefile --- linux-2.6.36-orig/fs/Makefile 2010-09-13 01:07:37.0 +0200 +++ linux-2.6.36/fs/Makefile2010-09-14 18:49:52.0 +0200 @@ -126,3 +126,4 @@ obj-$(CONFIG_BTRFS_FS) += btrfs/ obj-$(CONFIG_GFS2_FS) += gfs2/ obj-$(CONFIG_EXOFS_FS) += exofs/ obj-$(CONFIG_CEPH_FS) += ceph/ +obj-$(CONFIG_PRAMFS) += pramfs/ diff -Nurp linux-2.6.36-orig/fs/Kconfig linux-2.6.36/fs/Kconfig --- linux-2.6.36-orig/fs/Kconfig2010-09-13 01:07:37.0 +0200 +++ linux-2.6.36/fs/Kconfig 2010-09-14 18:49:52.0 +0200 @@ -13,7 +13,7 @@ source fs/ext4/Kconfig config FS_XIP # execute in place bool - depends on EXT2_FS_XIP + depends on EXT2_FS_XIP || PRAMFS_XIP default y source fs/jbd/Kconfig @@ -25,13 +25,14 @@ config FS_MBCACHE default y if EXT2_FS=y EXT2_FS_XATTR default y if EXT3_FS=y EXT3_FS_XATTR default y if EXT4_FS=y EXT4_FS_XATTR - default m if EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR + default y if PRAMFS=y PRAMFS_XATTR + default m if EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR || PRAMFS_XATTR source fs/reiserfs/Kconfig source fs/jfs/Kconfig config FS_POSIX_ACL -# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4) +# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4/pramfs) # # NOTE: you can implement Posix ACLs without these helpers (XFS does). # Never use this symbol for ifdefs. @@ -189,6 +190,7 @@ source fs/romfs/Kconfig source fs/sysv/Kconfig source fs/ufs/Kconfig source fs/exofs/Kconfig +source fs/pramfs/Kconfig endif # MISC_FILESYSTEMS diff -Nurp linux-2.6.36-orig/fs/pramfs/Kconfig linux-2.6.36/fs/pramfs/Kconfig --- linux-2.6.36-orig/fs/pramfs/Kconfig 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/Kconfig 2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,72 @@ +config PRAMFS + tristate Persistent and Protected RAM file system support + depends on HAS_IOMEM EXPERIMENTAL + select CRC16 + help + If your system has a block of fast (comparable in access speed to + system memory) and non-volatile RAM and you wish to mount a + light-weight, full-featured, and space-efficient filesystem over it, + say Y here, and read file:Documentation/filesystems/pramfs.txt. + + To compile this as a module, choose M here: the module will be + called pramfs.ko. + +config PRAMFS_XIP + bool Enable Execute-in-place in PRAMFS + depends on PRAMFS !PRAMFS_WRITE_PROTECT + help + Say Y here to enable xip feature of PRAMFS. + +config PRAMFS_WRITE_PROTECT + bool Enable PRAMFS write protection + depends on PRAMFS MMU + default y + help + Say Y here to enable the write protect feature of PRAMFS. + +config PRAMFS_XATTR + bool PRAMFS extended attributes + depends on PRAMFS + help + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + http://acl.bestbits.at/ for details). + + If unsure, say N. + +config PRAMFS_POSIX_ACL + bool PRAMFS POSIX Access Control Lists + depends on PRAMFS_XATTR + select FS_POSIX_ACL + help + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website http://acl.bestbits.at/. + + If you don't know what Access Control Lists are, say N + +config PRAMFS_SECURITY + bool PRAMFS Security Labels + depends on PRAMFS_XATTR + help + Security labels support alternative access control models + implemented by security modules like SELinux. This option + enables an extended attribute handler for file security + labels in the pram filesystem. + + If you are not using a security module that requires using + extended attributes for file security labels, say N. + +config PRAMFS_TEST + boolean + depends on PRAMFS + +config TEST_MODULE + tristate PRAMFS Test + depends on PRAMFS m + select PRAMFS_TEST + help + Say Y here to build a simple module to test the protection of + PRAMFS. The module will be called pramfs_test.ko. diff -Nurp linux-2.6.36-orig/fs/pramfs/Makefile linux-2.6.36/fs/pramfs/Makefile --- linux-2.6.36-orig/fs/pramfs/Makefile1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/Makefile 2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,14 @@ +# +# Makefile for the linux pram-filesystem
[PATCH 13/16] pramfs: xattr block descriptors tree
From: Marco Stornelli marco.storne...@gmail.com Extended attributes block descriptors tree. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/desctree.c linux-2.6.36/fs/pramfs/desctree.c --- linux-2.6.36-orig/fs/pramfs/desctree.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/desctree.c 2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,184 @@ +/* + * FILE NAME fs/pramfs/desctree.c + * + * BRIEF DESCRIPTION + * + * Extended attributes block descriptors tree. + * + * Copyright 2010 Marco Stornelli marco.storne...@gmail.com + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/spinlock.h +#include desctree.h +#include pram.h + +/* xblock_desc_init_always() + * + * These are initializations that need to be done on every + * descriptor allocation as the fields are not initialised + * by slab allocation. + */ +void xblock_desc_init_always(struct pram_xblock_desc *desc) +{ + atomic_set(desc-refcount, 0); + desc-blocknr = 0; + desc-flags = 0; +} + +/* xblock_desc_init_once() + * + * These are initializations that only need to be done + * once, because the fields are idempotent across use + * of the descriptor, so let the slab aware of that. + */ +void xblock_desc_init_once(struct pram_xblock_desc *desc) +{ + mutex_init(desc-lock); +} + +/* __insert_xblock_desc() + * + * Insert a new descriptor in the tree. + * + */ +static void __insert_xblock_desc(struct pram_sb_info *sbi, +unsigned long blocknr, struct rb_node *node) +{ + struct rb_node **p = (sbi-desc_tree.rb_node); + struct rb_node *parent = NULL; + struct pram_xblock_desc *desc; + + while (*p) { + parent = *p; + desc = rb_entry(parent, struct pram_xblock_desc, node); + + if (blocknr desc-blocknr) + p = (*p)-rb_left; + else if (blocknr desc-blocknr) + p = (*p)-rb_right; + else + /* Oops...an other descriptor for the same block ? */ + BUG(); + } + + rb_link_node(node, parent, p); + rb_insert_color(node, sbi-desc_tree); +} + +void insert_xblock_desc(struct pram_sb_info *sbi, struct pram_xblock_desc *desc) +{ + spin_lock(sbi-desc_tree_lock); + __insert_xblock_desc(sbi, desc-blocknr, desc-node); + spin_unlock(sbi-desc_tree_lock); +}; + +/* __lookup_xblock_desc() + * + * Search an extended attribute descriptor in the tree via the + * block number. It returns the descriptor if it's found or + * NULL. If not found it creates a new descriptor if create is not 0. + */ +static struct pram_xblock_desc *__lookup_xblock_desc(struct pram_sb_info *sbi, + unsigned long blocknr, + struct kmem_cache *cache, + int create) +{ + struct rb_node *n = sbi-desc_tree.rb_node; + struct pram_xblock_desc *desc = NULL; + + while (n) { + desc = rb_entry(n, struct pram_xblock_desc, node); + + if (blocknr desc-blocknr) + n = n-rb_left; + else if (blocknr desc-blocknr) + n = n-rb_right; + else { + atomic_inc(desc-refcount); + goto out; + } + } + + /* not found */ + if (create) { + desc = kmem_cache_alloc(cache, GFP_NOFS); + if (!desc) + return ERR_PTR(-ENOMEM); + xblock_desc_init_always(desc); + atomic_set(desc-refcount, 1); + desc-blocknr = blocknr; + __insert_xblock_desc(sbi, desc-blocknr, desc-node); + } +out: + return desc; +} + +struct pram_xblock_desc *lookup_xblock_desc(struct pram_sb_info *sbi, + unsigned long blocknr, + struct kmem_cache *cache, + int create) +{ + struct pram_xblock_desc *desc = NULL; + + spin_lock(sbi-desc_tree_lock); + desc = __lookup_xblock_desc(sbi, blocknr, cache, create); + spin_unlock(sbi-desc_tree_lock); + return desc; +} + +/* put_xblock_desc() + * + * Decrement the reference count and if it reaches zero and the + * desciptor has been marked to be free, then we free it. + * It returns 0 if the descriptor has been deleted and 1 otherwise. + */ +int put_xblock_desc(struct pram_sb_info *sbi, struct pram_xblock_desc *desc) +{ + int ret = 1; + if (!desc) + return ret; + + if (atomic_dec_and_lock(desc-refcount, sbi-desc_tree_lock
[PATCH 11/16] pramfs: ACL management
From: Marco Stornelli marco.storne...@gmail.com ACL operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/acl.c linux-2.6.36/fs/pramfs/acl.c --- linux-2.6.36-orig/fs/pramfs/acl.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/acl.c2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,418 @@ +/* + * FILE NAME fs/pramfs/acl.h + * + * BRIEF MODULE DESCRIPTION + * + * POSIX ACL operations + * + * Copyright 2010 Marco Stornelli marco.storne...@gmail.com + * + * based on fs/ext2/acl.c with the following copyright: + * + * Copyright (C) 2001-2003 Andreas Gruenbacher, agr...@suse.de + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/capability.h +#include linux/init.h +#include linux/sched.h +#include linux/slab.h +#include linux/fs.h +#include pram.h +#include xattr.h +#include acl.h + +/* + * Load ACL information from filesystem. + */ +static struct posix_acl *pram_acl_load(const void *value, size_t size) +{ + const char *end = (char *)value + size; + int n, count; + struct posix_acl *acl; + + if (!value) + return NULL; + if (size sizeof(struct pram_acl_header)) +return ERR_PTR(-EINVAL); + if (((struct pram_acl_header *)value)-a_version != + cpu_to_be32(PRAM_ACL_VERSION)) + return ERR_PTR(-EINVAL); + value = (char *)value + sizeof(struct pram_acl_header); + count = pram_acl_count(size); + if (count 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + acl = posix_acl_alloc(count, GFP_KERNEL); + if (!acl) + return ERR_PTR(-ENOMEM); + for (n = 0; n count; n++) { + struct pram_acl_entry *entry = (struct pram_acl_entry *)value; + if ((char *)value + sizeof(struct pram_acl_entry_short) end) + goto fail; + acl-a_entries[n].e_tag = be16_to_cpu(entry-e_tag); + acl-a_entries[n].e_perm = be16_to_cpu(entry-e_perm); + switch (acl-a_entries[n].e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + value = (char *)value + + sizeof(struct pram_acl_entry_short); + acl-a_entries[n].e_id = ACL_UNDEFINED_ID; + break; + case ACL_USER: + case ACL_GROUP: + value = (char *)value + sizeof(struct pram_acl_entry); + if ((char *)value end) + goto fail; + acl-a_entries[n].e_id = + be32_to_cpu(entry-e_id); + break; + default: + goto fail; + } + } + if (value != end) + goto fail; + return acl; + +fail: + posix_acl_release(acl); + return ERR_PTR(-EINVAL); +} + +/* + * Save ACL information into the filesystem. + */ +static void *pram_acl_save(const struct posix_acl *acl, size_t *size) +{ + struct pram_acl_header *ext_acl; + char *e; + size_t n; + + *size = pram_acl_size(acl-a_count); + ext_acl = kmalloc(sizeof(struct pram_acl_header) + acl-a_count * + sizeof(struct pram_acl_entry), GFP_KERNEL); + if (!ext_acl) + return ERR_PTR(-ENOMEM); + ext_acl-a_version = cpu_to_be32(PRAM_ACL_VERSION); + e = (char *)ext_acl + sizeof(struct pram_acl_header); + for (n = 0; n acl-a_count; n++) { + struct pram_acl_entry *entry = (struct pram_acl_entry *)e; + entry-e_tag = cpu_to_be16(acl-a_entries[n].e_tag); + entry-e_perm = cpu_to_be16(acl-a_entries[n].e_perm); + switch (acl-a_entries[n].e_tag) { + case ACL_USER: + case ACL_GROUP: + entry-e_id = + cpu_to_be32(acl-a_entries[n].e_id); + e += sizeof(struct pram_acl_entry); + break; + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + e += sizeof(struct pram_acl_entry_short); + break; + default: + goto fail; + } + } + return (char *)ext_acl; + +fail: + kfree(ext_acl); + return ERR_PTR(-EINVAL); +} + +/* + * inode-i_mutex: don't care + */ +static struct posix_acl *pram_get_acl(struct inode *inode, int type) +{ + int name_index; + char *value = NULL; + struct posix_acl
[PATCH 15/16] pramfs: test module
From: Marco Stornelli marco.storne...@gmail.com Test module. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/pramfs_test.c linux-2.6.36/fs/pramfs/pramfs_test.c --- linux-2.6.36-orig/fs/pramfs/pramfs_test.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/pramfs_test.c2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,49 @@ +/* + * FILE NAME fs/pramfs/namei.c + * + * BRIEF DESCRIPTION + * + * Pramfs test module. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ +#include linux/module.h +#include linux/version.h +#include linux/init.h +#include linux/fs.h +#include pram.h + +int __init test_pramfs_write(void) +{ + struct pram_super_block *psb; + + psb = get_pram_super(); + if (!psb) { + printk(KERN_ERR + %s: PRAMFS super block not found (not mounted?)\n, + __func__); + return 1; + } + + /* +* Attempt an unprotected clear of checksum information in the +* superblock, this should cause a kernel page protection fault. +*/ + printk(%s: writing to kernel VA %p\n, __func__, psb); + psb-s_sum = 0; + + return 0; +} + +void test_pramfs_write_cleanup(void) {} + +/* Module information */ +MODULE_LICENSE(GPL); +module_init(test_pramfs_write); +module_exit(test_pramfs_write_cleanup); -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 04/16] pramfs: file operations
From: Marco Stornelli marco.storne...@gmail.com File operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/file.c linux-2.6.36/fs/pramfs/file.c --- linux-2.6.36-orig/fs/pramfs/file.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/file.c 2010-09-24 18:34:03.0 +0200 @@ -0,0 +1,166 @@ +/* + * FILE NAME fs/pramfs/file.c + * + * BRIEF DESCRIPTION + * + * File operations for files. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ +#include linux/fs.h +#include linux/sched.h +#include linux/slab.h +#include linux/uio.h +#include linux/mm.h +#include linux/uaccess.h +#include pram.h +#include acl.h +#include xip.h +#include xattr.h + +static int pram_open_file(struct inode *inode, struct file *filp) +{ +#ifndef CONFIG_PRAMFS_XIP + /* Without XIP we force to use Direct IO */ + filp-f_flags |= O_DIRECT; +#endif + return generic_file_open(inode, filp); +} + +ssize_t __pram_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +{ + struct file *file = iocb-ki_filp; + struct inode *inode = file-f_mapping-host; + struct super_block *sb = inode-i_sb; + int progress = 0, hole = 0; + ssize_t retval = 0; + void *tmp = NULL; + unsigned long blocknr, blockoff; + int num_blocks, blocksize_mask, blocksize, blocksize_bits; + char __user *buf = iov-iov_base; + size_t length = iov_length(iov, nr_segs); + + if (length 0) + return -EINVAL; + if ((rw == READ) (offset + length inode-i_size)) + length = inode-i_size - offset; + if (!length) + goto out; + + blocksize_bits = inode-i_sb-s_blocksize_bits; + blocksize = 1 blocksize_bits; + blocksize_mask = blocksize - 1; + + /* find starting block number to access */ + blocknr = offset blocksize_bits; + /* find starting offset within starting block */ + blockoff = offset blocksize_mask; + /* find number of blocks to access */ + num_blocks = (blockoff + length + blocksize_mask) blocksize_bits; + + if (rw == WRITE) { + /* prepare a temporary buffer to hold a user data block + for writing. */ + tmp = kmalloc(blocksize, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + /* now allocate the data blocks we'll need */ + retval = pram_alloc_blocks(inode, blocknr, num_blocks); + if (retval) + goto fail1; + } + + while (length) { + int count; + u8 *bp = NULL; + u64 block = pram_find_data_block(inode, blocknr++); + if (unlikely(!block rw == READ)) { + /* We are falling in a hole */ + hole = 1; + } else { + bp = (u8 *)pram_get_block(sb, block); + if (!bp) + goto fail2; + } + + count = blockoff + length blocksize ? + blocksize - blockoff : length; + + if (rw == READ) { + if (unlikely(hole)) { + retval = clear_user(buf, count); + if (retval) { + retval = -EFAULT; + goto fail1; + } + } else { + retval = copy_to_user(buf, bp[blockoff], count); + if (retval) { + retval = -EFAULT; + goto fail1; + } + } + } else { + retval = copy_from_user(tmp, buf, count); + if (retval) { + retval = -EFAULT; + goto fail1; + } + + pram_memunlock_block(inode-i_sb, bp); + memcpy(bp[blockoff], tmp, count); + pram_memlock_block(inode-i_sb, bp); + } + + progress += count; + buf += count; + length -= count; + blockoff = 0; + hole = 0; + } + +fail2: + retval = progress; +fail1: + kfree(tmp); +out
[PATCH 10/16] pramfs: xip operations
From: Marco Stornelli marco.storne...@gmail.com XIP operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/xip.c linux-2.6.36/fs/pramfs/xip.c --- linux-2.6.36-orig/fs/pramfs/xip.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/xip.c2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,90 @@ +/* + * FILE NAME fs/pramfs/xip.c + * + * BRIEF DESCRIPTION + * + * XIP operations. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/mm.h +#include linux/fs.h +#include linux/genhd.h +#include linux/buffer_head.h +#include pram.h +#include xip.h + +static int pram_find_and_alloc_blocks(struct inode *inode, sector_t iblock, +sector_t *data_block, int create) +{ + int err = -EIO; + u64 block; + + mutex_lock(PRAM_I(inode)-truncate_lock); + + block = pram_find_data_block(inode, iblock); + + if (!block) { + if (!create) { + err = -ENODATA; + goto err; + } + + err = pram_alloc_blocks(inode, iblock, 1); + if (err) + goto err; + + block = pram_find_data_block(inode, iblock); + if (!block) { + err = -ENODATA; + goto err; + } + } + + *data_block = block; + err = 0; + + err: + mutex_unlock(PRAM_I(inode)-truncate_lock); + return err; +} + + +static int __pram_get_block(struct inode *inode, pgoff_t pgoff, int create, + sector_t *result) +{ + int rc = 0; + sector_t iblock; + + /* find starting block number to access */ + iblock = (sector_t)pgoff (PAGE_CACHE_SHIFT - inode-i_blkbits); + + rc = pram_find_and_alloc_blocks(inode, iblock, result, create); + + if (rc == -ENODATA) + BUG_ON(create); + + return rc; +} + +int pram_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, int create, + void **kmem, unsigned long *pfn) +{ + int rc; + sector_t block; + + /* first, retrieve the block */ + rc = __pram_get_block(mapping-host, pgoff, create, block); + if (rc) + goto exit; + + *kmem = pram_get_block(mapping-host-i_sb, block); + *pfn = page_to_pfn(virt_to_page((unsigned long)*kmem)); + +exit: + return rc; +} diff -Nurp linux-2.6.36-orig/fs/pramfs/xip.h linux-2.6.36/fs/pramfs/xip.h --- linux-2.6.36-orig/fs/pramfs/xip.h 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/xip.h2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,24 @@ +/* + * FILE NAME fs/pramfs/xip.h + * + * BRIEF DESCRIPTION + * + * XIP operations. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#ifdef CONFIG_PRAMFS_XIP + +int pram_get_xip_mem(struct address_space *, pgoff_t, int, void **, + unsigned long *); + +#else + +#define pram_get_xip_mem NULL + +#endif + -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 14(16] pramfs: memory protection
2010/10/10 Andi Kleen a...@firstfloor.org: Marco Stornelli marco.storne...@gmail.com writes: + + do { + pgd = pgd_offset(init_mm, address); + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) + goto out; + + pud = pud_offset(pgd, address); + if (pud_none(*pud) || unlikely(pud_bad(*pud))) + goto out; + + pmd = pmd_offset(pud, address); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + goto out; + + ptep = pte_offset_kernel(pmd, addr); + pte = *ptep; + if (pte_present(pte)) { This won't work at all on x86 because you don't handle large pages. On x86 works because I tested. Maybe there's a particular configuration with large pages. Sincerly I'm only an user, so if you/Linus or others want to change it or rewrite it, for me it's ok. The pte manipulation are a bit out of scope for a fs, so I let the things to the mm experts. -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 15/16] pramfs: test module
2010/10/10 Randy Dunlap rdun...@xenotime.net: On Sun, 10 Oct 2010 18:37:49 +0200 Marco Stornelli wrote: Above 2 lines need to indented more. Ack. + return 1; + } + + /* + * Attempt an unprotected clear of checksum information in the + * superblock, this should cause a kernel page protection fault. + */ + printk(%s: writing to kernel VA %p\n, __func__, psb); + psb-s_sum = 0; + + return 0; +} + +void test_pramfs_write_cleanup(void) {} + +/* Module information */ +MODULE_LICENSE(GPL); +module_init(test_pramfs_write); +module_exit(test_pramfs_write_cleanup); -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 16/16] pramfs Makefile and Kconfig
2010/10/10 Randy Dunlap rdun...@xenotime.net: On Sun, 10 Oct 2010 18:39:11 +0200 Marco Stornelli wrote: From: Marco Stornelli marco.storne...@gmail.com Makefile and Kconfig. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/Kconfig linux-2.6.36/fs/pramfs/Kconfig --- linux-2.6.36-orig/fs/pramfs/Kconfig 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/Kconfig 2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,72 @@ +config PRAMFS + tristate Persistent and Protected RAM file system support + depends on HAS_IOMEM EXPERIMENTAL + select CRC16 + help + If your system has a block of fast (comparable in access speed to + system memory) and non-volatile RAM and you wish to mount a + light-weight, full-featured, and space-efficient filesystem over it, + say Y here, and read file:Documentation/filesystems/pramfs.txt. + + To compile this as a module, choose M here: the module will be + called pramfs.ko. called pramfs. (we don't add the .ko suffix; well, we try not to do that) Ok. + +config PRAMFS_XIP + bool Enable Execute-in-place in PRAMFS + depends on PRAMFS !PRAMFS_WRITE_PROTECT + help + Say Y here to enable xip feature of PRAMFS. XIP Ok. + +config PRAMFS_WRITE_PROTECT + bool Enable PRAMFS write protection + depends on PRAMFS MMU + default y + help + Say Y here to enable the write protect feature of PRAMFS. + +config PRAMFS_XATTR + bool PRAMFS extended attributes + depends on PRAMFS + help + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + http://acl.bestbits.at/ for details). + + If unsure, say N. + +config PRAMFS_POSIX_ACL + bool PRAMFS POSIX Access Control Lists + depends on PRAMFS_XATTR + select FS_POSIX_ACL + help + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website http://acl.bestbits.at/. + + If you don't know what Access Control Lists are, say N end sentence with period ('.'). Ok. -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 11/16] pramfs: ACL management
Il 11/10/2010 14:26, Kieran Bingham ha scritto: On 10/10/2010 17:33, Marco Stornelli wrote: From: Marco Stornellimarco.storne...@gmail.com ACL operations. Signed-off-by: Marco Stornellimarco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/acl.c linux-2.6.36/fs/pramfs/acl.c --- linux-2.6.36-orig/fs/pramfs/acl.c1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/acl.c2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,418 @@ +/* + * FILE NAME fs/pramfs/acl.h Found another one :) FILE NAME != acl.h ... -- KB Oops, damn copypaste ;) I'll fix it asap. Thanks. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 14(16] pramfs: memory protection
Il 10/10/2010 18:46, Andi Kleen ha scritto: This won't work at all on x86 because you don't handle large pages. And it doesn't work on x86-64 because the first 2GB are double mapped (direct and kernel text mapping) Thirdly I expect it won't either on architectures that map the direct mapping with special registers (like IA64 or MIPS) Andi, what do you think to use the already implemented follow_pte instead? int writeable_kernel_pte_range(unsigned long address, unsigned long size, unsigned int rw) { unsigned long addr = address PAGE_MASK; unsigned long end = address + size; unsigned long start = addr; int ret = -EINVAL; pte_t *ptep, pte; spinlock_t *lock = init_mm.page_table_lock; do { ret = follow_pte(init_mm, addr, ptep, lock); if (ret) goto out; pte = *ptep; if (pte_present(pte)) { pte = rw ? pte_mkwrite(pte) : pte_wrprotect(pte); *ptep = pte; } pte_unmap_unlock(ptep, lock); addr += PAGE_SIZE; } while (addr (addr end)); ret = 0; out: flush_tlb_kernel_range(start, end); return ret; } I'm not sure this is very useful anyways. It doesn't protect against stray DMA and it doesn't protect against writes through broken user PTEs. -Andi It's a way to have more protection against kernel bug, for a in-memory fs can be important. However this option can be enabled/disabled at fs level. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 14(16] pramfs: memory protection
2010/10/12 Andi Kleen a...@firstfloor.org: On Mon, Oct 11, 2010 at 07:32:10PM +0200, Marco Stornelli wrote: Il 10/10/2010 18:46, Andi Kleen ha scritto: This won't work at all on x86 because you don't handle large pages. And it doesn't work on x86-64 because the first 2GB are double mapped (direct and kernel text mapping) Thirdly I expect it won't either on architectures that map the direct mapping with special registers (like IA64 or MIPS) Andi, what do you think to use the already implemented follow_pte instead? Has all the same problems. Really you need an per architecture function. Perhaps some architectures could use a common helper, but certainly not all. per-arch?! Wow. Mmm...maybe I have to change something at fs level to avoid that. An alternative could be to use the follow_pte solution but avoid the protection via Kconfig if the fs is used on some archs (ia64 or MIPS), with large pages and so on. An help of the kernel community to know all these particular cases is welcome. Regards, Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 00/16 v2] pramfs: persistent and protected RAM Filesystem
Hi all, I send the patch series again. I fix documentation problems reported by Randy Dunlap and Kieran Bingham. I reworked the memory protection functions according to the suggestions of Andi Kleen. I ask to Andrew to evaluate to insert this fs in mainline. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 01/16 v2] pramfs: documentation
From: Marco Stornelli marco.storne...@gmail.com Documentation for PRAMFS. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/Documentation/filesystems/pramfs.txt linux-2.6.36/Documentation/filesystems/pramfs.txt --- linux-2.6.36-orig/Documentation/filesystems/pramfs.txt 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/Documentation/filesystems/pramfs.txt 2010-10-23 09:04:32.0 +0200 @@ -0,0 +1,296 @@ + +PRAMFS Overview +=== + +Many embedded systems have a block of non-volatile RAM separate from +normal system memory, i.e. of which the kernel maintains no memory page +descriptors. For such systems it would be beneficial to mount a +fast read/write filesystem over this I/O memory, for storing frequently +accessed data that must survive system reboots and power cycles. An +example usage might be system logs under /var/log, or a user address +book in a cell phone or PDA. + +Linux traditionally had no support for a persistent, non-volatile RAM-based +filesystem, persistent meaning the filesystem survives a system reboot +or power cycle intact. The RAM-based filesystems such as tmpfs and ramfs +have no actual backing store but exist entirely in the page and buffer +caches, hence the filesystem disappears after a system reboot or +power cycle. + +A relatively straightforward solution is to write a simple block driver +for the non-volatile RAM, and mount over it any disk-based filesystem such +as ext2, ext3, ext4, etc. + +But the disk-based fs over non-volatile RAM block driver approach has +some drawbacks: + +1. Complexity of disk-based fs: disk-based filesystems such as ext2/ext3/ext4 + were designed for optimum performance on spinning disk media, so they + implement features such as block groups, which attempts to group inode data + into a contiguous set of data blocks to minimize disk seeking when accessing + files. For RAM there is no such concern; a file's data blocks can be + scattered throughout the media with no access speed penalty at all. So block + groups in a filesystem mounted over RAM just adds unnecessary + complexity. A better approach is to use a filesystem specifically + tailored to RAM media which does away with these disk-based features. + This increases the efficient use of space on the media, i.e. more + space is dedicated to actual file data storage and less to meta-data + needed to maintain that file data. + +2. Different problems between disks and RAM: Because PRAMFS attempts to avoid + filesystem corruption caused by kernel bugs, dirty pages in the page cache + are not allowed to be written back to the backing-store RAM. This way, an + errant write into the page cache will not get written back to the filesystem. + However, if the backing-store RAM is comparable in access speed to system + memory, the penalty of not using caching is minimal. With this consideration + it's better to move file data directly between the user buffers and the backing + store RAM, i.e. use direct I/O. This prevents the unnecessary populating of + the page cache with dirty pages. However direct I/O has to be enabled at + every file open. To enable direct I/O at all times for all regular files + requires either that applications be modified to include the O_DIRECT flag on + all file opens, or that the filesystem used performs direct I/O by default. + +The Persistent/Protected RAM Special Filesystem (PRAMFS) is a read/write +filesystem that has been designed to address these issues. PRAMFS is targeted +to fast I/O memory, and if the memory is non-volatile, the filesystem will be +persistent. + +In PRAMFS, direct I/O is enabled across all files in the filesystem, in other +words the O_DIRECT flag is forced on every open of a PRAMFS file. Also, file +I/O in the PRAMFS is always synchronous. There is no need to block the current +process while the transfer to/from the PRAMFS is in progress, since one of +the requirements of the PRAMFS is that the filesystem exists in fast RAM. So +file I/O in PRAMFS is always direct, synchronous, and never blocks. + +The data organization in PRAMFS can be thought of as an extremely simplified +version of ext2, such that the ratio of data to meta-data is very high. + +PRAMFS supports the execute-in-place. With XIP, instead of keeping data in the +page cache, the need to have a page cache copy is eliminated completely. +Readwrite type operations are performed directly from/to the memory. For file +mappings, the RAM itself is mapped directly into userspace. XIP, in addition, +speed up the applications start-up time because it removes the needs of any +copies. + +PRAMFS is write protected. The page table entries that map the backing-store +RAM are normally marked read-only. Write operations into the filesystem +temporarily mark the affected pages as writeable, the write operation is +carried out with locks held, and then the page table entries is +marked read-only
[PATCH 02/16 v2] pramfs: super block operations
From: Marco Stornelli marco.storne...@gmail.com Super block operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/super.c linux-2.6.36/fs/pramfs/super.c --- linux-2.6.36-orig/fs/pramfs/super.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/super.c 2010-09-25 14:09:47.0 +0200 @@ -0,0 +1,740 @@ +/* + * FILE NAME fs/pramfs/super.c + * + * BRIEF DESCRIPTION + * + * Super block operations. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/module.h +#include linux/string.h +#include linux/slab.h +#include linux/init.h +#include linux/blkdev.h +#include linux/parser.h +#include linux/vfs.h +#include linux/uaccess.h +#include linux/io.h +#include linux/seq_file.h +#include linux/mount.h +#include linux/mm.h +#include linux/ctype.h +#include linux/bitops.h +#include linux/magic.h +#include linux/exportfs.h +#include linux/random.h +#include xattr.h +#include pram.h + +static struct super_operations pram_sops; +static const struct export_operations pram_export_ops; +static struct kmem_cache *pram_inode_cachep; + +#ifdef CONFIG_PRAMFS_TEST +static void *first_pram_super; + +struct pram_super_block *get_pram_super(void) +{ + return (struct pram_super_block *)first_pram_super; +} +EXPORT_SYMBOL(get_pram_super); +#endif + +static void pram_set_blocksize(struct super_block *sb, unsigned long size) +{ + int bits; + + /* + * We've already validated the user input and the value here must be + * between PRAM_MAX_BLOCK_SIZE and PRAM_MIN_BLOCK_SIZE + * and it must be a power of 2. + */ + bits = fls(size) - 1; + sb-s_blocksize_bits = bits; + sb-s_blocksize = (1bits); +} + +static inline void *pram_ioremap(phys_addr_t phys_addr, ssize_t size) +{ + void *retval; + + /* +* NOTE: Userland may not map this resource, we will mark the region so +* /dev/mem and the sysfs MMIO access will not be allowed. This +* restriction depends on STRICT_DEVMEM option. If this option is +* disabled or not available we mark the region only as busy. +*/ + retval = request_mem_region_exclusive(phys_addr, size, pramfs); + if (!retval) + goto fail; + + retval = ioremap_nocache(phys_addr, size); + + if (retval) + wrprotect(retval, size); +fail: + return retval; +} + +static loff_t pram_max_size(int bits) +{ + loff_t res; + res = (1ULL (3*bits - 6)) - 1; + + if (res MAX_LFS_FILESIZE) + res = MAX_LFS_FILESIZE; + + pram_info(Max file size %llu bytes, res); + return res; +} + +enum { + Opt_addr, Opt_bpi, Opt_size, + Opt_num_inodes, Opt_mode, Opt_uid, + Opt_gid, Opt_blocksize, Opt_err +}; + +static const match_table_t tokens = { + {Opt_bpi, physaddr=%x}, + {Opt_bpi, bpi=%u}, + {Opt_size, init=%s}, + {Opt_num_inodes, N=%u}, + {Opt_mode, mode=%o}, + {Opt_uid, uid=%u}, + {Opt_gid, gid=%u}, + {Opt_blocksize, bs=%s}, + {Opt_err, NULL}, +}; + +static phys_addr_t get_phys_addr(void **data) +{ + phys_addr_t phys_addr; + char *options = (char *) *data; + + if (!options || strncmp(options, physaddr=, 9) != 0) + return (phys_addr_t)ULLONG_MAX; + options += 9; + phys_addr = (phys_addr_t)simple_strtoull(options, options, 0); + if (*options *options != ',') { + pram_err(Invalid phys addr specification: %s\n, + (char *) *data); + return (phys_addr_t)ULLONG_MAX; + } + if (phys_addr (PAGE_SIZE - 1)) { + pram_err(physical address 0x%16llx for pramfs isn't + aligned to a page boundary\n, + (u64)phys_addr); + return (phys_addr_t)ULLONG_MAX; + } + if (*options == ',') + options++; + *data = (void *) options; + return phys_addr; +} + +static int pram_parse_options(char *options, struct pram_sb_info *sbi) +{ + char *p, *rest; + substring_t args[MAX_OPT_ARGS]; + int option; + + if (!options) + return 0; + + while ((p = strsep(options, ,)) != NULL) { + int token; + if (!*p) + continue; + + token = match_token(p, tokens, args); + switch (token) { + case Opt_addr: { + /* physaddr managed
[PATCH 03/16 v2] pramfs: inode operations
From: Marco Stornelli marco.storne...@gmail.com Inode methods (allocate/free/read/write). Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/inode.c linux-2.6.36/fs/pramfs/inode.c --- linux-2.6.36-orig/fs/pramfs/inode.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/inode.c 2010-09-26 18:04:38.0 +0200 @@ -0,0 +1,710 @@ +/* + * FILE NAME fs/pramfs/inode.c + * + * BRIEF DESCRIPTION + * + * Inode methods (allocate/free/read/write). + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/fs.h +#include linux/smp_lock.h +#include linux/sched.h +#include linux/highuid.h +#include linux/quotaops.h +#include linux/module.h +#include linux/mpage.h +#include linux/backing-dev.h +#include pram.h +#include xattr.h +#include xip.h +#include acl.h + +struct backing_dev_info pram_backing_dev_info __read_mostly = { + .ra_pages = 0,/* No readahead */ + .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, +}; + +/* + * allocate a data block for inode and return it's absolute blocknr. + * Zeroes out the block if zero set. Increments inode-i_blocks. + */ +static int pram_new_data_block(struct inode *inode, unsigned long *blocknr, int zero) +{ + int errval = pram_new_block(inode-i_sb, blocknr, zero); + + if (!errval) { + struct pram_inode *pi = pram_get_inode(inode-i_sb, + inode-i_ino); + inode-i_blocks++; + pram_memunlock_inode(pi); + pi-i_blocks = cpu_to_be32(inode-i_blocks); + pram_memlock_inode(pi); + } + + return errval; +} + +/* + * find the offset to the block represented by the given inode's file + * relative block number. + */ +u64 pram_find_data_block(struct inode *inode, int file_blocknr) +{ + struct super_block *sb = inode-i_sb; + struct pram_inode *pi; + u64 *row; /* ptr to row block */ + u64 *col; /* ptr to column blocks */ + u64 bp = 0; + int i_row, i_col; + int N = sb-s_blocksize 3; /* num block ptrs per block */ + int Nbits = sb-s_blocksize_bits - 3; + + pi = pram_get_inode(sb, inode-i_ino); + + i_row = file_blocknr Nbits; + i_col = file_blocknr (N-1); + + row = pram_get_block(sb, be64_to_cpu(pi-i_type.reg.row_block)); + if (row) { + col = pram_get_block(sb, be64_to_cpu(row[i_row])); + if (col) + bp = be64_to_cpu(col[i_col]); + } + + return bp; +} + +/* + * Free data blocks from inode in the range start = end + */ +static void __pram_truncate_blocks(struct inode *inode, loff_t start, loff_t end) +{ + struct super_block *sb = inode-i_sb; + struct pram_inode *pi = pram_get_inode(sb, inode-i_ino); + int N = sb-s_blocksize 3; /* num block ptrs per block */ + int Nbits = sb-s_blocksize_bits - 3; + int first_row_index, last_row_index, i, j; + unsigned long blocknr, first_blocknr, last_blocknr; + unsigned int freed = 0; + u64 *row; /* ptr to row block */ + u64 *col; /* ptr to column blocks */ + + if (start end || !inode-i_blocks || !pi-i_type.reg.row_block) + return; + + mutex_lock(PRAM_I(inode)-truncate_mutex); + + first_blocknr = (start + sb-s_blocksize - 1) sb-s_blocksize_bits; + last_blocknr = (end + sb-s_blocksize - 1) sb-s_blocksize_bits; + first_row_index = first_blocknr Nbits; + last_row_index = last_blocknr Nbits; + + row = pram_get_block(sb, be64_to_cpu(pi-i_type.reg.row_block)); + + for (i = first_row_index; i = last_row_index; i++) { + int first_col_index = (i == first_row_index) ? + first_blocknr (N-1) : 0; + int last_col_index = (i == last_row_index) ? + last_blocknr (N-1) : N-1; + + if (unlikely(!row[i])) + continue; + + col = pram_get_block(sb, be64_to_cpu(row[i])); + + for (j = first_col_index; j = last_col_index; j++) { + + if (unlikely(!col[j])) + continue; + + blocknr = pram_get_blocknr(sb, be64_to_cpu(col[j])); + pram_free_block(sb, blocknr); + freed++; + pram_memunlock_block(sb, col); + col[j] = 0; + pram_memlock_block(sb, col); + } + + if (first_col_index == 0
[PATCH 04/16 v2] pramfs: file operations
From: Marco Stornelli marco.storne...@gmail.com File operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/file.c linux-2.6.36/fs/pramfs/file.c --- linux-2.6.36-orig/fs/pramfs/file.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/file.c 2010-09-24 18:34:03.0 +0200 @@ -0,0 +1,166 @@ +/* + * FILE NAME fs/pramfs/file.c + * + * BRIEF DESCRIPTION + * + * File operations for files. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ +#include linux/fs.h +#include linux/sched.h +#include linux/slab.h +#include linux/uio.h +#include linux/mm.h +#include linux/uaccess.h +#include pram.h +#include acl.h +#include xip.h +#include xattr.h + +static int pram_open_file(struct inode *inode, struct file *filp) +{ +#ifndef CONFIG_PRAMFS_XIP + /* Without XIP we force to use Direct IO */ + filp-f_flags |= O_DIRECT; +#endif + return generic_file_open(inode, filp); +} + +ssize_t __pram_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +{ + struct file *file = iocb-ki_filp; + struct inode *inode = file-f_mapping-host; + struct super_block *sb = inode-i_sb; + int progress = 0, hole = 0; + ssize_t retval = 0; + void *tmp = NULL; + unsigned long blocknr, blockoff; + int num_blocks, blocksize_mask, blocksize, blocksize_bits; + char __user *buf = iov-iov_base; + size_t length = iov_length(iov, nr_segs); + + if (length 0) + return -EINVAL; + if ((rw == READ) (offset + length inode-i_size)) + length = inode-i_size - offset; + if (!length) + goto out; + + blocksize_bits = inode-i_sb-s_blocksize_bits; + blocksize = 1 blocksize_bits; + blocksize_mask = blocksize - 1; + + /* find starting block number to access */ + blocknr = offset blocksize_bits; + /* find starting offset within starting block */ + blockoff = offset blocksize_mask; + /* find number of blocks to access */ + num_blocks = (blockoff + length + blocksize_mask) blocksize_bits; + + if (rw == WRITE) { + /* prepare a temporary buffer to hold a user data block + for writing. */ + tmp = kmalloc(blocksize, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + /* now allocate the data blocks we'll need */ + retval = pram_alloc_blocks(inode, blocknr, num_blocks); + if (retval) + goto fail1; + } + + while (length) { + int count; + u8 *bp = NULL; + u64 block = pram_find_data_block(inode, blocknr++); + if (unlikely(!block rw == READ)) { + /* We are falling in a hole */ + hole = 1; + } else { + bp = (u8 *)pram_get_block(sb, block); + if (!bp) + goto fail2; + } + + count = blockoff + length blocksize ? + blocksize - blockoff : length; + + if (rw == READ) { + if (unlikely(hole)) { + retval = clear_user(buf, count); + if (retval) { + retval = -EFAULT; + goto fail1; + } + } else { + retval = copy_to_user(buf, bp[blockoff], count); + if (retval) { + retval = -EFAULT; + goto fail1; + } + } + } else { + retval = copy_from_user(tmp, buf, count); + if (retval) { + retval = -EFAULT; + goto fail1; + } + + pram_memunlock_block(inode-i_sb, bp); + memcpy(bp[blockoff], tmp, count); + pram_memlock_block(inode-i_sb, bp); + } + + progress += count; + buf += count; + length -= count; + blockoff = 0; + hole = 0; + } + +fail2: + retval = progress; +fail1: + kfree(tmp); +out
[PATCH 05/16 v2] pramfs: block allocation
From: Marco Stornelli marco.storne...@gmail.com Block allocation operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/balloc.c linux-2.6.36/fs/pramfs/balloc.c --- linux-2.6.36-orig/fs/pramfs/balloc.c1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/balloc.c 2010-09-26 18:05:06.0 +0200 @@ -0,0 +1,155 @@ +/* + * FILE NAME fs/pramfs/balloc.c + * + * BRIEF MODULE DESCRIPTION + * + * The blocks allocation and deallocation routines. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/fs.h +#include linux/bitops.h +#include pram.h + +/* + * This just marks in-use the blocks that make up the bitmap. + * The bitmap must be writeable before calling. + */ +void pram_init_bitmap(struct super_block *sb) +{ + struct pram_super_block *ps = pram_get_super(sb); + u64 *bitmap = pram_get_bitmap(sb); + int blocks = be32_to_cpu(ps-s_bitmap_blocks); + + memset(bitmap, 0, blocks sb-s_blocksize_bits); + + while (blocks = 64) { + *bitmap++ = (u64)ULLONG_MAX; + blocks -= 64; + } + + if (blocks) + *bitmap = cpu_to_le64((1ULL blocks) - 1); +} + + +/* Free absolute blocknr */ +void pram_free_block(struct super_block *sb, unsigned long blocknr) +{ + struct pram_super_block *ps; + u64 bitmap_block; + unsigned long bitmap_bnr; + void *bitmap; + void *bp; + + lock_super(sb); + + bitmap = pram_get_bitmap(sb); + /* +* find the block within the bitmap that contains the inuse bit +* for the block we need to free. We need to unlock this bitmap +* block to clear the inuse bit. +*/ + bitmap_bnr = blocknr (3 + sb-s_blocksize_bits); + bitmap_block = pram_get_block_off(sb, bitmap_bnr); + bp = pram_get_block(sb, bitmap_block); + + pram_memunlock_block(sb, bp); + pram_clear_bit(blocknr, bitmap); /* mark the block free */ + pram_memlock_block(sb, bp); + + ps = pram_get_super(sb); + pram_memunlock_super(ps); + if (blocknr be32_to_cpu(ps-s_free_blocknr_hint)) + ps-s_free_blocknr_hint = cpu_to_be32(blocknr); + be32_add_cpu(ps-s_free_blocks_count, 1); + pram_memlock_super(ps); + + unlock_super(sb); +} + + +/* + * allocate a block and return it's absolute blocknr. Zeroes out the + * block if zero set. + */ +int pram_new_block(struct super_block *sb, unsigned long *blocknr, int zero) +{ + struct pram_super_block *ps; + off_t bitmap_block; + unsigned long bnr, bitmap_bnr; + int errval; + void *bitmap; + void *bp; + + lock_super(sb); + ps = pram_get_super(sb); + bitmap = pram_get_bitmap(sb); + + if (ps-s_free_blocks_count) { + /* find the oldest unused block */ + bnr = pram_find_next_zero_bit(bitmap, +be32_to_cpu(ps-s_blocks_count), +be32_to_cpu(ps-s_free_blocknr_hint)); + + if (bnr be32_to_cpu(ps-s_bitmap_blocks) || + bnr = be32_to_cpu(ps-s_blocks_count)) { + pram_err(no free blocks found!\n); + errval = -ENOSPC; + goto fail; + } + + pram_dbg(allocating blocknr %lu\n, bnr); + pram_memunlock_super(ps); + be32_add_cpu(ps-s_free_blocks_count, -1); + if (bnr (be32_to_cpu(ps-s_blocks_count)-1)) + ps-s_free_blocknr_hint = cpu_to_be32(bnr+1); + else + ps-s_free_blocknr_hint = 0; + pram_memlock_super(ps); + } else { + pram_err(all blocks allocated\n); + errval = -ENOSPC; + goto fail; + } + + /* +* find the block within the bitmap that contains the inuse bit +* for the unused block we just found. We need to unlock it to +* set the inuse bit. +*/ + bitmap_bnr = bnr (3 + sb-s_blocksize_bits); + bitmap_block = pram_get_block_off(sb, bitmap_bnr); + bp = pram_get_block(sb, bitmap_block); + + pram_memunlock_block(sb, bp); + pram_set_bit(bnr, bitmap); /* mark the new block in use */ + pram_memlock_block(sb, bp); + + if (zero) { + bp = pram_get_block(sb, pram_get_block_off(sb, bnr)); + pram_memunlock_block(sb, bp); + memset(bp, 0, sb-s_blocksize
[PATCH 07/16 v2] pramfs: symbolic links
From: Marco Stornelli marco.storne...@gmail.com Symlink operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/symlink.c linux-2.6.36/fs/pramfs/symlink.c --- linux-2.6.36-orig/fs/pramfs/symlink.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/symlink.c2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,78 @@ +/* + * FILE NAME fs/pramfs/symlink.c + * + * BRIEF DESCRIPTION + * + * Symlink operations + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/fs.h +#include pram.h +#include xattr.h + +int pram_block_symlink(struct inode *inode, const char *symname, int len) +{ + struct super_block *sb = inode-i_sb; + u64 block; + char *blockp; + int err; + + err = pram_alloc_blocks(inode, 0, 1); + if (err) + return err; + + block = pram_find_data_block(inode, 0); + blockp = pram_get_block(sb, block); + + pram_memunlock_block(sb, blockp); + memcpy(blockp, symname, len); + blockp[len] = '\0'; + pram_memlock_block(sb, blockp); + return 0; +} + +static int pram_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + struct inode *inode = dentry-d_inode; + struct super_block *sb = inode-i_sb; + u64 block; + char *blockp; + + block = pram_find_data_block(inode, 0); + blockp = pram_get_block(sb, block); + return vfs_readlink(dentry, buffer, buflen, blockp); +} + +static void *pram_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct inode *inode = dentry-d_inode; + struct super_block *sb = inode-i_sb; + off_t block; + int status; + char *blockp; + + block = pram_find_data_block(inode, 0); + blockp = pram_get_block(sb, block); + status = vfs_follow_link(nd, blockp); + return ERR_PTR(status); +} + +struct inode_operations pram_symlink_inode_operations = { + .readlink = pram_readlink, + .follow_link= pram_follow_link, + .setattr= pram_notify_change, +#ifdef CONFIG_PRAMFS_XATTR + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = pram_listxattr, + .removexattr= generic_removexattr, +#endif +}; -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 08/16 v2] pramfs: headers
From: Marco Stornelli marco.storne...@gmail.com Definitions for the PRAMFS filesystem. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/pram.h linux-2.6.36/fs/pramfs/pram.h --- linux-2.6.36-orig/fs/pramfs/pram.h 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/pram.h 2010-10-30 12:02:45.0 +0200 @@ -0,0 +1,317 @@ +/* + * FILE NAME pram.h + * + * BRIEF DESCRIPTION + * + * Definitions for the PRAMFS filesystem. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ +#ifndef __PRAM_H +#define __PRAM_H + +#include linux/buffer_head.h +#include linux/pram_fs.h +#include linux/pram_fs_sb.h +#include linux/crc16.h +#include linux/mutex.h +#include linux/types.h + +/* + * Debug code + */ +#define pram_dbg(s, args...) pr_debug(PRAMFS: s, ## args) +#define pram_err(s, args...) pr_err(PRAMFS: s, ## args) +#define pram_warn(s, args...) pr_warning(PRAMFS: s, ## args) +#define pram_info(s, args...) pr_info(PRAMFS: s, ## args) + +/* Function Prototypes */ + +#ifdef CONFIG_PRAMFS_XIP + +#define pram_read xip_file_read +#define pram_write xip_file_write +#define pram_mmap xip_file_mmap +#define pram_aio_read NULL +#define pram_aio_write NULL +#define pram_readpage NULL +#define pram_direct_IO NULL + +#else + +#define pram_read do_sync_read +#define pram_write do_sync_write +#define pram_mmap __pram_mmap +#define pram_aio_read generic_file_aio_read +#define pram_aio_write generic_file_aio_write +#define pram_direct_IO __pram_direct_IO +#define pram_readpage __pram_readpage + +extern int pram_get_and_update_block(struct inode *inode, sector_t iblock, +struct buffer_head *bh, int create); + +static inline int __pram_readpage(struct file *file, struct page *page) +{ + return block_read_full_page(page, pram_get_and_update_block); +} + +/* file.c */ +extern ssize_t __pram_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs); + + +#endif /* CONFIG_PRAMFS_XIP */ + +#define pram_set_bit ext2_set_bit +#define pram_clear_bit ext2_clear_bit +#define pram_find_next_zero_bitext2_find_next_zero_bit + +/* balloc.c */ +extern void pram_init_bitmap(struct super_block *sb); +extern void pram_free_block(struct super_block *sb, unsigned long blocknr); +extern int pram_new_block(struct super_block *sb, unsigned long *blocknr, int zero); +extern unsigned long pram_count_free_blocks(struct super_block *sb); + +/* dir.c */ +extern int pram_add_link(struct dentry *dentry, struct inode *inode); +extern int pram_remove_link(struct inode *inode); + +/* namei.c */ +extern struct dentry *pram_get_parent(struct dentry *child); + +/* inode.c */ +extern int pram_alloc_blocks(struct inode *inode, int file_blocknr, int num); +extern u64 pram_find_data_block(struct inode *inode, +int file_blocknr); + +extern struct inode *pram_iget(struct super_block *sb, unsigned long ino); +extern void pram_put_inode(struct inode *inode); +extern void pram_evict_inode(struct inode *inode); +extern struct inode *pram_new_inode(struct inode *dir, int mode); +extern int pram_update_inode(struct inode *inode); +extern int pram_write_inode(struct inode *inode, struct writeback_control *wbc); +extern void pram_dirty_inode(struct inode *inode); +extern int pram_notify_change(struct dentry *dentry, struct iattr *attr); + + +/* super.c */ +#ifdef CONFIG_PRAMFS_TEST +extern struct pram_super_block *get_pram_super(void); +#endif +extern struct super_block *pram_read_super(struct super_block *sb, + void *data, + int silent); +extern int pram_statfs(struct dentry *d, struct kstatfs *buf); +extern int pram_remount(struct super_block *sb, int *flags, char *data); + +/* symlink.c */ +extern int pram_block_symlink(struct inode *inode, + const char *symname, int len); + + +#ifdef CONFIG_PRAMFS_WRITE_PROTECT +extern void pram_writeable(void *vaddr, unsigned long size, int rw); + +#define wrprotect(addr, size) pram_writeable(addr, size, 0) + +#else + +#define wrprotect(addr, size) do {} while (0) + +#endif /* CONFIG PRAMFS_WRITE_PROTECT */ + +/* Inline functions start here */ + +static inline int pram_calc_checksum(u8 *data, int n) +{ + u16 crc = 0; + crc = crc16(~0, (__u8 *)data + sizeof(__be16), n - sizeof(__be16)); + if (*((__be16 *)data
[PATCH 09/16 v2] pramfs: dir operations
From: Marco Stornelli marco.storne...@gmail.com File operations for directories. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/dir.c linux-2.6.36/fs/pramfs/dir.c --- linux-2.6.36-orig/fs/pramfs/dir.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/dir.c2010-09-17 19:08:54.0 +0200 @@ -0,0 +1,215 @@ +/* + * FILE NAME fs/pramfs/dir.c + * + * BRIEF DESCRIPTION + * + * File operations for directories. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/fs.h +#include linux/pagemap.h +#include pram.h + +/* + * Parent is locked. + */ +int pram_add_link(struct dentry *dentry, struct inode *inode) +{ + struct inode *dir = dentry-d_parent-d_inode; + struct pram_inode *pidir, *pi, *pitail = NULL; + u64 tail_ino, prev_ino; + + const char *name = dentry-d_name.name; + + int namelen = dentry-d_name.len PRAM_NAME_LEN ? + PRAM_NAME_LEN : dentry-d_name.len; + + pidir = pram_get_inode(dir-i_sb, dir-i_ino); + pi = pram_get_inode(dir-i_sb, inode-i_ino); + + dir-i_mtime = dir-i_ctime = CURRENT_TIME; + + tail_ino = be64_to_cpu(pidir-i_type.dir.tail); + if (tail_ino != 0) { + pitail = pram_get_inode(dir-i_sb, tail_ino); + pram_memunlock_inode(pitail); + pitail-i_d.d_next = cpu_to_be64(inode-i_ino); + pram_memlock_inode(pitail); + + prev_ino = tail_ino; + + pram_memunlock_inode(pidir); + pidir-i_type.dir.tail = cpu_to_be64(inode-i_ino); + pidir-i_mtime = cpu_to_be32(dir-i_mtime.tv_sec); + pidir-i_ctime = cpu_to_be32(dir-i_ctime.tv_sec); + pram_memlock_inode(pidir); + } else { + /* the directory is empty */ + prev_ino = 0; + + pram_memunlock_inode(pidir); + pidir-i_type.dir.tail = cpu_to_be64(inode-i_ino); + pidir-i_type.dir.head = cpu_to_be64(inode-i_ino); + pidir-i_mtime = cpu_to_be32(dir-i_mtime.tv_sec); + pidir-i_ctime = cpu_to_be32(dir-i_ctime.tv_sec); + pram_memlock_inode(pidir); + } + + + pram_memunlock_inode(pi); + pi-i_d.d_prev = cpu_to_be64(prev_ino); + pi-i_d.d_parent = cpu_to_be64(dir-i_ino); + memcpy(pi-i_d.d_name, name, namelen); + pi-i_d.d_name[namelen] = '\0'; + pram_memlock_inode(pi); + return 0; +} + +int pram_remove_link(struct inode *inode) +{ + struct super_block *sb = inode-i_sb; + struct pram_inode *prev = NULL; + struct pram_inode *next = NULL; + struct pram_inode *pidir, *pi; + + pi = pram_get_inode(sb, inode-i_ino); + pidir = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_parent)); + if (!pidir) + return -EACCES; + + if (inode-i_ino == be64_to_cpu(pidir-i_type.dir.head)) { + /* first inode in directory */ + next = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_next)); + + if (next) { + pram_memunlock_inode(next); + next-i_d.d_prev = 0; + pram_memlock_inode(next); + + pram_memunlock_inode(pidir); + pidir-i_type.dir.head = pi-i_d.d_next; + } else { + pram_memunlock_inode(pidir); + pidir-i_type.dir.head = 0; + pidir-i_type.dir.tail = 0; + } + pram_memlock_inode(pidir); + } else if (inode-i_ino == be64_to_cpu(pidir-i_type.dir.tail)) { + /* last inode in directory */ + prev = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_prev)); + + pram_memunlock_inode(prev); + prev-i_d.d_next = 0; + pram_memlock_inode(prev); + + pram_memunlock_inode(pidir); + pidir-i_type.dir.tail = pi-i_d.d_prev; + pram_memlock_inode(pidir); + } else { + /* somewhere in the middle */ + prev = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_prev)); + next = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_next)); + + if (prev next) { + pram_memunlock_inode(prev); + prev-i_d.d_next = pi-i_d.d_next; + pram_memlock_inode(prev); + + pram_memunlock_inode(next); + next-i_d.d_prev = pi-i_d.d_prev
[PATCH 10/16 v2] pramfs: XIP operations
From: Marco Stornelli marco.storne...@gmail.com XIP operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/xip.c linux-2.6.36/fs/pramfs/xip.c --- linux-2.6.36-orig/fs/pramfs/xip.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/xip.c2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,90 @@ +/* + * FILE NAME fs/pramfs/xip.c + * + * BRIEF DESCRIPTION + * + * XIP operations. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/mm.h +#include linux/fs.h +#include linux/genhd.h +#include linux/buffer_head.h +#include pram.h +#include xip.h + +static int pram_find_and_alloc_blocks(struct inode *inode, sector_t iblock, +sector_t *data_block, int create) +{ + int err = -EIO; + u64 block; + + mutex_lock(PRAM_I(inode)-truncate_lock); + + block = pram_find_data_block(inode, iblock); + + if (!block) { + if (!create) { + err = -ENODATA; + goto err; + } + + err = pram_alloc_blocks(inode, iblock, 1); + if (err) + goto err; + + block = pram_find_data_block(inode, iblock); + if (!block) { + err = -ENODATA; + goto err; + } + } + + *data_block = block; + err = 0; + + err: + mutex_unlock(PRAM_I(inode)-truncate_lock); + return err; +} + + +static int __pram_get_block(struct inode *inode, pgoff_t pgoff, int create, + sector_t *result) +{ + int rc = 0; + sector_t iblock; + + /* find starting block number to access */ + iblock = (sector_t)pgoff (PAGE_CACHE_SHIFT - inode-i_blkbits); + + rc = pram_find_and_alloc_blocks(inode, iblock, result, create); + + if (rc == -ENODATA) + BUG_ON(create); + + return rc; +} + +int pram_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, int create, + void **kmem, unsigned long *pfn) +{ + int rc; + sector_t block; + + /* first, retrieve the block */ + rc = __pram_get_block(mapping-host, pgoff, create, block); + if (rc) + goto exit; + + *kmem = pram_get_block(mapping-host-i_sb, block); + *pfn = page_to_pfn(virt_to_page((unsigned long)*kmem)); + +exit: + return rc; +} diff -Nurp linux-2.6.36-orig/fs/pramfs/xip.h linux-2.6.36/fs/pramfs/xip.h --- linux-2.6.36-orig/fs/pramfs/xip.h 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/xip.h2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,24 @@ +/* + * FILE NAME fs/pramfs/xip.h + * + * BRIEF DESCRIPTION + * + * XIP operations. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#ifdef CONFIG_PRAMFS_XIP + +int pram_get_xip_mem(struct address_space *, pgoff_t, int, void **, + unsigned long *); + +#else + +#define pram_get_xip_mem NULL + +#endif + -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 11/16 v2] pramfs: ACL management
From: Marco Stornelli marco.storne...@gmail.com ACL operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/acl.c linux-2.6.36/fs/pramfs/acl.c --- linux-2.6.36-orig/fs/pramfs/acl.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/acl.c2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,418 @@ +/* + * FILE NAME fs/pramfs/acl.c + * + * BRIEF MODULE DESCRIPTION + * + * POSIX ACL operations + * + * Copyright 2010 Marco Stornelli marco.storne...@gmail.com + * + * based on fs/ext2/acl.c with the following copyright: + * + * Copyright (C) 2001-2003 Andreas Gruenbacher, agr...@suse.de + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/capability.h +#include linux/init.h +#include linux/sched.h +#include linux/slab.h +#include linux/fs.h +#include pram.h +#include xattr.h +#include acl.h + +/* + * Load ACL information from filesystem. + */ +static struct posix_acl *pram_acl_load(const void *value, size_t size) +{ + const char *end = (char *)value + size; + int n, count; + struct posix_acl *acl; + + if (!value) + return NULL; + if (size sizeof(struct pram_acl_header)) +return ERR_PTR(-EINVAL); + if (((struct pram_acl_header *)value)-a_version != + cpu_to_be32(PRAM_ACL_VERSION)) + return ERR_PTR(-EINVAL); + value = (char *)value + sizeof(struct pram_acl_header); + count = pram_acl_count(size); + if (count 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + acl = posix_acl_alloc(count, GFP_KERNEL); + if (!acl) + return ERR_PTR(-ENOMEM); + for (n = 0; n count; n++) { + struct pram_acl_entry *entry = (struct pram_acl_entry *)value; + if ((char *)value + sizeof(struct pram_acl_entry_short) end) + goto fail; + acl-a_entries[n].e_tag = be16_to_cpu(entry-e_tag); + acl-a_entries[n].e_perm = be16_to_cpu(entry-e_perm); + switch (acl-a_entries[n].e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + value = (char *)value + + sizeof(struct pram_acl_entry_short); + acl-a_entries[n].e_id = ACL_UNDEFINED_ID; + break; + case ACL_USER: + case ACL_GROUP: + value = (char *)value + sizeof(struct pram_acl_entry); + if ((char *)value end) + goto fail; + acl-a_entries[n].e_id = + be32_to_cpu(entry-e_id); + break; + default: + goto fail; + } + } + if (value != end) + goto fail; + return acl; + +fail: + posix_acl_release(acl); + return ERR_PTR(-EINVAL); +} + +/* + * Save ACL information into the filesystem. + */ +static void *pram_acl_save(const struct posix_acl *acl, size_t *size) +{ + struct pram_acl_header *ext_acl; + char *e; + size_t n; + + *size = pram_acl_size(acl-a_count); + ext_acl = kmalloc(sizeof(struct pram_acl_header) + acl-a_count * + sizeof(struct pram_acl_entry), GFP_KERNEL); + if (!ext_acl) + return ERR_PTR(-ENOMEM); + ext_acl-a_version = cpu_to_be32(PRAM_ACL_VERSION); + e = (char *)ext_acl + sizeof(struct pram_acl_header); + for (n = 0; n acl-a_count; n++) { + struct pram_acl_entry *entry = (struct pram_acl_entry *)e; + entry-e_tag = cpu_to_be16(acl-a_entries[n].e_tag); + entry-e_perm = cpu_to_be16(acl-a_entries[n].e_perm); + switch (acl-a_entries[n].e_tag) { + case ACL_USER: + case ACL_GROUP: + entry-e_id = + cpu_to_be32(acl-a_entries[n].e_id); + e += sizeof(struct pram_acl_entry); + break; + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + e += sizeof(struct pram_acl_entry_short); + break; + default: + goto fail; + } + } + return (char *)ext_acl; + +fail: + kfree(ext_acl); + return ERR_PTR(-EINVAL); +} + +/* + * inode-i_mutex: don't care + */ +static struct posix_acl *pram_get_acl(struct inode *inode, int type) +{ + int name_index; + char *value = NULL; + struct posix_acl
[PATCH 12/16 v2] pramfs: extended attributes
From: Marco Stornelli marco.storne...@gmail.com Extended attributes operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/xattr.c linux-2.6.36/fs/pramfs/xattr.c --- linux-2.6.36-orig/fs/pramfs/xattr.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/xattr.c 2010-09-14 19:45:40.0 +0200 @@ -0,0 +1,1108 @@ +/* + * FILE NAME fs/pramfs/xattr.c + * + * BRIEF DESCRIPTION + * + * Extended attributes operations. + * + * Copyright 2010 Marco Stornelli marco.storne...@gmail.com + * + * based on fs/ext2/xattr.c with the following copyright: + * + * Fix by Harrison Xing harri...@mountainviewdata.com. + * Extended attributes for symlinks and special files added per + * suggestion of Luka Renko luka.re...@hermes.si. + * xattr consolidation Copyright (c) 2004 James Morris jmor...@redhat.com, + * Red Hat Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +/* + * Extended attributes are stored in blocks allocated outside of + * any inode. The i_xattr field is then made to point to this allocated + * block. If all extended attributes of an inode are identical, these + * inodes may share the same extended attribute block. Such situations + * are automatically detected by keeping a cache of recent attribute block + * numbers and hashes over the block's contents in memory. + * + * + * Extended attribute block layout: + * + * +--+ + * | header | + * | entry 1 | | + * | entry 2 | | growing downwards + * | entry 3 | v + * | four null bytes | + * | . . .| + * | value 1 | ^ + * | value 3 | | growing upwards + * | value 2 | | + * +--+ + * + * The block header is followed by multiple entry descriptors. These entry + * descriptors are variable in size, and alligned to PRAM_XATTR_PAD + * byte boundaries. The entry descriptors are sorted by attribute name, + * so that two extended attribute blocks can be compared efficiently. + * + * Attribute values are aligned to the end of the block, stored in + * no specific order. They are also padded to PRAM_XATTR_PAD byte + * boundaries. No additional gaps are left between them. + * + * Locking strategy + * + * pi-i_xattr is protected by PRAM_I(inode)-xattr_sem. + * EA blocks are only changed if they are exclusive to an inode, so + * holding xattr_sem also means that nothing but the EA block's reference + * count will change. Multiple writers to an EA block are synchronized + * by the mutex in each block descriptor. Block descriptors are kept in a + * red black tree and the key is the absolute block number. + */ + +#include linux/module.h +#include linux/init.h +#include linux/mbcache.h +#include linux/rwsem.h +#include linux/security.h +#include pram.h +#include xattr.h +#include acl.h +#include desctree.h + +#define HDR(bp) ((struct pram_xattr_header *)(bp)) +#define ENTRY(ptr) ((struct pram_xattr_entry *)(ptr)) +#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) +#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) +#define GET_DESC(sbi, blocknr) lookup_xblock_desc(sbi, blocknr, pram_xblock_desc_cache, 1) +#define LOOKUP_DESC(sbi, blocknr) lookup_xblock_desc(sbi, blocknr, NULL, 0) + +#ifdef PRAM_XATTR_DEBUG +# define ea_idebug(inode, f...) do { \ + printk(KERN_DEBUG inode %ld: , inode-i_ino); \ + printk(f); \ + printk(\n); \ + } while (0) +# define ea_bdebug(blocknr, f...) do { \ + printk(KERN_DEBUG block %lu: , blocknr); \ + printk(f); \ + printk(\n); \ + } while (0) +#else +# define ea_idebug(f...) +# define ea_bdebug(f...) +#endif + +static int pram_xattr_set2(struct inode *, char *, struct pram_xblock_desc *, struct pram_xattr_header *); + +static int pram_xattr_cache_insert(struct super_block *sb, unsigned long blocknr, u32 xhash); +static struct pram_xblock_desc *pram_xattr_cache_find(struct inode *, +struct pram_xattr_header *); +static void pram_xattr_rehash(struct pram_xattr_header *, + struct pram_xattr_entry *); + +static struct mb_cache *pram_xattr_cache; +static struct kmem_cache *pram_xblock_desc_cache; + +static const struct xattr_handler *pram_xattr_handler_map[] = { + [PRAM_XATTR_INDEX_USER] = pram_xattr_user_handler, +#ifdef CONFIG_PRAMFS_POSIX_ACL + [PRAM_XATTR_INDEX_POSIX_ACL_ACCESS] = pram_xattr_acl_access_handler, + [PRAM_XATTR_INDEX_POSIX_ACL_DEFAULT] = pram_xattr_acl_default_handler, +#endif + [PRAM_XATTR_INDEX_TRUSTED] = pram_xattr_trusted_handler, +#ifdef CONFIG_PRAMFS_SECURITY + [PRAM_XATTR_INDEX_SECURITY] = pram_xattr_security_handler, +#endif +}; + +const
[PATCH 13/16 v2] pramfs: xattr block descriptors tree
From: Marco Stornelli marco.storne...@gmail.com Extended attributes block descriptors tree. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/desctree.c linux-2.6.36/fs/pramfs/desctree.c --- linux-2.6.36-orig/fs/pramfs/desctree.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/desctree.c 2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,184 @@ +/* + * FILE NAME fs/pramfs/desctree.c + * + * BRIEF DESCRIPTION + * + * Extended attributes block descriptors tree. + * + * Copyright 2010 Marco Stornelli marco.storne...@gmail.com + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/spinlock.h +#include desctree.h +#include pram.h + +/* xblock_desc_init_always() + * + * These are initializations that need to be done on every + * descriptor allocation as the fields are not initialised + * by slab allocation. + */ +void xblock_desc_init_always(struct pram_xblock_desc *desc) +{ + atomic_set(desc-refcount, 0); + desc-blocknr = 0; + desc-flags = 0; +} + +/* xblock_desc_init_once() + * + * These are initializations that only need to be done + * once, because the fields are idempotent across use + * of the descriptor, so let the slab aware of that. + */ +void xblock_desc_init_once(struct pram_xblock_desc *desc) +{ + mutex_init(desc-lock); +} + +/* __insert_xblock_desc() + * + * Insert a new descriptor in the tree. + * + */ +static void __insert_xblock_desc(struct pram_sb_info *sbi, +unsigned long blocknr, struct rb_node *node) +{ + struct rb_node **p = (sbi-desc_tree.rb_node); + struct rb_node *parent = NULL; + struct pram_xblock_desc *desc; + + while (*p) { + parent = *p; + desc = rb_entry(parent, struct pram_xblock_desc, node); + + if (blocknr desc-blocknr) + p = (*p)-rb_left; + else if (blocknr desc-blocknr) + p = (*p)-rb_right; + else + /* Oops...an other descriptor for the same block ? */ + BUG(); + } + + rb_link_node(node, parent, p); + rb_insert_color(node, sbi-desc_tree); +} + +void insert_xblock_desc(struct pram_sb_info *sbi, struct pram_xblock_desc *desc) +{ + spin_lock(sbi-desc_tree_lock); + __insert_xblock_desc(sbi, desc-blocknr, desc-node); + spin_unlock(sbi-desc_tree_lock); +}; + +/* __lookup_xblock_desc() + * + * Search an extended attribute descriptor in the tree via the + * block number. It returns the descriptor if it's found or + * NULL. If not found it creates a new descriptor if create is not 0. + */ +static struct pram_xblock_desc *__lookup_xblock_desc(struct pram_sb_info *sbi, + unsigned long blocknr, + struct kmem_cache *cache, + int create) +{ + struct rb_node *n = sbi-desc_tree.rb_node; + struct pram_xblock_desc *desc = NULL; + + while (n) { + desc = rb_entry(n, struct pram_xblock_desc, node); + + if (blocknr desc-blocknr) + n = n-rb_left; + else if (blocknr desc-blocknr) + n = n-rb_right; + else { + atomic_inc(desc-refcount); + goto out; + } + } + + /* not found */ + if (create) { + desc = kmem_cache_alloc(cache, GFP_NOFS); + if (!desc) + return ERR_PTR(-ENOMEM); + xblock_desc_init_always(desc); + atomic_set(desc-refcount, 1); + desc-blocknr = blocknr; + __insert_xblock_desc(sbi, desc-blocknr, desc-node); + } +out: + return desc; +} + +struct pram_xblock_desc *lookup_xblock_desc(struct pram_sb_info *sbi, + unsigned long blocknr, + struct kmem_cache *cache, + int create) +{ + struct pram_xblock_desc *desc = NULL; + + spin_lock(sbi-desc_tree_lock); + desc = __lookup_xblock_desc(sbi, blocknr, cache, create); + spin_unlock(sbi-desc_tree_lock); + return desc; +} + +/* put_xblock_desc() + * + * Decrement the reference count and if it reaches zero and the + * desciptor has been marked to be free, then we free it. + * It returns 0 if the descriptor has been deleted and 1 otherwise. + */ +int put_xblock_desc(struct pram_sb_info *sbi, struct pram_xblock_desc *desc) +{ + int ret = 1; + if (!desc) + return ret; + + if (atomic_dec_and_lock(desc-refcount, sbi-desc_tree_lock
[PATCH 15/16 v2] pramfs: test module
From: Marco Stornelli marco.storne...@gmail.com Test module. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/pramfs_test.c linux-2.6.36/fs/pramfs/pramfs_test.c --- linux-2.6.36-orig/fs/pramfs/pramfs_test.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/pramfs_test.c2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,49 @@ +/* + * FILE NAME fs/pramfs/namei.c + * + * BRIEF DESCRIPTION + * + * Pramfs test module. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ +#include linux/module.h +#include linux/version.h +#include linux/init.h +#include linux/fs.h +#include pram.h + +int __init test_pramfs_write(void) +{ + struct pram_super_block *psb; + + psb = get_pram_super(); + if (!psb) { + printk(KERN_ERR + %s: PRAMFS super block not found (not mounted?)\n, + __func__); + return 1; + } + + /* +* Attempt an unprotected clear of checksum information in the +* superblock, this should cause a kernel page protection fault. +*/ + printk(%s: writing to kernel VA %p\n, __func__, psb); + psb-s_sum = 0; + + return 0; +} + +void test_pramfs_write_cleanup(void) {} + +/* Module information */ +MODULE_LICENSE(GPL); +module_init(test_pramfs_write); +module_exit(test_pramfs_write_cleanup); -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 16/16 v2] pramfs: Makefile and Kconfig
From: Marco Stornelli marco.storne...@gmail.com Makefile and Kconfig. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/Makefile linux-2.6.36/fs/Makefile --- linux-2.6.36-orig/fs/Makefile 2010-09-13 01:07:37.0 +0200 +++ linux-2.6.36/fs/Makefile2010-09-14 18:49:52.0 +0200 @@ -126,3 +126,4 @@ obj-$(CONFIG_BTRFS_FS) += btrfs/ obj-$(CONFIG_GFS2_FS) += gfs2/ obj-$(CONFIG_EXOFS_FS) += exofs/ obj-$(CONFIG_CEPH_FS) += ceph/ +obj-$(CONFIG_PRAMFS) += pramfs/ diff -Nurp linux-2.6.36-orig/fs/Kconfig linux-2.6.36/fs/Kconfig --- linux-2.6.36-orig/fs/Kconfig2010-09-13 01:07:37.0 +0200 +++ linux-2.6.36/fs/Kconfig 2010-09-14 18:49:52.0 +0200 @@ -13,7 +13,7 @@ source fs/ext4/Kconfig config FS_XIP # execute in place bool - depends on EXT2_FS_XIP + depends on EXT2_FS_XIP || PRAMFS_XIP default y source fs/jbd/Kconfig @@ -25,13 +25,14 @@ config FS_MBCACHE default y if EXT2_FS=y EXT2_FS_XATTR default y if EXT3_FS=y EXT3_FS_XATTR default y if EXT4_FS=y EXT4_FS_XATTR - default m if EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR + default y if PRAMFS=y PRAMFS_XATTR + default m if EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR || PRAMFS_XATTR source fs/reiserfs/Kconfig source fs/jfs/Kconfig config FS_POSIX_ACL -# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4) +# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4/pramfs) # # NOTE: you can implement Posix ACLs without these helpers (XFS does). # Never use this symbol for ifdefs. @@ -189,6 +190,7 @@ source fs/romfs/Kconfig source fs/sysv/Kconfig source fs/ufs/Kconfig source fs/exofs/Kconfig +source fs/pramfs/Kconfig endif # MISC_FILESYSTEMS diff -Nurp linux-2.6.36-orig/fs/pramfs/Kconfig linux-2.6.36/fs/pramfs/Kconfig --- linux-2.6.36-orig/fs/pramfs/Kconfig 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/Kconfig 2010-10-30 10:30:19.0 +0200 @@ -0,0 +1,72 @@ +config PRAMFS + tristate Persistent and Protected RAM file system support + depends on HAS_IOMEM EXPERIMENTAL + select CRC16 + help + If your system has a block of fast (comparable in access speed to + system memory) and non-volatile RAM and you wish to mount a + light-weight, full-featured, and space-efficient filesystem over it, + say Y here, and read file:Documentation/filesystems/pramfs.txt. + + To compile this as a module, choose M here: the module will be + called pramfs. + +config PRAMFS_XIP + bool Enable Execute-in-place in PRAMFS + depends on PRAMFS !PRAMFS_WRITE_PROTECT + help + Say Y here to enable XIP feature of PRAMFS. + +config PRAMFS_WRITE_PROTECT + bool Enable PRAMFS write protection + depends on PRAMFS MMU HAVE_SET_MEMORY_RO + default y + help + Say Y here to enable the write protect feature of PRAMFS. + +config PRAMFS_XATTR + bool PRAMFS extended attributes + depends on PRAMFS + help + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + http://acl.bestbits.at/ for details). + + If unsure, say N. + +config PRAMFS_POSIX_ACL + bool PRAMFS POSIX Access Control Lists + depends on PRAMFS_XATTR + select FS_POSIX_ACL + help + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website http://acl.bestbits.at/. + + If you don't know what Access Control Lists are, say N. + +config PRAMFS_SECURITY + bool PRAMFS Security Labels + depends on PRAMFS_XATTR + help + Security labels support alternative access control models + implemented by security modules like SELinux. This option + enables an extended attribute handler for file security + labels in the pram filesystem. + + If you are not using a security module that requires using + extended attributes for file security labels, say N. + +config PRAMFS_TEST + boolean + depends on PRAMFS + +config TEST_MODULE + tristate PRAMFS Test + depends on PRAMFS m + select PRAMFS_TEST + help + Say Y here to build a simple module to test the protection of + PRAMFS. The module will be called pramfs_test. diff -Nurp linux-2.6.36-orig/fs/pramfs/Makefile linux-2.6.36/fs/pramfs/Makefile --- linux-2.6.36-orig/fs/pramfs/Makefile1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/Makefile 2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,14 @@ +# +# Makefile for the linux
Re: [PATCH 01/16 v2] pramfs: documentation
Il 06/11/2010 11:39, James Hogan ha scritto: Hi, On Sat, Nov 06, 2010 at 09:56:18AM +0100, Marco Stornelli wrote: From: Marco Stornelli marco.storne...@gmail.com +PRAMFS is write protected. The page table entries that map the backing-store +RAM are normally marked read-only. Write operations into the filesystem +temporarily mark the affected pages as writeable, the write operation is +carried out with locks held, and then the page table entries is +marked read-only again. +This feature provides protection against filesystem corruption caused by errant Looks like an accidental lost newline in the patch here, should that be are marked or is there some text missing? My fault, a problem during email formatting. I'll resend this patch. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/16 v2] pramfs: super block operations
Il 06/11/2010 12:16, James Hogan ha scritto: Hi Marco, On Sat, Nov 06, 2010 at 09:56:39AM +0100, Marco Stornelli wrote: From: Marco Stornelli marco.storne...@gmail.com +static void pram_set_blocksize(struct super_block *sb, unsigned long size) +{ +int bits; + +/* +* We've already validated the user input and the value here must be +* between PRAM_MAX_BLOCK_SIZE and PRAM_MIN_BLOCK_SIZE +* and it must be a power of 2. +*/ Should this comment have spaces after the tabs to be consistent with the other multiline comments (pram_ioremap) and the coding style? Ok, no problem. Thanks for the review. Regards, Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 10/16 v2] pramfs: XIP operations
Il 06/11/2010 14:33, James Hogan ha scritto: Hi, On Sat, Nov 06, 2010 at 09:59:27AM +0100, Marco Stornelli wrote: diff -Nurp linux-2.6.36-orig/fs/pramfs/xip.c linux-2.6.36/fs/pramfs/xip.c --- linux-2.6.36-orig/fs/pramfs/xip.c1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/xip.c 2010-09-14 18:49:52.0 +0200 snip +static int pram_find_and_alloc_blocks(struct inode *inode, sector_t iblock, + sector_t *data_block, int create) +{ +int err = -EIO; +u64 block; + +mutex_lock(PRAM_I(inode)-truncate_lock); fs/pramfs/xip.c: In function ‘pram_find_and_alloc_blocks’: fs/pramfs/xip.c:27: error: ‘struct pram_inode_vfs’ has no member named ‘truncate_lock’ fs/pramfs/xip.c:52: error: ‘struct pram_inode_vfs’ has no member named ‘truncate_lock’ i guess that should be truncate_mutex. Oops, my fault, yes it's truncate_mutex. I'll fix it asap. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 08/16 v2] pramfs: headers
2010/11/7 Ryan Mallon r...@bluewatersys.com: On 11/06/2010 09:58 PM, Marco Stornelli wrote: From: Marco Stornelli marco.storne...@gmail.com Definitions for the PRAMFS filesystem. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/pram.h linux-2.6.36/fs/pramfs/pram.h --- linux-2.6.36-orig/fs/pramfs/pram.h 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/pram.h 2010-10-30 12:02:45.0 +0200 @@ -0,0 +1,317 @@ +/* + * Structure of the super block in PRAMFS + */ +struct pram_super_block { + __be16 s_sum; /* checksum of this sb, including padding */ + __be64 s_size; /* total size of fs in bytes */ + __be32 s_blocksize; /* blocksize in bytes */ + __be32 s_inodes_count; /* total inodes count (used or free) */ + __be32 s_free_inodes_count;/* free inodes count */ + __be32 s_free_inode_hint; /* start hint for locating free inodes */ + __be32 s_blocks_count; /* total data blocks count (used or free) */ + __be32 s_free_blocks_count;/* free data blocks count */ + __be32 s_free_blocknr_hint;/* free data blocks count */ + __be64 s_bitmap_start; /* data block in-use bitmap location */ + __be32 s_bitmap_blocks;/* size of bitmap in number of blocks */ + __be32 s_mtime; /* Mount time */ + __be32 s_wtime; /* Write time */ + __be16 s_magic; /* Magic signature */ + char s_volume_name[16]; /* volume name */ +}; Is there a particular reason to use big endian types for the data structures? On a little endian machine you will end up converting values everywhere. I assume that you don't expect the machine to change endianess between reboots :-). If this is for generating/reading filesystems from userspace, wouldn't it be better to have the userspace tools specify the target endianess and do the conversions there? ~Ryan Yes, there is a reason. In the first review a comment was: the fs must have a fix endianess layout. This fs is designed for the embedded world mainly. Since most of cpus used in this case are big-endian, it means that for typical use case, there is no cost for endianess conversion. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 08/16 v2] pramfs: headers
2010/11/8 Ryan Mallon r...@bluewatersys.com: On 11/08/2010 08:49 PM, Marco Stornelli wrote: 2010/11/7 Ryan Mallon r...@bluewatersys.com: On 11/06/2010 09:58 PM, Marco Stornelli wrote: From: Marco Stornelli marco.storne...@gmail.com Definitions for the PRAMFS filesystem. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/pram.h linux-2.6.36/fs/pramfs/pram.h --- linux-2.6.36-orig/fs/pramfs/pram.h 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/pram.h 2010-10-30 12:02:45.0 +0200 @@ -0,0 +1,317 @@ +/* + * Structure of the super block in PRAMFS + */ +struct pram_super_block { + __be16 s_sum; /* checksum of this sb, including padding */ + __be64 s_size; /* total size of fs in bytes */ + __be32 s_blocksize; /* blocksize in bytes */ + __be32 s_inodes_count; /* total inodes count (used or free) */ + __be32 s_free_inodes_count;/* free inodes count */ + __be32 s_free_inode_hint; /* start hint for locating free inodes */ + __be32 s_blocks_count; /* total data blocks count (used or free) */ + __be32 s_free_blocks_count;/* free data blocks count */ + __be32 s_free_blocknr_hint;/* free data blocks count */ + __be64 s_bitmap_start; /* data block in-use bitmap location */ + __be32 s_bitmap_blocks;/* size of bitmap in number of blocks */ + __be32 s_mtime; /* Mount time */ + __be32 s_wtime; /* Write time */ + __be16 s_magic; /* Magic signature */ + char s_volume_name[16]; /* volume name */ +}; Is there a particular reason to use big endian types for the data structures? On a little endian machine you will end up converting values everywhere. I assume that you don't expect the machine to change endianess between reboots :-). If this is for generating/reading filesystems from userspace, wouldn't it be better to have the userspace tools specify the target endianess and do the conversions there? ~Ryan Yes, there is a reason. In the first review a comment was: the fs must have a fix endianess layout. This fs is designed for the embedded world mainly. Since most of cpus used in this case are big-endian, it means that for typical use case, there is no cost for endianess conversion. ARM, which is a large portion of the embedded space, is typically little endian. Not always. Indeed, I didn't say *all* cpu used are big-endian. Why does a filesystem need to have a specific endianess layout? Especially for a highly specialised filesystem like this. I didn't agree with it, but in the first review there was more than one developer that said this thing. The main reason was to read the format (for example with JTAG) or to create an image with a fix format. I remember that someone said that there was a similar problem with jffs2 and the experience tell to us that a fix endianess is important. At that point I decided to use big-endian. You can see all the discussion in lkml. The review has been done at June 2009. Regards, Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 00/16 v3] pramfs: persistent and protected RAM filesystem
Hi all, third round for the patch series (I hope this is the last one :)). I summarize here the changes to improve the review: v3: - fix a possible memory leak in an error path reported by yidong zhang - fix a warning when using XIP about not used __pram_mmap symbol - fix test module header description and replaced TEST_MODULE with PRAMFS_TEST_MODULE in the Kconfig and Makefile according to the comments done by Randy Dunlap - fix a compilation warning in super.c reported by James Hogan - fix a compilation error when XIP was enabled - removed not used symbol PRAM_XATTR_INDEX_LUSTRE - fix some comment style issue v2: - fix documentation errors reported by Randy Dunlap and Kieran Bingham - reworked memory write protection functions with the suggestions of Andi Kleen v1: - first draft Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 01/16 v3] pramfs; documentation
From: Marco Stornelli marco.storne...@gmail.com Documentation for PRAMFS. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/Documentation/filesystems/pramfs.txt linux-2.6.36/Documentation/filesystems/pramfs.txt --- linux-2.6.36-orig/Documentation/filesystems/pramfs.txt 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/Documentation/filesystems/pramfs.txt 2010-10-23 09:04:32.0 +0200 @@ -0,0 +1,296 @@ + +PRAMFS Overview +=== + +Many embedded systems have a block of non-volatile RAM separate from +normal system memory, i.e. of which the kernel maintains no memory page +descriptors. For such systems it would be beneficial to mount a +fast read/write filesystem over this I/O memory, for storing frequently +accessed data that must survive system reboots and power cycles. An +example usage might be system logs under /var/log, or a user address +book in a cell phone or PDA. + +Linux traditionally had no support for a persistent, non-volatile RAM-based +filesystem, persistent meaning the filesystem survives a system reboot +or power cycle intact. The RAM-based filesystems such as tmpfs and ramfs +have no actual backing store but exist entirely in the page and buffer +caches, hence the filesystem disappears after a system reboot or +power cycle. + +A relatively straightforward solution is to write a simple block driver +for the non-volatile RAM, and mount over it any disk-based filesystem such +as ext2, ext3, ext4, etc. + +But the disk-based fs over non-volatile RAM block driver approach has +some drawbacks: + +1. Complexity of disk-based fs: disk-based filesystems such as ext2/ext3/ext4 + were designed for optimum performance on spinning disk media, so they + implement features such as block groups, which attempts to group inode data + into a contiguous set of data blocks to minimize disk seeking when accessing + files. For RAM there is no such concern; a file's data blocks can be + scattered throughout the media with no access speed penalty at all. So block + groups in a filesystem mounted over RAM just adds unnecessary + complexity. A better approach is to use a filesystem specifically + tailored to RAM media which does away with these disk-based features. + This increases the efficient use of space on the media, i.e. more + space is dedicated to actual file data storage and less to meta-data + needed to maintain that file data. + +2. Different problems between disks and RAM: Because PRAMFS attempts to avoid + filesystem corruption caused by kernel bugs, dirty pages in the page cache + are not allowed to be written back to the backing-store RAM. This way, an + errant write into the page cache will not get written back to the filesystem. + However, if the backing-store RAM is comparable in access speed to system + memory, the penalty of not using caching is minimal. With this consideration + it's better to move file data directly between the user buffers and the backing + store RAM, i.e. use direct I/O. This prevents the unnecessary populating of + the page cache with dirty pages. However direct I/O has to be enabled at + every file open. To enable direct I/O at all times for all regular files + requires either that applications be modified to include the O_DIRECT flag on + all file opens, or that the filesystem used performs direct I/O by default. + +The Persistent/Protected RAM Special Filesystem (PRAMFS) is a read/write +filesystem that has been designed to address these issues. PRAMFS is targeted +to fast I/O memory, and if the memory is non-volatile, the filesystem will be +persistent. + +In PRAMFS, direct I/O is enabled across all files in the filesystem, in other +words the O_DIRECT flag is forced on every open of a PRAMFS file. Also, file +I/O in the PRAMFS is always synchronous. There is no need to block the current +process while the transfer to/from the PRAMFS is in progress, since one of +the requirements of the PRAMFS is that the filesystem exists in fast RAM. So +file I/O in PRAMFS is always direct, synchronous, and never blocks. + +The data organization in PRAMFS can be thought of as an extremely simplified +version of ext2, such that the ratio of data to meta-data is very high. + +PRAMFS supports the execute-in-place. With XIP, instead of keeping data in the +page cache, the need to have a page cache copy is eliminated completely. +Readwrite type operations are performed directly from/to the memory. For file +mappings, the RAM itself is mapped directly into userspace. XIP, in addition, +speed up the applications start-up time because it removes the needs of any +copies. + +PRAMFS is write protected. The page table entries that map the backing-store +RAM are normally marked read-only. Write operations into the filesystem +temporarily mark the affected pages as writeable, the write operation is +carried out with locks held, and then the page table entries is +marked read-only
[PATCH 03/16 v3] pramfs: inode operations
From: Marco Stornelli marco.storne...@gmail.com Inode methods (allocate/free/read/write). Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/inode.c linux-2.6.36/fs/pramfs/inode.c --- linux-2.6.36-orig/fs/pramfs/inode.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/inode.c 2010-09-26 18:04:38.0 +0200 @@ -0,0 +1,710 @@ +/* + * FILE NAME fs/pramfs/inode.c + * + * BRIEF DESCRIPTION + * + * Inode methods (allocate/free/read/write). + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/fs.h +#include linux/smp_lock.h +#include linux/sched.h +#include linux/highuid.h +#include linux/quotaops.h +#include linux/module.h +#include linux/mpage.h +#include linux/backing-dev.h +#include pram.h +#include xattr.h +#include xip.h +#include acl.h + +struct backing_dev_info pram_backing_dev_info __read_mostly = { + .ra_pages = 0,/* No readahead */ + .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, +}; + +/* + * allocate a data block for inode and return it's absolute blocknr. + * Zeroes out the block if zero set. Increments inode-i_blocks. + */ +static int pram_new_data_block(struct inode *inode, unsigned long *blocknr, int zero) +{ + int errval = pram_new_block(inode-i_sb, blocknr, zero); + + if (!errval) { + struct pram_inode *pi = pram_get_inode(inode-i_sb, + inode-i_ino); + inode-i_blocks++; + pram_memunlock_inode(pi); + pi-i_blocks = cpu_to_be32(inode-i_blocks); + pram_memlock_inode(pi); + } + + return errval; +} + +/* + * find the offset to the block represented by the given inode's file + * relative block number. + */ +u64 pram_find_data_block(struct inode *inode, int file_blocknr) +{ + struct super_block *sb = inode-i_sb; + struct pram_inode *pi; + u64 *row; /* ptr to row block */ + u64 *col; /* ptr to column blocks */ + u64 bp = 0; + int i_row, i_col; + int N = sb-s_blocksize 3; /* num block ptrs per block */ + int Nbits = sb-s_blocksize_bits - 3; + + pi = pram_get_inode(sb, inode-i_ino); + + i_row = file_blocknr Nbits; + i_col = file_blocknr (N-1); + + row = pram_get_block(sb, be64_to_cpu(pi-i_type.reg.row_block)); + if (row) { + col = pram_get_block(sb, be64_to_cpu(row[i_row])); + if (col) + bp = be64_to_cpu(col[i_col]); + } + + return bp; +} + +/* + * Free data blocks from inode in the range start = end + */ +static void __pram_truncate_blocks(struct inode *inode, loff_t start, loff_t end) +{ + struct super_block *sb = inode-i_sb; + struct pram_inode *pi = pram_get_inode(sb, inode-i_ino); + int N = sb-s_blocksize 3; /* num block ptrs per block */ + int Nbits = sb-s_blocksize_bits - 3; + int first_row_index, last_row_index, i, j; + unsigned long blocknr, first_blocknr, last_blocknr; + unsigned int freed = 0; + u64 *row; /* ptr to row block */ + u64 *col; /* ptr to column blocks */ + + if (start end || !inode-i_blocks || !pi-i_type.reg.row_block) + return; + + mutex_lock(PRAM_I(inode)-truncate_mutex); + + first_blocknr = (start + sb-s_blocksize - 1) sb-s_blocksize_bits; + last_blocknr = (end + sb-s_blocksize - 1) sb-s_blocksize_bits; + first_row_index = first_blocknr Nbits; + last_row_index = last_blocknr Nbits; + + row = pram_get_block(sb, be64_to_cpu(pi-i_type.reg.row_block)); + + for (i = first_row_index; i = last_row_index; i++) { + int first_col_index = (i == first_row_index) ? + first_blocknr (N-1) : 0; + int last_col_index = (i == last_row_index) ? + last_blocknr (N-1) : N-1; + + if (unlikely(!row[i])) + continue; + + col = pram_get_block(sb, be64_to_cpu(row[i])); + + for (j = first_col_index; j = last_col_index; j++) { + + if (unlikely(!col[j])) + continue; + + blocknr = pram_get_blocknr(sb, be64_to_cpu(col[j])); + pram_free_block(sb, blocknr); + freed++; + pram_memunlock_block(sb, col); + col[j] = 0; + pram_memlock_block(sb, col); + } + + if (first_col_index == 0
[PATCH 04/16 v3] pramfs: file operations
From: Marco Stornelli marco.storne...@gmail.com File operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/file.c linux-2.6.36/fs/pramfs/file.c --- linux-2.6.36-orig/fs/pramfs/file.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/file.c 2010-09-24 18:34:03.0 +0200 @@ -0,0 +1,166 @@ +/* + * FILE NAME fs/pramfs/file.c + * + * BRIEF DESCRIPTION + * + * File operations for files. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ +#include linux/fs.h +#include linux/sched.h +#include linux/slab.h +#include linux/uio.h +#include linux/mm.h +#include linux/uaccess.h +#include pram.h +#include acl.h +#include xip.h +#include xattr.h + +static int pram_open_file(struct inode *inode, struct file *filp) +{ +#ifndef CONFIG_PRAMFS_XIP + /* Without XIP we force to use Direct IO */ + filp-f_flags |= O_DIRECT; +#endif + return generic_file_open(inode, filp); +} + +ssize_t __pram_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +{ + struct file *file = iocb-ki_filp; + struct inode *inode = file-f_mapping-host; + struct super_block *sb = inode-i_sb; + int progress = 0, hole = 0; + ssize_t retval = 0; + void *tmp = NULL; + unsigned long blocknr, blockoff; + int num_blocks, blocksize_mask, blocksize, blocksize_bits; + char __user *buf = iov-iov_base; + size_t length = iov_length(iov, nr_segs); + + if (length 0) + return -EINVAL; + if ((rw == READ) (offset + length inode-i_size)) + length = inode-i_size - offset; + if (!length) + goto out; + + blocksize_bits = inode-i_sb-s_blocksize_bits; + blocksize = 1 blocksize_bits; + blocksize_mask = blocksize - 1; + + /* find starting block number to access */ + blocknr = offset blocksize_bits; + /* find starting offset within starting block */ + blockoff = offset blocksize_mask; + /* find number of blocks to access */ + num_blocks = (blockoff + length + blocksize_mask) blocksize_bits; + + if (rw == WRITE) { + /* prepare a temporary buffer to hold a user data block + for writing. */ + tmp = kmalloc(blocksize, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + /* now allocate the data blocks we'll need */ + retval = pram_alloc_blocks(inode, blocknr, num_blocks); + if (retval) + goto fail1; + } + + while (length) { + int count; + u8 *bp = NULL; + u64 block = pram_find_data_block(inode, blocknr++); + if (unlikely(!block rw == READ)) { + /* We are falling in a hole */ + hole = 1; + } else { + bp = (u8 *)pram_get_block(sb, block); + if (!bp) + goto fail2; + } + + count = blockoff + length blocksize ? + blocksize - blockoff : length; + + if (rw == READ) { + if (unlikely(hole)) { + retval = clear_user(buf, count); + if (retval) { + retval = -EFAULT; + goto fail1; + } + } else { + retval = copy_to_user(buf, bp[blockoff], count); + if (retval) { + retval = -EFAULT; + goto fail1; + } + } + } else { + retval = copy_from_user(tmp, buf, count); + if (retval) { + retval = -EFAULT; + goto fail1; + } + + pram_memunlock_block(inode-i_sb, bp); + memcpy(bp[blockoff], tmp, count); + pram_memlock_block(inode-i_sb, bp); + } + + progress += count; + buf += count; + length -= count; + blockoff = 0; + hole = 0; + } + +fail2: + retval = progress; +fail1: + kfree(tmp); +out
[PATCH 07/16 v3] pramfs: symbolic links
From: Marco Stornelli marco.storne...@gmail.com Symlink operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/symlink.c linux-2.6.36/fs/pramfs/symlink.c --- linux-2.6.36-orig/fs/pramfs/symlink.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/symlink.c2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,78 @@ +/* + * FILE NAME fs/pramfs/symlink.c + * + * BRIEF DESCRIPTION + * + * Symlink operations + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/fs.h +#include pram.h +#include xattr.h + +int pram_block_symlink(struct inode *inode, const char *symname, int len) +{ + struct super_block *sb = inode-i_sb; + u64 block; + char *blockp; + int err; + + err = pram_alloc_blocks(inode, 0, 1); + if (err) + return err; + + block = pram_find_data_block(inode, 0); + blockp = pram_get_block(sb, block); + + pram_memunlock_block(sb, blockp); + memcpy(blockp, symname, len); + blockp[len] = '\0'; + pram_memlock_block(sb, blockp); + return 0; +} + +static int pram_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + struct inode *inode = dentry-d_inode; + struct super_block *sb = inode-i_sb; + u64 block; + char *blockp; + + block = pram_find_data_block(inode, 0); + blockp = pram_get_block(sb, block); + return vfs_readlink(dentry, buffer, buflen, blockp); +} + +static void *pram_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct inode *inode = dentry-d_inode; + struct super_block *sb = inode-i_sb; + off_t block; + int status; + char *blockp; + + block = pram_find_data_block(inode, 0); + blockp = pram_get_block(sb, block); + status = vfs_follow_link(nd, blockp); + return ERR_PTR(status); +} + +struct inode_operations pram_symlink_inode_operations = { + .readlink = pram_readlink, + .follow_link= pram_follow_link, + .setattr= pram_notify_change, +#ifdef CONFIG_PRAMFS_XATTR + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = pram_listxattr, + .removexattr= generic_removexattr, +#endif +}; -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 08/16 v3] pramfs: headers
From: Marco Stornelli marco.storne...@gmail.com Definitions for the PRAMFS filesystem. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/pram.h linux-2.6.36/fs/pramfs/pram.h --- linux-2.6.36-orig/fs/pramfs/pram.h 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/pram.h 2010-10-30 12:02:45.0 +0200 @@ -0,0 +1,317 @@ +/* + * FILE NAME pram.h + * + * BRIEF DESCRIPTION + * + * Definitions for the PRAMFS filesystem. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ +#ifndef __PRAM_H +#define __PRAM_H + +#include linux/buffer_head.h +#include linux/pram_fs.h +#include linux/pram_fs_sb.h +#include linux/crc16.h +#include linux/mutex.h +#include linux/types.h + +/* + * Debug code + */ +#define pram_dbg(s, args...) pr_debug(PRAMFS: s, ## args) +#define pram_err(s, args...) pr_err(PRAMFS: s, ## args) +#define pram_warn(s, args...) pr_warning(PRAMFS: s, ## args) +#define pram_info(s, args...) pr_info(PRAMFS: s, ## args) + +/* Function Prototypes */ + +#ifdef CONFIG_PRAMFS_XIP + +#define pram_read xip_file_read +#define pram_write xip_file_write +#define pram_mmap xip_file_mmap +#define pram_aio_read NULL +#define pram_aio_write NULL +#define pram_readpage NULL +#define pram_direct_IO NULL + +#else + +#define pram_read do_sync_read +#define pram_write do_sync_write +#define pram_mmap __pram_mmap +#define pram_aio_read generic_file_aio_read +#define pram_aio_write generic_file_aio_write +#define pram_direct_IO __pram_direct_IO +#define pram_readpage __pram_readpage + +extern int pram_get_and_update_block(struct inode *inode, sector_t iblock, +struct buffer_head *bh, int create); + +static inline int __pram_readpage(struct file *file, struct page *page) +{ + return block_read_full_page(page, pram_get_and_update_block); +} + +/* file.c */ +extern ssize_t __pram_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs); +extern int __pram_mmap(struct file *file, struct vm_area_struct *vma); + +#endif /* CONFIG_PRAMFS_XIP */ + +#define pram_set_bit ext2_set_bit +#define pram_clear_bit ext2_clear_bit +#define pram_find_next_zero_bitext2_find_next_zero_bit + +/* balloc.c */ +extern void pram_init_bitmap(struct super_block *sb); +extern void pram_free_block(struct super_block *sb, unsigned long blocknr); +extern int pram_new_block(struct super_block *sb, unsigned long *blocknr, int zero); +extern unsigned long pram_count_free_blocks(struct super_block *sb); + +/* dir.c */ +extern int pram_add_link(struct dentry *dentry, struct inode *inode); +extern int pram_remove_link(struct inode *inode); + +/* namei.c */ +extern struct dentry *pram_get_parent(struct dentry *child); + +/* inode.c */ +extern int pram_alloc_blocks(struct inode *inode, int file_blocknr, int num); +extern u64 pram_find_data_block(struct inode *inode, +int file_blocknr); + +extern struct inode *pram_iget(struct super_block *sb, unsigned long ino); +extern void pram_put_inode(struct inode *inode); +extern void pram_evict_inode(struct inode *inode); +extern struct inode *pram_new_inode(struct inode *dir, int mode); +extern int pram_update_inode(struct inode *inode); +extern int pram_write_inode(struct inode *inode, struct writeback_control *wbc); +extern void pram_dirty_inode(struct inode *inode); +extern int pram_notify_change(struct dentry *dentry, struct iattr *attr); + + +/* super.c */ +#ifdef CONFIG_PRAMFS_TEST +extern struct pram_super_block *get_pram_super(void); +#endif +extern struct super_block *pram_read_super(struct super_block *sb, + void *data, + int silent); +extern int pram_statfs(struct dentry *d, struct kstatfs *buf); +extern int pram_remount(struct super_block *sb, int *flags, char *data); + +/* symlink.c */ +extern int pram_block_symlink(struct inode *inode, + const char *symname, int len); + + +#ifdef CONFIG_PRAMFS_WRITE_PROTECT +extern void pram_writeable(void *vaddr, unsigned long size, int rw); + +#define wrprotect(addr, size) pram_writeable(addr, size, 0) + +#else + +#define wrprotect(addr, size) do {} while (0) + +#endif /* CONFIG PRAMFS_WRITE_PROTECT */ + +/* Inline functions start here */ + +static inline int pram_calc_checksum(u8 *data, int n) +{ + u16 crc = 0; + crc = crc16(~0, (__u8 *)data + sizeof
[PATCH 09/16 v3] pramfs: dir operations
From: Marco Stornelli marco.storne...@gmail.com File operations for directories. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/dir.c linux-2.6.36/fs/pramfs/dir.c --- linux-2.6.36-orig/fs/pramfs/dir.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/dir.c2010-09-17 19:08:54.0 +0200 @@ -0,0 +1,215 @@ +/* + * FILE NAME fs/pramfs/dir.c + * + * BRIEF DESCRIPTION + * + * File operations for directories. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/fs.h +#include linux/pagemap.h +#include pram.h + +/* + * Parent is locked. + */ +int pram_add_link(struct dentry *dentry, struct inode *inode) +{ + struct inode *dir = dentry-d_parent-d_inode; + struct pram_inode *pidir, *pi, *pitail = NULL; + u64 tail_ino, prev_ino; + + const char *name = dentry-d_name.name; + + int namelen = dentry-d_name.len PRAM_NAME_LEN ? + PRAM_NAME_LEN : dentry-d_name.len; + + pidir = pram_get_inode(dir-i_sb, dir-i_ino); + pi = pram_get_inode(dir-i_sb, inode-i_ino); + + dir-i_mtime = dir-i_ctime = CURRENT_TIME; + + tail_ino = be64_to_cpu(pidir-i_type.dir.tail); + if (tail_ino != 0) { + pitail = pram_get_inode(dir-i_sb, tail_ino); + pram_memunlock_inode(pitail); + pitail-i_d.d_next = cpu_to_be64(inode-i_ino); + pram_memlock_inode(pitail); + + prev_ino = tail_ino; + + pram_memunlock_inode(pidir); + pidir-i_type.dir.tail = cpu_to_be64(inode-i_ino); + pidir-i_mtime = cpu_to_be32(dir-i_mtime.tv_sec); + pidir-i_ctime = cpu_to_be32(dir-i_ctime.tv_sec); + pram_memlock_inode(pidir); + } else { + /* the directory is empty */ + prev_ino = 0; + + pram_memunlock_inode(pidir); + pidir-i_type.dir.tail = cpu_to_be64(inode-i_ino); + pidir-i_type.dir.head = cpu_to_be64(inode-i_ino); + pidir-i_mtime = cpu_to_be32(dir-i_mtime.tv_sec); + pidir-i_ctime = cpu_to_be32(dir-i_ctime.tv_sec); + pram_memlock_inode(pidir); + } + + + pram_memunlock_inode(pi); + pi-i_d.d_prev = cpu_to_be64(prev_ino); + pi-i_d.d_parent = cpu_to_be64(dir-i_ino); + memcpy(pi-i_d.d_name, name, namelen); + pi-i_d.d_name[namelen] = '\0'; + pram_memlock_inode(pi); + return 0; +} + +int pram_remove_link(struct inode *inode) +{ + struct super_block *sb = inode-i_sb; + struct pram_inode *prev = NULL; + struct pram_inode *next = NULL; + struct pram_inode *pidir, *pi; + + pi = pram_get_inode(sb, inode-i_ino); + pidir = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_parent)); + if (!pidir) + return -EACCES; + + if (inode-i_ino == be64_to_cpu(pidir-i_type.dir.head)) { + /* first inode in directory */ + next = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_next)); + + if (next) { + pram_memunlock_inode(next); + next-i_d.d_prev = 0; + pram_memlock_inode(next); + + pram_memunlock_inode(pidir); + pidir-i_type.dir.head = pi-i_d.d_next; + } else { + pram_memunlock_inode(pidir); + pidir-i_type.dir.head = 0; + pidir-i_type.dir.tail = 0; + } + pram_memlock_inode(pidir); + } else if (inode-i_ino == be64_to_cpu(pidir-i_type.dir.tail)) { + /* last inode in directory */ + prev = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_prev)); + + pram_memunlock_inode(prev); + prev-i_d.d_next = 0; + pram_memlock_inode(prev); + + pram_memunlock_inode(pidir); + pidir-i_type.dir.tail = pi-i_d.d_prev; + pram_memlock_inode(pidir); + } else { + /* somewhere in the middle */ + prev = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_prev)); + next = pram_get_inode(sb, be64_to_cpu(pi-i_d.d_next)); + + if (prev next) { + pram_memunlock_inode(prev); + prev-i_d.d_next = pi-i_d.d_next; + pram_memlock_inode(prev); + + pram_memunlock_inode(next); + next-i_d.d_prev = pi-i_d.d_prev
[PATCH 10/16 v3] pramfs: XIP operations
From: Marco Stornelli marco.storne...@gmail.com XIP operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/xip.c linux-2.6.36/fs/pramfs/xip.c --- linux-2.6.36-orig/fs/pramfs/xip.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/xip.c2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,90 @@ +/* + * FILE NAME fs/pramfs/xip.c + * + * BRIEF DESCRIPTION + * + * XIP operations. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/mm.h +#include linux/fs.h +#include linux/genhd.h +#include linux/buffer_head.h +#include pram.h +#include xip.h + +static int pram_find_and_alloc_blocks(struct inode *inode, sector_t iblock, +sector_t *data_block, int create) +{ + int err = -EIO; + u64 block; + + mutex_lock(PRAM_I(inode)-truncate_mutex); + + block = pram_find_data_block(inode, iblock); + + if (!block) { + if (!create) { + err = -ENODATA; + goto err; + } + + err = pram_alloc_blocks(inode, iblock, 1); + if (err) + goto err; + + block = pram_find_data_block(inode, iblock); + if (!block) { + err = -ENODATA; + goto err; + } + } + + *data_block = block; + err = 0; + + err: + mutex_unlock(PRAM_I(inode)-truncate_mutex); + return err; +} + + +static int __pram_get_block(struct inode *inode, pgoff_t pgoff, int create, + sector_t *result) +{ + int rc = 0; + sector_t iblock; + + /* find starting block number to access */ + iblock = (sector_t)pgoff (PAGE_CACHE_SHIFT - inode-i_blkbits); + + rc = pram_find_and_alloc_blocks(inode, iblock, result, create); + + if (rc == -ENODATA) + BUG_ON(create); + + return rc; +} + +int pram_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, int create, + void **kmem, unsigned long *pfn) +{ + int rc; + sector_t block; + + /* first, retrieve the block */ + rc = __pram_get_block(mapping-host, pgoff, create, block); + if (rc) + goto exit; + + *kmem = pram_get_block(mapping-host-i_sb, block); + *pfn = page_to_pfn(virt_to_page((unsigned long)*kmem)); + +exit: + return rc; +} diff -Nurp linux-2.6.36-orig/fs/pramfs/xip.h linux-2.6.36/fs/pramfs/xip.h --- linux-2.6.36-orig/fs/pramfs/xip.h 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/xip.h2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,24 @@ +/* + * FILE NAME fs/pramfs/xip.h + * + * BRIEF DESCRIPTION + * + * XIP operations. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#ifdef CONFIG_PRAMFS_XIP + +int pram_get_xip_mem(struct address_space *, pgoff_t, int, void **, + unsigned long *); + +#else + +#define pram_get_xip_mem NULL + +#endif + -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 12/16 v3] pramfs: extended attributes
From: Marco Stornelli marco.storne...@gmail.com Extended attributes operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/xattr.c linux-2.6.36/fs/pramfs/xattr.c --- linux-2.6.36-orig/fs/pramfs/xattr.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/xattr.c 2010-09-14 19:45:40.0 +0200 @@ -0,0 +1,1108 @@ +/* + * FILE NAME fs/pramfs/xattr.c + * + * BRIEF DESCRIPTION + * + * Extended attributes operations. + * + * Copyright 2010 Marco Stornelli marco.storne...@gmail.com + * + * based on fs/ext2/xattr.c with the following copyright: + * + * Fix by Harrison Xing harri...@mountainviewdata.com. + * Extended attributes for symlinks and special files added per + * suggestion of Luka Renko luka.re...@hermes.si. + * xattr consolidation Copyright (c) 2004 James Morris jmor...@redhat.com, + * Red Hat Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +/* + * Extended attributes are stored in blocks allocated outside of + * any inode. The i_xattr field is then made to point to this allocated + * block. If all extended attributes of an inode are identical, these + * inodes may share the same extended attribute block. Such situations + * are automatically detected by keeping a cache of recent attribute block + * numbers and hashes over the block's contents in memory. + * + * + * Extended attribute block layout: + * + * +--+ + * | header | + * | entry 1 | | + * | entry 2 | | growing downwards + * | entry 3 | v + * | four null bytes | + * | . . .| + * | value 1 | ^ + * | value 3 | | growing upwards + * | value 2 | | + * +--+ + * + * The block header is followed by multiple entry descriptors. These entry + * descriptors are variable in size, and alligned to PRAM_XATTR_PAD + * byte boundaries. The entry descriptors are sorted by attribute name, + * so that two extended attribute blocks can be compared efficiently. + * + * Attribute values are aligned to the end of the block, stored in + * no specific order. They are also padded to PRAM_XATTR_PAD byte + * boundaries. No additional gaps are left between them. + * + * Locking strategy + * + * pi-i_xattr is protected by PRAM_I(inode)-xattr_sem. + * EA blocks are only changed if they are exclusive to an inode, so + * holding xattr_sem also means that nothing but the EA block's reference + * count will change. Multiple writers to an EA block are synchronized + * by the mutex in each block descriptor. Block descriptors are kept in a + * red black tree and the key is the absolute block number. + */ + +#include linux/module.h +#include linux/init.h +#include linux/mbcache.h +#include linux/rwsem.h +#include linux/security.h +#include pram.h +#include xattr.h +#include acl.h +#include desctree.h + +#define HDR(bp) ((struct pram_xattr_header *)(bp)) +#define ENTRY(ptr) ((struct pram_xattr_entry *)(ptr)) +#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) +#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) +#define GET_DESC(sbi, blocknr) lookup_xblock_desc(sbi, blocknr, pram_xblock_desc_cache, 1) +#define LOOKUP_DESC(sbi, blocknr) lookup_xblock_desc(sbi, blocknr, NULL, 0) + +#ifdef PRAM_XATTR_DEBUG +# define ea_idebug(inode, f...) do { \ + printk(KERN_DEBUG inode %ld: , inode-i_ino); \ + printk(f); \ + printk(\n); \ + } while (0) +# define ea_bdebug(blocknr, f...) do { \ + printk(KERN_DEBUG block %lu: , blocknr); \ + printk(f); \ + printk(\n); \ + } while (0) +#else +# define ea_idebug(f...) +# define ea_bdebug(f...) +#endif + +static int pram_xattr_set2(struct inode *, char *, struct pram_xblock_desc *, struct pram_xattr_header *); + +static int pram_xattr_cache_insert(struct super_block *sb, unsigned long blocknr, u32 xhash); +static struct pram_xblock_desc *pram_xattr_cache_find(struct inode *, +struct pram_xattr_header *); +static void pram_xattr_rehash(struct pram_xattr_header *, + struct pram_xattr_entry *); + +static struct mb_cache *pram_xattr_cache; +static struct kmem_cache *pram_xblock_desc_cache; + +static const struct xattr_handler *pram_xattr_handler_map[] = { + [PRAM_XATTR_INDEX_USER] = pram_xattr_user_handler, +#ifdef CONFIG_PRAMFS_POSIX_ACL + [PRAM_XATTR_INDEX_POSIX_ACL_ACCESS] = pram_xattr_acl_access_handler, + [PRAM_XATTR_INDEX_POSIX_ACL_DEFAULT] = pram_xattr_acl_default_handler, +#endif + [PRAM_XATTR_INDEX_TRUSTED] = pram_xattr_trusted_handler, +#ifdef CONFIG_PRAMFS_SECURITY + [PRAM_XATTR_INDEX_SECURITY] = pram_xattr_security_handler, +#endif +}; + +const
[PATCH 13/16 v3] pramfs: xattr attributes block descriptors tree
From: Marco Stornelli marco.storne...@gmail.com Extended attributes block descriptors tree. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/desctree.c linux-2.6.36/fs/pramfs/desctree.c --- linux-2.6.36-orig/fs/pramfs/desctree.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/desctree.c 2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,183 @@ +/* + * FILE NAME fs/pramfs/desctree.c + * + * BRIEF DESCRIPTION + * + * Extended attributes block descriptors tree. + * + * Copyright 2010 Marco Stornelli marco.storne...@gmail.com + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/spinlock.h +#include desctree.h +#include pram.h + +/* xblock_desc_init_always() + * + * These are initializations that need to be done on every + * descriptor allocation as the fields are not initialised + * by slab allocation. + */ +void xblock_desc_init_always(struct pram_xblock_desc *desc) +{ + atomic_set(desc-refcount, 0); + desc-blocknr = 0; + desc-flags = 0; +} + +/* xblock_desc_init_once() + * + * These are initializations that only need to be done + * once, because the fields are idempotent across use + * of the descriptor, so let the slab aware of that. + */ +void xblock_desc_init_once(struct pram_xblock_desc *desc) +{ + mutex_init(desc-lock); +} + +/* __insert_xblock_desc() + * + * Insert a new descriptor in the tree. + */ +static void __insert_xblock_desc(struct pram_sb_info *sbi, +unsigned long blocknr, struct rb_node *node) +{ + struct rb_node **p = (sbi-desc_tree.rb_node); + struct rb_node *parent = NULL; + struct pram_xblock_desc *desc; + + while (*p) { + parent = *p; + desc = rb_entry(parent, struct pram_xblock_desc, node); + + if (blocknr desc-blocknr) + p = (*p)-rb_left; + else if (blocknr desc-blocknr) + p = (*p)-rb_right; + else + /* Oops...an other descriptor for the same block ? */ + BUG(); + } + + rb_link_node(node, parent, p); + rb_insert_color(node, sbi-desc_tree); +} + +void insert_xblock_desc(struct pram_sb_info *sbi, struct pram_xblock_desc *desc) +{ + spin_lock(sbi-desc_tree_lock); + __insert_xblock_desc(sbi, desc-blocknr, desc-node); + spin_unlock(sbi-desc_tree_lock); +}; + +/* __lookup_xblock_desc() + * + * Search an extended attribute descriptor in the tree via the + * block number. It returns the descriptor if it's found or + * NULL. If not found it creates a new descriptor if create is not 0. + */ +static struct pram_xblock_desc *__lookup_xblock_desc(struct pram_sb_info *sbi, + unsigned long blocknr, + struct kmem_cache *cache, + int create) +{ + struct rb_node *n = sbi-desc_tree.rb_node; + struct pram_xblock_desc *desc = NULL; + + while (n) { + desc = rb_entry(n, struct pram_xblock_desc, node); + + if (blocknr desc-blocknr) + n = n-rb_left; + else if (blocknr desc-blocknr) + n = n-rb_right; + else { + atomic_inc(desc-refcount); + goto out; + } + } + + /* not found */ + if (create) { + desc = kmem_cache_alloc(cache, GFP_NOFS); + if (!desc) + return ERR_PTR(-ENOMEM); + xblock_desc_init_always(desc); + atomic_set(desc-refcount, 1); + desc-blocknr = blocknr; + __insert_xblock_desc(sbi, desc-blocknr, desc-node); + } +out: + return desc; +} + +struct pram_xblock_desc *lookup_xblock_desc(struct pram_sb_info *sbi, + unsigned long blocknr, + struct kmem_cache *cache, + int create) +{ + struct pram_xblock_desc *desc = NULL; + + spin_lock(sbi-desc_tree_lock); + desc = __lookup_xblock_desc(sbi, blocknr, cache, create); + spin_unlock(sbi-desc_tree_lock); + return desc; +} + +/* put_xblock_desc() + * + * Decrement the reference count and if it reaches zero and the + * desciptor has been marked to be free, then we free it. + * It returns 0 if the descriptor has been deleted and 1 otherwise. + */ +int put_xblock_desc(struct pram_sb_info *sbi, struct pram_xblock_desc *desc) +{ + int ret = 1; + if (!desc) + return ret; + + if (atomic_dec_and_lock(desc-refcount, sbi-desc_tree_lock
[PATCH 14/16 v3] pramfs: memory protection
From: Marco Stornelli marco.storne...@gmail.com Memory write protection. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/wprotect.c linux-2.6.36/fs/pramfs/wprotect.c --- linux-2.6.36-orig/fs/pramfs/wprotect.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/wprotect.c 2010-10-30 11:59:54.0 +0200 @@ -0,0 +1,41 @@ +/* + * FILE NAME fs/pramfs/wprotect.c + * + * BRIEF DESCRIPTION + * + * Write protection for the filesystem pages. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/module.h +#include linux/fs.h +#include linux/mm.h +#include linux/io.h +#include pram.h + +void pram_writeable(void *vaddr, unsigned long size, int rw) +{ + int ret = 0; + unsigned long nrpages = size PAGE_SHIFT; + unsigned long addr = (unsigned long)vaddr; + + /* Page aligned */ + addr = PAGE_MASK; + + if (size (PAGE_SIZE - 1)) + nrpages++; + + if (rw) + ret = set_memory_rw(addr, nrpages); + else + ret = set_memory_ro(addr, nrpages); + + BUG_ON(ret); +} -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 16/16 v3] pramfs: makefile and Kconfig
From: Marco Stornelli marco.storne...@gmail.com Makefile and Kconfig. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/Makefile linux-2.6.36/fs/Makefile --- linux-2.6.36-orig/fs/Makefile 2010-09-13 01:07:37.0 +0200 +++ linux-2.6.36/fs/Makefile2010-09-14 18:49:52.0 +0200 @@ -126,3 +126,4 @@ obj-$(CONFIG_BTRFS_FS) += btrfs/ obj-$(CONFIG_GFS2_FS) += gfs2/ obj-$(CONFIG_EXOFS_FS) += exofs/ obj-$(CONFIG_CEPH_FS) += ceph/ +obj-$(CONFIG_PRAMFS) += pramfs/ diff -Nurp linux-2.6.36-orig/fs/Kconfig linux-2.6.36/fs/Kconfig --- linux-2.6.36-orig/fs/Kconfig2010-09-13 01:07:37.0 +0200 +++ linux-2.6.36/fs/Kconfig 2010-09-14 18:49:52.0 +0200 @@ -13,7 +13,7 @@ source fs/ext4/Kconfig config FS_XIP # execute in place bool - depends on EXT2_FS_XIP + depends on EXT2_FS_XIP || PRAMFS_XIP default y source fs/jbd/Kconfig @@ -25,13 +25,14 @@ config FS_MBCACHE default y if EXT2_FS=y EXT2_FS_XATTR default y if EXT3_FS=y EXT3_FS_XATTR default y if EXT4_FS=y EXT4_FS_XATTR - default m if EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR + default y if PRAMFS=y PRAMFS_XATTR + default m if EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR || PRAMFS_XATTR source fs/reiserfs/Kconfig source fs/jfs/Kconfig config FS_POSIX_ACL -# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4) +# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4/pramfs) # # NOTE: you can implement Posix ACLs without these helpers (XFS does). # Never use this symbol for ifdefs. @@ -189,6 +190,7 @@ source fs/romfs/Kconfig source fs/sysv/Kconfig source fs/ufs/Kconfig source fs/exofs/Kconfig +source fs/pramfs/Kconfig endif # MISC_FILESYSTEMS diff -Nurp linux-2.6.36-orig/fs/pramfs/Kconfig linux-2.6.36/fs/pramfs/Kconfig --- linux-2.6.36-orig/fs/pramfs/Kconfig 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/Kconfig 2010-10-30 10:30:19.0 +0200 @@ -0,0 +1,72 @@ +config PRAMFS + tristate Persistent and Protected RAM file system support + depends on HAS_IOMEM EXPERIMENTAL + select CRC16 + help + If your system has a block of fast (comparable in access speed to + system memory) and non-volatile RAM and you wish to mount a + light-weight, full-featured, and space-efficient filesystem over it, + say Y here, and read file:Documentation/filesystems/pramfs.txt. + + To compile this as a module, choose M here: the module will be + called pramfs. + +config PRAMFS_XIP + bool Enable Execute-in-place in PRAMFS + depends on PRAMFS !PRAMFS_WRITE_PROTECT + help + Say Y here to enable XIP feature of PRAMFS. + +config PRAMFS_WRITE_PROTECT + bool Enable PRAMFS write protection + depends on PRAMFS MMU HAVE_SET_MEMORY_RO + default y + help + Say Y here to enable the write protect feature of PRAMFS. + +config PRAMFS_XATTR + bool PRAMFS extended attributes + depends on PRAMFS + help + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + http://acl.bestbits.at/ for details). + + If unsure, say N. + +config PRAMFS_POSIX_ACL + bool PRAMFS POSIX Access Control Lists + depends on PRAMFS_XATTR + select FS_POSIX_ACL + help + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website http://acl.bestbits.at/. + + If you don't know what Access Control Lists are, say N. + +config PRAMFS_SECURITY + bool PRAMFS Security Labels + depends on PRAMFS_XATTR + help + Security labels support alternative access control models + implemented by security modules like SELinux. This option + enables an extended attribute handler for file security + labels in the pram filesystem. + + If you are not using a security module that requires using + extended attributes for file security labels, say N. + +config PRAMFS_TEST + boolean + depends on PRAMFS + +config PRAMFS_TEST_MODULE + tristate PRAMFS Test + depends on PRAMFS m + select PRAMFS_TEST + help + Say Y here to build a simple module to test the protection of + PRAMFS. The module will be called pramfs_test. diff -Nurp linux-2.6.36-orig/fs/pramfs/Makefile linux-2.6.36/fs/pramfs/Makefile --- linux-2.6.36-orig/fs/pramfs/Makefile1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/Makefile 2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,14 @@ +# +# Makefile
[PATCH 15/16 v3] pramfs: test module
From: Marco Stornelli marco.storne...@gmail.com Test module. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/pramfs_test.c linux-2.6.36/fs/pramfs/pramfs_test.c --- linux-2.6.36-orig/fs/pramfs/pramfs_test.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/pramfs_test.c2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,49 @@ +/* + * FILE NAME fs/pramfs/pramfs_test.c + * + * BRIEF DESCRIPTION + * + * Pramfs test module. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ +#include linux/module.h +#include linux/version.h +#include linux/init.h +#include linux/fs.h +#include pram.h + +int __init test_pramfs_write(void) +{ + struct pram_super_block *psb; + + psb = get_pram_super(); + if (!psb) { + printk(KERN_ERR + %s: PRAMFS super block not found (not mounted?)\n, + __func__); + return 1; + } + + /* +* Attempt an unprotected clear of checksum information in the +* superblock, this should cause a kernel page protection fault. +*/ + printk(%s: writing to kernel VA %p\n, __func__, psb); + psb-s_sum = 0; + + return 0; +} + +void test_pramfs_write_cleanup(void) {} + +/* Module information */ +MODULE_LICENSE(GPL); +module_init(test_pramfs_write); +module_exit(test_pramfs_write_cleanup); -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/16 v3] pramfs: super operations
2010/11/15 yidong zhang zhang...@gmail.com: hi Marco + retval = 0; + out: + if (retval sbi-virt_addr) { + iounmap(sbi-virt_addr); + release_mem_region(sbi-phys_addr, initsize); + kfree(sbi); + } + + return retval; +} + I think kfree(sbi) should not be put here. In case of pram_parse_options failure, sbi should also be freed too. How about change it to the list below? And change some “goto out” branches to “goto out_free”. // retval = 0; return 0; out: if (retval sbi-virt_addr) { iounmap(sbi-virt_addr); release_mem_region(sbi-phys_addr, initsize); } out_free: kfree(sbi); return retval; } Yeah, you're right. It's not always true that virt addr is valid, kfree should be used out of this if. I'll fix it. Marco -- To unsubscribe from this list: send the line unsubscribe linux-embedded in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 01/16 v4] pramfs: documentation
From: Marco Stornelli marco.storne...@gmail.com Documentation for PRAMFS. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/Documentation/filesystems/pramfs.txt linux-2.6.36/Documentation/filesystems/pramfs.txt --- linux-2.6.36-orig/Documentation/filesystems/pramfs.txt 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/Documentation/filesystems/pramfs.txt 2010-10-23 09:04:32.0 +0200 @@ -0,0 +1,296 @@ + +PRAMFS Overview +=== + +Many embedded systems have a block of non-volatile RAM separate from +normal system memory, i.e. of which the kernel maintains no memory page +descriptors. For such systems it would be beneficial to mount a +fast read/write filesystem over this I/O memory, for storing frequently +accessed data that must survive system reboots and power cycles. An +example usage might be system logs under /var/log, or a user address +book in a cell phone or PDA. + +Linux traditionally had no support for a persistent, non-volatile RAM-based +filesystem, persistent meaning the filesystem survives a system reboot +or power cycle intact. The RAM-based filesystems such as tmpfs and ramfs +have no actual backing store but exist entirely in the page and buffer +caches, hence the filesystem disappears after a system reboot or +power cycle. + +A relatively straightforward solution is to write a simple block driver +for the non-volatile RAM, and mount over it any disk-based filesystem such +as ext2, ext3, ext4, etc. + +But the disk-based fs over non-volatile RAM block driver approach has +some drawbacks: + +1. Complexity of disk-based fs: disk-based filesystems such as ext2/ext3/ext4 + were designed for optimum performance on spinning disk media, so they + implement features such as block groups, which attempts to group inode data + into a contiguous set of data blocks to minimize disk seeking when accessing + files. For RAM there is no such concern; a file's data blocks can be + scattered throughout the media with no access speed penalty at all. So block + groups in a filesystem mounted over RAM just adds unnecessary + complexity. A better approach is to use a filesystem specifically + tailored to RAM media which does away with these disk-based features. + This increases the efficient use of space on the media, i.e. more + space is dedicated to actual file data storage and less to meta-data + needed to maintain that file data. + +2. Different problems between disks and RAM: Because PRAMFS attempts to avoid + filesystem corruption caused by kernel bugs, dirty pages in the page cache + are not allowed to be written back to the backing-store RAM. This way, an + errant write into the page cache will not get written back to the filesystem. + However, if the backing-store RAM is comparable in access speed to system + memory, the penalty of not using caching is minimal. With this consideration + it's better to move file data directly between the user buffers and the backing + store RAM, i.e. use direct I/O. This prevents the unnecessary populating of + the page cache with dirty pages. However direct I/O has to be enabled at + every file open. To enable direct I/O at all times for all regular files + requires either that applications be modified to include the O_DIRECT flag on + all file opens, or that the filesystem used performs direct I/O by default. + +The Persistent/Protected RAM Special Filesystem (PRAMFS) is a read/write +filesystem that has been designed to address these issues. PRAMFS is targeted +to fast I/O memory, and if the memory is non-volatile, the filesystem will be +persistent. + +In PRAMFS, direct I/O is enabled across all files in the filesystem, in other +words the O_DIRECT flag is forced on every open of a PRAMFS file. Also, file +I/O in the PRAMFS is always synchronous. There is no need to block the current +process while the transfer to/from the PRAMFS is in progress, since one of +the requirements of the PRAMFS is that the filesystem exists in fast RAM. So +file I/O in PRAMFS is always direct, synchronous, and never blocks. + +The data organization in PRAMFS can be thought of as an extremely simplified +version of ext2, such that the ratio of data to meta-data is very high. + +PRAMFS supports the execute-in-place. With XIP, instead of keeping data in the +page cache, the need to have a page cache copy is eliminated completely. +Readwrite type operations are performed directly from/to the memory. For file +mappings, the RAM itself is mapped directly into userspace. XIP, in addition, +speed up the applications start-up time because it removes the needs of any +copies. + +PRAMFS is write protected. The page table entries that map the backing-store +RAM are normally marked read-only. Write operations into the filesystem +temporarily mark the affected pages as writeable, the write operation is +carried out with locks held, and then the page table entries is +marked read-only
[PATCH 03/26 v4] pramfs: inode operations
From: Marco Stornelli marco.storne...@gmail.com Inode methods (allocate/free/read/write). Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/inode.c linux-2.6.36/fs/pramfs/inode.c --- linux-2.6.36-orig/fs/pramfs/inode.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/inode.c 2010-09-26 18:04:38.0 +0200 @@ -0,0 +1,710 @@ +/* + * FILE NAME fs/pramfs/inode.c + * + * BRIEF DESCRIPTION + * + * Inode methods (allocate/free/read/write). + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/fs.h +#include linux/smp_lock.h +#include linux/sched.h +#include linux/highuid.h +#include linux/quotaops.h +#include linux/module.h +#include linux/mpage.h +#include linux/backing-dev.h +#include pram.h +#include xattr.h +#include xip.h +#include acl.h + +struct backing_dev_info pram_backing_dev_info __read_mostly = { + .ra_pages = 0,/* No readahead */ + .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, +}; + +/* + * allocate a data block for inode and return it's absolute blocknr. + * Zeroes out the block if zero set. Increments inode-i_blocks. + */ +static int pram_new_data_block(struct inode *inode, unsigned long *blocknr, int zero) +{ + int errval = pram_new_block(inode-i_sb, blocknr, zero); + + if (!errval) { + struct pram_inode *pi = pram_get_inode(inode-i_sb, + inode-i_ino); + inode-i_blocks++; + pram_memunlock_inode(pi); + pi-i_blocks = cpu_to_be32(inode-i_blocks); + pram_memlock_inode(pi); + } + + return errval; +} + +/* + * find the offset to the block represented by the given inode's file + * relative block number. + */ +u64 pram_find_data_block(struct inode *inode, int file_blocknr) +{ + struct super_block *sb = inode-i_sb; + struct pram_inode *pi; + u64 *row; /* ptr to row block */ + u64 *col; /* ptr to column blocks */ + u64 bp = 0; + int i_row, i_col; + int N = sb-s_blocksize 3; /* num block ptrs per block */ + int Nbits = sb-s_blocksize_bits - 3; + + pi = pram_get_inode(sb, inode-i_ino); + + i_row = file_blocknr Nbits; + i_col = file_blocknr (N-1); + + row = pram_get_block(sb, be64_to_cpu(pi-i_type.reg.row_block)); + if (row) { + col = pram_get_block(sb, be64_to_cpu(row[i_row])); + if (col) + bp = be64_to_cpu(col[i_col]); + } + + return bp; +} + +/* + * Free data blocks from inode in the range start = end + */ +static void __pram_truncate_blocks(struct inode *inode, loff_t start, loff_t end) +{ + struct super_block *sb = inode-i_sb; + struct pram_inode *pi = pram_get_inode(sb, inode-i_ino); + int N = sb-s_blocksize 3; /* num block ptrs per block */ + int Nbits = sb-s_blocksize_bits - 3; + int first_row_index, last_row_index, i, j; + unsigned long blocknr, first_blocknr, last_blocknr; + unsigned int freed = 0; + u64 *row; /* ptr to row block */ + u64 *col; /* ptr to column blocks */ + + if (start end || !inode-i_blocks || !pi-i_type.reg.row_block) + return; + + mutex_lock(PRAM_I(inode)-truncate_mutex); + + first_blocknr = (start + sb-s_blocksize - 1) sb-s_blocksize_bits; + last_blocknr = (end + sb-s_blocksize - 1) sb-s_blocksize_bits; + first_row_index = first_blocknr Nbits; + last_row_index = last_blocknr Nbits; + + row = pram_get_block(sb, be64_to_cpu(pi-i_type.reg.row_block)); + + for (i = first_row_index; i = last_row_index; i++) { + int first_col_index = (i == first_row_index) ? + first_blocknr (N-1) : 0; + int last_col_index = (i == last_row_index) ? + last_blocknr (N-1) : N-1; + + if (unlikely(!row[i])) + continue; + + col = pram_get_block(sb, be64_to_cpu(row[i])); + + for (j = first_col_index; j = last_col_index; j++) { + + if (unlikely(!col[j])) + continue; + + blocknr = pram_get_blocknr(sb, be64_to_cpu(col[j])); + pram_free_block(sb, blocknr); + freed++; + pram_memunlock_block(sb, col); + col[j] = 0; + pram_memlock_block(sb, col); + } + + if (first_col_index == 0
[PATCH 04/16 v4] pramfs: file operations
From: Marco Stornelli marco.storne...@gmail.com File operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/file.c linux-2.6.36/fs/pramfs/file.c --- linux-2.6.36-orig/fs/pramfs/file.c 1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/file.c 2010-09-24 18:34:03.0 +0200 @@ -0,0 +1,166 @@ +/* + * FILE NAME fs/pramfs/file.c + * + * BRIEF DESCRIPTION + * + * File operations for files. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ +#include linux/fs.h +#include linux/sched.h +#include linux/slab.h +#include linux/uio.h +#include linux/mm.h +#include linux/uaccess.h +#include pram.h +#include acl.h +#include xip.h +#include xattr.h + +static int pram_open_file(struct inode *inode, struct file *filp) +{ +#ifndef CONFIG_PRAMFS_XIP + /* Without XIP we force to use Direct IO */ + filp-f_flags |= O_DIRECT; +#endif + return generic_file_open(inode, filp); +} + +ssize_t __pram_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +{ + struct file *file = iocb-ki_filp; + struct inode *inode = file-f_mapping-host; + struct super_block *sb = inode-i_sb; + int progress = 0, hole = 0; + ssize_t retval = 0; + void *tmp = NULL; + unsigned long blocknr, blockoff; + int num_blocks, blocksize_mask, blocksize, blocksize_bits; + char __user *buf = iov-iov_base; + size_t length = iov_length(iov, nr_segs); + + if (length 0) + return -EINVAL; + if ((rw == READ) (offset + length inode-i_size)) + length = inode-i_size - offset; + if (!length) + goto out; + + blocksize_bits = inode-i_sb-s_blocksize_bits; + blocksize = 1 blocksize_bits; + blocksize_mask = blocksize - 1; + + /* find starting block number to access */ + blocknr = offset blocksize_bits; + /* find starting offset within starting block */ + blockoff = offset blocksize_mask; + /* find number of blocks to access */ + num_blocks = (blockoff + length + blocksize_mask) blocksize_bits; + + if (rw == WRITE) { + /* prepare a temporary buffer to hold a user data block + for writing. */ + tmp = kmalloc(blocksize, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + /* now allocate the data blocks we'll need */ + retval = pram_alloc_blocks(inode, blocknr, num_blocks); + if (retval) + goto fail1; + } + + while (length) { + int count; + u8 *bp = NULL; + u64 block = pram_find_data_block(inode, blocknr++); + if (unlikely(!block rw == READ)) { + /* We are falling in a hole */ + hole = 1; + } else { + bp = (u8 *)pram_get_block(sb, block); + if (!bp) + goto fail2; + } + + count = blockoff + length blocksize ? + blocksize - blockoff : length; + + if (rw == READ) { + if (unlikely(hole)) { + retval = clear_user(buf, count); + if (retval) { + retval = -EFAULT; + goto fail1; + } + } else { + retval = copy_to_user(buf, bp[blockoff], count); + if (retval) { + retval = -EFAULT; + goto fail1; + } + } + } else { + retval = copy_from_user(tmp, buf, count); + if (retval) { + retval = -EFAULT; + goto fail1; + } + + pram_memunlock_block(inode-i_sb, bp); + memcpy(bp[blockoff], tmp, count); + pram_memlock_block(inode-i_sb, bp); + } + + progress += count; + buf += count; + length -= count; + blockoff = 0; + hole = 0; + } + +fail2: + retval = progress; +fail1: + kfree(tmp); +out
[PATCH 05/16 v4] pramfs: block allocation
From: Marco Stornelli marco.storne...@gmail.com Block allocation operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- diff -Nurp linux-2.6.36-orig/fs/pramfs/balloc.c linux-2.6.36/fs/pramfs/balloc.c --- linux-2.6.36-orig/fs/pramfs/balloc.c1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/balloc.c 2010-09-26 18:05:06.0 +0200 @@ -0,0 +1,149 @@ +/* + * FILE NAME fs/pramfs/balloc.c + * + * BRIEF MODULE DESCRIPTION + * + * The blocks allocation and deallocation routines. + * + * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com + * Copyright 2003 Sony Corporation + * Copyright 2003 Matsushita Electric Industrial Co., Ltd. + * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed as is without any + * warranty of any kind, whether express or implied. + */ + +#include linux/fs.h +#include linux/bitops.h +#include pram.h + +/* + * This just marks in-use the blocks that make up the bitmap. + * The bitmap must be writeable before calling. + */ +void pram_init_bitmap(struct super_block *sb) +{ + struct pram_super_block *ps = pram_get_super(sb); + unsigned long *bitmap = pram_get_bitmap(sb); + int blocks = be32_to_cpu(ps-s_bitmap_blocks); + + memset(bitmap, 0, blocks sb-s_blocksize_bits); + + bitmap_set(bitmap, 0, blocks); +} + + +/* Free absolute blocknr */ +void pram_free_block(struct super_block *sb, unsigned long blocknr) +{ + struct pram_super_block *ps; + u64 bitmap_block; + unsigned long bitmap_bnr; + void *bitmap; + void *bp; + + lock_super(sb); + + bitmap = pram_get_bitmap(sb); + /* +* find the block within the bitmap that contains the inuse bit +* for the block we need to free. We need to unlock this bitmap +* block to clear the inuse bit. +*/ + bitmap_bnr = blocknr (3 + sb-s_blocksize_bits); + bitmap_block = pram_get_block_off(sb, bitmap_bnr); + bp = pram_get_block(sb, bitmap_block); + + pram_memunlock_block(sb, bp); + pram_clear_bit(blocknr, bitmap); /* mark the block free */ + pram_memlock_block(sb, bp); + + ps = pram_get_super(sb); + pram_memunlock_super(ps); + if (blocknr be32_to_cpu(ps-s_free_blocknr_hint)) + ps-s_free_blocknr_hint = cpu_to_be32(blocknr); + be32_add_cpu(ps-s_free_blocks_count, 1); + pram_memlock_super(ps); + + unlock_super(sb); +} + + +/* + * allocate a block and return it's absolute blocknr. Zeroes out the + * block if zero set. + */ +int pram_new_block(struct super_block *sb, unsigned long *blocknr, int zero) +{ + struct pram_super_block *ps; + u64 bitmap_block; + unsigned long bnr, bitmap_bnr; + int errval; + void *bitmap; + void *bp; + + lock_super(sb); + ps = pram_get_super(sb); + bitmap = pram_get_bitmap(sb); + + if (ps-s_free_blocks_count) { + /* find the oldest unused block */ + bnr = pram_find_next_zero_bit(bitmap, +be32_to_cpu(ps-s_blocks_count), +be32_to_cpu(ps-s_free_blocknr_hint)); + + if (bnr be32_to_cpu(ps-s_bitmap_blocks) || + bnr = be32_to_cpu(ps-s_blocks_count)) { + pram_err(no free blocks found!\n); + errval = -ENOSPC; + goto fail; + } + + pram_dbg(allocating blocknr %lu\n, bnr); + pram_memunlock_super(ps); + be32_add_cpu(ps-s_free_blocks_count, -1); + if (bnr (be32_to_cpu(ps-s_blocks_count)-1)) + ps-s_free_blocknr_hint = cpu_to_be32(bnr+1); + else + ps-s_free_blocknr_hint = 0; + pram_memlock_super(ps); + } else { + pram_err(all blocks allocated\n); + errval = -ENOSPC; + goto fail; + } + + /* +* find the block within the bitmap that contains the inuse bit +* for the unused block we just found. We need to unlock it to +* set the inuse bit. +*/ + bitmap_bnr = bnr (3 + sb-s_blocksize_bits); + bitmap_block = pram_get_block_off(sb, bitmap_bnr); + bp = pram_get_block(sb, bitmap_block); + + pram_memunlock_block(sb, bp); + pram_set_bit(bnr, bitmap); /* mark the new block in use */ + pram_memlock_block(sb, bp); + + if (zero) { + bp = pram_get_block(sb, pram_get_block_off(sb, bnr)); + pram_memunlock_block(sb, bp); + memset(bp, 0, sb-s_blocksize); + pram_memlock_block(sb, bp); + } + + *blocknr = bnr; + pram_dbg(allocated blocknr %lu, bnr); + errval = 0; + fail