* Re: New elinux.org mailing lists
From: David Anders @ 2008-08-20 2:31 UTC (permalink / raw)
To: linux-embedded, Bill Traynor
In-Reply-To: <0c62747a6e9b254692b71bbe55f82510.squirrel@www.geekisp.com>
bill aka wmat,
could you add something for hacking news? maybe something like device-hacking@elinux.org ?
i think this would be good to use for things like the zipit and news of cheap devices for hacking.
dave aka prpplague
--- On Tue, 8/19/08, Bill Traynor <wmat@naoi.ca> wrote:
> From: Bill Traynor <wmat@naoi.ca>
> Subject: New elinux.org mailing lists
> To: linux-embedded@vger.kernel.org
> Date: Tuesday, August 19, 2008, 2:56 PM
> I've added a few mailing lists to elinux.org at
> http://elinux.org/ELinuxWiki:Mailing_List
>
> "Announce" is the ubiquitous announce list and
> will be extremely low traffic.
> "wiki-dev" is for anyone interested in the
> content/functionality of the wiki.
> "discuss" is for everything else.
>
> The "discuss" list is probably most applicable to
> the linux-embedded
> audience and will be dedicated to topics that would
> otherwise not be
> applicable to this list, such as detailed discussion about
> particular
> devices, and or non-kernel specific topics.
>
> Thanks
> Bill
> --
> To unsubscribe from this list: send the line
> "unsubscribe linux-embedded" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at
> http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Adding a new platform
From: Paul Gortmaker @ 2008-08-20 3:19 UTC (permalink / raw)
To: David VomLehn; +Cc: Ralf Baechle, Linux Embedded Maillist, corbet
In-Reply-To: <48AB0A7A.8040209@cisco.com>
On Tue, Aug 19, 2008 at 2:01 PM, David VomLehn <dvomlehn@cisco.com> wrote:
> I'm working to educate our management on the need to get our platform in the
> kernel mainline. I expect I will be asked to tell them how much work this
> is. What do we need to do to add a new MIPS platform?
Based on the phrase "educate our management" -- I would strongly suggest you
have a look at Jonathan Corbet's document that describes the process and the
eventual value-add of having things in-kernel -- with an audience of non-kernel
hackers in mind. I think this will really assist you in your efforts,
and I'm glad that
Jonathan put the time into this that he did.
His original post can be viewed here:
http://lkml.org/lkml/2008/7/29/363
or here:
http://lwn.net/Articles/291967/
Paul.
> --
> David VomLehn
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-embedded" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: New elinux.org mailing lists
From: Bill Traynor @ 2008-08-20 3:42 UTC (permalink / raw)
To: dave123_aml; +Cc: linux-embedded
In-Reply-To: <188734.8313.qm@web54402.mail.yahoo.com>
David Anders wrote:
> bill aka wmat,
>
> could you add something for hacking news? maybe something like device-hacking@elinux.org ?
>
> i think this would be good to use for things like the zipit and news of cheap devices for hacking.
>
Couldn't we just use the discuss list for these things?
> dave aka prpplague
>
>
>
>
>
> --- On Tue, 8/19/08, Bill Traynor <wmat@naoi.ca> wrote:
>
>
>> From: Bill Traynor <wmat@naoi.ca>
>> Subject: New elinux.org mailing lists
>> To: linux-embedded@vger.kernel.org
>> Date: Tuesday, August 19, 2008, 2:56 PM
>> I've added a few mailing lists to elinux.org at
>> http://elinux.org/ELinuxWiki:Mailing_List
>>
>> "Announce" is the ubiquitous announce list and
>> will be extremely low traffic.
>> "wiki-dev" is for anyone interested in the
>> content/functionality of the wiki.
>> "discuss" is for everything else.
>>
>> The "discuss" list is probably most applicable to
>> the linux-embedded
>> audience and will be dedicated to topics that would
>> otherwise not be
>> applicable to this list, such as detailed discussion about
>> particular
>> devices, and or non-kernel specific topics.
>>
>> Thanks
>> Bill
>> --
>> To unsubscribe from this list: send the line
>> "unsubscribe linux-embedded" in
>> the body of a message to majordomo@vger.kernel.org
>> 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 majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: Adding a new platform
From: vb @ 2008-08-20 3:57 UTC (permalink / raw)
To: Paul Gortmaker; +Cc: Linux Embedded Maillist, corbet
In-Reply-To: <7d1d9c250808192019g6ec73ec7x53563b8ad2130df@mail.gmail.com>
On Tue, Aug 19, 2008 at 8:19 PM, Paul Gortmaker
<paul.gortmaker@gmail.com> wrote:
> On Tue, Aug 19, 2008 at 2:01 PM, David VomLehn <dvomlehn@cisco.com> wrote:
>> I'm working to educate our management on the need to get our platform in the
>> kernel mainline. I expect I will be asked to tell them how much work this
>> is. What do we need to do to add a new MIPS platform?
>
> Based on the phrase "educate our management" -- I would strongly suggest you
> have a look at Jonathan Corbet's document that describes the process and the
> eventual value-add of having things in-kernel -- with an audience of non-kernel
> hackers in mind. I think this will really assist you in your efforts,
> and I'm glad that
> Jonathan put the time into this that he did.
>
> His original post can be viewed here:
>
> http://lkml.org/lkml/2008/7/29/363
>
> or here:
>
> http://lwn.net/Articles/291967/
>
This indeed is a very interesting document. I can hardly agree with
the below point, however:
+- While kernel developers strive to maintain a stable interface to user
+ space, the internal kernel API is in constant flux. The lack of a stable
+ internal interface is a deliberate design decision; it allows fundamental
+ improvements to be made at any time and results in higher-quality code.
+ But one result of that policy is that any out-of-tree code requires
+ constant upkeep if it is to work with new kernels. Maintaining
+ out-of-tree code requires significant amounts of work just to keep that
+ code working.
so, say a developer submits a proprietary driver and it gets accepted.
Then some internal kernel interface gets changed. Who now has to
modify and retest the driver? Is it the person who introduces the
change (how can he even do this, as he does not have the proprietary
hardware available)? Or is this the original submitter - then where is
the benefit of saving on upkeep?
This constant change of the kernel innards is hardly a good selling
point, would you agree?
cheers,
/vb
^ permalink raw reply
* Re: Adding a new platform
From: Paul Gortmaker @ 2008-08-20 4:29 UTC (permalink / raw)
To: vb; +Cc: Linux Embedded Maillist, corbet
In-Reply-To: <f608b67d0808192057w29988500o2793dfb7f0c99314@mail.gmail.com>
On Tue, Aug 19, 2008 at 11:57 PM, vb <vb@vsbe.com> wrote:
> On Tue, Aug 19, 2008 at 8:19 PM, Paul Gortmaker
> <paul.gortmaker@gmail.com> wrote:
>> On Tue, Aug 19, 2008 at 2:01 PM, David VomLehn <dvomlehn@cisco.com> wrote:
>>> I'm working to educate our management on the need to get our platform in the
>>> kernel mainline. I expect I will be asked to tell them how much work this
>>> is. What do we need to do to add a new MIPS platform?
>>
>> Based on the phrase "educate our management" -- I would strongly suggest you
>> have a look at Jonathan Corbet's document that describes the process and the
>> eventual value-add of having things in-kernel -- with an audience of non-kernel
>> hackers in mind. I think this will really assist you in your efforts,
>> and I'm glad that
>> Jonathan put the time into this that he did.
>>
>> His original post can be viewed here:
>>
>> http://lkml.org/lkml/2008/7/29/363
>>
>> or here:
>>
>> http://lwn.net/Articles/291967/
>>
>
> This indeed is a very interesting document. I can hardly agree with
> the below point, however:
>
> +- While kernel developers strive to maintain a stable interface to user
> + space, the internal kernel API is in constant flux. The lack of a stable
> + internal interface is a deliberate design decision; it allows fundamental
> + improvements to be made at any time and results in higher-quality code.
> + But one result of that policy is that any out-of-tree code requires
> + constant upkeep if it is to work with new kernels. Maintaining
> + out-of-tree code requires significant amounts of work just to keep that
> + code working.
>
> so, say a developer submits a proprietary driver and it gets accepted.
Doesn't happen. By design. If the driver is proprietary then it is presumably
not meant for open distribution, and hence not compatible with GPL and
widespread distribution into 100,000 public git repositories. So it won't
get submitted and it won't get accepted.
> Then some internal kernel interface gets changed. Who now has to
> modify and retest the driver? Is it the person who introduces the
> change (how can he even do this, as he does not have the proprietary
> hardware available)? Or is this the original submitter - then where is
> the benefit of saving on upkeep?
I'd suggest you feed google "stable API nonsense" and continue reading
from there if you are interested in the topic.
Paul.
>
> This constant change of the kernel innards is hardly a good selling
> point, would you agree?
>
> cheers,
> /vb
>
^ permalink raw reply
* Re: Adding a new platform
From: Paul Mundt @ 2008-08-20 4:44 UTC (permalink / raw)
To: vb; +Cc: Paul Gortmaker, Linux Embedded Maillist, corbet
In-Reply-To: <f608b67d0808192057w29988500o2793dfb7f0c99314@mail.gmail.com>
On Tue, Aug 19, 2008 at 08:57:59PM -0700, vb wrote:
> On Tue, Aug 19, 2008 at 8:19 PM, Paul Gortmaker
> <paul.gortmaker@gmail.com> wrote:
> > On Tue, Aug 19, 2008 at 2:01 PM, David VomLehn <dvomlehn@cisco.com> wrote:
> >> I'm working to educate our management on the need to get our platform in the
> >> kernel mainline. I expect I will be asked to tell them how much work this
> >> is. What do we need to do to add a new MIPS platform?
> >
> > Based on the phrase "educate our management" -- I would strongly suggest you
> > have a look at Jonathan Corbet's document that describes the process and the
> > eventual value-add of having things in-kernel -- with an audience of non-kernel
> > hackers in mind. I think this will really assist you in your efforts,
> > and I'm glad that
> > Jonathan put the time into this that he did.
> >
> > His original post can be viewed here:
> >
> > http://lkml.org/lkml/2008/7/29/363
> >
> > or here:
> >
> > http://lwn.net/Articles/291967/
> >
>
> This indeed is a very interesting document. I can hardly agree with
> the below point, however:
>
> +- While kernel developers strive to maintain a stable interface to user
> + space, the internal kernel API is in constant flux. The lack of a stable
> + internal interface is a deliberate design decision; it allows fundamental
> + improvements to be made at any time and results in higher-quality code.
> + But one result of that policy is that any out-of-tree code requires
> + constant upkeep if it is to work with new kernels. Maintaining
> + out-of-tree code requires significant amounts of work just to keep that
> + code working.
>
> so, say a developer submits a proprietary driver and it gets accepted.
This doesn't make any sense to begin with. It's not possible to merge a
proprietary driver in to the kernel. If you're talking about a GPLed
driver, then the word proprietary here is meaningless (ie, whether
hardware is widely available or not is not a concern as long as someone
is actively looking after the code). On the other hand, if you are
talking about an out-of-tree driver, then the maintenance burden is
purely on whoever is maintaining that.
> Then some internal kernel interface gets changed. Who now has to
> modify and retest the driver? Is it the person who introduces the
> change (how can he even do this, as he does not have the proprietary
> hardware available)? Or is this the original submitter - then where is
> the benefit of saving on upkeep?
>
In the general case, interface changes are done carefully, and in-tree
users are converted over as to minimize breakage. Obviously whoever is
making the change is not going to be able to test each driver, so it
usually comes down to common sense. If there's something that's
potentially problematic for a given driver, then testing is solicited
from those that have a vested interest in the continued functionality of
said driver. Likewise, if the change goes in and breaks things, that's a
regression, and is usually reverted or quickly fixed once it's been
identified. People that habitually cause regressions will suddenly find
it much more difficult to get anything applied to the kernel, it's fairly
self-regulating.
People don't inherently go out of their way to break others code, but it
certainly does happen. The main thing is that we have a pretty good
process in place to handle those sorts of problems as they come up, so
there's generally no reason _not_ to keep things changing.
On the embedded side there is obviously the issue that some people will
only test things once or twice a year, but at that level of active
involvement, they may as well just do all of their things out-of-tree
instead.
> This constant change of the kernel innards is hardly a good selling
> point, would you agree?
>
No, but there are others that might. Have you considered BSD?
^ permalink raw reply
* Re: Adding a new platform
From: vb @ 2008-08-20 5:15 UTC (permalink / raw)
To: Paul Gortmaker; +Cc: Linux Embedded Maillist, corbet
In-Reply-To: <7d1d9c250808192129j3fb7ef28p8f404c6affd82078@mail.gmail.com>
On Tue, Aug 19, 2008 at 9:29 PM, Paul Gortmaker
<paul.gortmaker@gmail.com> wrote:
> On Tue, Aug 19, 2008 at 11:57 PM, vb <vb@vsbe.com> wrote:
>>
>> so, say a developer submits a proprietary driver and it gets accepted.
>
> Doesn't happen. By design. If the driver is proprietary then it is presumably
> not meant for open distribution, and hence not compatible with GPL and
> widespread distribution into 100,000 public git repositories. So it won't
> get submitted and it won't get accepted.
>
I guess 'proprietary' is not the right term then, how do you call a
driver which is not a secret and not a problem to release, but
controls some hardware present in only in certain devices of a certain
company.
Would such a driver be accepted? Wouldn't such a driver get stale
after a few kernel releases?
^ permalink raw reply
* Re: Adding a new platform
From: Haavard Skinnemoen @ 2008-08-20 8:10 UTC (permalink / raw)
To: vb; +Cc: Paul Gortmaker, Linux Embedded Maillist, corbet
In-Reply-To: <f608b67d0808192215q5b8ffbf0w70531c31cdd66bcd@mail.gmail.com>
vb <vb@vsbe.com> wrote:
> Would such a driver be accepted? Wouldn't such a driver get stale
> after a few kernel releases?
Yes, the kernel contains tons of such platform-specific drivers. No, it
won't get stale as long as someone who has access to the hardware is
willing to test a -rc kernel every once in a while.
You can't really expect to get away with no maintenance at all, but in
my experience, it takes much less effort to maintain a driver in-tree
than out-of-tree. It's also much easier to get help if it's in-tree.
Haavard
^ permalink raw reply
* Re: Module init for compiled in vs loaded modules
From: Geert Uytterhoeven @ 2008-08-20 9:06 UTC (permalink / raw)
To: Fundu; +Cc: linux embedded, Amol Lad
In-Reply-To: <487558.67644.qm@web63404.mail.re1.yahoo.com>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 1547 bytes --]
On Tue, 19 Aug 2008, Fundu wrote:
> > linux/init.h:
> >
> > #ifndef MODULE
> > ...
> > #define module_init(x) __initcall(x);
> > #define __initcall(fn) device_initcall(fn)
> > #define device_initcall(fn)
> > __define_initcall("6",fn)
> > #define __define_initcall(level,fn) \
> > static initcall_t __initcall_##fn __attribute_used__
> > \
> > __attribute__((__section__(".initcall" level
> > ".init"))) = fn
> > ...
> > #endif
> >
> > initcalls are processed in do_initcalls function in
> > init/main.c
> >
> > static void __init do_basic_setup(void)
> > {
> > ....
> > do_initcalls();
> > }
> >
> > >
> > > thanks !
> >
> > Amol
> thanks Rajat and Amol.
>
> One other question,
> 1) how does the kernel know which module to load first in order to satisfy dependencies issues ?
By looking at the needed symbols (cfr. depmod).
> 2) is there a way i could print the module init fn name from do_initcalls. to see in what order compiled in modules are called.
Add `initcall_debug' to the kernel command line (if you would have looked at
do_initcalls() and do_one_initcall(), you would have known).
With kind regards,
Geert Uytterhoeven
Software Architect
Sony Techsoft Centre Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
Phone: +32 (0)2 700 8453
Fax: +32 (0)2 700 8622
E-mail: Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/
A division of Sony Europe (Belgium) N.V.
VAT BE 0413.825.160 · RPR Brussels
Fortis · BIC GEBABEBB · IBAN BE41293037680010
^ permalink raw reply
* Re: Adding a new platform
From: vb @ 2008-08-20 15:39 UTC (permalink / raw)
To: Haavard Skinnemoen; +Cc: Linux Embedded Maillist, corbet
In-Reply-To: <20080820101044.5df8b7d8@hskinnemo-gx745.norway.atmel.com>
On Wed, Aug 20, 2008 at 1:10 AM, Haavard Skinnemoen
<haavard.skinnemoen@atmel.com> wrote:
> vb <vb@vsbe.com> wrote:
>> Would such a driver be accepted? Wouldn't such a driver get stale
>> after a few kernel releases?
>
> Yes, the kernel contains tons of such platform-specific drivers. No, it
> won't get stale as long as someone who has access to the hardware is
> willing to test a -rc kernel every once in a while.
>
> You can't really expect to get away with no maintenance at all, but in
> my experience, it takes much less effort to maintain a driver in-tree
> than out-of-tree. It's also much easier to get help if it's in-tree.
>
fair enough, maybe this paragraph should be added to the original document.
cheers,
/v
> Haavard
>
^ permalink raw reply
* Re: Adding a new platform
From: Charles Manning @ 2008-08-21 3:02 UTC (permalink / raw)
To: vb; +Cc: Paul Gortmaker, Linux Embedded Maillist, corbet
In-Reply-To: <f608b67d0808192215q5b8ffbf0w70531c31cdd66bcd@mail.gmail.com>
On Wednesday 20 August 2008 17:15:01 vb wrote:
> On Tue, Aug 19, 2008 at 9:29 PM, Paul Gortmaker
>
> <paul.gortmaker@gmail.com> wrote:
> > On Tue, Aug 19, 2008 at 11:57 PM, vb <vb@vsbe.com> wrote:
> >> so, say a developer submits a proprietary driver and it gets accepted.
> >
> > Doesn't happen. By design. If the driver is proprietary then it is
> > presumably not meant for open distribution, and hence not compatible with
> > GPL and widespread distribution into 100,000 public git repositories. So
> > it won't get submitted and it won't get accepted.
>
> I guess 'proprietary' is not the right term then, how do you call a
> driver which is not a secret and not a problem to release, but
> controls some hardware present in only in certain devices of a certain
> company.
>
> Would such a driver be accepted? Wouldn't such a driver get stale
> after a few kernel releases?
In-tree is no silver bullet.
When people modify internal APIs they will likely fix anything that breaks
compilation. However many things are more subtle than that and it is very
easy to end up with a driver or other code that compiles but does not work
properly.
Luckily APIs for drivers (the most common stuff that people work on) don't
change that much, and the interfaces are reasonably clear. If you want some
hell then try working on file systems :-).
^ permalink raw reply
* [PATCH 00/10] AXFS: Advanced XIP filesystem
From: Jared Hulbert @ 2008-08-21 5:44 UTC (permalink / raw)
To: Linux-kernel, linux-embedded, linux-mtd, Jörn Engel,
tim.bird, cotte
I'd like to get a first round of review on my AXFS filesystem. This is a simple
read only compressed filesystem like Squashfs and cramfs. AXFS is special
because it also allows for execute-in-place of your applications. It is a major
improvement over the cramfs XIP patches that have been floating around for ages.
The biggest improvement is in the way AXFS allows for each page to be XIP or
not. First, a user collects information about which pages are accessed on a
compressed image for each mmap()ed region from /proc/axfs/volume0. That
'profile' is used as an input to the image builder. The resulting image has
only the relevant pages uncompressed and XIP. The result is smaller memory
sizes and faster launches.
See http://axfs.sourceforge.net for more info.
fs/Kconfig | 21 +
fs/Makefile | 1
fs/axfs/Makefile | 7
fs/axfs/axfs_bdev.c | 158 ++++++++
fs/axfs/axfs_inode.c | 490 ++++++++++++++++++++++++++
fs/axfs/axfs_mtd.c | 233 ++++++++++++
fs/axfs/axfs_profiling.c | 594 +++++++++++++++++++++++++++++++
fs/axfs/axfs_super.c | 866 ++++++++++++++++++++++++++++++++++++++++++++++
fs/axfs/axfs_uml.c | 47 ++
fs/axfs/axfs_uncompress.c | 97 +++++
include/linux/axfs.h | 358 +++++++++++++++++++
11 files changed, 2872 insertions(+)
^ permalink raw reply
* [PATCH 01/10] AXFS: exporting xip_file_fault() for use with AXFS
From: Jared Hulbert @ 2008-08-21 5:44 UTC (permalink / raw)
To: Linux-kernel, linux-embedded, linux-mtd, Jörn Engel,
tim.bird, cotte
We'll need this for AXFS. The equivalent function in filemap.c is exported.
Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
---
include/linux/mm.h | 4 ++++
mm/filemap_xip.c | 3 ++-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 72a15dc..2be5c22 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -161,6 +161,10 @@ struct vm_fault {
*/
};
+#ifdef CONFIG_FS_XIP
+extern int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
+#endif
+
/*
* These are the virtual MM functions - opening of an area, closing and
* unmapping it (needed to keep files on disk up-to-date etc), pointer
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
index 380ab40..ab2f174 100644
--- a/mm/filemap_xip.c
+++ b/mm/filemap_xip.c
@@ -206,7 +206,7 @@ __xip_unmap (struct address_space * mapping,
*
* This function is derived from filemap_fault, but used for execute in place
*/
-static int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct file *file = vma->vm_file;
struct address_space *mapping = file->f_mapping;
@@ -262,6 +262,7 @@ found:
return 0;
}
}
+EXPORT_SYMBOL_GPL(xip_file_fault);
static struct vm_operations_struct xip_file_vm_ops = {
.fault = xip_file_fault,
^ permalink raw reply related
* [PATCH 02/10] AXFS: Kconfig and Makefiles
From: Jared Hulbert @ 2008-08-21 5:45 UTC (permalink / raw)
To: Linux-kernel, linux-embedded, linux-mtd, Jörn Engel,
tim.bird, cotte
The Kconfig edits and Makefiles required for AXFS.
Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
---
diff --git a/fs/Kconfig b/fs/Kconfig
index d387358..02d5f48 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1033,6 +1033,26 @@ config AFFS_FS
To compile this file system support as a module, choose M here: the
module will be called affs. If unsure, say N.
+config AXFS
+ tristate "Advanced XIP File System (AXFS) support (EXPERIMENTAL)"
+ select FS_XIP
+ select ZLIB_INFLATE
+ default n
+ help
+ The Advanced XIP File System or (AXFS) is a highly compressed
+ readonly filesystem like cramfs or squashfs. It also can be
+ configured to store individual pages of files compressed or
+ uncompressed as XIP pages. This allows for faster boot up and
+ application launch time with a smaller memory footprint.
+
+config AXFS_PROFILING
+ bool "Profiling extensions for AXFS (EXPERIMENTAL)"
+ depends on AXFS
+ default n
+ help
+ Profiling tooling used to identify what pages in the filesystem
+ image are actually accessed and how much.
+
config ECRYPT_FS
tristate "eCrypt filesystem layer support (EXPERIMENTAL)"
depends on EXPERIMENTAL && KEYS && CRYPTO && NET
diff --git a/fs/Makefile b/fs/Makefile
index a1482a5..8636019 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_JBD) += jbd/
obj-$(CONFIG_JBD2) += jbd2/
obj-$(CONFIG_EXT2_FS) += ext2/
obj-$(CONFIG_CRAMFS) += cramfs/
+obj-$(CONFIG_AXFS) += axfs/
obj-y += ramfs/
obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
obj-$(CONFIG_CODA_FS) += coda/
diff --git a/fs/axfs/Makefile b/fs/axfs/Makefile
new file mode 100644
index 0000000..4c40e13
--- /dev/null
+++ b/fs/axfs/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the linux axfs routines
+#
+
+obj-$(CONFIG_AXFS) += axfs.o
+
+axfs-objs := axfs_inode.o axfs_super.o axfs_uncompress.o axfs_profiling.o axfs_uml.o axfs_mtd.o axfs_bdev.o
^ permalink raw reply related
* [PATCH 03/10] AXFS: axfs.h
From: Jared Hulbert @ 2008-08-21 5:45 UTC (permalink / raw)
To: Linux-kernel, linux-embedded, linux-mtd, Jörn Engel,
tim.bird, cotte
The AXFS header.
Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
---
diff --git a/include/linux/axfs.h b/include/linux/axfs.h
new file mode 100644
index 0000000..87af84a
--- /dev/null
+++ b/include/linux/axfs.h
@@ -0,0 +1,360 @@
+/*
+ * Advanced XIP File System for Linux - AXFS
+ * Readonly, compressed, and XIP filesystem for Linux systems big and small
+ *
+ * Copyright(c) 2008 Numonyx
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * Authors:
+ * Eric Anderson
+ * Jared Hulbert <jaredeh@gmail.com>
+ * Sujaya Srinivasan
+ * Justin Treon
+ *
+ * Project url: http://axfs.sourceforge.net
+ */
+
+#ifndef __AXFS_H
+#define __AXFS_H
+
+
+#ifdef __KERNEL__
+#include <linux/rwsem.h>
+#endif
+#include <linux/errno.h>
+#include <linux/time.h>
+
+#define AXFS_MAGIC 0x48A0E4CD /* some random number */
+#define AXFS_SIGNATURE "Advanced XIP FS"
+#define AXFS_MAXPATHLEN 255
+
+/* Uncompression interfaces to the underlying zlib */
+int axfs_uncompress_block(void *, int, void *, int);
+int axfs_uncompress_init(void);
+int axfs_uncompress_exit(void);
+
+struct axfs_profiling_data {
+ u64 inode_number;
+ unsigned long count;
+};
+
+enum axfs_node_types {
+ XIP = 0,
+ Compressed,
+ Byte_Aligned,
+};
+
+enum axfs_compression_types {
+ ZLIB = 0
+};
+
+/*
+ * on media struct describing a data region
+ */
+struct axfs_region_desc_onmedia {
+ u64 fsoffset;
+ u64 size;
+ u64 compressed_size;
+ u64 max_index;
+ u8 table_byte_depth;
+ u8 incore;
+};
+
+struct axfs_region_desc {
+ u64 fsoffset;
+ u64 size;
+ u64 compressed_size;
+ u64 max_index;
+ void *virt_addr;
+ u8 table_byte_depth;
+ u8 incore;
+};
+
+/*
+ * axfs_super is the on media format for the super block it must be big endian
+ */
+struct axfs_super_onmedia {
+ u32 magic; /* 0x48A0E4CD - random number */
+ u8 signature[16]; /* "Advanced XIP FS" */
+ u8 digest[40]; /* sha1 digest for checking data integrity */
+ u32 cblock_size; /* maximum size of the block being compressed */
+ u64 files; /* number of inodes/files in fs */
+ u64 size; /* total image size */
+ u64 blocks; /* number of nodes in fs */
+ u64 mmap_size; /* size of the memory mapped part of image */
+ u64 strings; /* offset to strings region descriptor */
+ u64 xip; /* offset to xip region descriptor */
+ u64 byte_aligned; /* offset to the byte aligned region desc */
+ u64 compressed; /* offset to the compressed region desc */
+ u64 node_type; /* offset to node type region desc */
+ u64 node_index; /* offset to node index region desc */
+ u64 cnode_offset; /* offset to cnode offset region desc */
+ u64 cnode_index; /* offset to cnode index region desc */
+ u64 banode_offset; /* offset to banode offset region desc */
+ u64 cblock_offset; /* offset to cblock offset region desc */
+ u64 inode_file_size; /* offset to inode file size desc*/
+ u64 inode_name_offset; /* offset to inode num_entries region desc */
+ u64 inode_num_entries; /* offset to inode num_entries region desc */
+ u64 inode_mode_index; /* offset to inode mode index region desc */
+ u64 inode_array_index; /* offset to inode node index region desc */
+ u64 modes; /* offset to mode mode region desc */
+ u64 uids; /* offset to mode uid index region desc */
+ u64 gids; /* offset to mode gid index region desc */
+ u8 version_major;
+ u8 version_minor;
+ u8 version_sub;
+ u8 compression_type; /* Identifies type of compression used on FS */
+ u64 timestamp; /* UNIX time_t of filesystem build time */
+};
+
+/*
+ * axfs super-block data in core
+ */
+struct axfs_super {
+ u32 magic;
+ u8 version_major;
+ u8 version_minor;
+ u8 version_sub;
+ u8 padding;
+ u64 files;
+ u64 size;
+ u64 blocks;
+ u64 mmap_size;
+ struct axfs_region_desc strings;
+ struct axfs_region_desc xip;
+ struct axfs_region_desc compressed;
+ struct axfs_region_desc byte_aligned;
+ struct axfs_region_desc node_type;
+ struct axfs_region_desc node_index;
+ struct axfs_region_desc cnode_offset;
+ struct axfs_region_desc cnode_index;
+ struct axfs_region_desc banode_offset;
+ struct axfs_region_desc cblock_offset;
+ struct axfs_region_desc inode_file_size;
+ struct axfs_region_desc inode_name_offset;
+ struct axfs_region_desc inode_num_entries;
+ struct axfs_region_desc inode_mode_index;
+ struct axfs_region_desc inode_array_index;
+ struct axfs_region_desc modes;
+ struct axfs_region_desc uids;
+ struct axfs_region_desc gids;
+ unsigned long phys_start_addr;
+ unsigned long virt_start_addr;
+ char *second_dev;
+ unsigned long iomem_size;
+ void *mtd0; /* primary device */
+ void *mtd1; /* secondary device */
+ u32 cblock_size;
+ u64 current_cnode_index;
+ void *cblock_buffer[2];
+ struct rw_semaphore lock;
+ struct axfs_profiling_data *profile_data_ptr;
+ u8 profiling_on; /* Determines if profiling is on or off */
+ u8 mtd_pointed;
+ u8 compression_type;
+ struct timespec timestamp;
+};
+
+#define AXFS_PAGE_SIZE 4096
+
+#define AXFS_SB(sb) (struct axfs_super *)((sb)->s_fs_info)
+#define AXFS_MTD(sb) (void *)((sb)->s_mtd)
+#define AXFS_MTD0(sb) (((AXFS_SB(sb))->mtd0) ? \
+ ((AXFS_SB(sb))->mtd0) : (AXFS_MTD(sb)))
+#define AXFS_MTD1(sb) ((AXFS_SB(sb))->mtd1)
+
+#define AXFS_BDEV(sb) ((sb)->s_bdev)
+
+#define AXFS_HAS_BDEV(sb) \
+ ((AXFS_BDEV(sb) != NULL) ? TRUE : FALSE)
+#define AXFS_HAS_MTD(sb) \
+ (((AXFS_MTD0(sb) != NULL) || \
+ (AXFS_MTD1(sb) != NULL) || \
+ (AXFS_MTD(sb) != NULL)) ? TRUE : FALSE)
+
+#define AXFS_NODEV(sb) \
+ ((!AXFS_HAS_MTD(sb) && !AXFS_HAS_BDEV(sb)) ? TRUE : FALSE)
+
+static inline u64 axfs_bytetable_stitch(u8 depth, u8 *table, u64 index)
+{
+ u64 i;
+ u64 output = 0;
+ u64 byte = 0;
+ u64 j;
+ u64 bits;
+
+ for (i = 0; i < depth; i++) {
+ j = index * depth + i;
+ bits = 8 * (depth - i - 1);
+ byte = table[j];
+ output += byte << bits;
+ }
+ return output;
+}
+
+#define AXFS_GET_BYTETABLE_VAL(desc,index) \
+ axfs_bytetable_stitch(((struct axfs_region_desc)(desc)).table_byte_depth,\
+ (u8 *)((struct axfs_region_desc)(desc)).virt_addr, index)
+
+#define AXFS_GET_NODE_TYPE(sbi,node_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->node_type,\
+ (node_index))
+
+#define AXFS_GET_NODE_INDEX(sbi,node__index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->node_index,\
+ (node__index))
+
+#define AXFS_IS_NODE_XIP(sbi,node_index) \
+ (AXFS_GET_NODE_TYPE(sbi, (node_index)) == XIP)
+
+#define AXFS_GET_CNODE_INDEX(sbi,node_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->cnode_index,\
+ (node_index))
+
+#define AXFS_GET_CNODE_OFFSET(desc,node_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->cnode_offset,\
+ (node_index))
+
+#define AXFS_GET_BANODE_OFFSET(desc,node_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->banode_offset,\
+ (node_index))
+
+#define AXFS_GET_CBLOCK_OFFSET(desc,node_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->cblock_offset,\
+ (node_index))
+
+#define AXFS_GET_INODE_FILE_SIZE(sbi,inode_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->inode_file_size,\
+ (inode_index))
+
+#define AXFS_GET_INODE_NAME_OFFSET(sbi,inode_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->inode_name_offset,\
+ (inode_index))
+
+#define AXFS_GET_INODE_NUM_ENTRIES(sbi,inode_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->inode_num_entries,\
+ (inode_index))
+
+#define AXFS_GET_INODE_MODE_INDEX(sbi,inode_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->inode_mode_index,\
+ (inode_index))
+
+#define AXFS_GET_INODE_ARRAY_INDEX(sbi,inode_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->inode_array_index,\
+ (inode_index))
+
+#define AXFS_GET_MODE(sbi,mode_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->modes,\
+ (AXFS_GET_INODE_MODE_INDEX(sbi, (mode_index))))
+
+#define AXFS_GET_UID(sbi,mode_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->uids,\
+ (AXFS_GET_INODE_MODE_INDEX(sbi, (mode_index))))
+
+#define AXFS_GET_GID(sbi,mode_index) \
+ AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->gids,\
+ (AXFS_GET_INODE_MODE_INDEX(sbi, (mode_index))))
+
+#define AXFS_IS_REGION_COMPRESSED(_region) \
+ (( \
+ ((struct axfs_region_desc *)(_region))->compressed_size > \
+ 0 \
+ ) ? TRUE : FALSE)
+
+#define AXFS_PHYSADDR_IS_VALID(sbi) \
+ (((((struct axfs_super *)(sbi))->phys_start_addr) > 0 \
+ ) ? TRUE : FALSE)
+
+#define AXFS_VIRTADDR_IS_VALID(sbi) \
+ (((((struct axfs_super *)(sbi))->virt_start_addr) > 0 \
+ ) ? TRUE : FALSE)
+
+#define AXFS_IS_IOMEM(sbi) \
+ (((((struct axfs_super *)(sbi))->iomem_size) > 0) ? TRUE : FALSE)
+
+#define AXFS_IS_POINTED(sbi) \
+ (((((struct axfs_super *)(sbi))->mtd_pointed) > 0) ? TRUE : FALSE)
+
+#define AXFS_IS_PHYSMEM(sbi) \
+ (( \
+ AXFS_PHYSADDR_IS_VALID(sbi) \
+ && !AXFS_IS_IOMEM(sbi) \
+ && !AXFS_IS_POINTED(sbi) \
+ ) ? TRUE : FALSE)
+
+#define AXFS_IS_MMAPABLE(sbi,offset) \
+ ((\
+ (((struct axfs_super *)(sbi))->mmap_size) > (offset) \
+ ) ? TRUE : FALSE)
+
+#define AXFS_IS_OFFSET_MMAPABLE(sbi,offset) \
+ (( \
+ AXFS_IS_MMAPABLE(sbi, offset) && AXFS_VIRTADDR_IS_VALID(sbi) \
+ ) ? TRUE : FALSE)
+
+#define AXFS_IS_REGION_MMAPABLE(sbi,_region) \
+ (( \
+ AXFS_IS_MMAPABLE(sbi, ((struct axfs_region_desc *)(_region))->fsoffset) \
+ && AXFS_VIRTADDR_IS_VALID(sbi) \
+ ) ? TRUE : FALSE)
+
+#define AXFS_IS_REGION_INCORE(_region) \
+ (((_region)->incore > 0) ? TRUE : FALSE)
+
+#define AXFS_IS_REGION_XIP(sbi,_region) \
+ (( \
+ !AXFS_IS_REGION_COMPRESSED(_region) && \
+ !AXFS_IS_REGION_INCORE(_region) && \
+ AXFS_IS_REGION_MMAPABLE(sbi,_region) \
+ ) ? TRUE : FALSE)
+
+#define AXFS_GET_XIP_REGION_PHYSADDR(sbi) \
+ (unsigned long)((sbi)->phys_start_addr + (sbi)->xip.fsoffset)
+
+#define AXFS_GET_INODE_NAME(sbi,inode_index) \
+ (char *)( \
+ (sbi)->strings.virt_addr \
+ + AXFS_GET_INODE_NAME_OFFSET(sbi,inode_index) \
+ )
+
+#define AXFS_GET_CBLOCK_ADDRESS(sbi, cnode_index)\
+ (unsigned long)( \
+ (sbi)->compressed.virt_addr \
+ + AXFS_GET_CBLOCK_OFFSET(sbi, cnode_index) \
+ )
+
+#define AXFS_GET_NODE_ADDRESS(sbi,node__index) \
+ (unsigned long)( \
+ (sbi)->node_index.virt_addr \
+ + AXFS_GET_NODE_INDEX(sbi, node__index) \
+ )
+
+#define AXFS_GET_BANODE_ADDRESS(sbi,banode_index) \
+ (unsigned long)( \
+ (sbi)->byte_aligned.virt_addr \
+ + AXFS_GET_BANODE_OFFSET(sbi, banode_index) \
+ )
+
+#define AXFS_FSOFFSET_2_DEVOFFSET(sbi,fsoffset) \
+ (( \
+ ((sbi)->phys_start_addr == 0) && ((sbi)->virt_start_addr == 0) \
+ ) ? (fsoffset) : (fsoffset - (sbi)->mmap_size) \
+ )
+
+#define AXFS_GET_CBLOCK_LENGTH(sbi,cblock_index) \
+ (u64)( \
+ (u64)AXFS_GET_CBLOCK_OFFSET(sbi, ((u64)(cblock_index)+(u64)1)) \
+ - (u64)AXFS_GET_CBLOCK_OFFSET(sbi, (cblock_index)) \
+ )
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#endif
^ permalink raw reply related
* [PATCH 04/10] AXFS: axfs_inode.c
From: Jared Hulbert @ 2008-08-21 5:45 UTC (permalink / raw)
To: Linux-kernel, linux-embedded, linux-mtd, Jörn Engel,
tim.bird, cotte
This is the main filesystem logic.
Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
---
diff --git a/fs/axfs/axfs_inode.c b/fs/axfs/axfs_inode.c
new file mode 100644
index 0000000..cbf3dd1
--- /dev/null
+++ b/fs/axfs/axfs_inode.c
@@ -0,0 +1,488 @@
+/*
+ * Advanced XIP File System for Linux - AXFS
+ * Readonly, compressed, and XIP filesystem for Linux systems big and small
+ *
+ * Copyright(c) 2008 Numonyx
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * Authors:
+ * Eric Anderson
+ * Jared Hulbert <jaredeh@gmail.com>
+ * Sujaya Srinivasan
+ * Justin Treon
+ *
+ * Project url: http://axfs.sourceforge.net
+ *
+ * Borrowed heavily from fs/cramfs/inode.c by Linus Torvalds
+ *
+ * axfs_inode.c -
+ * Contains the most of the filesystem logic with the major exception of the
+ * mounting infrastructure.
+ *
+ */
+
+#include <linux/axfs.h>
+#include <linux/pagemap.h>
+
+/***************** functions in other axfs files ******************************/
+int axfs_get_sb(struct file_system_type *, int, const char *, void *,
+ struct vfsmount *);
+void axfs_kill_super(struct super_block *);
+void axfs_profiling_add(struct axfs_super *, unsigned long, unsigned int);
+int axfs_copy_mtd(struct super_block *, void *, u64, u64);
+int axfs_copy_block(struct super_block *, void *, u64, u64);
+/******************************************************************************/
+static int axfs_readdir(struct file *, void *, filldir_t);
+static int axfs_mmap(struct file *, struct vm_area_struct *);
+static ssize_t axfs_file_read(struct file *, char __user *, size_t, loff_t *);
+static int axfs_readpage(struct file *, struct page *);
+static int axfs_fault(struct vm_area_struct *, struct vm_fault *);
+static struct dentry *axfs_lookup(struct inode *, struct dentry *,
+ struct nameidata *);
+static int axfs_get_xip_mem(struct address_space *, pgoff_t, int, void **,
+ unsigned long *);
+
+/******************************************************************************/
+
+static struct file_operations axfs_directory_operations = {
+ .llseek = generic_file_llseek,
+ .read = generic_read_dir,
+ .readdir = axfs_readdir,
+};
+
+static struct file_operations axfs_fops = {
+ .read = axfs_file_read,
+ .aio_read = generic_file_aio_read,
+ .mmap = axfs_mmap,
+};
+
+static struct address_space_operations axfs_aops = {
+ .readpage = axfs_readpage,
+ .get_xip_mem = axfs_get_xip_mem,
+};
+
+static struct inode_operations axfs_dir_inode_operations = {
+ .lookup = axfs_lookup,
+};
+
+static struct vm_operations_struct axfs_vm_ops = {
+ .fault = axfs_fault,
+};
+
+static int axfs_copy_data(struct super_block *sb, void *dst,
+ struct axfs_region_desc *region, u64 offset, u64 len)
+{
+ u64 mmapped = 0;
+ u64 end = region->fsoffset + offset + len;
+ u64 begin = region->fsoffset + offset;
+ u64 left;
+ void *addr;
+ void *newdst;
+ struct axfs_super *sbi = AXFS_SB(sb);
+
+ if (len == 0)
+ return 0;
+
+ if (region->virt_addr) {
+ if (sbi->mmap_size >= end) {
+ mmapped = len;
+ } else if (sbi->mmap_size > begin) {
+ mmapped = sbi->mmap_size - begin;
+ }
+ }
+
+ if (mmapped) {
+ addr = (void *)(region->virt_addr + offset);
+ memcpy(dst, addr, mmapped);
+ }
+
+ newdst = (void *)(dst + mmapped);
+ left = len - mmapped;
+
+ if (left == 0)
+ return len;
+
+ if (AXFS_HAS_BDEV(sb)) {
+ return axfs_copy_block(sb, newdst, begin + mmapped, left);
+ } else if (AXFS_HAS_MTD(sb)) {
+ return axfs_copy_mtd(sb, newdst, begin + mmapped, left);
+ } else {
+ return 0;
+ }
+}
+
+static int axfs_iget5_test(struct inode *inode, void *opaque)
+{
+ u64 *inode_number = (u64 *) opaque;
+
+ if (inode->i_sb == NULL) {
+ printk(KERN_ERR "axfs_iget5_test:"
+ " the super block is set to null\n");
+ }
+ if (inode->i_ino == *inode_number)
+ return 1; /* matches */
+ else
+ return 0; /* does not match */
+}
+
+static int axfs_iget5_set(struct inode *inode, void *opaque)
+{
+ u64 *inode_number = (u64 *) opaque;
+
+ if (inode->i_sb == NULL) {
+ printk(KERN_ERR "axfs_iget5_set:"
+ " the super block is set to null \n");
+ }
+ inode->i_ino = *inode_number;
+ return 0;
+}
+
+struct inode *axfs_create_vfs_inode(struct super_block *sb, int ino)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ struct inode *inode;
+ u64 size;
+
+ inode = iget5_locked(sb, ino, axfs_iget5_test, axfs_iget5_set, &ino);
+
+ if (!(inode && (inode->i_state & I_NEW)))
+ return inode;
+
+ inode->i_mode = AXFS_GET_MODE(sbi, ino);
+ inode->i_uid = AXFS_GET_UID(sbi, ino);
+ size = AXFS_GET_INODE_FILE_SIZE(sbi, ino);
+ inode->i_size = size;
+ inode->i_blocks = AXFS_GET_INODE_NUM_ENTRIES(sbi, ino);
+ inode->i_blkbits = PAGE_CACHE_SIZE * 8;
+ inode->i_gid = AXFS_GET_GID(sbi, ino);
+
+ inode->i_mtime = inode->i_atime = inode->i_ctime = sbi->timestamp;
+ inode->i_ino = ino;
+
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_fop = &axfs_fops;
+ inode->i_data.a_ops = &axfs_aops;
+ inode->i_mapping->a_ops = &axfs_aops;
+ } else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &axfs_dir_inode_operations;
+ inode->i_fop = &axfs_directory_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_data.a_ops = &axfs_aops;
+ } else {
+ inode->i_size = 0;
+ inode->i_blocks = 0;
+ init_special_inode(inode, inode->i_mode, old_decode_dev(size));
+ }
+ unlock_new_inode(inode);
+
+ return inode;
+}
+
+
+static int axfs_mmap(struct file *file, struct vm_area_struct *vma)
+{
+
+ file_accessed(file);
+
+ vma->vm_ops = &axfs_vm_ops;
+
+ vma->vm_flags |= VM_CAN_NONLINEAR | VM_MIXEDMAP;
+
+ return 0;
+}
+
+static struct dentry *axfs_lookup(struct inode *dir, struct dentry *dentry,
+ struct nameidata *nd)
+{
+ struct super_block *sb = dir->i_sb;
+ struct axfs_super *sbi = AXFS_SB(sb);
+ u64 ino_number = dir->i_ino;
+ u64 dir_index = 0;
+ u64 entry;
+ char *name;
+ int namelen, err;
+
+ while (dir_index < AXFS_GET_INODE_NUM_ENTRIES(sbi, ino_number)) {
+ entry = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number);
+ entry += dir_index;
+
+ name = AXFS_GET_INODE_NAME(sbi, entry);
+ namelen = strlen(name);
+
+ /* fast test, the entries are sorted alphabetically and the
+ * first letter is smaller than the first letter in the search
+ * name then it isn't in this directory. Keeps this loop from
+ * needing to scan through always.
+ */
+ if (dentry->d_name.name[0] < name[0])
+ break;
+
+ dir_index++;
+
+ /* Quick check that the name is roughly the right length */
+ if (dentry->d_name.len != namelen)
+ continue;
+
+ err = memcmp(dentry->d_name.name, name, namelen);
+ if (err > 0)
+ continue;
+
+ /* The file name isn't present in the directory. */
+ if (err < 0)
+ break;
+
+ d_add(dentry, axfs_create_vfs_inode(dir->i_sb, entry));
+ goto out;
+
+ }
+ d_add(dentry, NULL);
+
+out:
+ return NULL;
+}
+
+static int axfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct super_block *sb = inode->i_sb;
+ struct axfs_super *sbi = AXFS_SB(sb);
+ u64 ino_number = inode->i_ino;
+ u64 entry;
+ loff_t dir_index;
+ char *name;
+ int namelen, mode;
+ int err = 0;
+
+ /* Get the current index into the directory and verify it is not beyond
+ the end of the list */
+ dir_index = filp->f_pos;
+ if (dir_index >= AXFS_GET_INODE_NUM_ENTRIES(sbi, ino_number))
+ goto out;
+
+ /* Verify the inode is for a directory */
+ if (!(S_ISDIR(inode->i_mode))) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ while (dir_index < AXFS_GET_INODE_NUM_ENTRIES(sbi, ino_number)) {
+ entry = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number) + dir_index;
+
+ name = (char *)AXFS_GET_INODE_NAME(sbi, entry);
+ namelen = strlen(name);
+
+ mode = (int)AXFS_GET_MODE(sbi, entry);
+ err = filldir(dirent, name, namelen, dir_index, entry, mode);
+
+ if (err)
+ break;
+
+ dir_index++;
+ filp->f_pos = dir_index;
+ }
+
+out:
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * axfs_fault
+ *
+ * Description: This function is mapped into the VMA operations vector, and
+ * gets called on a page fault. Depending on whether the page
+ * is XIP or compressed, xip_file_fault or filemap_fault is
+ * called. This function also logs when a fault occurs when
+ * profiling is on.
+ *
+ * Parameters:
+ * (IN) vma - The virtual memory area corresponding to a file
+ *
+ * (IN) vmf - The fault info pass in by the fault handler
+ *
+ * Returns:
+ * 0 or error number
+ *
+ *****************************************************************************/
+static int axfs_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ struct file *file = vma->vm_file;
+ struct inode *inode = file->f_dentry->d_inode;
+ struct super_block *sb = inode->i_sb;
+ struct axfs_super *sbi = AXFS_SB(sb);
+ u64 ino_number = inode->i_ino;
+ u64 array_index;
+
+ array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number) + vmf->pgoff;
+
+ /* if that pages are marked for write they will probably end up in RAM
+ therefore we don't want their counts for being XIP'd */
+ if (!(vma->vm_flags & VM_WRITE))
+ axfs_profiling_add(sbi, array_index, ino_number);
+
+ /* figure out if the node is XIP or compressed and call the
+ appropriate function
+ */
+ if (AXFS_IS_NODE_XIP(sbi, array_index))
+ return xip_file_fault(vma, vmf);
+ return filemap_fault(vma, vmf);
+
+}
+
+
+/******************************************************************************
+ *
+ * axfs_file_read
+ *
+ * Description: axfs_file_read is mapped into the file_operations vector for
+ * all axfs files. It loops through the pages to be read and calls
+ * either do_sync_read (if the page is a compressed one) or
+ * xip_file_read (if the page is XIP).
+ *
+ * Parameters:
+ * (IN) filp - file to be read
+ *
+ * (OUT) buf - user buffer that is filled with the data that we read.
+ *
+ * (IN) len - length of file to be read
+ *
+ * (IN) ppos - offset within the file to read from
+ *
+ * Returns:
+ * actual size of data read.
+ *
+ *****************************************************************************/
+static ssize_t axfs_file_read(struct file *filp, char __user *buf, size_t len,
+ loff_t *ppos)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct super_block *sb = inode->i_sb;
+ struct axfs_super *sbi = AXFS_SB(sb);
+ size_t read = 0, total_read = 0;
+ size_t readlength, actual_size, file_size, remaining;
+ u64 ino_number = inode->i_ino;
+ u64 size, array_index;
+
+ file_size = AXFS_GET_INODE_FILE_SIZE(sbi, ino_number);
+ remaining = file_size - *ppos;
+ actual_size = len > remaining ? remaining : len;
+ readlength = actual_size < PAGE_SIZE ? actual_size : PAGE_SIZE;
+
+ for (size = actual_size; size > 0; size -= read) {
+ array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number);
+ array_index += *ppos >> PAGE_SHIFT;
+
+ if (AXFS_IS_NODE_XIP(sbi, array_index)) {
+ read = xip_file_read(filp, buf, readlength, ppos);
+ } else {
+ read = do_sync_read(filp, buf, readlength, ppos);
+ }
+ buf += read;
+ total_read += read;
+
+ if ((len - total_read < PAGE_SIZE) && (total_read != len))
+ readlength = len - total_read;
+ }
+
+ return total_read;
+}
+
+static int axfs_readpage(struct file *file, struct page *page)
+{
+ struct inode *inode = page->mapping->host;
+ struct super_block *sb = inode->i_sb;
+ struct axfs_super *sbi = AXFS_SB(sb);
+ u64 array_index, node_index, cnode_index, maxblock, ofs;
+ u64 ino_number = inode->i_ino;
+ u32 max_len, cnode_offset;
+ u32 cblk_size = sbi->cblock_size;
+ u32 len = 0;
+ u8 node_type;
+ void *pgdata;
+ void *src;
+ void *cblk0 = sbi->cblock_buffer[0];
+ void *cblk1 = sbi->cblock_buffer[1];
+
+ maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ pgdata = kmap(page);
+
+ if (page->index >= maxblock)
+ goto out;
+
+ array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number);
+ array_index += page->index;
+
+ node_index = AXFS_GET_NODE_INDEX(sbi, array_index);
+ node_type = AXFS_GET_NODE_TYPE(sbi, array_index);
+
+ if (node_type == Compressed) {
+ /* node is in compessed region */
+ cnode_offset = AXFS_GET_CNODE_OFFSET(sbi, node_index);
+ cnode_index = AXFS_GET_CNODE_INDEX(sbi, node_index);
+ down_write(&sbi->lock);
+ if (cnode_index != sbi->current_cnode_index) {
+ /* uncompress only necessary if different cblock */
+ ofs = AXFS_GET_CBLOCK_OFFSET(sbi, cnode_index);
+ len = AXFS_GET_CBLOCK_OFFSET(sbi, cnode_index + 1);
+ len -= ofs;
+ axfs_copy_data(sb, cblk1, &(sbi->compressed), ofs, len);
+ axfs_uncompress_block(cblk0, cblk_size, cblk1, len);
+ sbi->current_cnode_index = cnode_index;
+ }
+ downgrade_write(&sbi->lock);
+ max_len = cblk_size - cnode_offset;
+ len = max_len > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : max_len;
+ src = (void *)((unsigned long)cblk0 + cnode_offset);
+ memcpy(pgdata, src, len);
+ up_read(&sbi->lock);
+ } else if (node_type == Byte_Aligned) {
+ /* node is in BA region */
+ ofs = AXFS_GET_BANODE_OFFSET(sbi, node_index);
+ max_len = sbi->byte_aligned.size - ofs;
+ len = max_len > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : max_len;
+ axfs_copy_data(sb, pgdata, &(sbi->byte_aligned), ofs, len);
+ } else {
+ /* node is XIP */
+ ofs = node_index << PAGE_SHIFT;
+ len = PAGE_CACHE_SIZE;
+ axfs_copy_data(sb, pgdata, &(sbi->xip), ofs, len);
+ }
+
+out:
+ memset(pgdata + len, 0, PAGE_CACHE_SIZE - len);
+ kunmap(page);
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ unlock_page(page);
+ return 0;
+}
+
+static int axfs_get_xip_mem(struct address_space *mapping, pgoff_t offset,
+ int create, void **kaddr, unsigned long *pfn)
+{
+ struct inode *inode = mapping->host;
+ struct super_block *sb = inode->i_sb;
+ struct axfs_super *sbi = AXFS_SB(sb);
+ u64 ino_number = inode->i_ino;
+ u64 ino_index, node_index;
+
+ ino_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number);
+ ino_index += offset;
+
+ node_index = AXFS_GET_NODE_INDEX(sbi, ino_index);
+
+ *kaddr = (void *)(sbi->xip.virt_addr + (node_index << PAGE_SHIFT));
+ if (AXFS_PHYSADDR_IS_VALID(sbi)) {
+ *pfn = (AXFS_GET_XIP_REGION_PHYSADDR(sbi) >> PAGE_SHIFT);
+ *pfn += node_index;
+ } else {
+ *pfn = page_to_pfn(virt_to_page((unsigned long)*kaddr));
+ }
+
+ return 0;
+}
+
^ permalink raw reply related
* [PATCH 05/10] AXFS: axfs_profiling.c
From: Jared Hulbert @ 2008-08-21 5:45 UTC (permalink / raw)
To: Linux-kernel, linux-embedded, linux-mtd, Jörn Engel,
tim.bird, cotte
Profiling is a fault instrumentation and /proc formating system.
This is used to get an accurate picture of what the pages are actually used.
Using this info the image can be optimized for XIP
Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
---
diff --git a/fs/axfs/axfs_profiling.c b/fs/axfs/axfs_profiling.c
new file mode 100644
index 0000000..30d881c
--- /dev/null
+++ b/fs/axfs/axfs_profiling.c
@@ -0,0 +1,594 @@
+/*
+ * Advanced XIP File System for Linux - AXFS
+ * Readonly, compressed, and XIP filesystem for Linux systems big and small
+ *
+ * Copyright(c) 2008 Numonyx
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * Authors:
+ * Eric Anderson
+ * Jared Hulbert <jaredeh@gmail.com>
+ * Sujaya Srinivasan
+ * Justin Treon
+ *
+ * More info and current contacts at http://axfs.sourceforge.net
+ *
+ * axfs_profiling.c -
+ * Tracks pages of files that enter the page cache. Outputs through a proc
+ * file which generates a comma separated data file with path, page offset,
+ * count of times entered page cache.
+ */
+
+#include <linux/axfs.h>
+#ifdef CONFIG_AXFS_PROFILING
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+
+#define AXFS_PROC_DIR_NAME "axfs"
+
+struct axfs_profiling_manager {
+ struct axfs_profiling_data *profiling_data;
+ struct axfs_super *sbi;
+ u32 *dir_structure;
+ u32 size;
+};
+
+#define MAX_STRING_LEN 1024
+
+/* Handles for our Directory and File */
+static struct proc_dir_entry *axfs_proc_dir;
+static u32 proc_name_inc;
+
+/******************************************************************************
+ *
+ * axfs_init_profile_dir_structure
+ *
+ * Description:
+ * Creates the structures for tracking the page usage data and creates the
+ * proc file that will be used to get the data.
+ *
+ * Parameters:
+ * (IN) manager - pointer to the profile manager for the filing system
+ *
+ * (IN) num_inodes - number of files in the system
+ *
+ * Returns:
+ * 0
+ *
+ *****************************************************************************/
+static int axfs_init_profile_dir_structure(struct axfs_profiling_manager
+ *manager, u32 num_inodes)
+{
+
+ struct axfs_super *sbi = (struct axfs_super *)manager->sbi;
+ u32 child_index = 0, i, j;
+ u32 *dir_structure = manager->dir_structure;
+
+ /* loop through each inode in the image and find all
+ of the directories and mark their children */
+ for (i = 0; i < num_inodes; i++) {
+ /* determine if the entry is a directory */
+ if (!S_ISDIR(AXFS_GET_MODE(sbi, i)))
+ continue;
+
+ /* get the index number for this directory */
+ child_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, i);
+
+ /* get the offset to its children */
+ for (j = 0; j < AXFS_GET_INODE_NUM_ENTRIES(sbi, i); j++) {
+ if (dir_structure[child_index + j] != 0) {
+ printk(KERN_ERR
+ "axfs: ERROR inode was already set old "
+ "%lu new %lu\n", (unsigned long)
+ dir_structure[child_index + j],
+ (unsigned long)i);
+ }
+ dir_structure[child_index + j] = i;
+ }
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * axfs_get_directory_path
+ *
+ * Description:
+ * Determines the directory path of every file for printing the spreadsheet.
+ *
+ * Parameters:
+ * (IN) manager - Pointer to axfs profile manager
+ *
+ * (OUT) buffer - Pointer to the printable directory path for each file
+ *
+ * (IN) inode_number - Inode number of file to look up
+ *
+ * Returns:
+ * Size of the path to the file
+ *
+ *
+ **************************************************************************/
+static int axfs_get_directory_path(struct axfs_profiling_manager *manager,
+ char *buffer, u32 inode_number)
+{
+ u32 path_depth = 0;
+ u32 path_size = 0;
+ u32 string_len = 0;
+ u32 index = inode_number;
+ u32 dir_number;
+ u8 **path_array = NULL;
+ struct axfs_super *sbi = (struct axfs_super *)manager->sbi;
+ int i;
+
+ /* determine how deep the directory path is and how big the name
+ string will be walk back until the root directory index is found
+ (index 0 is root) */
+ while (manager->dir_structure[index] != 0) {
+ path_depth++;
+ /* set the index to the index of the parent directory */
+ index = manager->dir_structure[index];
+ }
+
+ if (path_depth != 0) {
+ /* create an array that will hold a pointer for each of the
+ directories names */
+ path_array = vmalloc(path_depth * sizeof(*path_array));
+ if (path_array == NULL) {
+ printk(KERN_DEBUG
+ "axfs: directory_path vmalloc failed.\n");
+ goto out;
+ }
+ }
+
+ index = manager->dir_structure[inode_number];
+ for (i = path_depth; i > 0; i--) {
+ /* get the array_index for the directory corresponding to
+ index */
+ dir_number = AXFS_GET_INODE_ARRAY_INDEX(sbi, index);
+
+ /* store a pointer to the name in the array */
+ path_array[(i - 1)] = (u8 *) AXFS_GET_INODE_NAME(sbi, index);
+
+ index = manager->dir_structure[index];
+ }
+
+ /* now print out the directory structure from the begining */
+ string_len = sprintf(buffer, "./");
+ path_size += string_len;
+ for (i = 0; i < path_depth; i++) {
+ buffer = buffer + string_len;
+ string_len = sprintf(buffer, "%s/", (char *)path_array[i]);
+ path_size += string_len;
+ }
+
+ if (path_array != NULL)
+ vfree(path_array);
+
+out:
+ return path_size;
+
+}
+
+static ssize_t axfs_procfile_read(char *buffer,
+ char **buffer_location,
+ off_t offset, int buffer_length, int *eof,
+ void *data)
+{
+ struct axfs_profiling_manager *man;
+ struct axfs_profiling_data *profile;
+ struct axfs_super *sbi;
+ u64 array_index;
+ u64 loop_size, inode_page_offset, node_offset, inode_number;
+ u64 print_len = 0;
+ unsigned long addr;
+ int len = 0;
+ int i;
+ char *buff, *name = NULL;
+
+ man = (struct axfs_profiling_manager *)data;
+ sbi = man->sbi;
+
+ loop_size = man->size / sizeof(*profile);
+
+ /* If all data has been returned set EOF */
+ if (offset >= loop_size) {
+ *eof = 1;
+ return 0;
+ }
+
+ buff = buffer;
+ /* print as much as the buffer can take */
+ for (i = offset; i < loop_size; i++) {
+
+ if ((print_len + MAX_STRING_LEN) > buffer_length)
+ break;
+ /* get the first profile data structure */
+ profile = &(man->profiling_data[i]);
+
+ if (profile->count == 0)
+ continue;
+
+ inode_number = profile->inode_number;
+
+ /* file names can be duplicated so we must print out the path */
+ len = axfs_get_directory_path(man, buff, inode_number);
+
+ print_len += len;
+ buff += len;
+
+ /* get a pointer to the inode name */
+ array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, inode_number);
+ name = (char *)AXFS_GET_INODE_NAME(sbi, inode_number);
+
+ /* need to convert the page number in the node area to
+ the page number within the file */
+ node_offset = i;
+ /* gives the offset of the node in the node list area
+ then substract that from the */
+ inode_page_offset = node_offset - array_index;
+
+ /* set everything up to print out */
+ addr = (unsigned long)(inode_page_offset * PAGE_SIZE);
+ len = sprintf(buff, "%s,%lu,%lu\n", name, addr, profile->count);
+
+ print_len += len;
+ buff += len;
+ }
+
+ /* return the number of items printed.
+ This will be added to offset and passed back to us */
+ *buffer_location = (char *)(i - offset);
+
+ return print_len;
+}
+
+static ssize_t axfs_procfile_write(struct file *file,
+ const char *buffer, unsigned long count,
+ void *data)
+{
+ struct axfs_profiling_manager *man_ptr =
+ (struct axfs_profiling_manager *)data;
+
+ if ((count >= 2) && (0 == memcmp(buffer, "on", 2))) {
+ man_ptr->sbi->profiling_on = TRUE;
+ } else if ((count >= 3) && (0 == memcmp(buffer, "off", 3))) {
+ man_ptr->sbi->profiling_on = FALSE;
+ } else if ((count >= 5) && (0 == memcmp(buffer, "clear", 5))) {
+ memset(man_ptr->profiling_data, 0, man_ptr->size);
+ } else {
+ printk(KERN_INFO
+ "axfs: Unknown command. Supported options are:\n");
+ printk(KERN_INFO "\t\"on\"\tTurn on profiling\n");
+ printk(KERN_INFO "\t\"off\"\tTurn off profiling\n");
+ printk(KERN_INFO "\t\"clear\"\tClear profiling buffer\n");
+ }
+
+ return count;
+}
+
+static int axfs_create_proc_directory(void)
+{
+ if (axfs_proc_dir == NULL) {
+ axfs_proc_dir = proc_mkdir(AXFS_PROC_DIR_NAME, NULL);
+ if (!axfs_proc_dir) {
+ printk(KERN_WARNING
+ "axfs: Failed to create directory\n");
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static void axfs_delete_proc_directory(void)
+{
+ /* Determine if there are any directory elements
+ and remove if all of the proc files are removed. */
+ if (axfs_proc_dir != NULL) {
+ if (axfs_proc_dir->subdir == NULL) {
+ remove_proc_entry(AXFS_PROC_DIR_NAME, NULL);
+ axfs_proc_dir = NULL;
+ }
+ }
+}
+
+/******************************************************************************
+ *
+ * axfs_delete_proc_file
+ *
+ * Description:
+ * Will search through the proc directory for the correct proc file,
+ * then delete it
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer to determine which proc file to remove
+ *
+ * Returns:
+ * The profiling manager pointer for the proc file.
+ *
+ *****************************************************************************/
+static struct axfs_profiling_manager *axfs_delete_proc_file(struct axfs_super
+ *sbi)
+{
+ struct proc_dir_entry *current_proc_file;
+ struct axfs_profiling_manager *manager;
+ void *rv = NULL;
+
+ if (!axfs_proc_dir)
+ return NULL;
+
+ /* Walk through the proc file entries to find the matching sbi */
+ current_proc_file = axfs_proc_dir->subdir;
+
+ while (current_proc_file != NULL) {
+ manager = current_proc_file->data;
+ if (manager == NULL) {
+ printk(KERN_WARNING
+ "axfs: Error removing proc file private "
+ "data was NULL.\n");
+ rv = NULL;
+ break;
+ }
+ if (manager->sbi == sbi) {
+ /* we found the match */
+ remove_proc_entry(current_proc_file->name,
+ axfs_proc_dir);
+ rv = (void *)manager;
+ break;
+ }
+ current_proc_file = axfs_proc_dir->next;
+ }
+ return (struct axfs_profiling_manager *)rv;
+}
+
+/******************************************************************************
+ *
+ * axfs_register_profiling_proc
+ *
+ * Description:
+ * Will register the instance of the proc file for a given volume.
+ *
+ * Parameters:
+ * (IN) manager - Pointer to the profiling manager for the axfs volume
+ *
+ * Returns:
+ * 0 or error number
+ *
+ *****************************************************************************/
+static int axfs_register_profiling_proc(struct axfs_profiling_manager *manager)
+{
+ int rv = 0;
+ struct proc_dir_entry *proc_file;
+ char file_name[20];
+
+ if (!axfs_create_proc_directory()) {
+ rv = -ENOMEM;
+ goto out;
+ }
+
+ sprintf(file_name, "volume%d", proc_name_inc);
+ proc_file = create_proc_entry(file_name, (mode_t) 0644, axfs_proc_dir);
+ if (proc_file == NULL) {
+ remove_proc_entry(file_name, axfs_proc_dir);
+ axfs_delete_proc_directory();
+ rv = -ENOMEM;
+ goto out;
+ }
+
+ proc_name_inc++;
+ proc_file->read_proc = axfs_procfile_read;
+ proc_file->write_proc = axfs_procfile_write;
+ proc_file->owner = THIS_MODULE;
+ proc_file->mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ proc_file->uid = 0;
+ proc_file->gid = 0;
+ proc_file->data = manager;
+
+ printk(KERN_DEBUG "axfs: Proc entry created\n");
+
+out:
+ return rv;
+}
+
+/******************************************************************************
+ *
+ * axfs_unregister_profiling_proc
+ *
+ * Description:
+ * Will unregister the instance of the proc file for the volume that was
+ * mounted. If this is the last volume mounted then the proc directory
+ * will also be removed.
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer to determine which proc file to remove
+ *
+ * Returns:
+ * The profiling manager pointer for the proc file.
+ *
+ *****************************************************************************/
+static struct axfs_profiling_manager *axfs_unregister_profiling_proc(struct
+ axfs_super
+ *sbi)
+{
+ struct axfs_profiling_manager *manager;
+ manager = axfs_delete_proc_file(sbi);
+ axfs_delete_proc_directory();
+ return manager;
+}
+
+/******************************************************************************
+ *
+ * axfs_init_profiling
+ *
+ * Description:
+ * Creates the structures for tracking the page usage data and creates the
+ * proc file that will be used to get the data.
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer
+ *
+ * Returns:
+ * TRUE or FALSE
+ *
+ *****************************************************************************/
+int axfs_init_profiling(struct axfs_super *sbi)
+{
+
+ u32 num_nodes, num_inodes;
+ struct axfs_profiling_manager *manager = NULL;
+ struct axfs_profiling_data *profile_data = NULL;
+ int err = -ENOMEM;
+
+ /* determine the max number of pages in the FS */
+ num_nodes = sbi->blocks;
+ if (!num_nodes)
+ return 0;
+
+ manager = vmalloc(sizeof(*manager));
+ if (!manager)
+ goto out;
+
+ profile_data = vmalloc(num_nodes * sizeof(*profile_data));
+ if (!profile_data)
+ goto out;
+
+ memset(profile_data, 0, num_nodes * sizeof(*profile_data));
+
+ /* determine the max number of inodes in the FS */
+ num_inodes = sbi->files;
+
+ manager->dir_structure = vmalloc(num_inodes * sizeof(u32 *));
+ if (!manager->dir_structure)
+ goto out;
+
+ memset(manager->dir_structure, 0, (num_inodes * sizeof(u32 *)));
+
+ manager->profiling_data = profile_data;
+ manager->size = num_nodes * sizeof(*profile_data);
+ manager->sbi = sbi;
+ sbi->profiling_on = TRUE; /* Turn on profiling by default */
+ sbi->profile_data_ptr = profile_data;
+
+ err = axfs_init_profile_dir_structure(manager, num_inodes);
+ if (err)
+ goto out;
+
+ err = axfs_register_profiling_proc(manager);
+ if (err)
+ goto out;
+
+ return 0;
+
+out:
+ if (manager->dir_structure)
+ vfree(manager->dir_structure);
+ if (profile_data)
+ vfree(profile_data);
+ if (manager)
+ vfree(manager);
+ return err;
+}
+
+/******************************************************************************
+ *
+ * axfs_shutdown_profiling
+ *
+ * Description:
+ * Remove the proc file for this volume and release the memory in the
+ * profiling manager
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer
+ *
+ * Returns:
+ * TRUE or FALSE
+ *
+ *****************************************************************************/
+int axfs_shutdown_profiling(struct axfs_super *sbi)
+{
+ struct axfs_profiling_manager *manager;
+ /* remove the proc file for this volume and release the memory in the
+ profiling manager */
+
+ if (!sbi)
+ return TRUE;
+
+ if (!sbi->profile_data_ptr)
+ return TRUE;
+
+ manager = axfs_unregister_profiling_proc(sbi);
+
+ if (manager == NULL)
+ return FALSE;
+
+ if (manager->dir_structure)
+ vfree(manager->dir_structure);
+ if (manager->profiling_data)
+ vfree(manager->profiling_data);
+ if (manager)
+ vfree(manager);
+ return TRUE;
+}
+
+/******************************************************************************
+ *
+ * axfs_profiling_add
+ *
+ * Description:
+ * Log when a node is paged into memory by incrementing the count in the
+ * array profile data structure.
+ *
+ * Parameters:
+ * (IN) sbi- axfs superblock pointer
+ *
+ * (IN) array_index - The offset into the nodes table of file (node number)
+ *
+ * (IN) axfs_inode_number - Inode of the node to determine file name later
+ *
+ * Returns:
+ * none
+ *
+ *****************************************************************************/
+void axfs_profiling_add(struct axfs_super *sbi, unsigned long array_index,
+ unsigned int axfs_inode_number)
+{
+ unsigned long addr;
+ struct axfs_profiling_data *profile_data;
+
+ if (sbi->profiling_on != TRUE)
+ return;
+
+ addr = (unsigned long)sbi->profile_data_ptr;
+ addr += array_index * sizeof(*profile_data);
+
+ profile_data = (struct axfs_profiling_data *)addr;
+
+ /* Record the inode number to determine the file name later. */
+ profile_data->inode_number = axfs_inode_number;
+
+ /* Increment the number of times the node has been paged in */
+ profile_data->count++;
+}
+
+#else
+
+int axfs_init_profiling(struct axfs_super *sbi)
+{
+ return 0;
+}
+
+int axfs_shutdown_profiling(struct axfs_super *sbi)
+{
+ return 0;
+}
+
+void axfs_profiling_add(struct axfs_super *sbi, unsigned long array_index,
+ unsigned int axfs_inode_number)
+{
+}
+
+#endif /* CONFIG_AXFS_PROFILING */
^ permalink raw reply related
* [PATCH 06/10] AXFS: axfs_super.c
From: Jared Hulbert @ 2008-08-21 5:45 UTC (permalink / raw)
To: Linux-kernel, linux-embedded, linux-mtd, Jörn Engel,
tim.bird, cotte
The many different devices AXFS can mount to and the various
dual device mounting schemes are supported here.
Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
---
diff --git a/fs/axfs/axfs_super.c b/fs/axfs/axfs_super.c
new file mode 100644
index 0000000..5efab38
--- /dev/null
+++ b/fs/axfs/axfs_super.c
@@ -0,0 +1,864 @@
+/*
+ * Advanced XIP File System for Linux - AXFS
+ * Readonly, compressed, and XIP filesystem for Linux systems big and small
+ *
+ * Copyright(c) 2008 Numonyx
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * Authors:
+ * Eric Anderson
+ * Jared Hulbert <jaredeh@gmail.com>
+ * Sujaya Srinivasan
+ * Justin Treon
+ *
+ * More info and current contacts at http://axfs.sourceforge.net
+ *
+ * axfs_super.c -
+ * Contains the core code used to mount the fs.
+ *
+ */
+
+#include <linux/axfs.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/parser.h>
+#include <linux/statfs.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/mtd/mtd.h>
+
+/******************** Function Declarations ****************************/
+static struct super_operations axfs_sops;
+static struct axfs_super *axfs_get_sbi(void);
+static void axfs_put_sbi(struct axfs_super *);
+/***************** functions in other axfs files ***************************/
+int axfs_get_sb_bdev(struct file_system_type *, int, const char *,
+ struct axfs_super *, struct vfsmount *, int *);
+void axfs_kill_block_super(struct super_block *);
+int axfs_copy_block(struct super_block *, void *, u64, u64);
+int axfs_is_dev_bdev(char *);
+int axfs_map_mtd(struct super_block *);
+void axfs_unmap_mtd(struct super_block *);
+int axfs_copy_mtd(struct super_block *, void *, u64, u64);
+int axfs_get_sb_mtd(struct file_system_type *, int, const char *,
+ struct axfs_super *, struct vfsmount *, int *);
+int axfs_is_dev_mtd(char *, int *);
+void axfs_kill_mtd_super(struct super_block *);
+struct inode *axfs_create_vfs_inode(struct super_block *, int);
+int axfs_get_uml_address(char *, unsigned long *, unsigned long *);
+int axfs_init_profiling(struct axfs_super *);
+int axfs_shutdown_profiling(struct axfs_super *);
+void axfs_profiling_add(struct axfs_super *, unsigned long, unsigned int);
+struct inode *axfs_create_vfs_inode(struct super_block *, int);
+/******************************************************************************/
+
+static void axfs_free_region(struct axfs_super *sbi,
+ struct axfs_region_desc *region)
+{
+ if (!region)
+ return;
+
+ if (AXFS_IS_REGION_XIP(sbi, region))
+ return;
+
+ if (region->virt_addr)
+ vfree(region->virt_addr);
+}
+
+static void axfs_put_sbi(struct axfs_super *sbi)
+{
+ if (!sbi)
+ return;
+
+ axfs_shutdown_profiling(sbi);
+
+ axfs_free_region(sbi, &sbi->strings);
+ axfs_free_region(sbi, &sbi->xip);
+ axfs_free_region(sbi, &sbi->compressed);
+ axfs_free_region(sbi, &sbi->byte_aligned);
+ axfs_free_region(sbi, &sbi->node_type);
+ axfs_free_region(sbi, &sbi->node_index);
+ axfs_free_region(sbi, &sbi->cnode_offset);
+ axfs_free_region(sbi, &sbi->cnode_index);
+ axfs_free_region(sbi, &sbi->banode_offset);
+ axfs_free_region(sbi, &sbi->cblock_offset);
+ axfs_free_region(sbi, &sbi->inode_file_size);
+ axfs_free_region(sbi, &sbi->inode_name_offset);
+ axfs_free_region(sbi, &sbi->inode_num_entries);
+ axfs_free_region(sbi, &sbi->inode_mode_index);
+ axfs_free_region(sbi, &sbi->inode_array_index);
+ axfs_free_region(sbi, &sbi->modes);
+ axfs_free_region(sbi, &sbi->uids);
+ axfs_free_region(sbi, &sbi->gids);
+
+ if (sbi->second_dev)
+ kfree(sbi->second_dev);
+
+ if (sbi->cblock_buffer[0])
+ vfree(sbi->cblock_buffer[0]);
+ if (sbi->cblock_buffer[1])
+ vfree(sbi->cblock_buffer[1]);
+
+ kfree(sbi);
+}
+
+static void axfs_put_super(struct super_block *sb)
+{
+ axfs_unmap_mtd(sb);
+ axfs_put_sbi(AXFS_SB(sb));
+ sb->s_fs_info = NULL;
+}
+
+static int axfs_copy_mem(struct super_block *sb, void *buf, u64 fsoffset,
+ u64 len)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ unsigned long addr;
+
+ addr = sbi->virt_start_addr + (unsigned long)fsoffset;
+ memcpy(buf, (void *)addr, (size_t) len);
+ return 0;
+}
+
+static int axfs_copy_metadata(struct super_block *sb, void *buf, u64 fsoffset,
+ u64 len)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ u64 end = fsoffset + len;
+ u64 a = sbi->mmap_size - fsoffset;
+ u64 b = end - sbi->mmap_size;
+ void *bb = (void *)((unsigned long)buf + (unsigned long)a);
+ int err;
+
+ /* Catches case where sbi is not yet fully initialized. */
+ if ((sbi->magic == 0) && (sbi->virt_start_addr != 0))
+ return axfs_copy_mem(sb, buf, fsoffset, len);
+
+ if (fsoffset < sbi->mmap_size) {
+ if (end > sbi->mmap_size) {
+ err = axfs_copy_metadata(sb, buf, fsoffset, a);
+ if (err)
+ return err;
+ err = axfs_copy_metadata(sb, bb, sbi->mmap_size, b);
+ } else {
+ if (AXFS_IS_OFFSET_MMAPABLE(sbi, fsoffset)) {
+ err = axfs_copy_mem(sb, buf, fsoffset, len);
+ } else if (AXFS_HAS_MTD(sb)) {
+ err = axfs_copy_mtd(sb, buf, fsoffset, len);
+ } else if (AXFS_HAS_BDEV(sb)) {
+ err = axfs_copy_block(sb, buf, fsoffset, len);
+ } else {
+ err = -EINVAL;
+ }
+ }
+ } else {
+ if (AXFS_NODEV(sb)) {
+ err = axfs_copy_mem(sb, buf, fsoffset, len);
+ } else if (AXFS_HAS_BDEV(sb)) {
+ err = axfs_copy_block(sb, buf, fsoffset, len);
+ } else if (AXFS_HAS_MTD(sb)) {
+ err = axfs_copy_mtd(sb, buf, fsoffset, len);
+ } else {
+ err = -EINVAL;
+ }
+ }
+ return err;
+}
+
+static int axfs_fill_region_data(struct super_block *sb,
+ struct axfs_region_desc *region, int force)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ unsigned long addr;
+ void *buff = NULL;
+ void *vaddr;
+ int err = -ENOMEM;
+ u64 size = region->size;
+ u64 fsoffset = region->fsoffset;
+ u64 end = fsoffset + size;
+ u64 c_size = region->compressed_size;
+
+ if (size == 0)
+ return 0;
+
+ if (AXFS_IS_REGION_INCORE(region))
+ goto incore;
+
+ if (AXFS_IS_REGION_COMPRESSED(region))
+ goto incore;
+
+ if (AXFS_IS_REGION_XIP(sbi, region)) {
+ if ((end > sbi->mmap_size) && (force))
+ goto incore;
+ addr = sbi->virt_start_addr;
+ addr += (unsigned long)fsoffset;
+ region->virt_addr = (void *)addr;
+ return 0;
+ }
+
+ if (force)
+ goto incore;
+
+ region->virt_addr = NULL;
+ return 0;
+
+incore:
+ region->virt_addr = vmalloc(size);
+ if (!region->virt_addr)
+ goto out;
+ vaddr = region->virt_addr;
+
+ if (AXFS_IS_REGION_COMPRESSED(region)) {
+ buff = vmalloc(c_size);
+ if (!buff)
+ goto out;
+ axfs_copy_metadata(sb, buff, fsoffset, c_size);
+ err = axfs_uncompress_block(vaddr, size, buff, c_size);
+ if (!err)
+ goto out;
+ vfree(buff);
+ } else {
+ axfs_copy_metadata(sb, vaddr, fsoffset, size);
+ }
+
+ return 0;
+
+out:
+ if (buff)
+ vfree(buff);
+ if (region->virt_addr)
+ vfree(region->virt_addr);
+ return err;
+}
+
+static int axfs_fill_region_data_ptrs(struct super_block *sb)
+{
+ int err;
+ struct axfs_super *sbi = AXFS_SB(sb);
+
+ err = axfs_fill_region_data(sb, &sbi->strings, TRUE);
+ if (err)
+ goto out;
+
+ err = axfs_fill_region_data(sb, &sbi->xip, TRUE);
+ if (err)
+ goto out;
+
+ err = axfs_fill_region_data(sb, &sbi->compressed, FALSE);
+ if (err)
+ goto out;
+
+ err = axfs_fill_region_data(sb, &sbi->byte_aligned, FALSE);
+ if (err)
+ goto out;
+
+ err = axfs_fill_region_data(sb, &sbi->node_type, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->node_index, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->cnode_offset, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->cnode_index, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->banode_offset, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->cblock_offset, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->inode_file_size, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->inode_name_offset, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->inode_num_entries, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->inode_mode_index, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->inode_array_index, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->modes, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->uids, TRUE);
+ if (err)
+ goto out;
+ err = axfs_fill_region_data(sb, &sbi->gids, TRUE);
+ if (err)
+ goto out;
+
+out:
+ return err;
+}
+
+static int axfs_init_cblock_buffers(struct axfs_super *sbi)
+{
+ sbi->current_cnode_index = -1;
+ sbi->cblock_buffer[0] = vmalloc(sbi->cblock_size);
+ sbi->cblock_buffer[1] = vmalloc(sbi->cblock_size);
+ if ((!sbi->cblock_buffer[0]) || (!sbi->cblock_buffer[1]))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int axfs_fixup_devices(struct super_block *sb)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ int err = 0;
+
+ if (AXFS_HAS_MTD(sb)) {
+ err = axfs_map_mtd(sb);
+ } else if (AXFS_IS_IOMEM(sbi)) {
+ sbi->phys_start_addr = 0;
+ }
+ return err;
+}
+
+static void axfs_fill_region_desc(struct super_block *sb,
+ struct axfs_region_desc_onmedia *out,
+ u64 offset_be, struct axfs_region_desc *in)
+{
+ u64 offset = be64_to_cpu(offset_be);
+
+ axfs_copy_metadata(sb, (void *)out, offset, sizeof(*out));
+
+ in->fsoffset = be64_to_cpu(out->fsoffset);
+ in->size = be64_to_cpu(out->size);
+ in->compressed_size = be64_to_cpu(out->compressed_size);
+ in->max_index = be64_to_cpu(out->max_index);
+ in->table_byte_depth = out->table_byte_depth;
+ in->incore = out->incore;
+}
+
+static int axfs_fill_region_descriptors(struct super_block *sb,
+ struct axfs_super_onmedia *sbo)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ struct axfs_region_desc_onmedia *out;
+
+ out = kmalloc(sizeof(*out), GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+ memset(out, 0, sizeof(*out));
+
+ axfs_fill_region_desc(sb, out, sbo->strings, &sbi->strings);
+ axfs_fill_region_desc(sb, out, sbo->xip, &sbi->xip);
+ axfs_fill_region_desc(sb, out, sbo->compressed, &sbi->compressed);
+ axfs_fill_region_desc(sb, out, sbo->byte_aligned, &sbi->byte_aligned);
+ axfs_fill_region_desc(sb, out, sbo->node_type, &sbi->node_type);
+ axfs_fill_region_desc(sb, out, sbo->node_index, &sbi->node_index);
+ axfs_fill_region_desc(sb, out, sbo->cnode_offset, &sbi->cnode_offset);
+ axfs_fill_region_desc(sb, out, sbo->cnode_index, &sbi->cnode_index);
+ axfs_fill_region_desc(sb, out, sbo->banode_offset, &sbi->banode_offset);
+ axfs_fill_region_desc(sb, out, sbo->cblock_offset, &sbi->cblock_offset);
+ axfs_fill_region_desc(sb, out, sbo->inode_file_size,
+ &sbi->inode_file_size);
+ axfs_fill_region_desc(sb, out, sbo->inode_name_offset,
+ &sbi->inode_name_offset);
+ axfs_fill_region_desc(sb, out, sbo->inode_num_entries,
+ &sbi->inode_num_entries);
+ axfs_fill_region_desc(sb, out, sbo->inode_mode_index,
+ &sbi->inode_mode_index);
+ axfs_fill_region_desc(sb, out, sbo->inode_array_index,
+ &sbi->inode_array_index);
+ axfs_fill_region_desc(sb, out, sbo->modes, &sbi->modes);
+ axfs_fill_region_desc(sb, out, sbo->uids, &sbi->uids);
+ axfs_fill_region_desc(sb, out, sbo->gids, &sbi->gids);
+
+ kfree(out);
+
+ return 0;
+}
+
+int axfs_set_compression_type(struct axfs_super *sbi)
+{
+ if (sbi->compression_type != ZLIB)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int axfs_get_onmedia_super(struct super_block *sb)
+{
+ int err;
+ struct axfs_super *sbi = AXFS_SB(sb);
+ struct axfs_super_onmedia *sbo;
+
+ sbo = kmalloc(sizeof(*sbo), GFP_KERNEL);
+ if (!sbo)
+ return -ENOMEM;
+
+ axfs_copy_metadata(sb, (void *)sbo, 0, sizeof(*sbo));
+
+ /* Do sanity checks on the superblock */
+ if (be32_to_cpu(sbo->magic) != AXFS_MAGIC) {
+ printk(KERN_ERR "axfs: wrong magic\n");
+ err = -EINVAL;
+ goto out;
+ }
+
+ /* verify the signiture is correct */
+ if (strncmp(sbo->signature, AXFS_SIGNATURE, sizeof(AXFS_SIGNATURE))) {
+ printk(KERN_ERR "axfs: wrong axfs signature,"
+ " read %s, expected %s\n",
+ sbo->signature, AXFS_SIGNATURE);
+ err = -EINVAL;
+ goto out;
+ }
+
+ sbi->magic = be32_to_cpu(sbo->magic);
+ sbi->version_major = sbo->version_major;
+ sbi->version_minor = sbo->version_minor;
+ sbi->version_sub = sbo->version_sub;
+ sbi->files = be64_to_cpu(sbo->files);
+ sbi->size = be64_to_cpu(sbo->size);
+ sbi->blocks = be64_to_cpu(sbo->blocks);
+ sbi->mmap_size = be64_to_cpu(sbo->mmap_size);
+ sbi->cblock_size = be32_to_cpu(sbo->cblock_size);
+ sbi->timestamp.tv_sec = be64_to_cpu(sbo->timestamp);
+ sbi->timestamp.tv_nsec = 0;
+ sbi->compression_type = sbo->compression_type;
+
+ err = axfs_set_compression_type(sbi);
+ if (err)
+ goto out;
+
+ /* If no block or MTD device, adjust mmapable to cover all image */
+ if (AXFS_NODEV(sb))
+ sbi->mmap_size = sbi->size;
+
+ err = axfs_fill_region_descriptors(sb, sbo);
+ if (err)
+ goto out;
+
+ err = 0;
+out:
+ kfree(sbo);
+ return err;
+}
+
+/* Verify that the size of the block segment of a split filesystem
+ is less than or equal to that of the device containing it.
+ Validation of the size of an mmap segment vs. the device containing
+ it is handled by the point() function in axfs_map_mtd.
+*/
+int axfs_verify_device_sizes(struct super_block *sb)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ struct mtd_info *mtd0 = AXFS_MTD(sb);
+ struct mtd_info *mtd1 = AXFS_MTD1(sb);
+ int sndsize = sbi->size - sbi->mmap_size;
+
+ /* Whole FS on one device */
+ if (mtd0 && !mtd1 && (mtd0->size < sbi->size)) {
+ printk(KERN_ERR "axfs: ERROR: Filesystem extends beyond end of"
+ "MTD! Filesystem cannot be safely mounted!\n");
+ printk(KERN_ERR "mtd name: %s, mtd size: 0x%x,"
+ " fs size: 0x%llx\n", mtd0->name, mtd0->size, sbi->size);
+ return -EINVAL;
+ }
+
+ /* Split filesystem using physaddr */
+ if (sndsize && !mtd0 && mtd1 && (mtd1->size < sndsize)) {
+ printk(KERN_ERR "axfs: ERROR: The specified second_dev device "
+ "is smaller than the store and download segment!\n");
+ printk(KERN_ERR "mtd name: %s, mtd size: 0x%x, "
+ "snd size: 0x%x\n", mtd1->name, mtd1->size, sndsize);
+ return -EINVAL;
+ }
+
+ /* Split filesystem using two devices */
+ if (sndsize && mtd0 && mtd1) {
+ if (mtd0->size < sbi->mmap_size) {
+ printk(KERN_ERR "axfs: ERROR: Mmap segment extends"
+ " beyond end of MTD!");
+ printk(KERN_ERR "mtd name: %s, mtd size: 0x%x, mmap "
+ "size: 0x%llx",
+ mtd0->name, mtd0->size, sbi->mmap_size);
+ return -EINVAL;
+ }
+ if (mtd1->size < sndsize) {
+ printk(KERN_ERR "axfs: ERROR: The specified second_dev "
+ "device is smaller than the store and download "
+ "segment!\n");
+ printk(KERN_ERR "mtd name: %s, mtd size: 0x%x, "
+ "snd size: 0x%x\n",
+ mtd1->name, mtd1->size, sndsize);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/* Read the last four bytes of the volume and make sure the AXFS magic is
+ present. */
+int axfs_verify_eofs_magic(struct super_block *sb)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ u32 buf = 0;
+ int err;
+ u32 fsoffset = sbi->size - sizeof(u32);
+ int len = sizeof(u32);
+
+ err = axfs_copy_metadata(sb, &buf, fsoffset, len);
+
+ if (err)
+ return -EINVAL;
+
+ if (be32_to_cpu(buf) != AXFS_MAGIC) {
+ printk(KERN_ERR "READ: 0x%x\n", be32_to_cpu(buf));
+ printk(KERN_ERR "ERROR: Filesystem is incomplete and cannot be "
+ "mounted!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int axfs_do_fill_super(struct super_block *sb)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ int err;
+
+ err = axfs_get_onmedia_super(sb);
+ if (err)
+ goto out;
+
+ err = axfs_fixup_devices(sb);
+ if (err)
+ goto out;
+
+ err = axfs_verify_device_sizes(sb);
+ if (err)
+ goto out;
+
+ err = axfs_verify_eofs_magic(sb);
+ if (err)
+ goto out;
+
+ err = axfs_fill_region_data_ptrs(sb);
+ if (err)
+ goto out;
+
+ /* Check that the root inode is in a sane state */
+ if (!S_ISDIR(AXFS_GET_MODE(sbi, 0))) {
+ printk(KERN_ERR "axfs: root is not a directory\n");
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (AXFS_GET_INODE_NUM_ENTRIES(sbi, 0) == 0) {
+ printk(KERN_INFO "axfs: empty filesystem");
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = axfs_init_cblock_buffers(sbi);
+ if (err)
+ goto out;
+
+ init_rwsem(&sbi->lock);
+
+ return 0;
+
+out:
+ axfs_put_super(sb);
+ return err;
+}
+
+int axfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+ struct axfs_super *sbi_in = (struct axfs_super *)data;
+ struct axfs_super *sbi;
+ struct inode *root;
+ int err;
+
+ sbi = axfs_get_sbi();
+ sb->s_fs_info = (void *)sbi;
+ memcpy(sbi, sbi_in, sizeof(*sbi));
+
+ /* fully populate the incore superblock structures */
+ err = axfs_do_fill_super(sb);
+ if (err)
+ goto out;
+
+ sb->s_flags |= MS_RDONLY;
+
+ /* Setup the VFS super block now */
+ sb->s_op = &axfs_sops;
+ root = axfs_create_vfs_inode(sb, 0);
+ if (!root) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ sb->s_root = d_alloc_root(root);
+ if (!sb->s_root) {
+ iput(root);
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = axfs_init_profiling(sbi);
+ if (err)
+ goto out;
+
+ return 0;
+
+out:
+ axfs_put_super(sb);
+ return err;
+}
+
+static int axfs_get_sb_address(struct file_system_type *fs_type, int flags,
+ struct axfs_super *sbi, struct vfsmount *mnt,
+ int *err)
+{
+ int mtdnr;
+ char *sd = sbi->second_dev;
+
+ if (sbi->phys_start_addr == 0)
+ return FALSE;
+
+ if (sbi->phys_start_addr & (PAGE_SIZE - 1)) {
+ printk(KERN_ERR
+ "axfs: address 0x%lx for axfs image isn't aligned"
+ " to a page boundary\n", sbi->phys_start_addr);
+ *err = -EINVAL;
+ return TRUE;
+ }
+
+ if (axfs_is_dev_mtd(sd, &mtdnr)) {
+ return axfs_get_sb_mtd(fs_type, flags, sd, sbi, mnt, err);
+ } else if (axfs_is_dev_bdev(sd)) {
+ return axfs_get_sb_bdev(fs_type, flags, sd, sbi, mnt, err);
+ } else {
+ *err = get_sb_nodev(fs_type, flags, sbi, axfs_fill_super, mnt);
+ }
+
+ return TRUE;
+}
+
+/* helpers for parse_axfs_options */
+enum {
+ OPTION_ERR,
+ OPTION_SECOND_DEV,
+ OPTION_PHYSICAL_ADDRESS_LOWER_X,
+ OPTION_PHYSICAL_ADDRESS_UPPER_X,
+ OPTION_IOMEM
+};
+
+/* helpers for parse_axfs_options */
+static match_table_t tokens = {
+ {OPTION_SECOND_DEV, "second_dev=%s"},
+ {OPTION_PHYSICAL_ADDRESS_LOWER_X, "physaddr=0x%s"},
+ {OPTION_PHYSICAL_ADDRESS_UPPER_X, "physaddr=0X%s"},
+ {OPTION_IOMEM, "iomem=%s"},
+ {OPTION_ERR, NULL}
+};
+
+static int axfs_check_options(char *options, struct axfs_super *sbi)
+{
+ unsigned long address = 0;
+ char *iomem = NULL;
+ unsigned long length = 0;
+ char *p;
+ int err = -EINVAL;
+ substring_t args[MAX_OPT_ARGS];
+
+ if (!options)
+ return 0;
+
+ if (!*options)
+ return 0;
+
+ while ((p = strsep(&options, ",")) != NULL) {
+ int token;
+ if (!*p)
+ continue;
+
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case OPTION_SECOND_DEV:
+ sbi->second_dev = match_strdup(&args[0]);
+ if (!(sbi->second_dev)) {
+ err = -ENOMEM;
+ goto out;
+ }
+ if (!*(sbi->second_dev))
+ goto bad_value;
+ break;
+ case OPTION_IOMEM:
+ iomem = match_strdup(&args[0]);
+ if (!(iomem)) {
+ err = -ENOMEM;
+ goto out;
+ }
+ if (!*iomem)
+ goto bad_value;
+ break;
+ case OPTION_PHYSICAL_ADDRESS_LOWER_X:
+ case OPTION_PHYSICAL_ADDRESS_UPPER_X:
+ if (match_hex(&args[0], (int *)&address))
+ goto out;
+ if (!address)
+ goto bad_value;
+ break;
+ default:
+ printk(KERN_ERR
+ "axfs: unrecognized mount option \"%s\" "
+ "or missing value\n", p);
+ goto out;
+ }
+ }
+
+ if (iomem) {
+ if (address)
+ goto out;
+ err = axfs_get_uml_address(iomem, &address, &length);
+ kfree(iomem);
+ sbi->iomem_size = length;
+ sbi->virt_start_addr = address;
+ }
+
+ sbi->phys_start_addr = address;
+ return 0;
+
+bad_value:
+ printk(KERN_ERR
+ "axfs: unrecognized mount option \"%s\" "
+ "or missing value\n", p);
+out:
+ if (iomem)
+ kfree(iomem);
+ return err;
+}
+
+int axfs_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, struct vfsmount *mnt)
+{
+ struct axfs_super *sbi;
+ int err;
+
+ sbi = axfs_get_sbi();
+ if (IS_ERR(sbi))
+ return PTR_ERR(sbi);
+
+ err = axfs_check_options((char *)data, sbi);
+ if (err)
+ goto out;
+
+ /* First we check if we are mounting directly to memory */
+ if (axfs_get_sb_address(fs_type, flags, sbi, mnt, &err))
+ goto out;
+
+ /* Next we assume there's a MTD device */
+ if (axfs_get_sb_mtd(fs_type, flags, dev_name, sbi, mnt, &err))
+ goto out;
+
+ /* Now we assume it's a block device */
+ if (sbi->second_dev) {
+ printk(KERN_ERR
+ "axfs: can't specify secondary block device %s because"
+ " %s is assumed to be a block device\n", sbi->second_dev,
+ dev_name);
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (axfs_get_sb_bdev(fs_type, flags, dev_name, sbi, mnt, &err))
+ goto out;
+
+ err = -EINVAL;
+
+out:
+ axfs_put_sbi(sbi);
+ return err;
+}
+
+static struct axfs_super *axfs_get_sbi(void)
+{
+ struct axfs_super *sbi;
+
+ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
+ if (sbi)
+ return sbi;
+
+ axfs_put_sbi(sbi);
+ return ERR_PTR(-ENOMEM);
+}
+
+static void axfs_kill_super(struct super_block *sb)
+{
+ if (AXFS_NODEV(sb))
+ return kill_anon_super(sb);
+
+ if (AXFS_HAS_MTD(sb))
+ axfs_kill_mtd_super(sb);
+
+ if (AXFS_HAS_BDEV(sb))
+ axfs_kill_block_super(sb);
+}
+
+static int axfs_remount(struct super_block *sb, int *flags, char *data)
+{
+ *flags |= MS_RDONLY;
+ return 0;
+}
+
+static int axfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+ struct axfs_super *sbi = AXFS_SB(dentry->d_sb);
+
+ buf->f_type = AXFS_MAGIC;
+ buf->f_bsize = AXFS_PAGE_SIZE;
+ buf->f_blocks = sbi->blocks;
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_files = sbi->files;
+ buf->f_ffree = 0;
+ buf->f_namelen = AXFS_MAXPATHLEN;
+ return 0;
+}
+
+static struct super_operations axfs_sops = {
+ .put_super = axfs_put_super,
+ .remount_fs = axfs_remount,
+ .statfs = axfs_statfs,
+};
+
+static struct file_system_type axfs_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "axfs",
+ .get_sb = axfs_get_sb,
+ .kill_sb = axfs_kill_super,
+};
+
+static int __init init_axfs_fs(void)
+{
+ axfs_uncompress_init();
+ return register_filesystem(&axfs_fs_type);
+}
+
+static void __exit exit_axfs_fs(void)
+{
+ axfs_uncompress_exit();
+ unregister_filesystem(&axfs_fs_type);
+}
+
+module_init(init_axfs_fs);
+module_exit(exit_axfs_fs);
+MODULE_LICENSE("GPL");
^ permalink raw reply related
* [PATCH 07/10] AXFS: axfs_bdev.c
From: Jared Hulbert @ 2008-08-21 5:45 UTC (permalink / raw)
To: Linux-kernel, linux-embedded, linux-mtd, Jörn Engel,
tim.bird, cotte
All the block device code goes here.
Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
---
diff --git a/fs/axfs/axfs_bdev.c b/fs/axfs/axfs_bdev.c
new file mode 100644
index 0000000..4c6f83c
--- /dev/null
+++ b/fs/axfs/axfs_bdev.c
@@ -0,0 +1,158 @@
+/*
+ * Advanced XIP File System for Linux - AXFS
+ * Readonly, compressed, and XIP filesystem for Linux systems big and small
+ *
+ * Copyright(c) 2008 Numonyx
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * Authors:
+ * Jared Hulbert <jaredeh@gmail.com>
+ *
+ * Project url: http://axfs.sourceforge.net
+ *
+ * axfs_bdev.c -
+ * Allows axfs to use block devices or has dummy functions if block
+ * device support is compiled out of the kernel.
+ *
+ */
+
+#include <linux/axfs.h>
+#include <linux/mount.h>
+#ifdef CONFIG_BLOCK
+#include <linux/buffer_head.h>
+#include <linux/namei.h>
+
+int axfs_fill_super(struct super_block *sb, void *data, int silent);
+
+int axfs_get_sb_bdev(struct file_system_type *fs_type, int flags,
+ const char *dev_name, struct axfs_super *sbi,
+ struct vfsmount *mnt, int *err)
+{
+ *err = get_sb_bdev(fs_type, flags, dev_name, sbi, axfs_fill_super, mnt);
+
+ if (*err)
+ return FALSE;
+ return TRUE;
+}
+
+void axfs_kill_block_super(struct super_block *sb)
+{
+ kill_block_super(sb);
+}
+
+/******************************************************************************
+ *
+ * axfs_copy_block_data
+ *
+ * Description: Helper function to read data from block device
+ *
+ * Parameters:
+ * (IN) sb - pointer to super block structure.
+ *
+ * (IN) dst_addr - pointer to buffer into which data is to be read.
+ *
+ * (IN) boffset - offset within block device
+ *
+ * (IN) len - length of data to be read
+ *
+ * Returns:
+ * 0 or error number
+ *
+ *****************************************************************************/
+int axfs_copy_block(struct super_block *sb, void *dst_addr, u64 fsoffset,
+ u64 len)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ u64 boffset = AXFS_FSOFFSET_2_DEVOFFSET(sbi, fsoffset);
+ u64 blocks;
+ u64 blksize = sb->s_blocksize;
+ unsigned long dst;
+ unsigned long src;
+ sector_t block;
+ size_t bytes;
+ struct buffer_head *bh;
+ u64 copied = 0;
+
+ if (len == 0)
+ return 0;
+
+ blocks = len / blksize;
+ if ((len % blksize) > 0)
+ blocks += 1;
+
+ while (copied < len) {
+ /* Explicit casting for ARM linker errors. */
+ block = (sector_t) boffset + (sector_t) copied;
+ block /= (sector_t) blksize;
+ bh = sb_bread(sb, block);
+ src = (unsigned long)bh->b_data;
+ dst = (unsigned long)dst_addr;
+ if (copied == 0) {
+ /* Explicit casting for ARM linker errors. */
+ bytes = (size_t) blksize;
+ bytes -= (size_t) boffset % (size_t) blksize;
+ if (bytes > len)
+ bytes = len;
+ /* Explicit casting for ARM linker errors. */
+ src += (unsigned long)boffset % (unsigned long)blksize;
+ } else {
+ dst += copied;
+ if ((len - copied) < blksize) {
+ bytes = len - copied;
+ } else {
+ bytes = blksize;
+ }
+ }
+ memcpy((void *)dst, (void *)src, bytes);
+ copied += bytes;
+ brelse(bh);
+ }
+ return 0;
+}
+
+int axfs_is_dev_bdev(char *path)
+{
+ struct nameidata nd;
+ int ret = FALSE;
+
+ if (!path)
+ return FALSE;
+
+ if (path_lookup(path, LOOKUP_FOLLOW, &nd))
+ return FALSE;
+
+ if (S_ISBLK(nd.path.dentry->d_inode->i_mode))
+ ret = TRUE;
+
+ path_put(&nd.path);
+ return ret;
+}
+
+#else
+
+int axfs_get_sb_bdev(struct file_system_type *fs_type, int flags,
+ const char *dev_name, struct axfs_super *sbi,
+ struct vfsmount *mnt, int *err)
+{
+ return FALSE;
+}
+
+void axfs_kill_block_super(struct super_block *sb)
+{
+}
+
+int axfs_copy_block(struct super_block *sb, void *dst_addr, u64 fsoffset,
+ u64 len)
+{
+ return -EINVAL;
+}
+
+int axfs_is_dev_bdev(char *path)
+{
+ return FALSE;
+}
+
+#endif /* CONFIG_BLOCK */
^ permalink raw reply related
* [PATCH 08/10] AXFS: axfs_mtd.c
From: Jared Hulbert @ 2008-08-21 5:45 UTC (permalink / raw)
To: Linux-kernel, linux-embedded, linux-mtd, Jörn Engel,
tim.bird, cotte
While we use mtd_super.c for most MTD mounting there are several things
we do here to interface with the MTD devices.
Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
---
diff --git a/fs/axfs/axfs_mtd.c b/fs/axfs/axfs_mtd.c
new file mode 100644
index 0000000..35c8a98
--- /dev/null
+++ b/fs/axfs/axfs_mtd.c
@@ -0,0 +1,233 @@
+/*
+ * Advanced XIP File System for Linux - AXFS
+ * Readonly, compressed, and XIP filesystem for Linux systems big and small
+ *
+ * Copyright(c) 2008 Numonyx
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * Authors:
+ * Jared Hulbert <jaredeh@gmail.com>
+ *
+ * Project url: http://axfs.sourceforge.net
+ *
+ * axfs_mtd.c -
+ * Allows axfs to use mtd devices or has dummy functions if mtd
+ * device support is compiled out of the kernel.
+ */
+
+#include <linux/axfs.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/ctype.h>
+#include <linux/namei.h>
+
+#ifdef CONFIG_MTD
+#include <linux/mtd/super.h>
+
+int axfs_fill_super(struct super_block *, void *, int);
+
+static struct mtd_info *axfs_get_mtd_device(int mtdnr)
+{
+ struct mtd_info *device;
+
+ device = get_mtd_device(NULL, mtdnr);
+
+ if (!PTR_ERR(device))
+ return NULL;
+
+ return device;
+}
+
+int axfs_is_dev_mtd(char *path, int *mtdnr)
+{
+ char *off = NULL;
+ char *endptr = NULL;
+ char dev[] = "/dev/\0";
+ char mtd[] = "mtd\0";
+ char mtdblk[] = "mtdblock\0";
+
+ if (!path || !*path)
+ return FALSE;
+
+ off = path;
+
+ if (strncmp(dev, off, strlen(dev)) == 0)
+ off += strlen(dev);
+
+ if (!strncmp(mtd, off, strlen(mtd)) && isdigit(off[strlen(mtd)]))
+ off += strlen(mtd);
+
+ if (!strncmp(mtdblk, off, strlen(mtdblk))
+ && isdigit(off[strlen(mtdblk)]))
+ off += strlen(mtdblk);
+
+ *mtdnr = simple_strtoul(off, &endptr, 0);
+
+ if (!*endptr)
+ return TRUE;
+
+ return FALSE;
+}
+
+static struct mtd_info *axfs_get_mtd_info(struct super_block *sb, u64 fsoffset)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+
+ if (fsoffset == 0)
+ return (struct mtd_info *)AXFS_MTD0(sb);
+
+ if (fsoffset < sbi->mmap_size)
+ return (struct mtd_info *)AXFS_MTD0(sb);
+
+ if (AXFS_MTD1(sb) != NULL)
+ return (struct mtd_info *)AXFS_MTD1(sb);
+
+ return (struct mtd_info *)AXFS_MTD0(sb);
+}
+
+int axfs_copy_mtd(struct super_block *sb, void *dst, u64 fsoffset, u64 len)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ u64 offset = AXFS_FSOFFSET_2_DEVOFFSET(sbi, fsoffset);
+ struct mtd_info *mtd;
+ u_char *mtdbuf = (u_char *) dst;
+ size_t retlen;
+ int err;
+
+ if (len == 0)
+ return 0;
+
+ mtd = axfs_get_mtd_info(sb, fsoffset);
+ err = mtd->read(mtd, (loff_t) offset, (size_t) len, &retlen, mtdbuf);
+
+ if (len != retlen)
+ return -EIO;
+
+ return err;
+}
+
+/******************************************************************************
+ *
+ * axfs_map_mtd
+ *
+ * Description: When provided, uses the mtd point() capability to map allow
+ * axfs a direct memory access to the filesystem.
+ *
+ * Parameters:
+ * (IN) sb - pointer to the super_block structure
+ *
+ * Returns:
+ * 0 or error number
+ *
+ *****************************************************************************/
+int axfs_map_mtd(struct super_block *sb)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ struct mtd_info *mtd = (struct mtd_info *)AXFS_MTD0(sb);
+ size_t retlen;
+ int err = 0;
+ void *virt;
+ resource_size_t phys;
+
+ if (!mtd->point || !mtd->unpoint)
+ return 0;
+
+ err = mtd->point(mtd, 0, sbi->mmap_size, &retlen, &virt, &phys);
+ if (err)
+ return err;
+
+ if (retlen != sbi->mmap_size) {
+ mtd->unpoint(mtd, 0, retlen);
+ return -EINVAL;
+ }
+
+ sbi->virt_start_addr = (unsigned long)virt;
+ sbi->phys_start_addr = (unsigned long)phys;
+ sbi->mtd_pointed = TRUE;
+
+ return 0;
+}
+
+void axfs_unmap_mtd(struct super_block *sb)
+{
+ struct axfs_super *sbi = AXFS_SB(sb);
+ struct mtd_info *mtd = (struct mtd_info *)AXFS_MTD0(sb);
+
+ if (!sbi)
+ return;
+
+ if (AXFS_MTD1(sb))
+ put_mtd_device((struct mtd_info *)AXFS_MTD1(sb));
+
+ if (AXFS_IS_POINTED(sbi)) {
+ mtd->unpoint(mtd, 0, sbi->mmap_size);
+ } else {
+ if (AXFS_MTD0(sb))
+ put_mtd_device((struct mtd_info *)AXFS_MTD0(sb));
+ }
+}
+
+
+int axfs_get_sb_mtd(struct file_system_type *fs_type, int flags,
+ const char *dev_name, struct axfs_super *sbi,
+ struct vfsmount *mnt, int *err)
+{
+ int nflags, mtdnr;
+
+ if (axfs_is_dev_mtd(sbi->second_dev, &mtdnr)) {
+ sbi->mtd1 = (void *)axfs_get_mtd_device(mtdnr);
+ if (!sbi->mtd1) {
+ *err = -EINVAL;
+ return FALSE;
+ }
+ }
+ nflags = flags & MS_SILENT;
+
+ *err = get_sb_mtd(fs_type, nflags, dev_name, sbi, axfs_fill_super, mnt);
+ if (*err)
+ return FALSE;
+
+ sbi->mtd0 = mnt->mnt_sb->s_mtd;
+ return TRUE;
+}
+
+void axfs_kill_mtd_super(struct super_block *sb)
+{
+ kill_mtd_super(sb);
+}
+#else
+
+int axfs_map_mtd(struct super_block *sb)
+{
+ return 0;
+}
+
+void axfs_unmap_mtd(struct super_block *sb)
+{
+}
+
+int axfs_copy_mtd(struct super_block *sb, void *dst, u64 fsoffset, u64 len)
+{
+ return -EINVAL;
+}
+
+int axfs_get_sb_mtd(struct file_system_type *fs_type, int flags,
+ const char *dev_name, char *second_dev,
+ struct axfs_super *sbi, struct vfsmount *mnt, int *err)
+{
+ return FALSE;
+}
+
+int axfs_is_dev_mtd(char *path, int *mtdnr)
+{
+ return FALSE;
+}
+
+void axfs_kill_mtd_super(struct super_block *sb)
+{
+}
+
+#endif /* CONFIG_MTD */
^ permalink raw reply related
* [PATCH 09/10] AXFS: axfs_uml.c
From: Jared Hulbert @ 2008-08-21 5:46 UTC (permalink / raw)
To: Linux-kernel, linux-embedded, linux-mtd, Jörn Engel,
tim.bird, cotte
UML specific code for working with iomem 'devices'. UML is handy for testing.
Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
---
diff --git a/fs/axfs/axfs_uml.c b/fs/axfs/axfs_uml.c
new file mode 100644
index 0000000..7d479a0
--- /dev/null
+++ b/fs/axfs/axfs_uml.c
@@ -0,0 +1,47 @@
+/*
+ * Advanced XIP File System for Linux - AXFS
+ * Readonly, compressed, and XIP filesystem for Linux systems big and small
+ *
+ * Copyright(c) 2008 Numonyx
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * Authors:
+ * Jared Hulbert <jaredeh@gmail.com>
+ *
+ * Project url: http://axfs.sourceforge.net
+ *
+ * axfs_uml.c -
+ * Allows axfs to a UML kernels find_iomem() interface as an XIP device or
+ * dummy functions if this is not a UML build.
+ */
+
+#include <linux/axfs.h>
+#ifdef CONFIG_UML
+#include <mem_user.h>
+int axfs_get_uml_address(char *iomem, unsigned long *address,
+ unsigned long *length)
+{
+ *address = find_iomem(iomem, length);
+ if (!(*address)) {
+ printk(KERN_DEBUG "axfs: find_iomem() failed\n");
+ return -EINVAL;
+ }
+
+ if (*length < PAGE_SIZE) {
+ printk(KERN_DEBUG
+ "axfs: iomem() too small, must be at least %li Bytes\n",
+ PAGE_SIZE);
+ return -EINVAL;
+ }
+ return 0;
+}
+#else
+int axfs_get_uml_address(char *iomem, unsigned long *address,
+ unsigned long *length)
+{
+ return 0;
+}
+#endif /* CONFIG_UML */
^ permalink raw reply related
* [PATCH 10/10] AXFS: axfs_uncompress.c
From: Jared Hulbert @ 2008-08-21 5:46 UTC (permalink / raw)
To: Linux-kernel, linux-embedded, linux-mtd, Jörn Engel,
tim.bird, cotte
Handles the decompression for axfs, modeled after fs/cramfs/uncompress.c.
Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
---
diff --git a/fs/axfs/axfs_uncompress.c b/fs/axfs/axfs_uncompress.c
new file mode 100644
index 0000000..b7a2060
--- /dev/null
+++ b/fs/axfs/axfs_uncompress.c
@@ -0,0 +1,97 @@
+/*
+ * Advanced XIP File System for Linux - AXFS
+ * Readonly, compressed, and XIP filesystem for Linux systems big and small
+ *
+ * Modified in 2006 by Eric Anderson
+ * from the cramfs sources fs/cramfs/uncompress.c
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ *
+ * axfs_uncompress.c -
+ * axfs interfaces to the uncompression library. There's really just
+ * three entrypoints:
+ *
+ * - axfs_uncompress_init() - called to initialize the thing.
+ * - axfs_uncompress_exit() - tell me when you're done
+ * - axfs_uncompress_block() - uncompress a block.
+ *
+ * NOTE NOTE NOTE! The uncompression is entirely single-threaded. We
+ * only have one stream, and we'll initialize it only once even if it
+ * then is used by multiple filesystems.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/vmalloc.h>
+#include <linux/zlib.h>
+#include <linux/mutex.h>
+
+static z_stream stream;
+static int initialized;
+static struct mutex axfs_uncmp_mutex;
+
+int axfs_uncompress_block(void *dst, int dstlen, void *src, int srclen)
+{
+ int err;
+ int out;
+
+ mutex_lock(&axfs_uncmp_mutex);
+
+ stream.next_in = src;
+ stream.avail_in = srclen;
+
+ stream.next_out = dst;
+ stream.avail_out = dstlen;
+
+ err = zlib_inflateReset(&stream);
+ if (err != Z_OK) {
+ printk(KERN_ERR "zlib_inflateReset error %d\n", err);
+ zlib_inflateEnd(&stream);
+ zlib_inflateInit(&stream);
+ }
+
+ err = zlib_inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END)
+ goto err;
+
+ out = stream.total_out;
+
+ mutex_unlock(&axfs_uncmp_mutex);
+
+ return out;
+
+err:
+
+ mutex_unlock(&axfs_uncmp_mutex);
+
+ printk(KERN_ERR "Error %d while decompressing!\n", err);
+ printk(KERN_ERR "%p(%d)->%p(%d)\n", src, srclen, dst, dstlen);
+ return 0;
+}
+
+int axfs_uncompress_init(void)
+{
+ if (!initialized++) {
+
+ mutex_init(&axfs_uncmp_mutex);
+
+ stream.workspace = vmalloc(zlib_inflate_workspacesize());
+ if (!stream.workspace) {
+ initialized = 0;
+ return -ENOMEM;
+ }
+ stream.next_in = NULL;
+ stream.avail_in = 0;
+ zlib_inflateInit(&stream);
+ }
+ return 0;
+}
+
+int axfs_uncompress_exit(void)
+{
+ if (!--initialized) {
+ zlib_inflateEnd(&stream);
+ vfree(stream.workspace);
+ }
+ return 0;
+}
^ permalink raw reply related
* Re: [PATCH 00/10] AXFS: Advanced XIP filesystem
From: Frans Meulenbroeks @ 2008-08-21 6:32 UTC (permalink / raw)
To: jaredeh
Cc: Linux-kernel, linux-embedded, linux-mtd, Jörn Engel,
tim.bird, cotte, nickpiggin
In-Reply-To: <48AD00C4.6060302@gmail.com>
Jared, nice work!
I've also read your paper from the linux symposium
(http://ols.fedoraproject.org/OLS/Reprints-2008/hulbert-reprint.pdf)
A few questions:
- how does this benchmark compared to cramfs and squashfs in a NAND-only system
(or is it just not a good plan to use this with NAND-only (of course
I won't get XIP with NAND, I understand that)
- would axfs be suitable as a filesystem on a ram disk?
Background for the last question is that if you do not have the memory
to retain all pages uncompressed (as you would with ramfs), this could
be a nice intermediate format.
Furthermore compared to ramfs, a filesystem on a ramdisk does not need
the initialisation during startup (decompressing the cpio file,
creating the files, copying the data), so when it comes to boot times
a filesystem on a ramdisk (e.g. axfs) could be a better choice.
Appreciate your feedback.
Frans.
^ permalink raw reply
* Re: [PATCH 01/10] AXFS: exporting xip_file_fault() for use with AXFS
From: Paulius Zaleckas @ 2008-08-21 7:25 UTC (permalink / raw)
To: jaredeh; +Cc: Jörn Engel, linux-mtd, Linux-kernel, linux-embedded,
tim.bird
In-Reply-To: <48AD00D5.5010904@gmail.com>
Jared Hulbert wrote:
> We'll need this for AXFS. The equivalent function in filemap.c is exported.
>
> Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
> ---
> include/linux/mm.h | 4 ++++
> mm/filemap_xip.c | 3 ++-
> 2 files changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 72a15dc..2be5c22 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -161,6 +161,10 @@ struct vm_fault {
> */
> };
>
> +#ifdef CONFIG_FS_XIP
> +extern int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
> +#endif
> +
No need for #ifdef here as this function is compiled and exported in .c
regardless of CONFIG_FS_XIP
> /*
> * These are the virtual MM functions - opening of an area, closing and
> * unmapping it (needed to keep files on disk up-to-date etc), pointer
> diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
> index 380ab40..ab2f174 100644
> --- a/mm/filemap_xip.c
> +++ b/mm/filemap_xip.c
> @@ -206,7 +206,7 @@ __xip_unmap (struct address_space * mapping,
> *
> * This function is derived from filemap_fault, but used for execute in place
> */
> -static int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
> +int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
> {
> struct file *file = vma->vm_file;
> struct address_space *mapping = file->f_mapping;
> @@ -262,6 +262,7 @@ found:
> return 0;
> }
> }
> +EXPORT_SYMBOL_GPL(xip_file_fault);
>
> static struct vm_operations_struct xip_file_vm_ops = {
> .fault = xip_file_fault,
>
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply
* Re: [PATCH 01/10] AXFS: exporting xip_file_fault() for use with AXFS
From: Paulius Zaleckas @ 2008-08-21 7:32 UTC (permalink / raw)
Cc: jaredeh, Jörn Engel, linux-mtd, Linux-kernel, linux-embedded,
tim.bird
In-Reply-To: <48AD1860.4040001@teltonika.lt>
Paulius Zaleckas wrote:
> Jared Hulbert wrote:
>> We'll need this for AXFS. The equivalent function in filemap.c is exported.
>>
>> Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
>> ---
>> include/linux/mm.h | 4 ++++
>> mm/filemap_xip.c | 3 ++-
>> 2 files changed, 6 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/mm.h b/include/linux/mm.h
>> index 72a15dc..2be5c22 100644
>> --- a/include/linux/mm.h
>> +++ b/include/linux/mm.h
>> @@ -161,6 +161,10 @@ struct vm_fault {
>> */
>> };
>>
>> +#ifdef CONFIG_FS_XIP
>> +extern int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
>> +#endif
>> +
>
> No need for #ifdef here as this function is compiled and exported in .c
> regardless of CONFIG_FS_XIP
Sorry I am wrong... Have to get more sleep :)
>> /*
>> * These are the virtual MM functions - opening of an area, closing and
>> * unmapping it (needed to keep files on disk up-to-date etc), pointer
>> diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
>> index 380ab40..ab2f174 100644
>> --- a/mm/filemap_xip.c
>> +++ b/mm/filemap_xip.c
>> @@ -206,7 +206,7 @@ __xip_unmap (struct address_space * mapping,
>> *
>> * This function is derived from filemap_fault, but used for execute in place
>> */
>> -static int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
>> +int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
>> {
>> struct file *file = vma->vm_file;
>> struct address_space *mapping = file->f_mapping;
>> @@ -262,6 +262,7 @@ found:
>> return 0;
>> }
>> }
>> +EXPORT_SYMBOL_GPL(xip_file_fault);
>>
>> static struct vm_operations_struct xip_file_vm_ops = {
>> .fault = xip_file_fault,
>>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox