linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Corrupted ASFS patch.
@ 2009-02-09 13:18 Pavel Fedin
  2009-02-09 13:31 ` maximilian attems
  0 siblings, 1 reply; 15+ messages in thread
From: Pavel Fedin @ 2009-02-09 13:18 UTC (permalink / raw)
  To: Matthew Wilcox; +Cc: linux-fsdevel

 Ouch, really sorry. Unfortunately i have Internet access only at work
and they block all ports except HTTP, FTP and (luckily) POP3. So i can
send mail only via web interface.
 Documentation says that i can also place the file somewhere on the
Web and provide a link. Here is it:
http://rapidshare.com/files/195946803/asfs-1.0b12_patch_2.6.24.diff.html
 As to endianess signing, sorry, i can't help here because actually
i'm not the filesystem's author. The author is Marek Szyprowski
<march@staszic.waw.pl>, he also tried to post this patch some time
ago, but gave up because someone said that SFS patch won't be accepted
because "Linux doesn't need one more exotic FS".
 I just adapted the driver to 2.6.24 kernel (this patch works on
2.6.28 without changes).
 You can contact him about the details.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Corrupted ASFS patch.
  2009-02-09 13:18 Corrupted ASFS patch Pavel Fedin
@ 2009-02-09 13:31 ` maximilian attems
  2009-02-12  8:24   ` Re[2]: " Pavel Fedin
  0 siblings, 1 reply; 15+ messages in thread
From: maximilian attems @ 2009-02-09 13:31 UTC (permalink / raw)
  To: Pavel Fedin, Marek Szyprowski; +Cc: Matthew Wilcox, linux-fsdevel

On Mon, Feb 09, 2009 at 04:18:39PM +0300, Pavel Fedin wrote:
>  Ouch, really sorry. Unfortunately i have Internet access only at work
> and they block all ports except HTTP, FTP and (luckily) POP3. So i can
> send mail only via web interface.
>  Documentation says that i can also place the file somewhere on the
> Web and provide a link. Here is it:
> http://rapidshare.com/files/195946803/asfs-1.0b12_patch_2.6.24.diff.html
>  As to endianess signing, sorry, i can't help here because actually
> i'm not the filesystem's author. The author is Marek Szyprowski
> <march@staszic.waw.pl>, he also tried to post this patch some time
> ago, but gave up because someone said that SFS patch won't be accepted
> because "Linux doesn't need one more exotic FS".
>  I just adapted the driver to 2.6.24 kernel (this patch works on
> 2.6.28 without changes).
>  You can contact him about the details.

a MIA fs dev is not a bonus point in order to get something merged.

as debian linux-2.6 maintainer we used to have this fs, but dropped as
the author showed no will or sign to go upstream.
the small but important critic does need to get worked on.
so if you wana help to get this somewhere get the fs fixed and
properly send in patches.

kind regards

-- 
maks


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re[2]: Corrupted ASFS patch.
  2009-02-09 13:31 ` maximilian attems
@ 2009-02-12  8:24   ` Pavel Fedin
  2009-02-12  9:42     ` Phillip Lougher
  0 siblings, 1 reply; 15+ messages in thread
From: Pavel Fedin @ 2009-02-12  8:24 UTC (permalink / raw)
  To: maximilian attems; +Cc: Matthew Wilcox, linux-fsdevel

Hello maximilian,

Monday, February 9, 2009, 4:31:20 PM, you wrote:

> as debian linux-2.6 maintainer we used to have this fs, but dropped as
> the author showed no will or sign to go upstream.
> the small but important critic does need to get worked on.

 Hm, he told me the opposite thing...
 Well, at least I am interested in merging it into the kernel. Well,
i'll try to get things fixed (however i don't have much time to do
it).

> so if you wana help to get this somewhere get the fs fixed and
> properly send in patches.

 First, i've worked around my company's firewall and now i'm at last able to
use e-mail client for sending messages again. :-)
 Second, sorry for re-posting the patch (it was still laying in The
Bat's outbox and when i pressed 'Send mail' it was succesfully sent.
Well, at least this would let you to review the patch better...
 Third, this is the question fot Matthew, about annotating endianess
in on-disk structures. What if the filesystem is bi-endian? Original
SFS (http://sourceforge.net/projects/smartfilesystem) is bi-endian. I
still don't know how much of support for little-endian version is implemented
in Linux version.

-- 
Best regards,
 Pavel                            mailto:sonic.amiga@gmail.com


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Corrupted ASFS patch.
  2009-02-12  8:24   ` Re[2]: " Pavel Fedin
@ 2009-02-12  9:42     ` Phillip Lougher
  2009-02-12 10:52       ` Re[2]: " Pavel Fedin
  0 siblings, 1 reply; 15+ messages in thread
From: Phillip Lougher @ 2009-02-12  9:42 UTC (permalink / raw)
  To: Pavel Fedin; +Cc: maximilian attems, Matthew Wilcox, linux-fsdevel

Pavel Fedin wrote:

>  Third, this is the question fot Matthew, about annotating endianess
> in on-disk structures. What if the filesystem is bi-endian? Original
> SFS (http://sourceforge.net/projects/smartfilesystem) is bi-endian. I
> still don't know how much of support for little-endian version is implemented
> in Linux version.
> 

This issue has come up before (over Squashfs which used to be
'bi-endian').  The general consensus is that all Linux filesystems
should be one endianness only, as it potentially simplifies code and
makes it more efficient (i.e. the swap code can be conditionally
compiled).

As SFS is not a native Linux filesystem you could argue that the
bi-endian layout is a legacy feature over which you have no control.
However, unless there are a lot of little-endian SFS filesystems
out there, supporting them is likely to give you more pain than
it's worth, and it will present an additional barrier to mainlining.

Phillip

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re[2]: Corrupted ASFS patch.
  2009-02-12  9:42     ` Phillip Lougher
@ 2009-02-12 10:52       ` Pavel Fedin
  2009-02-12 16:38         ` Phillip Lougher
  0 siblings, 1 reply; 15+ messages in thread
From: Pavel Fedin @ 2009-02-12 10:52 UTC (permalink / raw)
  To: Phillip Lougher; +Cc: linux-fsdevel

Hello Phillip,

Thursday, February 12, 2009, 12:42:42 PM, you wrote:

> As SFS is not a native Linux filesystem you could argue that the
> bi-endian layout is a legacy feature over which you have no control.
> However, unless there are a lot of little-endian SFS filesystems
> out there, supporting them is likely to give you more pain than
> it's worth, and it will present an additional barrier to mainlining.

 I've asked Michal Schulz at AROS IRC channel, he told me that
little-endian version was introduced as experimental and it did not
gave any significant speedup (just 1%). This ended its life - support
for little-endian SFS exists only in theory, it is not adviced for
production use, not supported by formatting and installation tools,
etc.
 So far the issue is closed. SFS is bigendian. End of story.
 Do i understand right that i just need to replace all 'uXX' with
'beXX' in on-disk structures definition ?


-- 
Best regards,
 Pavel                            mailto:sonic.amiga@gmail.com


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Corrupted ASFS patch.
  2009-02-12 10:52       ` Re[2]: " Pavel Fedin
@ 2009-02-12 16:38         ` Phillip Lougher
  2009-02-13  6:53           ` [PATCH 1/9] Amiga SmartFileSystem, revision 2 Pavel Fedin
                             ` (8 more replies)
  0 siblings, 9 replies; 15+ messages in thread
From: Phillip Lougher @ 2009-02-12 16:38 UTC (permalink / raw)
  To: Pavel Fedin; +Cc: linux-fsdevel

Pavel Fedin wrote:

>  So far the issue is closed. SFS is bigendian. End of story.
>  Do i understand right that i just need to replace all 'uXX' with
> 'beXX' in on-disk structures definition ?
> 

Yes, replace all uXX with __beXX in on-disk structures.

Phillip


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/9] Amiga SmartFileSystem, revision 2
  2009-02-12 16:38         ` Phillip Lougher
@ 2009-02-13  6:53           ` Pavel Fedin
  2009-02-13  6:54           ` [PATCH 2/9] " Pavel Fedin
                             ` (7 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Pavel Fedin @ 2009-02-13  6:53 UTC (permalink / raw)
  To: Phillip Lougher; +Cc: linux-fsdevel

diff -ruN linux-source-2.6.24.orig/Documentation/filesystems/00-INDEX linux-source-2.6.24/Documentation/filesystems/00-INDEX
--- linux-source-2.6.24.orig/Documentation/filesystems/00-INDEX 2008-01-25 01:58:37.000000000 +0300
+++ linux-source-2.6.24/Documentation/filesystems/00-INDEX      2008-12-14 23:05:04.000000000 +0300
@@ -12,6 +12,8 @@
        - info and examples for the distributed AFS (Andrew File System) fs.
 affs.txt
        - info and mount options for the Amiga Fast File System.
+asfs.txt
+       - info and mount options for the Amiga Smart File System.
 automount-support.txt
        - information about filesystem automount support.
 befs.txt
diff -ruN linux-source-2.6.24.orig/Documentation/filesystems/asfs.txt linux-source-2.6.24/Documentation/filesystems/asfs.txt
--- linux-source-2.6.24.orig/Documentation/filesystems/asfs.txt 1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/Documentation/filesystems/asfs.txt      2008-12-14 23:05:04.000000000 +0300
@@ -0,0 +1,161 @@
+
+Amiga SmartFileSystem, Linux implementation
+===========================================
+
+ASFS is a Amiga Smart FileSystem driver for Linux. It supports reading
+files and directories. From version 1.0 there is also an experimental 
+(almost full) write support. Experimental means that it hasn't been 
+tested enough yet, so use it with care. Symbolic links (in AmigaOS
+called soft links) are also supported read/write. Read notes below 
+about symlinks support.
+
+
+Unsupported features of Amiga SFS
+================================
+
+ASFS currently does not support safe-delete feature of Amiga SFS 
+filesystem. It simply deletes files instead of moving them to 
+".recycled" directory. It also doesn't remove files from ".recycled" 
+directory, when there is no space left on drive. 
+
+If there is no space left, you need to manually remove files from 
+".recycled" directory. Also if you want to delete a file in a safe 
+way, you need to move it to ".recycled" directory by hand.
+
+Because of all of above, the amount of free space on disk does not 
+include space used by all files from ".recycled" directory.
+
+
+Limitations
+===========
+
+There is no Amiga protection bits into Linux permission bits tranlation
+and vice versa. If you need this feature, mail me.
+
+ASFS will always keep some amount of blocks free. This means that you 
+cannot fill the drive completely. It is because Amiga SFS uses some 
+special methods of writing data (called safe write), which needs some
+additional free space.
+
+File systems with unfinished transactions (this happens when system crashed
+during writing data to disk on AmigaOS/MorphOS) will be mounted read-only
+to protect data. The only way to fix such filesystem is to mount it under
+AmigaOS or MorphOS.
+
+Do not try to mount and write to filesystem with errors. Bad things will
+happen.
+
+
+Mount options for the ASFS
+==========================
+
+setuid=uid     
+               This sets the owner of all files and directories in the file
+               system to uid.
+
+setgid=gid     
+               Same as above, but for gid.
+
+mode=mode      
+               Sets the mode flags to the given (octal) value. Directories 
+               will get an x permission if the corresponding r bit is set.
+               The default mode is 0644, which means that everybody are allowed 
+               to read files, but only root can write to them.
+               (for directories this means also that search bits are set).
+
+prefix=path    
+               Path will be prefixed to every absolute path name of symbolic 
+               links on an ASFS/AFFS partition. Default = "/". (See below.)
+
+volume=name
+               When symbolic links with an absolute path are created
+               on an ASFS/AFFS partition, name will be prepended as the
+               volume name. Default = "" (empty string). (See below.)
+
+lowercasevol
+               Translate all volume names in symlinks to lower case.
+               Disabled by default. (See below.)
+
+iocharset=name
+               Character set to use for converting file names. Specifies 
+               character set used by your Linux system. 
+codepage=name
+               Set the codepage number for converting file names. Specifies
+               character set used by your Amiga. Use full name (for example
+               'cp1251' instead of '1251') here, this allows to specify any
+               character set, not only numbered one (like 'iso8859-2').
+               Use special name 'none' to disable the NLS file name 
+               translation.
+
+Symbolic links
+==============
+
+Although the Amiga and Linux file systems resemble each other, there
+are some, not always subtle, differences. One of them becomes apparent
+with symbolic links. While Linux has a file system with exactly one
+root directory, the Amiga has a separate root directory for each
+file system (for example, partition, floppy disk, ...). With the Amiga,
+these entities are called "volumes". They have symbolic names which
+can be used to access them. Thus, symbolic links can point to a
+different volume. ASFS turns the volume name into a directory name
+and prepends the prefix path (see prefix option) to it. When option
+"lowercasevol" is set, it also translates volume names to lower case.
+If the volume name is the same as a name given in "volume" option,
+it will be ignored and an absolute path will be created.
+
+Example:
+You mount all your Amiga partitions under /amiga/<volume> (where
+<volume> is the name of the volume), and you give options
+`prefix="/amiga/",volume="Linux",lowercasevol' when mounting all your 
+ASFS partitions. (They might be "User", "WB" and "Graphics", the mount 
+points /amiga/user, /amiga/wb and /amiga/graphics). 
+
+A symbolic link referring to "USER:sc/include/dos/dos.h" will be 
+translated to "/amiga/user/sc/include/dos/dos.h".
+A symbolic link referring to "Linux:etc/fstab" will be translated to
+"/etc/fstab".
+If you create a symlink referring to "/amiga/graphics/data/pict.jpg",
+it will be saved as "graphics:data/pict.jpg".
+If you create a symlink referring to "/boot/System.map", it will be 
+saved as "Linux:boot/System.map".
+
+
+Other information
+=================
+
+Supported block sizes are: 512, 1024, 2048 and 4096 bytes. Larger blocks
+speed up almost everything at the expense of wasted disk space. The speed
+gain above 4K seems not really worth the price, so you don't lose too
+much here, either.
+
+This file system has been tested on Motorola PPC and 68k, as well as 
+Intel x86 systems. I don't know, if it works on other Linux systems.
+
+This filesystem is in BETA STAGE. This means that driver MIGHT corrupt
+or damage data on your disk. Remember! YOU USE IT ON YOUR OWN RISK! 
+
+I made almost all I could to minimalize this risk. On my systems several 
+gigabytes has been succesfully copied from and to SFS disks. I would also 
+appreciate any infomation if this filesystem works on your system or not. 
+See next paragraph for my email.
+
+Some parts of this documentation has been adapted from AFFS driver docs.
+
+
+Author, contact and copyright infos
+===================================
+
+ASFS has been written by Marek 'March' Szyprowski <marek@amiga.pl>.
+Mail me if you have any suggestions or found a bug.
+
+Copyright (C) 2003,2004,2005  Marek 'March' Szyprowski <marek@amiga.pl>
+
+Thanks to Marcin Kurek (Morgoth/Dreamolers-CAPS) for help and parts 
+of original amiga version of SmartFilesystem source code. 
+
+SmartFilesystem is copyrighted (C) 2003,2004 by: John Hendrikx, 
+Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek
+
+The ASFS driver is realased under the terms of of the GNU General 
+Public License. See source code for more details.
+
diff -ruN linux-source-2.6.24.orig/fs/asfs/adminspace.c linux-source-2.6.24/fs/asfs/adminspace.c
--- linux-source-2.6.24.orig/fs/asfs/adminspace.c       1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/adminspace.c    2008-12-14 23:05:05.000000000 +0300
@@ -0,0 +1,446 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta7
+ *
+ * This file contains some parts of the original amiga version of 
+ * SmartFilesystem source code.
+ *
+ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx, 
+ * Ralph Schmidt, Emmanuel Lesueur, David Gerber, and Marcin Kurek
+ * 
+ * Adapted and modified by Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include "asfs_fs.h"
+#include "bitfuncs.h"
+
+#include <asm/byteorder.h>
+
+#ifdef CONFIG_ASFS_RW
+
+static int setfreeblocks(struct super_block *sb, u32 freeblocks)
+{
+       struct buffer_head *bh;
+       if ((bh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
+               struct fsRootInfo *ri = (struct fsRootInfo *) ((u8 *) bh->b_data + sb->s_blocksize - sizeof(struct fsRootInfo));
+               ASFS_SB(sb)->freeblocks = freeblocks;
+               ri->freeblocks = cpu_to_be32(freeblocks);
+               asfs_bstore(sb, bh);
+               asfs_brelse(bh);
+               return 0;
+       }
+       return -EIO;
+}
+
+static inline int enoughspace(struct super_block *sb, u32 blocks)
+{
+       if (ASFS_SB(sb)->freeblocks - ASFS_ALWAYSFREE < blocks)
+               return FALSE;
+
+       return TRUE;
+}
+
+       /* Determines the amount of free blocks starting from block /block/.
+          If there are no blocks found or if there was an error -1 is returned,
+          otherwise this function will count the number of free blocks until
+          an allocated block is encountered or until maxneeded has been
+          exceeded. */
+
+static int availablespace(struct super_block *sb, u32 block, u32 maxneeded)
+{
+       struct buffer_head *bh = NULL;
+       struct fsBitmap *b;
+       u32 longs = ASFS_SB(sb)->blocks_inbitmap >> 5;
+       u32 maxbitmapblock = ASFS_SB(sb)->bitmapbase + ASFS_SB(sb)->blocks_bitmap;
+       int blocksfound = 0;
+       u32 bitstart;
+       int bitend;
+       u32 nextblock = ASFS_SB(sb)->bitmapbase + block / ASFS_SB(sb)->blocks_inbitmap;
+
+       bitstart = block % ASFS_SB(sb)->blocks_inbitmap;
+
+       while (nextblock < maxbitmapblock && (bh = asfs_breadcheck(sb, nextblock++, ASFS_BITMAP_ID))) {
+               b = (void *) bh->b_data;
+
+               if ((bitend = bmffz(b->bitmap, longs, bitstart)) >= 0) {
+                       blocksfound += bitend - bitstart;
+                       asfs_brelse(bh);
+                       return blocksfound;
+               }
+               blocksfound += ASFS_SB(sb)->blocks_inbitmap - bitstart;
+               if (blocksfound >= maxneeded) {
+                       asfs_brelse(bh);
+                       return blocksfound;
+               }
+               bitstart = 0;
+               asfs_brelse(bh);
+       }
+
+       if (bh == NULL)
+               return (-1);
+
+       return (blocksfound);
+}
+
+int asfs_findspace(struct super_block *sb, u32 maxneeded, u32 start, u32 end, u32 * returned_block, u32 * returned_blocks)
+{
+       struct buffer_head *bh;
+       u32 longs = ASFS_SB(sb)->blocks_inbitmap >> 5;
+       u32 space = 0;
+       u32 block;
+       u32 bitmapblock = ASFS_SB(sb)->bitmapbase + start / ASFS_SB(sb)->blocks_inbitmap;
+       u32 breakpoint;
+       int bitstart, bitend;
+       int reads;
+
+       if (enoughspace(sb, maxneeded) == FALSE) {
+               *returned_block = 0;
+               *returned_blocks = 0;
+               return -ENOSPC;
+       }
+
+       if (start >= ASFS_SB(sb)->totalblocks)
+               start -= ASFS_SB(sb)->totalblocks;
+
+       if (end == 0)
+               end = ASFS_SB(sb)->totalblocks;
+
+       reads = ((end - 1) / ASFS_SB(sb)->blocks_inbitmap) + 1 - start / ASFS_SB(sb)->blocks_inbitmap;
+
+       if (start >= end)
+               reads += (ASFS_SB(sb)->totalblocks - 1) / ASFS_SB(sb)->blocks_inbitmap + 1;
+
+       breakpoint = (start < end ? end : ASFS_SB(sb)->totalblocks);
+
+       *returned_block = 0;
+       *returned_blocks = 0;
+
+       bitend = start % ASFS_SB(sb)->blocks_inbitmap;
+       block = start - bitend;
+
+       while ((bh = asfs_breadcheck(sb, bitmapblock++, ASFS_BITMAP_ID))) {
+               struct fsBitmap *b = (void *) bh->b_data;
+               u32 localbreakpoint = breakpoint - block;
+
+               if (localbreakpoint > ASFS_SB(sb)->blocks_inbitmap)
+                       localbreakpoint = ASFS_SB(sb)->blocks_inbitmap;
+
+               /* At this point space contains the amount of free blocks at
+                  the end of the previous bitmap block.  If there are no
+                  free blocks at the start of this bitmap block, space will
+                  be set to zero, since in that case the space isn't adjacent. */
+
+               while ((bitstart = bmffo(b->bitmap, longs, bitend)) < ASFS_SB(sb)->blocks_inbitmap) {
+                       /* found the start of an empty space, now find out how large it is */
+
+                       if (bitstart >= localbreakpoint)
+                               break;
+
+                       if (bitstart != 0)
+                               space = 0;
+
+                       bitend = bmffz(b->bitmap, longs, bitstart);
+
+                       if (bitend > localbreakpoint)
+                               bitend = localbreakpoint;
+
+                       space += bitend - bitstart;
+
+                       if (*returned_blocks < space) {
+                               *returned_block = block + bitend - space;
+                               if (space >= maxneeded) {
+                                       *returned_blocks = maxneeded;
+                                       asfs_brelse(bh);
+                                       return 0;
+                               }
+                               *returned_blocks = space;
+                       }
+
+                       if (bitend >= localbreakpoint)
+                               break;
+               }
+
+               if (--reads == 0)
+                       break;
+
+               /* no (more) empty spaces found in this block */
+
+               if (bitend != ASFS_SB(sb)->blocks_inbitmap)
+                       space = 0;
+
+               bitend = 0;
+               block += ASFS_SB(sb)->blocks_inbitmap;
+
+               if (block >= ASFS_SB(sb)->totalblocks) {
+                       block = 0;
+                       space = 0;
+                       breakpoint = end;
+                       bitmapblock = ASFS_SB(sb)->bitmapbase;
+               }
+               asfs_brelse(bh);
+       }
+
+       if (bh == NULL)
+               return -EIO;
+
+       asfs_brelse(bh);
+
+       if (*returned_blocks == 0)
+               return -ENOSPC;
+       else
+               return 0;
+}
+
+int asfs_markspace(struct super_block *sb, u32 block, u32 blocks)
+{
+       int errorcode;
+
+       asfs_debug("markspace: Marking %d blocks from block %d\n", blocks, block);
+
+       if ((availablespace(sb, block, blocks)) < blocks) {
+               printk("ASFS: Attempted to mark %d blocks from block %d, but some of them were already full!\n", blocks, block);
+               return -EIO;
+       }
+
+       if ((errorcode = setfreeblocks(sb, ASFS_SB(sb)->freeblocks - blocks)) == 0) {
+               struct buffer_head *bh;
+               u32 skipblocks = block / ASFS_SB(sb)->blocks_inbitmap;
+               u32 longs = (sb->s_blocksize - sizeof(struct fsBitmap)) >> 2;
+               u32 bitmapblock;
+
+               block -= skipblocks * ASFS_SB(sb)->blocks_inbitmap;
+               bitmapblock = ASFS_SB(sb)->bitmapbase + skipblocks;
+
+               while (blocks > 0) {
+                       if ((bh = asfs_breadcheck(sb, bitmapblock++, ASFS_BITMAP_ID))) {
+                               struct fsBitmap *b = (void *) bh->b_data;
+
+                               blocks -= bmclr(b->bitmap, longs, block, blocks);
+                               block = 0;
+
+                               asfs_bstore(sb, bh);
+                               asfs_brelse(bh);
+                       } else
+                               return -EIO;
+               }
+       }
+
+       return (errorcode);
+}
+
+       /* This function checks the bitmap and tries to locate at least /blocksneeded/
+          adjacent unused blocks.  If found it sets returned_block to the start block
+          and returns no error.  If not found, ERROR_DISK_IS_FULL is returned and
+          returned_block is set to zero.  Any other errors are returned as well. */
+
+static inline int internalfindspace(struct super_block *sb, u32 blocksneeded, u32 startblock, u32 endblock, u32 * returned_block)
+{
+       u32 blocks;
+       int errorcode;
+
+       if ((errorcode = asfs_findspace(sb, blocksneeded, startblock, endblock, returned_block, &blocks)) == 0)
+               if (blocks != blocksneeded)
+                       return -ENOSPC;
+
+       return errorcode;
+}
+
+static int findandmarkspace(struct super_block *sb, u32 blocksneeded, u32 * returned_block)
+{
+       int errorcode;
+
+       if (enoughspace(sb, blocksneeded) != FALSE) {
+               if ((errorcode = internalfindspace(sb, blocksneeded, 0, ASFS_SB(sb)->totalblocks, returned_block)) == 0)
+                       errorcode = asfs_markspace(sb, *returned_block, blocksneeded);
+       } else
+               errorcode = -ENOSPC;
+
+       return (errorcode);
+}
+
+/* ************************** */
+
+int asfs_freespace(struct super_block *sb, u32 block, u32 blocks)
+{
+       int errorcode;
+
+       asfs_debug("freespace: Freeing %d blocks from block %d\n", blocks, block);
+
+       if ((errorcode = setfreeblocks(sb, ASFS_SB(sb)->freeblocks + blocks)) == 0) {
+               struct buffer_head *bh;
+               u32 skipblocks = block / ASFS_SB(sb)->blocks_inbitmap;
+               u32 longs = (sb->s_blocksize - sizeof(struct fsBitmap)) >> 2;
+               u32 bitmapblock;
+
+               block -= skipblocks * ASFS_SB(sb)->blocks_inbitmap;
+               bitmapblock = ASFS_SB(sb)->bitmapbase + skipblocks;
+
+               while (blocks > 0) {
+                       if ((bh = asfs_breadcheck(sb, bitmapblock++, ASFS_BITMAP_ID))) {
+                               struct fsBitmap *b = (void *) bh->b_data;
+
+                               blocks -= bmset(b->bitmap, longs, block, blocks);
+                               block = 0;
+
+                               asfs_bstore(sb, bh);
+                               asfs_brelse(bh);
+                       } else
+                               return -EIO;
+               }
+       }
+
+       return (errorcode);
+}
+
+/*************** admin space containers ****************/
+
+int asfs_allocadminspace(struct super_block *sb, u32 *returned_block)
+{
+       struct buffer_head *bh;
+       u32 adminspaceblock = ASFS_SB(sb)->adminspacecontainer;
+       int errorcode = -EIO;
+
+       asfs_debug("allocadminspace: allocating new block\n");
+
+       while ((bh = asfs_breadcheck(sb, adminspaceblock, ASFS_ADMINSPACECONTAINER_ID))) {
+               struct fsAdminSpaceContainer *asc1 = (void *) bh->b_data;
+               struct fsAdminSpace *as1 = asc1->adminspace;
+               int adminspaces1 = (sb->s_blocksize - sizeof(struct fsAdminSpaceContainer)) / sizeof(struct fsAdminSpace);
+
+               while (adminspaces1-- > 0) {
+                       s16 bitoffset;
+
+                       if (as1->space != 0 && (bitoffset = bfffz(be32_to_cpu(as1->bits), 0)) >= 0) {
+                               u32 emptyadminblock = be32_to_cpu(as1->space) + bitoffset;
+                               as1->bits |= cpu_to_be32(1 << (31 - bitoffset));
+                               asfs_bstore(sb, bh);
+                               *returned_block = emptyadminblock;
+                               asfs_brelse(bh);
+                               asfs_debug("allocadminspace: found block %d\n", *returned_block);
+                               return 0;
+                       }
+                       as1++;
+               }
+
+               adminspaceblock = be32_to_cpu(asc1->next);
+               asfs_brelse(bh);
+
+               if (adminspaceblock == 0) {
+                       u32 startblock;
+
+                       asfs_debug("allocadminspace: allocating new adminspace area\n");
+
+                       /* If we get here it means current adminspace areas are all filled.
+                          We would now need to find a new area and create a fsAdminSpace
+                          structure in one of the AdminSpaceContainer blocks.  If these
+                          don't have any room left for new adminspace areas a new
+                          AdminSpaceContainer would have to be created first which is
+                          placed as the first block in the newly found admin area. */
+
+                       adminspaceblock = ASFS_SB(sb)->adminspacecontainer;
+
+                       if ((errorcode = findandmarkspace(sb, 32, &startblock)))
+                               return errorcode;
+
+                       while ((bh = asfs_breadcheck(sb, adminspaceblock, ASFS_ADMINSPACECONTAINER_ID))) {
+                               struct fsAdminSpaceContainer *asc2 = (void *) bh->b_data;
+                               struct fsAdminSpace *as2 = asc2->adminspace;
+                               int adminspaces2 = (sb->s_blocksize - sizeof(struct fsAdminSpaceContainer)) / sizeof(struct fsAdminSpace);
+
+                               while (adminspaces2-- > 0 && as2->space != 0)
+                                       as2++;
+
+                               if (adminspaces2 >= 0) {        /* Found a unused AdminSpace in this AdminSpaceContainer! */
+                                       as2->space = cpu_to_be32(startblock);
+                                       as2->bits = 0;
+                                       asfs_bstore(sb, bh);
+                                       asfs_brelse(bh);
+                                       break;
+                               }
+
+                               if (asc2->next == 0) {
+                                       /* Oh-oh... we marked our new adminspace area in use, but we couldn't
+                                          find space to store a fsAdminSpace structure in the existing
+                                          fsAdminSpaceContainer blocks.  This means we need to create and
+                                          link a new fsAdminSpaceContainer as the first block in our newly
+                                          marked adminspace. */
+
+                                       asc2->next = cpu_to_be32(startblock);
+                                       asfs_bstore(sb, bh);
+                                       asfs_brelse(bh);
+
+                                       /* Now preparing new AdminSpaceContainer */
+
+                                       if ((bh = asfs_getzeroblk(sb, startblock)) == NULL)
+                                               return -EIO;
+
+                                       asc2 = (void *) bh->b_data;
+                                       asc2->bheader.id = cpu_to_be32(ASFS_ADMINSPACECONTAINER_ID);
+                                       asc2->bheader.ownblock = cpu_to_be32(startblock);
+                                       asc2->previous = cpu_to_be32(adminspaceblock);
+                                       asc2->adminspace[0].space = cpu_to_be32(startblock);
+                                       asc2->adminspace[0].bits = cpu_to_be32(0x80000000);
+                                       asc2->bits = 32;
+
+                                       asfs_bstore(sb, bh);
+                                       asfs_brelse(bh);
+
+                                       adminspaceblock = startblock;
+                                       break;  /* Breaks through to outer loop! */
+                               }
+                               adminspaceblock = be32_to_cpu(asc2->next);
+                               asfs_brelse(bh);
+                       }
+               }
+       }
+       return errorcode;
+}
+
+int asfs_freeadminspace(struct super_block *sb, u32 block)
+{
+       struct buffer_head *bh;
+       u32 adminspaceblock = ASFS_SB(sb)->adminspacecontainer;
+
+       asfs_debug("freeadminspace: Entry -- freeing block %d\n", block);
+
+       while ((bh = asfs_breadcheck(sb, adminspaceblock, ASFS_ADMINSPACECONTAINER_ID))) {
+               struct fsAdminSpaceContainer *asc = (void *) bh->b_data;
+               struct fsAdminSpace *as = asc->adminspace;
+               int adminspaces = (sb->s_blocksize - sizeof(struct fsAdminSpaceContainer)) / sizeof(struct fsAdminSpace);
+
+               while (adminspaces-- > 0) {
+                       if (block >= be32_to_cpu(as->space) && block < be32_to_cpu(as->space) + 32) {
+                               s16 bitoffset = block - be32_to_cpu(as->space);
+                               asfs_debug("freeadminspace: Block to be freed is located in AdminSpaceContainer block at %d\n", adminspaceblock);
+                               as->bits &= cpu_to_be32(~(1 << (31 - bitoffset)));
+                               asfs_bstore(sb, bh);
+                               asfs_brelse(bh);
+                               return 0;
+                       }
+                       as++;
+               }
+
+               if ((adminspaceblock = be32_to_cpu(asc->next)) == 0)
+                       break;
+
+               asfs_brelse(bh);
+       }
+
+       if (bh != NULL) {
+               asfs_brelse(bh);
+               printk("ASFS: Unable to free an administration block. The block cannot be found.");
+               return -ENOENT;
+       }
+
+       return -EIO;
+}
+
+#endif


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 2/9] Amiga SmartFileSystem, revision 2
  2009-02-12 16:38         ` Phillip Lougher
  2009-02-13  6:53           ` [PATCH 1/9] Amiga SmartFileSystem, revision 2 Pavel Fedin
@ 2009-02-13  6:54           ` Pavel Fedin
  2009-02-13  6:55           ` [PATCH 3/9] " Pavel Fedin
                             ` (6 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Pavel Fedin @ 2009-02-13  6:54 UTC (permalink / raw)
  To: Phillip Lougher; +Cc: linux-fsdevel

diff -ruN linux-source-2.6.24.orig/fs/asfs/asfs_fs.h linux-source-2.6.24/fs/asfs/asfs_fs.h
--- linux-source-2.6.24.orig/fs/asfs/asfs_fs.h  1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/asfs_fs.h       2008-12-14 23:34:17.000000000 +0300
@@ -0,0 +1,218 @@
+#ifndef __LINUX_ASFS_FS_H
+#define __LINUX_ASFS_FS_H
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <asm/byteorder.h>
+#include <linux/amigasfs.h>
+
+#define asfs_debug(fmt,arg...) /* no debug at all */
+//#define asfs_debug(fmt,arg...) printk(fmt,##arg)  /* general debug infos */
+
+#if !defined (__BIG_ENDIAN) && !defined (__LITTLE_ENDIAN)
+#error Endianes must be known for ASFS to work. Sorry.
+#endif
+
+#define ASFS_MAXFN_BUF (ASFS_MAXFN + 4)
+#define ASFS_DEFAULT_UID 0
+#define ASFS_DEFAULT_GID 0
+#define ASFS_DEFAULT_MODE 0644 /* default permission bits for files, dirs have same permission, but with "x" set */
+
+/* Extent structure located in RAM (e.g. inside inode structure), 
+   currently used to store last used extent */
+
+struct inramExtent {
+       u32 startblock; /* Block from begginig of the file */
+       u32 key;
+       u32 next;
+       u16 blocks;
+};
+
+/* inode in-kernel data */
+
+struct asfs_inode_info {
+       u32 firstblock;
+       u32 hashtable;
+       int modified;
+       loff_t mmu_private;
+       struct inramExtent ext_cache;
+       struct inode vfs_inode;
+};
+
+/* short cut to get to the asfs specific inode data */
+static inline struct asfs_inode_info *ASFS_I(struct inode *inode)
+{
+   return list_entry(inode, struct asfs_inode_info, vfs_inode);
+}
+
+/* Amiga SFS superblock in-core data */
+
+struct asfs_sb_info {
+       u32 totalblocks;
+       u32 rootobjectcontainer;
+       u32 extentbnoderoot;
+       u32 objectnoderoot;
+
+       u32 adminspacecontainer;
+       u32 bitmapbase;
+       u32 freeblocks;
+       u32 blocks_inbitmap;
+       u32 blocks_bitmap;
+       u32 block_rovingblockptr;
+
+       uid_t uid;
+       gid_t gid;
+       umode_t mode;
+       u16 flags;
+       char *prefix;
+       char *root_volume;              /* Volume prefix for absolute symlinks. */
+       char *iocharset;
+       char *codepage;
+       struct nls_table *nls_io;
+       struct nls_table *nls_disk;
+};
+
+/* short cut to get to the asfs specific sb data */
+static inline struct asfs_sb_info *ASFS_SB(struct super_block *sb)
+{
+       return sb->s_fs_info;
+}
+ 
+/* io inline code */
+
+u32 asfs_calcchecksum(void *block, u32 blocksize);
+
+static inline int
+asfs_check_block(struct fsBlockHeader *block, u32 blocksize, u32 n, u32 id)
+{
+       if (asfs_calcchecksum(block, blocksize) ==
+           be32_to_cpu(((struct fsBlockHeader *) block)->checksum) &&
+           n == be32_to_cpu(((struct fsBlockHeader *) block)->ownblock) &&
+           id == be32_to_cpu(((struct fsBlockHeader *) block)->id))
+               return TRUE;
+       return FALSE;
+}
+
+/* get fs structure from block and do some checks... */
+static inline struct buffer_head *
+asfs_breadcheck(struct super_block *sb, u32 n, u32 type)
+{
+       struct buffer_head *bh;
+       if ((bh = sb_bread(sb, n))) {
+               if (asfs_check_block ((void *)bh->b_data, sb->s_blocksize, n, type)) {
+                       return bh;      /* all okay */
+               }
+               brelse(bh);
+       }
+       return NULL;            /* error */
+}
+
+static inline struct buffer_head *
+asfs_getzeroblk(struct super_block *sb, int block)
+{
+       struct buffer_head *bh;
+       bh = sb_getblk(sb, block);
+       lock_buffer(bh);
+       memset(bh->b_data, 0, sb->s_blocksize);
+       set_buffer_uptodate(bh);
+       unlock_buffer(bh);
+       return bh;
+}
+
+static inline void 
+asfs_bstore(struct super_block *sb, struct buffer_head *bh)
+{
+       ((struct fsBlockHeader *) (bh->b_data))->checksum =
+           cpu_to_be32(asfs_calcchecksum(bh->b_data, sb->s_blocksize));
+       mark_buffer_dirty(bh);
+}
+
+static inline void asfs_brelse(struct buffer_head *bh)
+{
+       brelse(bh);
+}
+
+static inline void dec_count(struct inode *inode)
+{
+       inode->i_nlink--;
+       mark_inode_dirty(inode);
+}
+
+/* all prototypes */
+
+/* adminspace.c */
+int asfs_allocadminspace(struct super_block *sb, u32 * block);
+int asfs_freeadminspace(struct super_block *sb, u32 block);
+int asfs_markspace(struct super_block *sb, u32 block, u32 blocks);
+int asfs_freespace(struct super_block *sb, u32 block, u32 blocks);
+int asfs_findspace(struct super_block *sb, u32 maxneeded, u32 start, u32 end,
+             u32 * returned_block, u32 * returned_blocks);
+
+/* dir.c */
+int asfs_readdir(struct file *filp, void *dirent, filldir_t filldir);
+struct dentry *asfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd);
+
+/* extents.c */
+int asfs_getextent(struct super_block *sb, u32 key, struct buffer_head **ret_bh,
+             struct fsExtentBNode **ret_ebn);
+int asfs_deletebnode(struct super_block *sb, struct buffer_head *cb, u32 key);
+int asfs_deleteextents(struct super_block *sb, u32 key);
+int asfs_addblocks(struct super_block *sb, u16 blocks, u32 newspace,
+             u32 objectnode, u32 * io_lastextentbnode);
+
+/* file.c */
+int asfs_readpage(struct file *file, struct page *page);
+sector_t asfs_bmap(struct address_space *mapping, sector_t block);
+int asfs_writepage(struct page *page, struct writeback_control *wbc);
+int asfs_write_begin(struct file *file, struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned flags,
+                       struct page **pagep, void **fsdata);
+void asfs_truncate(struct inode *inode);
+int asfs_file_open(struct inode *inode, struct file *filp);
+int asfs_file_release(struct inode *inode, struct file *filp);
+
+/* inode.c */
+struct inode *asfs_get_root_inode(struct super_block *sb);
+void asfs_read_locked_inode(struct inode *inode, void *arg);
+
+/* namei */
+u8 asfs_lowerchar(u8 c);
+int asfs_check_name(const u8 *name, int len);
+int asfs_namecmp(u8 *s, u8 *ct, int casesensitive, struct nls_table *t);
+u16 asfs_hash(u8 *name, int casesensitive);
+void asfs_translate(u8 *to, u8 *from, struct nls_table *nls_to, struct nls_table *nls_from, int limit);
+
+/* nodes */
+int asfs_getnode(struct super_block *sb, u32 nodeno,
+           struct buffer_head **ret_bh, struct fsObjectNode **ret_node);
+int asfs_createnode(struct super_block *sb, struct buffer_head **returned_cb,
+              struct fsNode **returned_node, u32 * returned_nodeno);
+int asfs_deletenode(struct super_block *sb, u32 objectnode);
+
+/* objects */
+struct fsObject *asfs_nextobject(struct fsObject *obj);
+struct fsObject *asfs_find_obj_by_name(struct super_block *sb,
+               struct fsObjectContainer *objcont, u8 * name);
+int asfs_readobject(struct super_block *sb, u32 objectnode,
+              struct buffer_head **cb, struct fsObject **returned_object);
+int asfs_createobject(struct super_block *sb, struct buffer_head **io_cb,
+                struct fsObject **io_o, struct fsObject *src_o,
+                u8 * objname, int force);
+int asfs_deleteobject(struct super_block *sb, struct buffer_head *cb,
+                struct fsObject *o);
+int asfs_renameobject(struct super_block *sb, struct buffer_head *cb1,
+                struct fsObject *o1, struct buffer_head *cbparent,
+                struct fsObject *oparent, u8 * newname);
+
+int asfs_addblockstofile(struct super_block *sb, struct buffer_head *objcb,
+                   struct fsObject *o, u32 blocks, u32 * newspace,
+                   u32 * addedblocks);
+int asfs_truncateblocksinfile(struct super_block *sb, struct buffer_head *bh,
+                        struct fsObject *o, u32 newsize);
+
+/* symlink.c */
+int asfs_symlink_readpage(struct file *file, struct page *page);
+int asfs_write_symlink(struct inode *symfile, const char *symname);
+
+#endif
diff -ruN linux-source-2.6.24.orig/fs/asfs/bitfuncs.c linux-source-2.6.24/fs/asfs/bitfuncs.c
--- linux-source-2.6.24.orig/fs/asfs/bitfuncs.c 1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/bitfuncs.c      2008-12-14 23:05:05.000000000 +0300
@@ -0,0 +1,171 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include "bitfuncs.h"
+
+/* Bitmap (bm) functions:
+   These functions perform bit-operations on regions of memory which
+   are a multiple of 4 bytes in length. Bitmap is in bigendian byte order.
+*/
+
+/* This function finds the first set bit in a region of memory starting
+   with /bitoffset/.  The region of memory is /longs/ longs long.  It
+   returns the bitoffset of the first set bit it finds. */
+
+int bmffo(u32 *bitmap, int longs, int bitoffset)
+{
+       u32 *scan = bitmap;
+       int longoffset, bit;
+
+       longoffset = bitoffset >> 5;
+       longs -= longoffset;
+       scan += longoffset;
+
+       bitoffset = bitoffset & 0x1F;
+
+       if (bitoffset != 0) {
+               if ((bit = bfffo(be32_to_cpu(*scan), bitoffset)) >= 0) {
+                       return (bit + ((scan - bitmap) << 5));
+               }
+               scan++;
+               longs--;
+       }
+
+       while (longs-- > 0) {
+               if (*scan++ != 0) {
+                       return (bfffo(be32_to_cpu(*--scan), 0) + ((scan - bitmap) << 5));
+               }
+       }
+
+       return (-1);
+}
+
+/* This function finds the first unset bit in a region of memory starting
+   with /bitoffset/.  The region of memory is /longs/ longs long.  It
+   returns the bitoffset of the first unset bit it finds. */
+
+int bmffz(u32 *bitmap, int longs, int bitoffset)
+{
+       u32 *scan = bitmap;
+       int longoffset, bit;
+
+       longoffset = bitoffset >> 5;
+       longs -= longoffset;
+       scan += longoffset;
+
+       bitoffset = bitoffset & 0x1F;
+
+       if (bitoffset != 0) {
+               if ((bit = bfffz(be32_to_cpu(*scan), bitoffset)) >= 0) {
+                       return (bit + ((scan - bitmap) << 5));
+               }
+               scan++;
+               longs--;
+       }
+
+       while (longs-- > 0) {
+               if (*scan++ != 0xFFFFFFFF) {
+                       return (bfffz(be32_to_cpu(*--scan), 0) + ((scan - bitmap) << 5));
+               }
+       }
+
+       return (-1);
+}
+
+/* This function clears /bits/ bits in a region of memory starting
+   with /bitoffset/.  The region of memory is /longs/ longs long.  If
+   the region of memory is too small to clear /bits/ bits then this
+   function exits after having cleared all bits till the end of the
+   memory region.  In any case it returns the number of bits which
+   were actually cleared. */
+
+int bmclr(u32 *bitmap, int longs, int bitoffset, int bits)
+{
+       u32 *scan = bitmap;
+       int longoffset;
+       int orgbits = bits;
+
+       longoffset = bitoffset >> 5;
+       longs -= longoffset;
+       scan += longoffset;
+
+       bitoffset = bitoffset & 0x1F;
+
+       if (bitoffset != 0) {
+               if (bits < 32) {
+                       *scan = cpu_to_be32(bfclr(be32_to_cpu(*scan), bitoffset, bits));
+               } else {
+                       *scan = cpu_to_be32(bfclr(be32_to_cpu(*scan), bitoffset, 32));
+               }
+               scan++;
+               longs--;
+               bits -= 32 - bitoffset;
+       }
+
+       while (bits > 0 && longs-- > 0) {
+               if (bits > 31) {
+                       *scan++ = 0;
+               } else {
+                       *scan = cpu_to_be32(bfclr(be32_to_cpu(*scan), 0, bits));
+               }
+               bits -= 32;
+       }
+
+       if (bits <= 0) {
+               return (orgbits);
+       }
+       return (orgbits - bits);
+}
+
+/* This function sets /bits/ bits in a region of memory starting
+   with /bitoffset/.  The region of memory is /longs/ longs long.  If
+   the region of memory is too small to set /bits/ bits then this
+   function exits after having set all bits till the end of the
+   memory region.  In any case it returns the number of bits which
+   were actually set. */
+
+int bmset(u32 *bitmap, int longs, int bitoffset, int bits)
+{
+       u32 *scan = bitmap;
+       int longoffset;
+       int orgbits = bits;
+
+       longoffset = bitoffset >> 5;
+       longs -= longoffset;
+       scan += longoffset;
+
+       bitoffset = bitoffset & 0x1F;
+
+       if (bitoffset != 0) {
+               if (bits < 32) {
+                       *scan = cpu_to_be32(bfset(be32_to_cpu(*scan), bitoffset, bits));
+               } else {
+                       *scan = cpu_to_be32(bfset(be32_to_cpu(*scan), bitoffset, 32));
+               }
+               scan++;
+               longs--;
+               bits -= 32 - bitoffset;
+       }
+
+       while (bits > 0 && longs-- > 0) {
+               if (bits > 31) {
+                       *scan++ = 0xFFFFFFFF;
+               } else {
+                       *scan = cpu_to_be32(bfset(be32_to_cpu(*scan), 0, bits));
+               }
+               bits -= 32;
+       }
+
+       if (bits <= 0) {
+               return (orgbits);
+       }
+       return (orgbits - bits);
+}


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 3/9] Amiga SmartFileSystem, revision 2
  2009-02-12 16:38         ` Phillip Lougher
  2009-02-13  6:53           ` [PATCH 1/9] Amiga SmartFileSystem, revision 2 Pavel Fedin
  2009-02-13  6:54           ` [PATCH 2/9] " Pavel Fedin
@ 2009-02-13  6:55           ` Pavel Fedin
  2009-02-13  6:55           ` [PATCH 4/9] " Pavel Fedin
                             ` (5 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Pavel Fedin @ 2009-02-13  6:55 UTC (permalink / raw)
  To: Phillip Lougher; +Cc: linux-fsdevel

diff -ruN linux-source-2.6.24.orig/fs/asfs/bitfuncs.h linux-source-2.6.24/fs/asfs/bitfuncs.h
--- linux-source-2.6.24.orig/fs/asfs/bitfuncs.h 1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/bitfuncs.h      2008-12-14 23:42:39.000000000 +0300
@@ -0,0 +1,58 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef __BITFUNCS_H
+#define __BITFUNCS_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#include <linux/bitops.h>
+
+/* Finds first set bit in /data/ starting at /bitoffset/.  This function
+   considers the MSB to be the first bit. */
+static inline int bfffo(u32 data, int bitoffset)
+{
+       u32 mask = 0xffffffff >> bitoffset;
+       data &= mask;
+       return data == 0 ? -1 : 32-fls(data);
+}
+
+/* Finds first zero bit in /data/ starting at /bitoffset/.  This function
+   considers the MSB to be the first bit. */
+static inline int bfffz(u32 data, int bitoffset)
+{
+       return bfffo(~data, bitoffset);
+}
+
+/* Sets /bits/ bits starting from /bitoffset/ in /data/.
+   /bits/ must be between 1 and 32. */
+static inline u32 bfset(u32 data, int bitoffset, int bits)
+{
+       u32 mask = ~((1 << (32 - bits)) - 1);
+       mask >>= bitoffset;
+       return data | mask;
+}
+
+/* Clears /bits/ bits starting from /bitoffset/ in /data/.
+   /bits/ must be between 1 and 32. */
+static inline u32 bfclr(u32 data, int bitoffset, int bits)
+{
+       u32 mask = ~((1 << (32 - bits)) - 1);
+       mask >>= bitoffset;
+       return data & ~mask;
+}
+
+/* bm??? functions assumes that in-memory bitmap is in bigendian byte order */
+int bmffo(u32 *, int, int);
+int bmffz(u32 *, int, int);
+int bmclr(u32 *, int, int, int);
+int bmset(u32 *, int, int, int);
+
+#endif
diff -ruN linux-source-2.6.24.orig/fs/asfs/Changes linux-source-2.6.24/fs/asfs/Changes
--- linux-source-2.6.24.orig/fs/asfs/Changes    1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/Changes 2008-12-14 23:05:05.000000000 +0300
@@ -0,0 +1,120 @@
+
+Amiga Smart File System, Linux implementation
+
+Please direct bug reports to: marek@amiga.pl
+
+History:
+
+v1.0beta12 (03.12.2006)
+- adapted to 2.6.19 kernel VFS changes
+- fixed symlink write crash
+
+v1.0beta11 (22.09.2006)
+- adapted to 2.6.18 kernel VFS changes
+- made some functions static to reduce overhead in kernel namespace
+
+v1.0beta10 (13.06.2005)
+- fixed ugly bug introduced in beta9 that caused kernel crash on x86
+  (thanks to Emiliano for reporting it!)
+
+v1.0beta9 (17.03.2005)
+- added NLS support (thanks to Pavel Fedin!)
+
+v1.0beta8 (07.01.2005)
+- adapted to 2.6.10 kernel VFS changes
+- added workaround for buggy Mandrake kernel headers
+
+v1.0beta7 (25.06.2004)
+- small changes in documentation
+- code clean up: bitfuncs.c, super.c, inode.c, *.h, Makefile, added 
+  asfs_ prefix to function names, made some functions static
+  (big thanks to Christoph Hellwig for advice!)
+- fixed minor bugs (inode leak in super.c, not-realesed buffer during 
+  object renaming in inode.c)
+- now files/dirs are created with global ownership/permission bits
+
+v1.0beta6 (04.06.2004)
+- fixed: ASFS_SB(sb)->flags was always zero in 2.6.x code
+
+v1.0beta5 (07.05.2004)
+- finally fixed a problem with file size attrib. not being written
+  to disk
+- fixed some problems with GCC 3.x and debug enabled
+
+v1.0beta4 (12.04.2004)
+- removed dummy asfs_notify_change (this fixes major bug introduced
+  in 1.0beta3 - file size wasn't written to disk) until it will 
+  be implemented completely
+
+v1.0beta3 (22.03.2004) - still beta
+- updated for 2.6.x kernels VFS changes
+- code clean-up 
+- added dummy asfs_notify_change (chmod now returns no errors)
+- added symlinks write support
+- fixed: ASFS_SB(sb)->flags was always zero
+
+v1.0beta2 (11.01.2004) - special version for Pegasos][ kernel
+- separated read and write functions, can be compiled also
+  as read-only fs
+
+v1.0beta1 (02.12.2003) - first public beta with write support
+- added dentry hashing/comparing routines
+- code clean-up
+
+v1.0aplha4 (30.11.2003) - preparing for first public beta
+- fixed some problems with renaming/moving files
+- fixed two major bugs, which didn't occur when fs was mounted
+  on loopback device (newly allocated blocks were not written to
+  disk and state bits were not set correctly on newly mapped file
+  blocks)
+- fixed many small bugs in io code (some buffers were not freed)
+- added/modified sb locks in asfs_lookup and asfs_getblock
+- fixed serious bug in file block allocation routines
+
+v1.0aplha3 (23.11.2003)
+- added (hopefully) all byteswap code, should now work again on 
+  little-endian systems (also with write support!)
+- updated documentation
+
+v1.0alpha2 (13.11.2003) 
+- now alocates file blocks in chunks during one request
+- fixed some dead-locks, other fixes
+
+v1.0alpha (02.11.2003) - first working version with full write support
+- too much to list it here ;)
+
+... (working on write support)
+
+v0.7 (12.10.2003) - internal realase
+- added asfs_breadcheck, modified asfs_get_node, asfs_search_BTree, 
+  no more from_be32/16 macros, other...
+- code splitted into several files
+
+v0.6 (04.09.2003) - final read-only version
+- added support for HashTables, directory scaning should be
+  MUCH faster now
+- added checking of block IDs before reading any data from block
+
+v0.5 (19.07.2003)
+- added simple but effective extent cache - real speed-up 
+  in reading large files
+- added read support for symlinks - based on AFFS symlinks
+
+v0.4 (10.07.2003)
+- third code clean-up (thanks to Roman Zippel for advice)
+- now uses generic readpage and readinode routines
+
+v0.3beta (17.06.2003)
+- second code clean-up
+
+v0.2beta2 (15.06.2003)
+- fixed yet another stupid bug - driver can't read root block on little-endian systems
+v0.2beta (15.06.2003)
+- fixed stupid bug - now files have 'file' flag (S_IFREG) set...
+- added mount options to set uid, gid and mode of files and dirs
+- made hidden files & dirs really hidden (= not listed in directories)
+- code clean-up
+
+v0.1beta (11.06.2003) 
+- after many kernel crashes, finally got it! 
+- first working read-only filesystem driver
diff -ruN linux-source-2.6.24.orig/fs/asfs/dir.c linux-source-2.6.24/fs/asfs/dir.c
--- linux-source-2.6.24.orig/fs/asfs/dir.c      1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/dir.c   2008-12-14 23:05:05.000000000 +0300
@@ -0,0 +1,240 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta7
+ *
+ * Copyright (C) 2003,2004  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+
+extern struct dentry_operations asfs_dentry_operations;
+
+int asfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       struct inode *dir = filp->f_path.dentry->d_inode;
+       struct super_block *sb = dir->i_sb;
+       struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+       struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
+       u8 buf[512];
+       unsigned long f_pos;
+       int stored = 0;
+
+       struct buffer_head *bh;
+       struct fsObjectContainer *objcont;
+       struct fsObject *obj;
+       u32 block;
+       int startnode;
+       int add;
+
+       asfs_debug("asfs_readdir:\n");
+
+       if (filp->f_pos == ASFS_SB(sb)->totalblocks)
+               return stored;
+
+       f_pos = filp->f_pos;
+
+       if (f_pos == 0) {
+               filp->private_data = (void *)0;
+               if (filldir(dirent, ".", 1, f_pos, dir->i_ino, DT_DIR) < 0)
+                       return 0;
+               filp->f_pos = f_pos = 1;
+               stored++;
+       }
+       if (f_pos == 1) {
+               if (filldir(dirent, "..", 2, f_pos, parent_ino(filp->f_path.dentry), DT_DIR) < 0)
+                       return stored;
+               filp->f_pos = f_pos = 2;
+               stored++;
+       }
+
+       if (ASFS_I(dir)->firstblock == 0) {     /* empty directory */
+               filp->f_pos = ASFS_SB(sb)->totalblocks;
+               ASFS_I(dir)->modified = 0;
+               return stored;
+       }
+
+       if (f_pos == 2) {       /* reading directory from its beginning */
+               block = ASFS_I(dir)->firstblock;
+               add = 1;
+               startnode = 0;
+       } else {
+               startnode = (int)filp->private_data;
+               add = 0;
+               if (ASFS_I(dir)->modified == 0)
+                       block = f_pos;
+               else
+                       block = ASFS_I(dir)->firstblock;
+       }
+
+       do {
+               if (!(bh = asfs_breadcheck(sb, block, ASFS_OBJECTCONTAINER_ID)))
+                       return stored;
+               objcont = (struct fsObjectContainer *) bh->b_data;
+               obj = &(objcont->object[0]);
+
+               while (be32_to_cpu(obj->objectnode) > 0 && 
+                     ((char *)obj - (char *)objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
+
+                       if (!add && be32_to_cpu(obj->objectnode) == startnode)
+                               add++;
+
+                       if (add && !(obj->bits & OTYPE_HIDDEN)) {
+                               unsigned int type;
+                               asfs_translate(buf, obj->name, nls_io, nls_disk, 512);
+                               asfs_debug("ASFS: DirFilling: entry #%d \"%s\" (node %u offset %u), type %x\n", \
+                                          stored, buf, be32_to_cpu(obj->objectnode), block, obj->bits);
+                               filp->f_pos = block;
+
+                               if (obj->bits & OTYPE_DIR)
+                                       type = DT_DIR;
+                               else if (obj->bits & OTYPE_LINK && !(obj->bits & OTYPE_HARDLINK))
+                                       type = DT_LNK;
+                               else
+                                       type = DT_REG;
+
+                               if (filldir(dirent, buf, strlen(buf), block, be32_to_cpu(obj->objectnode), type) < 0) {
+                                       filp->private_data = (void *)be32_to_cpu(obj->objectnode);
+                                       ASFS_I(dir)->modified = 0;
+                                       asfs_debug("ASFS: DirFilling: to be continued...\n");
+                                       asfs_brelse(bh);
+                                       return stored;
+                               }
+                               stored++;
+                       }
+                       obj = asfs_nextobject(obj);
+               }
+               block = be32_to_cpu(objcont->next);
+               asfs_brelse(bh);
+
+       } while (block != 0);
+
+       filp->f_pos = ASFS_SB(sb)->totalblocks;
+       ASFS_I(dir)->modified = 0;
+
+       return stored;
+}
+
+static struct fsObject *asfs_find_obj_by_name_nls(struct super_block *sb, struct fsObjectContainer *objcont, u8 * name)
+{
+       struct fsObject *obj;
+       u8 buf[512];
+
+       obj = &(objcont->object[0]);
+       while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj - (char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
+               asfs_translate(buf, obj->name, ASFS_SB(sb)->nls_io, ASFS_SB(sb)->nls_disk, 512);
+               if (asfs_namecmp(buf, name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE, ASFS_SB(sb)->nls_io) == 0) {
+                       asfs_debug("Object found! Node %u, Name %s, Type %x, inCont %u\n", be32_to_cpu(obj->objectnode), obj->name, obj->bits, be32_to_cpu(objcont->bheader.ownblock));
+                       return obj;
+               }
+               obj = asfs_nextobject(obj);
+       }
+       return NULL;
+}
+
+struct dentry *asfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+{
+       int res = -EACCES;       /* placeholder for "no data here" */
+       struct inode *inode;
+       struct super_block *sb = dir->i_sb;
+       u8 *name = (u8 *) dentry->d_name.name;
+       struct buffer_head *bh;
+       struct fsObject *obj;
+       u8 bufname[ASFS_MAXFN_BUF];
+
+       asfs_translate(bufname, name, ASFS_SB(sb)->nls_disk, ASFS_SB(sb)->nls_io, ASFS_MAXFN_BUF);
+
+       asfs_debug("asfs_lookup: (searching \"%s\"...) ", name);
+
+       lock_super(sb);
+
+       if ((!strchr(name, '?')) && (ASFS_I(dir)->hashtable != 0)) {    /* hashtable block is available and name can be reverse translated, quick search */
+               struct fsObjectNode *node_p;
+               struct buffer_head *node_bh;
+               u32 node;
+               u16 hash16;
+
+               asfs_debug("(quick search) ");
+
+               if (!(bh = asfs_breadcheck(sb, ASFS_I(dir)->hashtable, ASFS_HASHTABLE_ID))) {
+                       unlock_super(sb);
+                       return ERR_PTR(res);
+               }
+               hash16 = asfs_hash(bufname, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE); 
+               node = be32_to_cpu(((struct fsHashTable *) bh->b_data)->hashentry[HASHCHAIN(hash16)]);
+               asfs_brelse(bh);
+
+               while (node != 0) {
+                       if (asfs_getnode(sb, node, &node_bh, &node_p) != 0)
+                               goto not_found;
+                       if (be16_to_cpu(node_p->hash16) == hash16) {
+                               if (!(bh = asfs_breadcheck(sb, be32_to_cpu(node_p->node.data), ASFS_OBJECTCONTAINER_ID))) {
+                                       asfs_brelse(node_bh);
+                                       unlock_super(sb);
+                                       return ERR_PTR(res);
+                               }
+                               if ((obj = asfs_find_obj_by_name(sb, (struct fsObjectContainer *) bh->b_data, bufname)) != NULL) {
+                                       asfs_brelse(node_bh);
+                                       goto found_inode;
+                               }
+                               asfs_brelse(bh);
+                       }
+                       node = be32_to_cpu(node_p->next);
+                       asfs_brelse(node_bh);
+               }
+       } else { /* hashtable not available or name can't be reverse-translated, long search */
+               struct fsObjectContainer *objcont;
+               u32 block;
+
+               asfs_debug("(long search) ");
+               block = ASFS_I(dir)->firstblock;
+               while (block != 0) {
+                       if (!(bh = asfs_breadcheck(sb, block, ASFS_OBJECTCONTAINER_ID))) {
+                               unlock_super(sb);
+                               return ERR_PTR(res);
+                       }
+                       objcont = (struct fsObjectContainer *) bh->b_data;
+                       if ((obj = asfs_find_obj_by_name_nls(sb, objcont, name)) != NULL)
+                               goto found_inode;
+                       block = be32_to_cpu(objcont->next);
+                       asfs_brelse(bh);
+               }
+       }
+
+not_found:
+       unlock_super(sb);
+       inode = NULL;
+       asfs_debug("object not found.\n");
+       if (0) {
+found_inode:
+               unlock_super(sb);
+               if (!(inode = iget_locked(sb, be32_to_cpu(obj->objectnode)))) {
+                       asfs_debug("ASFS: Strange - no inode allocated.\n");
+                       return ERR_PTR(res);
+               }
+               if (inode->i_state & I_NEW) {
+                       asfs_read_locked_inode(inode, obj);
+                       unlock_new_inode(inode);
+               }
+               asfs_brelse(bh);
+       }
+       res = 0;
+       dentry->d_op = &asfs_dentry_operations;
+       d_add(dentry, inode);
+       return ERR_PTR(res);
+}


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 4/9] Amiga SmartFileSystem, revision 2
  2009-02-12 16:38         ` Phillip Lougher
                             ` (2 preceding siblings ...)
  2009-02-13  6:55           ` [PATCH 3/9] " Pavel Fedin
@ 2009-02-13  6:55           ` Pavel Fedin
  2009-02-13  6:56           ` [PATCH 5/9] " Pavel Fedin
                             ` (4 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Pavel Fedin @ 2009-02-13  6:55 UTC (permalink / raw)
  To: Phillip Lougher; +Cc: linux-fsdevel

diff -ruN linux-source-2.6.24.orig/fs/asfs/extents.c linux-source-2.6.24/fs/asfs/extents.c
--- linux-source-2.6.24.orig/fs/asfs/extents.c  1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/extents.c       2008-12-14 23:05:05.000000000 +0300
@@ -0,0 +1,586 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta11
+ *
+ * This file contains some parts of the original amiga version of 
+ * SmartFilesystem source code.
+ *
+ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx, 
+ * Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek
+ * 
+ * Adapted and modified by Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+
+       /* This function looks for the BNode equal to the key.  If no
+          exact match is available then the BNode which is slightly
+          lower than key will be returned.  If no such BNode exists
+          either, then the first BNode in this block is returned.
+
+          This function will return the first BNode even if there
+          are no BNode's at all in this block (this can only happen
+          for the Root of the tree).  Be sure to check if the Root
+          is not empty before calling this function. */
+
+static struct BNode *searchforbnode(u32 key, struct BTreeContainer *tc)
+{
+       struct BNode *tn;
+       s16 n = be16_to_cpu(tc->nodecount) - 1;
+
+       tn = (struct BNode *) ((u8 *) tc->bnode + n * tc->nodesize);
+       for (;;) {
+               if (n <= 0 || key >= be32_to_cpu(tn->key))
+                       return tn;
+
+               tn = (struct BNode *) ((u8 *) tn - tc->nodesize);
+               n--;
+       }
+}
+
+/* This function finds the BNode with the given key.  If no exact match can be
+   found then this function will return either the next or previous closest
+   match (don't rely on this).
+
+   If there were no BNode's at all, then *returned_bh will be NULL. */
+
+static int findbnode(struct super_block *sb, u32 key, struct buffer_head **returned_bh, struct BNode **returned_bnode)
+{
+       u32 rootblock = ASFS_SB(sb)->extentbnoderoot;
+
+       asfs_debug("findbnode: Looking for BNode with key %d\n", key);
+
+       while ((*returned_bh = asfs_breadcheck(sb, rootblock, ASFS_BNODECONTAINER_ID))) {
+               struct fsBNodeContainer *bnc = (void *) (*returned_bh)->b_data;
+               struct BTreeContainer *btc = &bnc->btc;
+
+               if (btc->nodecount == 0) {
+                       *returned_bnode = NULL;
+                       break;
+               }
+
+               *returned_bnode = searchforbnode(key, btc);
+               if (btc->isleaf == TRUE)
+                       break;
+
+               rootblock = be32_to_cpu((*returned_bnode)->data);
+               asfs_brelse(*returned_bh);
+       }
+
+       if (*returned_bh == NULL)
+               return -EIO;
+
+       return 0;
+}
+
+int asfs_getextent(struct super_block *sb, u32 key, struct buffer_head **ret_bh, struct fsExtentBNode **ret_ebn)
+{
+       int result;
+       if ((result = findbnode(sb, key, ret_bh, (struct BNode **)ret_ebn)) == 0) 
+               if (be32_to_cpu((*ret_ebn)->key) != key) {
+                       brelse(*ret_bh);
+                       *ret_bh = NULL;
+                       return -ENOENT;
+               }
+
+       return result;
+}
+
+#ifdef CONFIG_ASFS_RW
+
+       /* This routine inserts a node sorted into a BTreeContainer.  It does
+          this by starting at the end, and moving the nodes one by one to
+          a higher slot until the empty slot has the correct position for
+          this key.  Donot use this function on completely filled
+          BTreeContainers! */
+
+static struct BNode *insertbnode(u32 key, struct BTreeContainer *btc)
+{
+       struct BNode *bn;
+       bn = (struct BNode *) ((u8 *) btc->bnode + btc->nodesize * (be16_to_cpu(btc->nodecount) - 1));
+
+       for (;;) {
+               if (bn < btc->bnode || key > be32_to_cpu(bn->key)) {
+                       bn = (struct BNode *) ((u8 *) bn + btc->nodesize);
+                       bn->key = cpu_to_be32(key);
+                       btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + 1);
+                       break;
+               } else 
+                       memmove((u8 *)bn + btc->nodesize, bn, btc->nodesize);
+
+               bn = (struct BNode *) ((u8 *) bn - btc->nodesize);
+       }
+
+       return bn;
+}
+
+static int getparentbtreecontainer(struct super_block *sb, struct buffer_head *bh, struct buffer_head **parent_bh)
+{
+       u32 rootblock = ASFS_SB(sb)->extentbnoderoot;
+       u32 childkey = be32_to_cpu(((struct fsBNodeContainer *) bh->b_data)->btc.bnode[0].key);
+       u32 childblock = be32_to_cpu(((struct fsBNodeContainer *) bh->b_data)->bheader.ownblock);
+
+       asfs_debug("getparentbtreecontainer: Getting parent of block %d\n", childblock);
+
+       /* This function gets the BTreeContainer parent of the passed in buffer_head. If
+          there is no parent this function sets dest_cont io_bh to NULL */
+
+       if (rootblock != childblock) {
+               while ((*parent_bh = asfs_breadcheck(sb, rootblock, ASFS_BNODECONTAINER_ID))) {
+                       struct fsBNodeContainer *bnc = (void *) (*parent_bh)->b_data;
+                       struct BTreeContainer *btc = &bnc->btc;
+                       struct BNode *bn;
+                       s16 n = be16_to_cpu(btc->nodecount);
+
+                       if (btc->isleaf == TRUE) {
+                               asfs_brelse(*parent_bh);
+                               break;
+                       }
+
+                       while (n-- > 0)
+                               if (be32_to_cpu(btc->bnode[n].data) == childblock)
+                                       return 0;       /* Found parent!! */
+
+                       bn = searchforbnode(childkey, btc);     /* This searchforbnode() doesn't have to get EXACT key matches. */
+                       rootblock = be32_to_cpu(bn->data);
+                       asfs_brelse(*parent_bh);
+               }
+               if (*parent_bh == NULL)
+                       return -EIO;
+       }
+
+       *parent_bh = NULL;
+       return 0;
+}
+
+/* Spits a btreecontainer. It realses passed in bh! */
+
+static int splitbtreecontainer(struct super_block *sb, struct buffer_head *bh)
+{
+       struct buffer_head *bhparent;
+       struct BNode *bn;
+       int errorcode;
+
+       asfs_debug("splitbtreecontainer: splitting block %u\n", be32_to_cpu(((struct fsBlockHeader *) bh->b_data)->ownblock));
+
+       if ((errorcode = getparentbtreecontainer(sb, bh, &bhparent)) == 0) {
+               if (bhparent == NULL) {
+                       u32 newbcontblock;
+                       u32 bcontblock;
+                       /* We need to create Root tree-container - adding new level to extent tree */
+
+                       asfs_debug("splitbtreecontainer: creating root tree-container.\n");
+
+                       bhparent = bh;
+                       if ((errorcode = asfs_allocadminspace(sb, &newbcontblock)) == 0 && (bh = asfs_getzeroblk(sb, newbcontblock))) {
+                               struct fsBNodeContainer *bnc = (void *) bh->b_data;
+                               struct fsBNodeContainer *bncparent = (void *) bhparent->b_data;
+                               struct BTreeContainer *btcparent = &bncparent->btc;
+
+                               bcontblock = be32_to_cpu(bncparent->bheader.ownblock);
+                               memcpy(bh->b_data, bhparent->b_data, sb->s_blocksize);
+                               bnc->bheader.ownblock = cpu_to_be32(newbcontblock);
+                               asfs_bstore(sb, bh);
+
+                               memset(bhparent->b_data, '\0', sb->s_blocksize);        /* Not strictly needed, but makes things more clear. */
+                               bncparent->bheader.id = cpu_to_be32(ASFS_BNODECONTAINER_ID);
+                               bncparent->bheader.ownblock = cpu_to_be32(bcontblock);
+                               btcparent->isleaf = FALSE;
+                               btcparent->nodesize = sizeof(struct BNode);
+                               btcparent->nodecount = 0;
+
+                               bn = insertbnode(0, btcparent);
+                               bn->data = cpu_to_be32(newbcontblock);
+
+                               asfs_bstore(sb, bhparent);
+                       }
+                       if (bh == NULL)
+                               errorcode = -EIO;
+               }
+
+               if (errorcode == 0) {
+                       struct fsBNodeContainer *bncparent = (void *) bhparent->b_data;
+                       struct BTreeContainer *btcparent = &bncparent->btc;
+                       int branches1 = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btcparent->nodesize;
+
+                       if (be16_to_cpu(btcparent->nodecount) == branches1) {
+                               /* We need to split the parent tree-container first! */
+                               if ((errorcode = splitbtreecontainer(sb, bhparent)) == 0) {
+                                       /* bhparent might have changed after the split and has been released */
+                                       if ((errorcode = getparentbtreecontainer(sb, bh, &bhparent)) == 0) {    
+                                               bncparent = (void *) bhparent->b_data;
+                                               btcparent = &bncparent->btc;
+                                       }
+                               }
+                       }
+
+                       if (errorcode == 0) {
+                               u32 newbcontblock;
+                               struct buffer_head *bhnew;
+
+                               /* We can split this container and add it to the parent
+                                  because the parent has enough room. */
+
+                               if ((errorcode = asfs_allocadminspace(sb, &newbcontblock)) == 0 && (bhnew = asfs_getzeroblk(sb, newbcontblock))) {
+                                       struct fsBNodeContainer *bncnew = (void *) bhnew->b_data;
+                                       struct BTreeContainer *btcnew = &bncnew->btc;
+                                       struct fsBNodeContainer *bnc = (void *) bh->b_data;
+                                       struct BTreeContainer *btc = &bnc->btc;
+                                       int branches2 = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btc->nodesize;
+                                       u32 newkey;
+
+                                       bncnew->bheader.id = cpu_to_be32(ASFS_BNODECONTAINER_ID);
+                                       bncnew->bheader.ownblock = cpu_to_be32(newbcontblock);
+
+                                       btcnew->isleaf = btc->isleaf;
+                                       btcnew->nodesize = btc->nodesize;
+
+                                       btcnew->nodecount = cpu_to_be16(branches2 - branches2 / 2);
+
+                                       memcpy(btcnew->bnode, (u8 *) btc->bnode + branches2 / 2 * btc->nodesize, (branches2 - branches2 / 2) * btc->nodesize);
+                                       newkey = be32_to_cpu(btcnew->bnode[0].key);
+
+                                       asfs_bstore(sb, bhnew);
+                                       asfs_brelse(bhnew);
+
+                                       btc->nodecount = cpu_to_be16(branches2 / 2);
+                                       asfs_bstore(sb, bh);
+
+                                       bn = insertbnode(newkey, btcparent);
+                                       bn->data = cpu_to_be32(newbcontblock);
+                                       asfs_bstore(sb, bhparent);
+                               }
+                       }
+               }
+               asfs_brelse(bhparent);
+       }
+       asfs_brelse(bh);
+
+       return errorcode;
+}
+
+/* Returns created extentbnode - returned_bh need to saved and realesed in caller funkction! */
+
+static int createextentbnode(struct super_block *sb, u32 key, struct buffer_head **returned_bh, struct BNode **returned_bnode)
+{
+       int errorcode;
+
+       asfs_debug("createbnode: Creating BNode with key %d\n", key);
+
+       while ((errorcode = findbnode(sb, key, returned_bh, returned_bnode)) == 0) {
+               struct fsBNodeContainer *bnc = (void *) (*returned_bh)->b_data;
+               struct BTreeContainer *btc = &bnc->btc;
+               int extbranches = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btc->nodesize;
+
+               asfs_debug("createbnode: findbnode found block %d\n", be32_to_cpu(((struct fsBlockHeader *) (*returned_bh)->b_data)->ownblock));
+
+               if (be16_to_cpu(btc->nodecount) < extbranches) {
+                       /* Simply insert new node in this BTreeContainer */
+                       asfs_debug("createbnode: Simple insert\n");
+                       *returned_bnode = insertbnode(key, btc);
+                       break;
+               } else if ((errorcode = splitbtreecontainer(sb, *returned_bh)) != 0)
+                       break;
+
+               /* Loop and try insert it the normal way again :-) */
+       }
+
+       return (errorcode);
+}
+
+
+/* This routine removes a node from a BTreeContainer indentified
+   by its key.  If no such key exists this routine does nothing.
+   It correctly handles empty BTreeContainers. */
+
+static void removebnode(u32 key, struct BTreeContainer *btc)
+{
+       struct BNode *bn = btc->bnode;
+       int n = 0;
+
+       asfs_debug("removebnode: key %d\n", key);
+
+       while (n < be16_to_cpu(btc->nodecount)) {
+               if (be32_to_cpu(bn->key) == key) {
+                       btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) - 1);
+                       memmove(bn, (u8 *) bn + btc->nodesize, (be16_to_cpu(btc->nodecount) - n) * btc->nodesize);
+                       break;
+               }
+               bn = (struct BNode *) ((u8 *) bn + btc->nodesize);
+               n++;
+       }
+}
+
+int asfs_deletebnode(struct super_block *sb, struct buffer_head *bh, u32 key)
+{
+       struct fsBNodeContainer *bnc1 = (void *) bh->b_data;
+       struct BTreeContainer *btc = &bnc1->btc;
+       u16 branches = (sb->s_blocksize - sizeof(struct fsBNodeContainer)) / btc->nodesize;
+       int errorcode = 0;
+
+       /* Deletes specified internal node. */
+
+       removebnode(key, btc);
+       asfs_bstore(sb, bh);
+
+       /* Now checks if the container still contains enough nodes,
+          and takes action accordingly. */
+
+       asfs_debug("deletebnode: branches = %d, btc->nodecount = %d\n", branches, be16_to_cpu(btc->nodecount));
+
+       if (be16_to_cpu(btc->nodecount) < (branches + 1) / 2) {
+               struct buffer_head *bhparent;
+               struct buffer_head *bhsec;
+
+               /* nodecount has become to low.  We need to merge this Container
+                  with a neighbouring Container, or we need to steal a few nodes
+                  from a neighbouring Container. */
+
+               /* We get the parent of the container here, so we can find out what
+                  containers neighbour the container which currently hasn't got enough nodes. */
+
+               if ((errorcode = getparentbtreecontainer(sb, bh, &bhparent)) == 0) {
+                       if (bhparent != NULL) {
+                               struct fsBNodeContainer *bncparent = (void *) bhparent->b_data;
+                               struct BTreeContainer *btcparent = &bncparent->btc;
+                               s16 n;
+
+                               asfs_debug("deletebnode: get parent returned block %d.\n", be32_to_cpu(((struct fsBlockHeader *) bhparent->b_data)->ownblock));
+
+                               for (n = 0; n < be16_to_cpu(btcparent->nodecount); n++)
+                                       if (btcparent->bnode[n].data == bnc1->bheader.ownblock)
+                                               break;
+                               /* n is now the offset of our own bnode. */
+
+                               if (n < be16_to_cpu(btcparent->nodecount) - 1) {        /* Check if we have a next neighbour. */
+                                       asfs_debug("deletebnode: using next container - merging blocks %d and %d\n", be32_to_cpu(bnc1->bheader.ownblock), be32_to_cpu(btcparent->bnode[n+1].data));
+
+                                       if ((bhsec = asfs_breadcheck(sb, be32_to_cpu(btcparent->bnode[n + 1].data), ASFS_BNODECONTAINER_ID))) {
+                                               struct fsBNodeContainer *bnc_next = (void *) bhsec->b_data;
+                                               struct BTreeContainer *btc_next = &bnc_next->btc;
+
+                                               if (be16_to_cpu(btc_next->nodecount) + be16_to_cpu(btc->nodecount) > branches) {        /* Check if we need to steal nodes. */
+                                                       s16 nodestosteal = (be16_to_cpu(btc_next->nodecount) + be16_to_cpu(btc->nodecount)) / 2 - be16_to_cpu(btc->nodecount);
+
+                                                       /* Merging them is not possible.  Steal a few nodes then. */
+                                                       memcpy((u8 *) btc->bnode + be16_to_cpu(btc->nodecount) * btc->nodesize, btc_next->bnode, nodestosteal * btc->nodesize);
+                                                       btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + nodestosteal);
+                                                       asfs_bstore(sb, bh);
+
+                                                       memcpy(btc_next->bnode, (u8 *) btc_next->bnode + btc_next->nodesize * nodestosteal,
+                                                              btc->nodesize * (be16_to_cpu(btc_next->nodecount) - nodestosteal));
+                                                       btc_next->nodecount = cpu_to_be16(be16_to_cpu(btc_next->nodecount) - nodestosteal);
+                                                       asfs_bstore(sb, bhsec);
+
+                                                       btcparent->bnode[n + 1].key = btc_next->bnode[0].key;
+                                                       asfs_bstore(sb, bhparent);
+                                               } else {        /* Merging is possible. */
+                                                       memcpy((u8 *) btc->bnode + btc->nodesize * be16_to_cpu(btc->nodecount), btc_next->bnode, btc->nodesize * be16_to_cpu(btc_next->nodecount));
+                                                       btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + be16_to_cpu(btc_next->nodecount));
+                                                       asfs_bstore(sb, bh);
+
+                                                       if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(((struct fsBlockHeader *) bhsec->b_data)->ownblock))) == 0)
+                                                               errorcode = asfs_deletebnode(sb, bhparent, be32_to_cpu(btcparent->bnode[n + 1].key));
+                                               }
+                                               asfs_brelse(bhsec);
+                                       }
+                               } else if (n > 0) {     /* Check if we have a previous neighbour. */
+                                       asfs_debug("deletebnode: using prev container.\n");
+
+                                       if ((bhsec = asfs_breadcheck(sb, be32_to_cpu(btcparent->bnode[n - 1].data), ASFS_BNODECONTAINER_ID)) == 0) {
+                                               struct fsBNodeContainer *bnc2 = (void *) bhsec->b_data;
+                                               struct BTreeContainer *btc2 = &bnc2->btc;
+
+                                               if (be16_to_cpu(btc2->nodecount) + be16_to_cpu(btc->nodecount) > branches) {
+                                                       /* Merging them is not possible.  Steal a few nodes then. */
+                                                       s16 nodestosteal = (be16_to_cpu(btc2->nodecount) + be16_to_cpu(btc->nodecount)) / 2 - be16_to_cpu(btc->nodecount);
+
+                                                       memmove((u8 *) btc->bnode + nodestosteal * btc->nodesize, btc->bnode, be16_to_cpu(btc->nodecount) * btc->nodesize);
+                                                       btc->nodecount = cpu_to_be16(be16_to_cpu(btc->nodecount) + nodestosteal);
+                                                       memcpy(btc->bnode, (u8 *) btc2->bnode + (be16_to_cpu(btc2->nodecount) - nodestosteal) * btc2->nodesize, nodestosteal * btc->nodesize);
+
+                                                       asfs_bstore(sb, bh);
+
+                                                       btc2->nodecount = cpu_to_be16(be16_to_cpu(btc2->nodecount) - nodestosteal);
+                                                       asfs_bstore(sb, bhsec);
+
+                                                       btcparent->bnode[n].key = btc->bnode[0].key;
+                                                       asfs_bstore(sb, bhparent);
+                                               } else {        /* Merging is possible. */
+                                                       memcpy((u8 *) btc2->bnode + be16_to_cpu(btc2->nodecount) * btc2->nodesize, btc->bnode, be16_to_cpu(btc->nodecount) * btc->nodesize);
+                                                       btc2->nodecount = cpu_to_be16(be16_to_cpu(btc2->nodecount) + be16_to_cpu(btc->nodecount));
+                                                       asfs_bstore(sb, bhsec);
+
+                                                       if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(((struct fsBlockHeader *) bhsec->b_data)->ownblock))) == 0)
+                                                               errorcode = asfs_deletebnode(sb, bhparent, be32_to_cpu(btcparent->bnode[n].key));
+                                               }
+                                               asfs_brelse(bhsec);
+                                       }
+                               }
+                               /*      else    
+                                  {
+                                  // Never happens, except for root and then we don't care.
+                                  } */
+                       } else if (btc->nodecount == 1) {
+                               /* No parent, so must be root. */
+
+                               asfs_debug("deletebnode: no parent so must be root\n");
+
+                               if (btc->isleaf == FALSE) {
+                                       struct fsBNodeContainer *bnc3 = (void *) bh->b_data;
+
+                                       /* The current root has only 1 node.  We now copy the data of this node into the
+                                          root and promote that data to be the new root.  The rootblock number stays the
+                                          same that way. */
+
+                                       if ((bhsec = asfs_breadcheck(sb, be32_to_cpu(btc->bnode[0].data), ASFS_BNODECONTAINER_ID))) {
+                                               u32 blockno = be32_to_cpu(((struct fsBlockHeader *) bh->b_data)->ownblock);
+                                               memcpy(bh->b_data, bhsec->b_data, sb->s_blocksize);
+                                               bnc3->bheader.ownblock = cpu_to_be32(blockno);
+
+                                               asfs_bstore(sb, bh);
+                                               errorcode = asfs_freeadminspace(sb, be32_to_cpu(((struct fsBlockHeader *) bhsec->b_data)->ownblock));
+                                               asfs_brelse(bhsec);
+                                       } else
+                                               errorcode = -EIO;
+                               }
+                               /* If not, then root contains leafs. */
+                       }
+
+                       asfs_debug("deletebnode: almost done\n");
+                       /* otherwise, it must be the root, and the root is allowed
+                          to contain less than the minimum amount of nodes. */
+
+               }
+               if (bhparent != NULL)
+                       asfs_brelse(bhparent);
+       }
+
+       return errorcode;
+}
+
+   /* Deletes an fsExtentBNode structure by key and any fsExtentBNodes linked to it.
+      This function DOES NOT fix the next pointer in a possible fsExtentBNode which
+      might have been pointing to the first BNode we are deleting.  Make sure you check
+      this yourself, if needed.
+
+      If key is zero, than this function does nothing. */
+
+int asfs_deleteextents(struct super_block *sb, u32 key)
+{
+       struct buffer_head *bh;
+       struct fsExtentBNode *ebn;
+       int errorcode = 0;
+
+       asfs_debug("deleteextents: Entry -- deleting extents from key %d\n", key);
+
+       while (key != 0 && (errorcode = findbnode(sb, key, &bh, (struct BNode **) &ebn)) == 0) {
+               /* node to be deleted located. */
+               key = be32_to_cpu(ebn->next);
+               if ((errorcode = asfs_freespace(sb, be32_to_cpu(ebn->key), be16_to_cpu(ebn->blocks))) != 0)
+                       break;
+
+               if ((errorcode = asfs_deletebnode(sb, bh, be32_to_cpu(ebn->key))) != 0)
+                       break;
+
+               asfs_brelse(bh);
+       }
+
+       return (errorcode);
+}
+
+   /* This function adds /blocks/ blocks starting at block /newspace/ to a file
+      identified by /objectnode/ and /lastextentbnode/.  /io_lastextentbnode/ can
+      be zero if there is no ExtentBNode chain attached to this file yet.
+      /blocks/ ranges from 1 to 8192.  To be able to extend Extents which are
+      almost full, it is wise to make this value no higher than 8192 blocks.
+      /io_lastextentbnode/ will contain the new lastextentbnode value when this
+      function completes.
+      If there was no chain yet, then this function will create a new one.  */
+
+int asfs_addblocks(struct super_block *sb, u16 blocks, u32 newspace, u32 objectnode, u32 *io_lastextentbnode)
+{
+       struct buffer_head *bh;
+       struct fsExtentBNode *ebn;
+       int errorcode = 0;
+
+       if (*io_lastextentbnode != 0) {
+               /* There was already a ExtentBNode chain for this file.  Extending it. */
+
+               asfs_debug("  addblocks: Extending existing ExtentBNode chain.\n");
+
+               if ((errorcode = asfs_getextent(sb, *io_lastextentbnode, &bh, &ebn)) == 0) {
+                       if (be32_to_cpu(ebn->key) + be16_to_cpu(ebn->blocks) == newspace && be16_to_cpu(ebn->blocks) + blocks < 65536) {
+                               /* It is possible to extent the last ExtentBNode! */
+                               asfs_debug("  addblocks: Extending last ExtentBNode.\n");
+
+                               ebn->blocks = cpu_to_be16(be16_to_cpu(ebn->blocks) + blocks);
+
+                               asfs_bstore(sb, bh);
+                               asfs_brelse(bh);
+                       } else {
+                               /* It isn't possible to extent the last ExtentBNode so we create
+                                  a new one and link it to the last ExtentBNode. */
+
+                               ebn->next = cpu_to_be32(newspace);
+                               asfs_bstore(sb, bh);
+                               asfs_brelse(bh);
+
+                               if ((errorcode = createextentbnode(sb, newspace, &bh, (struct BNode **) &ebn)) == 0) {
+                                       asfs_debug("  addblocks: Created new ExtentBNode.\n");
+
+                                       ebn->key = cpu_to_be32(newspace);
+                                       ebn->prev = cpu_to_be32(*io_lastextentbnode);
+                                       ebn->next = 0;
+                                       ebn->blocks = cpu_to_be16(blocks);
+
+                                       *io_lastextentbnode = newspace;
+
+                                       asfs_bstore(sb, bh);
+                                       asfs_brelse(bh);
+
+                                       ASFS_SB(sb)->block_rovingblockptr = newspace + blocks;
+
+       /* to be changed in the future */
+/*                                     if (ASFS_SB(sb)->block_rovingblockptr >= ASFS_SB(sb)->totalblocks)
+                                               ASFS_SB(sb)->block_rovingblockptr = 0;*/
+                               }
+                       }
+               }
+       } else {
+               /* There is no ExtentBNode chain yet for this file.  Attaching one! */
+               if ((errorcode = createextentbnode(sb, newspace, &bh, (struct BNode **) &ebn)) == 0) {
+                       asfs_debug("  addblocks: Created new ExtentBNode chain.\n");
+
+                       ebn->key = cpu_to_be32(newspace);
+                       ebn->prev = cpu_to_be32(objectnode + 0x80000000);
+                       ebn->next = 0;
+                       ebn->blocks = cpu_to_be16(blocks);
+
+                       *io_lastextentbnode = newspace;
+
+                       asfs_bstore(sb, bh);
+                       asfs_brelse(bh);
+
+                       ASFS_SB(sb)->block_rovingblockptr = newspace + blocks;
+
+/*                     if (ASFS_SB(sb)->block_rovingblockptr >= ASFS_SB(sb)->totalblocks)
+                               ASFS_SB(sb)->block_rovingblockptr = 0;*/
+               }
+       }
+
+       asfs_debug("  addblocks: done.\n");
+
+       return errorcode;
+}
+#endif


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 5/9] Amiga SmartFileSystem, revision 2
  2009-02-12 16:38         ` Phillip Lougher
                             ` (3 preceding siblings ...)
  2009-02-13  6:55           ` [PATCH 4/9] " Pavel Fedin
@ 2009-02-13  6:56           ` Pavel Fedin
  2009-02-13  6:56           ` [PATCH 6/9] " Pavel Fedin
                             ` (3 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Pavel Fedin @ 2009-02-13  6:56 UTC (permalink / raw)
  To: Phillip Lougher; +Cc: linux-fsdevel

diff -ruN linux-source-2.6.24.orig/fs/asfs/file.c linux-source-2.6.24/fs/asfs/file.c
--- linux-source-2.6.24.orig/fs/asfs/file.c     1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/file.c  2008-12-14 23:33:00.000000000 +0300
@@ -0,0 +1,255 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta7
+ *  
+ * Copyright (C) 2003,2004  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+
+static int
+asfs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create)
+{
+       struct buffer_head *ebn_bh;
+       struct fsExtentBNode extent, *ebn_p;
+       u32 filedata;
+       unsigned long pos;
+       struct super_block *sb = inode->i_sb;
+#ifdef CONFIG_ASFS_RW
+       int error;
+       struct buffer_head *bh;
+       struct fsObject *obj;
+#endif
+
+       asfs_debug("ASFS: get_block(%lu, %ld, %d)\n", inode->i_ino, block, create);
+
+       if (block < 0) {
+               printk(KERN_ERR "ASFS: asfsget_block: requested block (%ld) < 0!\n", block);
+               return -EIO;
+       } else if (block >= inode->i_blocks && !create) {
+               printk(KERN_ERR "ASFS: asfsget_block: strange block request %ld!\n", block);
+               return -EIO;
+       } 
+
+       if (create)
+#ifdef CONFIG_ASFS_RW
+               ASFS_I(inode)->modified = TRUE;
+#else
+               return -EROFS;
+#endif
+
+       if (block < inode->i_blocks)
+               create = 0;
+
+       lock_super(sb);
+
+#ifdef CONFIG_ASFS_RW
+       if (create) {
+               int blockstoadd;
+               u32 newspace, addedblocks;
+
+               blockstoadd = block - inode->i_blocks + 1;
+
+               if (blockstoadd < ASFS_BLOCKCHUNKS)
+                       blockstoadd = ASFS_BLOCKCHUNKS;
+ 
+               asfs_debug("ASFS get_block: Trying to add %d blocks to file\n", blockstoadd);
+               
+               if ((error = asfs_readobject(sb, inode->i_ino, &bh, &obj)) != 0) {
+                       unlock_super(sb);
+                       return error;
+               }
+
+               if ((error = asfs_addblockstofile(sb, bh, obj, blockstoadd, &newspace, &addedblocks)) != 0) {
+                       asfs_brelse(bh);
+                       unlock_super(sb);
+                       return error;
+               }
+               ASFS_I(inode)->mmu_private += addedblocks * sb->s_blocksize;
+               inode->i_blocks += addedblocks;
+               ASFS_I(inode)->ext_cache.key = 0;
+               ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
+               asfs_brelse(bh);
+       }
+#endif
+
+       if (ASFS_I(inode)->ext_cache.key > 0 && ASFS_I(inode)->ext_cache.startblock <= block) {
+               extent.key = ASFS_I(inode)->ext_cache.key;
+               extent.next = ASFS_I(inode)->ext_cache.next;
+               extent.blocks = ASFS_I(inode)->ext_cache.blocks;
+               pos = ASFS_I(inode)->ext_cache.startblock;
+       } else {
+               if (asfs_getextent(inode->i_sb, ASFS_I(inode)->firstblock, &ebn_bh, &ebn_p) != 0) {
+                       unlock_super(sb);
+                       return -EIO;
+               }
+               extent.key = be32_to_cpu(ebn_p->key);
+               extent.next = be32_to_cpu(ebn_p->next);
+               extent.blocks = be16_to_cpu(ebn_p->blocks);
+               pos = 0;
+               asfs_brelse(ebn_bh);
+       }
+       ebn_p = &extent;
+       filedata = ebn_p->next;
+
+       while (pos + ebn_p->blocks <= block && ebn_p->next != 0 && pos < inode->i_blocks) {
+               pos += ebn_p->blocks;
+               if (asfs_getextent(inode->i_sb, filedata, &ebn_bh, &ebn_p) != 0) {
+                       unlock_super(sb);
+                       return -EIO;
+               }
+               extent.key = be32_to_cpu(ebn_p->key);
+               extent.next = be32_to_cpu(ebn_p->next);
+               extent.blocks = be16_to_cpu(ebn_p->blocks);
+               ebn_p = &extent;        
+               filedata = ebn_p->next;
+               asfs_brelse(ebn_bh);
+       }
+
+       unlock_super(sb);
+
+       map_bh(bh_result, inode->i_sb, (sector_t) (ebn_p->key + block - pos));
+
+       if (create)
+               set_buffer_new(bh_result);
+
+       asfs_debug("ASFS: get_block - mapped block %lu\n", ebn_p->key + block - pos);
+
+       ASFS_I(inode)->ext_cache.startblock = pos;
+       ASFS_I(inode)->ext_cache.key = ebn_p->key;
+       ASFS_I(inode)->ext_cache.next = ebn_p->next;
+       ASFS_I(inode)->ext_cache.blocks = ebn_p->blocks;
+
+       return 0;
+}
+
+int asfs_readpage(struct file *file, struct page *page)
+{
+       asfs_debug("ASFS: %s\n", __FUNCTION__);
+       return block_read_full_page(page, asfs_get_block);
+}
+
+sector_t asfs_bmap(struct address_space *mapping, sector_t block)
+{
+       asfs_debug("ASFS: %s\n", __FUNCTION__);
+       return generic_block_bmap(mapping,block,asfs_get_block);
+}
+
+#ifdef CONFIG_ASFS_RW
+
+int asfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+       asfs_debug("ASFS: %s\n", __FUNCTION__);
+       return block_write_full_page(page, asfs_get_block, wbc);
+}
+
+int asfs_write_begin(struct file *file, struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned flags,
+                       struct page **pagep, void **fsdata)
+{
+       *pagep = NULL;
+       return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+                               asfs_get_block,
+                               &ASFS_I(mapping->host)->mmu_private);
+}
+
+void asfs_truncate(struct inode *inode)
+{
+       struct super_block *sb = inode->i_sb;
+       struct buffer_head *bh;
+       struct fsObject *obj;
+
+       asfs_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n",
+                (u32)inode->i_ino, (u32)ASFS_I(inode)->mmu_private, (u32)inode->i_size);
+
+       if (inode->i_size > ASFS_I(inode)->mmu_private) {
+               printk("ASFS: enlarging file is not supported yet\n");
+               return;
+       }
+
+       lock_super(sb);
+
+       if ((asfs_readobject(sb, inode->i_ino, &bh, &obj)) != 0) {
+               unlock_super(sb);
+               return;
+       }
+
+       if (asfs_truncateblocksinfile(sb, bh, obj, inode->i_size) != 0) {
+               asfs_brelse(bh);
+               unlock_super(sb);
+               return;
+       }
+               
+       obj->object.file.size = cpu_to_be32(inode->i_size);
+       ASFS_I(inode)->mmu_private = inode->i_size;
+       ASFS_I(inode)->modified = TRUE;
+       inode->i_blocks = (be32_to_cpu(obj->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+       asfs_bstore(sb, bh);
+       asfs_brelse(bh);
+
+       unlock_super(sb);
+}
+
+int asfs_file_open(struct inode *inode, struct file *filp)
+{
+       if (atomic_read(&filp->f_count) != 1)
+               return 0;
+       asfs_debug("ASFS: file open (node %d)\n", (int)inode->i_ino);
+       return 0;
+}
+
+int asfs_file_release(struct inode *inode, struct file *filp)
+{
+       int error = 0;
+
+       asfs_debug("ASFS: file release (node %d oc %d)\n", (int)inode->i_ino, atomic_read(&filp->f_count));
+
+       if (atomic_read(&filp->f_count) != 0)
+               return 0;
+
+       if (ASFS_I(inode)->modified == TRUE) {
+               struct buffer_head *bh;
+               struct fsObject *obj;
+               lock_super(inode->i_sb);
+
+               if ((error = asfs_readobject(inode->i_sb, inode->i_ino, &bh, &obj)) != 0) {
+                       unlock_super(inode->i_sb);
+                       return error;
+               }
+
+               obj->datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60);
+               if (inode->i_mode & S_IFREG) {
+                       error = asfs_truncateblocksinfile(inode->i_sb, bh, obj, (u32)inode->i_size);
+                       obj->object.file.size = cpu_to_be32(inode->i_size);
+                       ASFS_I(inode)->mmu_private = inode->i_size;
+                       inode->i_blocks = (be32_to_cpu(obj->object.file.size) + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+               }
+               asfs_bstore(inode->i_sb, bh);
+
+               unlock_super(inode->i_sb);
+
+               asfs_brelse(bh);
+       }
+       ASFS_I(inode)->modified = FALSE;
+
+       return error;
+}
+
+#endif
diff -ruN linux-source-2.6.24.orig/fs/asfs/inode.c linux-source-2.6.24/fs/asfs/inode.c
--- linux-source-2.6.24.orig/fs/asfs/inode.c    1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/inode.c 2008-12-14 23:31:39.000000000 +0300
@@ -0,0 +1,437 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta12
+ *  
+ * Copyright (C) 2003,2004,2005,2006  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/time.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include <linux/dirent.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+
+#ifdef CONFIG_ASFS_RW
+static int asfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd);
+static int asfs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+static int asfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname);
+static int asfs_rmdir(struct inode *dir, struct dentry *dentry);
+static int asfs_unlink(struct inode *dir, struct dentry *dentry);
+static int asfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+               struct inode *new_dir, struct dentry *new_dentry);
+/*static int asfs_notify_change(struct dentry *dentry, struct iattr *attr);*/
+#endif
+
+/* Mapping from our types to the kernel */
+
+static struct address_space_operations asfs_aops = {
+       .readpage       = asfs_readpage,
+       .sync_page      = block_sync_page,
+       .bmap           = asfs_bmap,
+#ifdef CONFIG_ASFS_RW
+       .writepage      = asfs_writepage,
+       .write_begin    = asfs_write_begin,
+       .write_end      = generic_write_end,
+#endif
+};
+
+static struct file_operations asfs_file_operations = {
+       .llseek         = generic_file_llseek,
+       .aio_read               = generic_file_aio_read,
+       .mmap           = generic_file_mmap,
+#ifdef CONFIG_ASFS_RW
+       .aio_write              = generic_file_aio_write,
+       .open           = asfs_file_open,
+       .release        = asfs_file_release,
+       .fsync          = file_fsync,
+#endif
+};
+
+static struct file_operations asfs_dir_operations = {
+       .read           = generic_read_dir,
+       .readdir        = asfs_readdir,
+};
+
+static struct inode_operations asfs_dir_inode_operations = {
+       .lookup         = asfs_lookup,
+#ifdef CONFIG_ASFS_RW
+       .create         = asfs_create,
+       .unlink         = asfs_unlink,
+       .symlink        = asfs_symlink,
+       .mkdir          = asfs_mkdir,
+       .rmdir          = asfs_rmdir,
+       .rename         = asfs_rename,
+/*     .setattr        = asfs_notify_change,*/
+#endif
+};
+
+static struct inode_operations asfs_file_inode_operations = {
+#ifdef CONFIG_ASFS_RW
+       .truncate       = asfs_truncate,
+/*     .setattr                = asfs_notify_change,*/
+#endif
+};
+
+static struct address_space_operations asfs_symlink_aops = {
+       .readpage       = asfs_symlink_readpage,
+};
+
+static struct inode_operations asfs_symlink_inode_operations = {
+       .readlink       = generic_readlink,
+       .follow_link    = page_follow_link_light,
+       .put_link       = page_put_link,
+#ifdef CONFIG_ASFS_RW
+/*     .setattr        = asfs_notify_change,*/
+#endif
+};
+
+void asfs_read_locked_inode(struct inode *inode, void *arg)
+{
+       struct super_block *sb = inode->i_sb;
+       struct fsObject *obj = arg;
+
+       inode->i_mode = ASFS_SB(sb)->mode;
+       inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = be32_to_cpu(obj->datemodified) + (365*8+2)*24*60*60;  
+       /* Linux: seconds since 01-01-1970, AmigaSFS: seconds since 01-01-1978 */
+       inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_atime.tv_nsec = 0;
+       inode->i_uid = ASFS_SB(sb)->uid;
+       inode->i_gid = ASFS_SB(sb)->gid;
+
+       asfs_debug("asfs_read_inode2: Setting-up node %lu... ", inode->i_ino);
+
+       if (obj->bits & OTYPE_DIR) {
+               asfs_debug("dir (FirstdirBlock: %u, HashTable %u)\n", \
+                          be32_to_cpu(obj->object.dir.firstdirblock), be32_to_cpu(obj->object.dir.hashtable));
+
+               inode->i_size = 0;
+               inode->i_op = &asfs_dir_inode_operations;
+               inode->i_fop = &asfs_dir_operations;
+               inode->i_mode |= S_IFDIR | ((inode->i_mode & 0400) ? 0100 : 0) | 
+                             ((inode->i_mode & 0040) ? 0010 : 0) | ((inode->i_mode & 0004) ? 0001 : 0);
+               ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.dir.firstdirblock);
+               ASFS_I(inode)->hashtable = be32_to_cpu(obj->object.dir.hashtable);
+               ASFS_I(inode)->modified = 0;
+       } else if (obj->bits & OTYPE_LINK && !(obj->bits & OTYPE_HARDLINK)) {
+               asfs_debug("symlink\n");
+               inode->i_size = 0;
+               inode->i_op = &asfs_symlink_inode_operations;
+               inode->i_data.a_ops = &asfs_symlink_aops;
+               inode->i_mode |= S_IFLNK | S_IRWXUGO;
+               ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
+       } else {
+               asfs_debug("file (Size: %u, FirstBlock: %u)\n", be32_to_cpu(obj->object.file.size), be32_to_cpu(obj->object.file.data));
+               inode->i_size = be32_to_cpu(obj->object.file.size);
+               inode->i_blocks = (be32_to_cpu(obj->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+               inode->i_op = &asfs_file_inode_operations;
+               inode->i_fop = &asfs_file_operations;
+               inode->i_mapping->a_ops = &asfs_aops;
+               inode->i_mode |= S_IFREG;
+               ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
+               ASFS_I(inode)->ext_cache.startblock = 0;
+               ASFS_I(inode)->ext_cache.key = 0;
+               ASFS_I(inode)->mmu_private = inode->i_size;
+       }
+       return; 
+}
+
+struct inode *asfs_get_root_inode(struct super_block *sb)
+{
+       struct inode *result = NULL;
+       struct fsObject *obj;
+       struct buffer_head *bh;
+
+       asfs_debug("asfs_get_root_inode\n");
+
+       if ((bh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
+               obj = &(((struct fsObjectContainer *)bh->b_data)->object[0]);
+               if (be32_to_cpu(obj->objectnode) > 0)
+                       result = iget_locked(sb, be32_to_cpu(obj->objectnode));
+
+               if (result != NULL && result->i_state & I_NEW) {
+                       asfs_read_locked_inode(result, obj);
+                       unlock_new_inode(result);
+               }
+               asfs_brelse(bh);
+       }
+       return result;
+}
+
+#ifdef CONFIG_ASFS_RW
+
+static void asfs_sync_dir_inode(struct inode *dir, struct fsObject *obj)
+{
+       ASFS_I(dir)->firstblock = be32_to_cpu(obj->object.dir.firstdirblock);
+       ASFS_I(dir)->modified = 1;
+       dir->i_mtime = dir->i_atime = dir->i_ctime = CURRENT_TIME;
+       obj->datemodified = cpu_to_be32(dir->i_mtime.tv_sec - (365*8+2)*24*60*60);
+}
+
+enum { it_file, it_dir, it_link };
+
+static int asfs_create_object(struct inode *dir, struct dentry *dentry, int mode, int type, const char *symname)
+{
+       int error;
+       struct super_block *sb = dir->i_sb;
+       struct inode *inode;
+       struct buffer_head *bh, *dir_bh;
+       struct fsObject obj_data, *dir_obj, *obj;
+       u8 *name = (u8 *) dentry->d_name.name;
+       u8 bufname[ASFS_MAXFN_BUF];
+
+       asfs_debug("asfs_create_obj %s in dir node %d\n", name, (int)dir->i_ino);
+
+       asfs_translate(bufname, name, ASFS_SB(sb)->nls_disk, ASFS_SB(sb)->nls_io, ASFS_MAXFN_BUF);
+       if ((error = asfs_check_name(bufname, strlen(bufname))) != 0)
+               return error;
+
+       sb = dir->i_sb;
+       inode = new_inode(sb);
+       if (!inode)
+               return -ENOMEM;
+
+       memset(&obj_data, 0, sizeof(struct fsObject));
+
+       obj_data.protection = cpu_to_be32(FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
+       obj_data.datemodified = cpu_to_be32(inode->i_mtime.tv_sec - (365*8+2)*24*60*60);
+       switch (type) {
+       case it_dir:
+               obj_data.bits = OTYPE_DIR;
+               break;
+       case it_link:
+               obj_data.bits = OTYPE_LINK;
+               break;
+       default:
+               break;
+       }
+
+       lock_super(sb);
+
+       if ((error = asfs_readobject(sb, dir->i_ino, &dir_bh, &dir_obj)) != 0) {
+               dec_count(inode);
+               unlock_super(sb);
+               return error;
+       }
+
+       bh = dir_bh;
+       obj = dir_obj;
+
+       if ((error = asfs_createobject(sb, &bh, &obj, &obj_data, bufname, FALSE)) != 0) {
+               asfs_brelse(dir_bh);
+               dec_count(inode);
+               unlock_super(sb);
+               return error;
+       }
+
+       inode->i_ino = be32_to_cpu(obj->objectnode);
+       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+       inode->i_size = inode->i_blocks = 0;
+       inode->i_uid = dir->i_uid;
+       inode->i_gid = dir->i_gid;
+       inode->i_mode = mode | ASFS_SB(sb)->mode;
+
+       switch (type) {
+       case it_dir:
+               inode->i_mode |= S_IFDIR;
+               inode->i_op = &asfs_dir_inode_operations;
+               inode->i_fop = &asfs_dir_operations;
+               ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.dir.firstdirblock);
+               ASFS_I(inode)->hashtable = be32_to_cpu(obj->object.dir.hashtable);
+               ASFS_I(inode)->modified = 0;
+               break;
+       case it_file:
+               inode->i_mode |= S_IFREG;
+               inode->i_op = &asfs_file_inode_operations;
+               inode->i_fop = &asfs_file_operations;
+               inode->i_mapping->a_ops = &asfs_aops;
+               ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
+               ASFS_I(inode)->ext_cache.startblock = 0;
+               ASFS_I(inode)->ext_cache.key = 0;
+               ASFS_I(inode)->mmu_private = inode->i_size;
+               break;
+       case it_link:
+               inode->i_mode = S_IFLNK | S_IRWXUGO;
+               inode->i_op = &page_symlink_inode_operations;
+               inode->i_mapping->a_ops = &asfs_symlink_aops;
+               ASFS_I(inode)->firstblock = be32_to_cpu(obj->object.file.data);
+               error = asfs_write_symlink(inode, symname);
+               break;
+       default:
+               break;
+       }
+
+       asfs_bstore(sb, bh);
+       insert_inode_hash(inode);
+       mark_inode_dirty(inode);
+       d_instantiate(dentry, inode);
+       asfs_sync_dir_inode(dir, dir_obj);
+       asfs_bstore(sb, dir_bh); 
+
+       unlock_super(sb);
+       asfs_brelse(bh);
+       asfs_brelse(dir_bh);
+       
+       return error;
+}
+
+static int asfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
+{
+       return asfs_create_object(dir, dentry, mode, it_file, NULL);
+}
+
+static int asfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+       return asfs_create_object(dir, dentry, mode, it_dir, NULL);
+}
+
+static int asfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+{
+       return asfs_create_object(dir, dentry, 0, it_link, symname);
+}
+
+static int asfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       asfs_debug("ASFS: %s\n", __FUNCTION__);
+
+       if (ASFS_I(dentry->d_inode)->firstblock != 0)
+               return -ENOTEMPTY;
+       
+       return asfs_unlink(dir, dentry);
+}
+
+static int asfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+       struct inode *inode = dentry->d_inode;
+       int error;
+       struct super_block *sb = dir->i_sb;
+       struct buffer_head *bh, *dir_bh;
+       struct fsObject *dir_obj, *obj;
+
+       asfs_debug("ASFS: %s\n", __FUNCTION__);
+
+       lock_super(sb);
+
+       if ((error = asfs_readobject(sb, inode->i_ino, &bh, &obj)) != 0) {
+               unlock_super(sb);
+               return error;
+       }
+       if ((error = asfs_deleteobject(sb, bh, obj)) != 0) {
+               asfs_brelse(bh);
+               unlock_super(sb);
+               return error;
+       }
+       asfs_brelse(bh);
+
+       /* directory data could change after removing the object */
+       if ((error = asfs_readobject(sb, dir->i_ino, &dir_bh, &dir_obj)) != 0) {
+               unlock_super(sb);
+               return error;
+       }
+
+       asfs_sync_dir_inode(dir, dir_obj);
+       asfs_bstore(sb, dir_bh); 
+
+       dec_count(inode);
+       unlock_super(sb);
+       asfs_brelse(dir_bh);
+
+       return 0;
+}
+
+static int asfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry)
+{
+       struct super_block *sb = old_dir->i_sb;
+       struct buffer_head *src_bh, *old_bh, *new_bh;
+       int error;
+       struct fsObject *src_obj, *old_obj, *new_obj;
+       u8 bufname[ASFS_MAXFN_BUF];
+
+       asfs_debug("ASFS: rename (old=%u,\"%*s\" to new=%u,\"%*s\")\n",
+                (u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
+                (u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
+
+       asfs_translate(bufname, (u8 *) new_dentry->d_name.name, ASFS_SB(sb)->nls_disk, ASFS_SB(sb)->nls_io, ASFS_MAXFN_BUF);
+       if ((error = asfs_check_name(bufname, strlen(bufname))) != 0)
+               return error;
+
+
+       /* Unlink destination if it already exists */
+       if (new_dentry->d_inode) 
+               if ((error = asfs_unlink(new_dir, new_dentry)) != 0)
+                       return error;
+
+       lock_super(sb);
+
+       if ((error = asfs_readobject(sb, old_dentry->d_inode->i_ino, &src_bh, &src_obj)) != 0) {
+               unlock_super(sb);
+               return error;
+       }
+       if ((error = asfs_readobject(sb, new_dir->i_ino, &new_bh, &new_obj)) != 0) {
+               asfs_brelse(src_bh);
+               unlock_super(sb);
+               return error;
+       }
+
+       if ((error = asfs_renameobject(sb, src_bh, src_obj, new_bh, new_obj, bufname)) != 0) {
+               asfs_brelse(src_bh);
+               asfs_brelse(new_bh);
+               unlock_super(sb);
+               return error;
+       }
+       asfs_brelse(src_bh);
+       asfs_brelse(new_bh);
+
+       if ((error = asfs_readobject(sb, old_dir->i_ino, &old_bh, &old_obj)) != 0) {
+               unlock_super(sb);
+               return error;
+       }
+       if ((error = asfs_readobject(sb, new_dir->i_ino, &new_bh, &new_obj)) != 0) {
+               asfs_brelse(old_bh);
+               unlock_super(sb);
+               return error;
+       }
+
+       asfs_sync_dir_inode(old_dir, old_obj);
+       asfs_sync_dir_inode(new_dir, new_obj);
+
+       asfs_bstore(sb, new_bh);        
+       asfs_bstore(sb, old_bh);
+
+       unlock_super(sb);
+       asfs_brelse(old_bh);
+       asfs_brelse(new_bh);
+
+       mark_inode_dirty(old_dir);
+       mark_inode_dirty(new_dir);
+
+       return 0;
+}
+
+/*
+int asfs_notify_change(struct dentry *dentry, struct iattr *attr)
+{
+       struct inode *inode = dentry->d_inode;
+       int error = 0;
+
+       asfs_debug("ASFS: notify_change(%lu,0x%x)\n",inode->i_ino,attr->ia_valid);
+
+       error = inode_change_ok(inode,attr);
+
+       return error;
+}
+*/
+#endif


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 6/9] Amiga SmartFileSystem, revision 2
  2009-02-12 16:38         ` Phillip Lougher
                             ` (4 preceding siblings ...)
  2009-02-13  6:56           ` [PATCH 5/9] " Pavel Fedin
@ 2009-02-13  6:56           ` Pavel Fedin
  2009-02-13  6:56           ` [PATCH 7/9] " Pavel Fedin
                             ` (2 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Pavel Fedin @ 2009-02-13  6:56 UTC (permalink / raw)
  To: Phillip Lougher; +Cc: linux-fsdevel

diff -ruN linux-source-2.6.24.orig/fs/asfs/Makefile linux-source-2.6.24/fs/asfs/Makefile
--- linux-source-2.6.24.orig/fs/asfs/Makefile   1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/Makefile        2008-12-14 23:05:05.000000000 +0300
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux asfs filesystem routines.
+#
+
+obj-$(CONFIG_ASFS_FS) += asfs.o
+
+asfs-y += dir.o extents.o file.o inode.o namei.o nodes.o objects.o super.o symlink.o
+asfs-$(CONFIG_ASFS_RW) += adminspace.o bitfuncs.o 
diff -ruN linux-source-2.6.24.orig/fs/asfs/namei.c linux-source-2.6.24/fs/asfs/namei.c
--- linux-source-2.6.24.orig/fs/asfs/namei.c    1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/namei.c 2008-12-14 23:05:05.000000000 +0300
@@ -0,0 +1,197 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta10
+ *
+ * Copyright (C) 2003,2004,2005  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+#include "asfs_fs.h"
+
+static inline u8 asfs_upperchar(u8 c)
+{
+       if ((c >= 224 && c <= 254 && c != 247) || (c >= 'a' && c <= 'z'))
+               c -= 32;
+       return (c);
+}
+
+u8 asfs_lowerchar(u8 c)
+{
+       if ((c >= 192 && c <= 222 && c != 215) || (c >= 'A' && c <= 'Z'))
+               c += 32;
+       return (c);
+}
+
+static inline u8 asfs_nls_upperchar(u8 c, struct nls_table *t)
+{
+       if (t) {
+               u8 nc = t->charset2upper[c];
+               return nc ? nc : c;
+       } else
+               return asfs_upperchar(c);
+}
+
+/* Check if the name is valid for a asfs object. */
+
+inline int asfs_check_name(const u8 *name, int len)
+{
+       int i;
+
+       if (len > ASFS_MAXFN)
+               return -ENAMETOOLONG;
+
+       for (i = 0; i < len; i++)
+               if (name[i] < ' ' || name[i] == ':' || (name[i] > 0x7e && name[i] < 0xa0))
+                       return -EINVAL;
+
+       return 0;
+}
+
+/* Note: the dentry argument is the parent dentry. */
+
+static int asfs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+{
+       struct super_block *sb = dentry->d_inode->i_sb;
+       const u8 *name = qstr->name;
+       unsigned long hash;
+       int i;
+       struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+
+       i = asfs_check_name(qstr->name,qstr->len);
+       if (i)
+               return i;
+
+       hash = init_name_hash();
+
+       if (ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE)
+               for (i=qstr->len; i > 0; name++, i--)
+                       hash = partial_name_hash(*name, hash);
+       else
+               for (i=qstr->len; i > 0; name++, i--)
+                       hash = partial_name_hash(asfs_nls_upperchar(*name, nls_io), hash);
+
+       qstr->hash = end_name_hash(hash);
+
+       return 0;
+}
+
+static int asfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
+{
+       struct super_block *sb = dentry->d_inode->i_sb;
+       const u8 *aname = a->name;
+       const u8 *bname = b->name;
+       int len;
+       struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+
+       /* 'a' is the qstr of an already existing dentry, so the name
+        * must be valid. 'b' must be validated first.
+        */
+
+       if (asfs_check_name(b->name,b->len))
+               return 1;
+
+       if (a->len != b->len)
+               return 1;
+
+       if (ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE) {
+               for (len=a->len; len > 0; len--)
+                       if (*aname++ != *bname++)
+                               return 1;
+       } else {
+               for (len=a->len; len > 0; len--)
+                       if (asfs_nls_upperchar(*aname++, nls_io) != asfs_nls_upperchar(*bname++, nls_io))
+                               return 1;
+       }
+
+       return 0;
+}
+
+struct dentry_operations asfs_dentry_operations = {
+       d_hash:         asfs_hash_dentry,
+       d_compare:      asfs_compare_dentry,
+};
+
+int asfs_namecmp(u8 *s, u8 *ct, int casesensitive, struct nls_table *t)
+{
+       if (casesensitive) {
+               while (*s == *ct && *ct != '\0' && *ct != '/') {
+                       s++;
+                       ct++;
+               }
+       } else {
+               while (asfs_nls_upperchar(*s, t) == asfs_nls_upperchar(*ct, t) && *ct != '\0'
+                      && *ct != '/') {
+                       s++;
+                       ct++;
+               }
+       }
+       return (*s == '\0' && (*ct == '\0' || *ct == '/')) ? 0 : *ct - *s;
+}
+
+u16 asfs_hash(u8 *name, int casesensitive)
+{
+       u16 hashval = 0;
+       while (name[hashval] != 0 && name[hashval] != '/')
+               hashval++;
+       if (casesensitive) {
+               u8 c = *name;
+               while (c != 0 && c != '/') {
+                       hashval = hashval * 13 + c;
+                       c = *++name;
+               }
+       } else {
+               u8 c = *name;
+               while (c != 0 && c != '/') {
+                       hashval = hashval * 13 + asfs_upperchar(c);
+                       c = *++name;
+               }
+       }
+       return hashval;
+}
+
+void asfs_translate(u8 *to, u8 *from, struct nls_table *nls_to, struct nls_table *nls_from, int limit)
+{
+       wchar_t uni;
+       int i, len;
+       int from_len, to_len = limit;
+
+       if (nls_to) {
+               from_len = strlen(from);
+               for (i=0; i < from_len && to_len > 1; ) {
+                       len = nls_from->char2uni(&from[i], from_len-i, &uni);
+                       if (len > 0) {
+                               i += len;
+                               len = nls_to->uni2char(uni, to, to_len);
+                               if (len > 0) {
+                                       to += len;
+                                       to_len -= len;
+                               }
+                       } else
+                               i++;
+                       if (len < 0) {
+                               *to++ = '?';
+                               to_len--;
+                       }
+               }
+               *to = '\0';
+       } else {
+               strncpy (to, from, limit);
+               to[limit-1] = '\0';
+       }
+}
diff -ruN linux-source-2.6.24.orig/fs/asfs/nodes.c linux-source-2.6.24/fs/asfs/nodes.c
--- linux-source-2.6.24.orig/fs/asfs/nodes.c    1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/nodes.c 2008-12-14 23:05:05.000000000 +0300
@@ -0,0 +1,455 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta7
+ *
+ * This file contains some parts of the original amiga version of 
+ * SmartFilesystem source code.
+ *
+ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx, 
+ * Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek
+ * 
+ * Adapted and modified by Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+
+/* Finds a specific node by number. */
+int asfs_getnode(struct super_block *sb, u32 nodeno, struct buffer_head **ret_bh, struct fsObjectNode **ret_node)
+{
+       struct buffer_head *bh;
+       struct fsNodeContainer *nodecont;
+       u32 nodeindex = ASFS_SB(sb)->objectnoderoot;
+
+       while ((bh = asfs_breadcheck(sb, nodeindex, ASFS_NODECONTAINER_ID))) {
+               nodecont = (struct fsNodeContainer *) bh->b_data;
+
+               if (be32_to_cpu(nodecont->nodes) == 1) {
+                       *ret_node = (struct fsObjectNode *) ((u8 *) nodecont->node + NODE_STRUCT_SIZE * (nodeno - be32_to_cpu(nodecont->nodenumber)));
+                       *ret_bh = bh;
+                       return 0;
+               } else {
+                       u16 containerentry = (nodeno - be32_to_cpu(nodecont->nodenumber)) / be32_to_cpu(nodecont->nodes);
+                       nodeindex = be32_to_cpu(nodecont->node[containerentry]) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY);
+               }
+               asfs_brelse(bh);
+       }
+       if (bh == NULL)
+               return -EIO;
+       return -ENOENT;
+}
+
+#ifdef CONFIG_ASFS_RW
+
+       /* Looks for the parent of the passed-in buffer_head (fsNodeContainer)
+          starting from the root.  It returns an error if any error occured.
+          If error is 0 and io_bh is NULL as well, then there was no parent (ie,
+          you asked parent of the root).  Otherwise io_bh should contain the
+          parent of the passed-in NodeContainer. */
+
+static int parentnodecontainer(struct super_block *sb, struct buffer_head **io_bh)
+{
+       u32 noderoot = ASFS_SB(sb)->objectnoderoot;
+       u32 childblock = be32_to_cpu(((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock);
+       u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) (*io_bh)->b_data)->nodenumber);
+       int errorcode = 0;
+
+       if (noderoot == childblock) {
+               *io_bh = NULL;
+               return 0;
+       }
+
+       while ((*io_bh = asfs_breadcheck(sb, noderoot, ASFS_NODECONTAINER_ID))) {
+               struct fsNodeContainer *nc = (void *) (*io_bh)->b_data;
+
+               if (be32_to_cpu(nc->nodes) == 1) {
+                       /* We've descended the tree to a leaf NodeContainer, something
+                          which should never happen if the passed-in io_bh had
+                          contained a valid fsNodeContainer. */
+                       printk("ASFS: Failed to locate the parent NodeContainer - node tree is corrupted!\n");
+                       *io_bh = NULL;
+                       return -EIO;
+               } else {
+                       u16 containerentry = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes);
+                       noderoot = be32_to_cpu(nc->node[containerentry]) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY);
+               }
+
+               if (noderoot == childblock)
+                       break;
+
+               asfs_brelse(*io_bh);
+       }
+
+       if (*io_bh == NULL)
+               return -EIO;
+
+       return errorcode;
+}
+
+
+static int isfull(struct super_block *sb, struct fsNodeContainer *nc)
+{
+       u32 *p = nc->node;
+       s16 n = NODECONT_BLOCK_COUNT;
+
+       while (--n >= 0) {
+               if (*p == 0 || (be32_to_cpu(*p) & 0x00000001) == 0) {
+                       break;
+               }
+               p++;
+       }
+
+       return n < 0;
+}
+
+static int markparentfull(struct super_block *sb, struct buffer_head *bh)
+{
+       u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) (bh->b_data))->nodenumber);
+       int errorcode;
+
+       if ((errorcode = parentnodecontainer(sb, &bh)) == 0 && bh != 0) {
+               struct fsNodeContainer *nc = (void *) bh->b_data;
+               u16 containerentry = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes);
+
+               nc->node[containerentry] = cpu_to_be32(be32_to_cpu(nc->node[containerentry]) | 0x00000001);
+
+               asfs_bstore(sb, bh);
+
+               if (isfull(sb, nc)) {   /* This container now is full as well!  Mark the next higher up container too then! */
+                       return markparentfull(sb, bh);
+               }
+               asfs_brelse(bh);
+       }
+
+       return errorcode;
+}
+
+static int addnewnodelevel(struct super_block *sb, u16 nodesize)
+{
+       struct buffer_head *bh;
+       u32 noderoot = ASFS_SB(sb)->objectnoderoot;
+       int errorcode;
+
+       /* Adds a new level to the Node tree. */
+
+       asfs_debug("addnewnodelevel: Entry\n");
+
+       if ((bh = asfs_breadcheck(sb, noderoot, ASFS_NODECONTAINER_ID))) {
+               struct buffer_head *newbh;
+               u32 newblock;
+
+               if ((errorcode = asfs_allocadminspace(sb, &newblock)) == 0 && (newbh = asfs_getzeroblk(sb, newblock))) {
+                       struct fsNodeContainer *nc = (void *) bh->b_data;
+                       struct fsNodeContainer *newnc = (void *) newbh->b_data;
+
+                       /* The newly allocated block will become a copy of the current root. */
+
+                       newnc->bheader.id = cpu_to_be32(ASFS_NODECONTAINER_ID);
+                       newnc->bheader.ownblock = cpu_to_be32(newblock);
+                       newnc->nodenumber = nc->nodenumber;
+                       newnc->nodes = nc->nodes;
+                       memcpy(newnc->node, nc->node, sb->s_blocksize - sizeof(struct fsNodeContainer));
+
+                       asfs_bstore(sb, newbh);
+                       asfs_brelse(newbh);
+
+                       /* The current root will now be transformed into a new root. */
+
+                       if (be32_to_cpu(nc->nodes) == 1)
+                               nc->nodes = cpu_to_be32((sb->s_blocksize - sizeof(struct fsNodeContainer)) / nodesize);
+                       else
+                               nc->nodes = cpu_to_be32(be32_to_cpu(nc->nodes) * NODECONT_BLOCK_COUNT);
+
+                       nc->node[0] = cpu_to_be32((newblock << (sb->s_blocksize_bits - ASFS_BLCKFACCURACY)) + 1);       /* Tree is full from that point! */
+                       memset(&nc->node[1], 0, sb->s_blocksize - sizeof(struct fsNodeContainer) - 4);
+
+                       asfs_bstore(sb, bh);
+               }
+               asfs_brelse(bh);
+       } else
+               errorcode = -EIO;
+
+       return errorcode;
+}
+
+static int createnodecontainer(struct super_block *sb, u32 nodenumber, u32 nodes, u32 * returned_block)
+{
+       struct buffer_head *bh;
+       int errorcode;
+       u32 newblock;
+
+       asfs_debug("createnodecontainer: nodenumber = %u, nodes = %u\n", nodenumber, nodes);
+
+       if ((errorcode = asfs_allocadminspace(sb, &newblock)) == 0 && (bh = asfs_getzeroblk(sb, newblock))) {
+               struct fsNodeContainer *nc = (void *) bh->b_data;
+
+               nc->bheader.id = cpu_to_be32(ASFS_NODECONTAINER_ID);
+               nc->bheader.ownblock = cpu_to_be32(newblock);
+
+               nc->nodenumber = cpu_to_be32(nodenumber);
+               nc->nodes = cpu_to_be32(nodes);
+
+               asfs_bstore(sb, bh);
+               asfs_brelse(bh);
+               *returned_block = newblock;
+       }
+
+       return errorcode;
+}
+
+       /* This function creates a new fsNode structure in a fsNodeContainer.  If needed
+          it will create a new fsNodeContainers and a new fsNodeIndexContainer. */
+
+int asfs_createnode(struct super_block *sb, struct buffer_head **returned_bh, struct fsNode **returned_node, u32 * returned_nodeno)
+{
+       u16 nodecount = (sb->s_blocksize - sizeof(struct fsNodeContainer)) / NODE_STRUCT_SIZE;
+       u32 noderoot = ASFS_SB(sb)->objectnoderoot;
+       u32 nodeindex = noderoot;
+       int errorcode = 0;
+
+       while ((*returned_bh = asfs_breadcheck(sb, nodeindex, ASFS_NODECONTAINER_ID))) {
+               struct fsNodeContainer *nc = (void *) (*returned_bh)->b_data;
+
+               if (be32_to_cpu(nc->nodes) == 1) {      /* Is it a leaf-container? */
+                       struct fsNode *n;
+                       s16 i = nodecount;
+
+                       n = (struct fsNode *) nc->node;
+
+                       while (i-- > 0) {
+                               if (n->data == 0)
+                                       break;
+
+                               n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE);
+                       }
+
+                       if (i >= 0) {
+                               /* Found an empty fsNode structure! */
+                               *returned_node = n;
+                               *returned_nodeno = be32_to_cpu(nc->nodenumber) + ((u8 *) n - (u8 *) nc->node) / NODE_STRUCT_SIZE;
+
+                               asfs_debug("createnode: Created Node %d\n", *returned_nodeno);
+
+                               /* Below we continue to look through the NodeContainer block.  We skip the entry
+                                  we found to be unused, and see if there are any more unused entries.  If we
+                                  do not find any more unused entries then this container is now full. */
+
+                               n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE);
+
+                               while (i-- > 0) {
+                                       if (n->data == 0)
+                                               break;
+
+                                       n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE);
+                               }
+
+                               if (i < 0) {
+                                       /* No more empty fsNode structures in this block.  Mark parent full. */
+                                       errorcode = markparentfull(sb, *returned_bh);
+                               }
+
+                               return errorcode;
+                       } else {
+                               /* What happened now is that we found a leaf-container which was
+                                  completely filled.  In practice this should only happen when there
+                                  is only a single NodeContainer (only this container), or when there
+                                  was an error in one of the full-bits in a higher level container. */
+
+                               if (noderoot != nodeindex) {
+                                       /*** Hmmm... it looks like there was a damaged full-bit or something.
+                                            In this case we'd probably better call markcontainerfull. */
+
+                                       printk("ASFS: Couldn't find empty Node in NodeContainer while NodeIndexContainer indicated there should be one!\n");
+
+                                       errorcode = -ENOSPC;
+                                       break;
+                               } else {
+                                       /* Container is completely filled. */
+
+                                       if ((errorcode = addnewnodelevel(sb, NODE_STRUCT_SIZE)) != 0)
+                                               return errorcode;
+
+                                       nodeindex = noderoot;
+                               }
+                       }
+               } else {        /* This isn't a leaf container */
+                       u32 *p = nc->node;
+                       s16 i = NODECONT_BLOCK_COUNT;
+
+                       /* We've read a normal container */
+
+                       while (i-- > 0) {
+                               if (*p != 0 && (be32_to_cpu(*p) & 0x00000001) == 0)
+                                       break;
+
+                               p++;
+                       }
+
+                       if (i >= 0) {
+                               /* Found a not completely filled Container */
+
+                               nodeindex = be32_to_cpu(*p) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY);
+                       } else {
+                               /* Everything in the NodeIndexContainer was completely filled.  There possibly
+                                  are some unused pointers in this block however.  */
+
+                               asfs_debug("createnode: NodeContainer at block has no empty Nodes.\n");
+
+                               p = nc->node;
+                               i = NODECONT_BLOCK_COUNT;
+
+                               while (i-- > 0) {
+                                       if (*p == 0)
+                                               break;
+
+                                       p++;
+                               }
+
+                               if (i >= 0) {
+                                       u32 newblock;
+                                       u32 nodes;
+
+                                       /* Found an unused Container pointer */
+
+                                       if (be32_to_cpu(nc->nodes) == (sb->s_blocksize - sizeof(struct fsNodeContainer)) / NODE_STRUCT_SIZE) {
+                                               nodes = 1;
+                                       } else {
+                                               nodes = be32_to_cpu(nc->nodes) / NODECONT_BLOCK_COUNT;
+                                       }
+
+                                       if ((errorcode = createnodecontainer(sb, be32_to_cpu(nc->nodenumber) + (p - nc->node) * be32_to_cpu(nc->nodes), nodes, &newblock)) != 0) {
+                                               break;
+                                       }
+
+                                       *p = cpu_to_be32(newblock << (sb->s_blocksize_bits - ASFS_BLCKFACCURACY));
+
+                                       asfs_bstore(sb, *returned_bh);
+                               } else {
+                                       /* Container is completely filled.  This must be the top-level NodeIndex container
+                                          as otherwise the full-bit would have been wrong! */
+
+                                       if ((errorcode = addnewnodelevel(sb, NODE_STRUCT_SIZE)) != 0)
+                                               break;
+
+                                       nodeindex = noderoot;
+                               }
+                       }
+               }
+               asfs_brelse(*returned_bh);
+       }
+
+       if (*returned_bh == NULL)
+               return -EIO;
+
+       return (errorcode);
+}
+
+static int markparentempty(struct super_block *sb, struct buffer_head *bh)
+{
+       u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) bh->b_data)->nodenumber);
+       int errorcode;
+
+       if ((errorcode = parentnodecontainer(sb, &bh)) == 0 && bh != 0) {
+               struct fsNodeContainer *nc = (void *) bh->b_data;
+               int wasfull;
+               u16 containerentry = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes);
+
+               wasfull = isfull(sb, nc);
+
+               nc->node[containerentry] = cpu_to_be32(be32_to_cpu(nc->node[containerentry]) & ~0x00000001);
+
+               asfs_bstore(sb, bh);
+
+               if (wasfull) {
+                       /* This container was completely full before!  Mark the next higher up container too then! */
+                       return markparentempty(sb, bh);
+               }
+               asfs_brelse(bh);
+       }
+
+       return errorcode;
+}
+
+static int freecontainer(struct super_block *sb, struct buffer_head *bh)
+{
+       u32 nodenumber = be32_to_cpu(((struct fsNodeContainer *) bh->b_data)->nodenumber);
+       int errorcode;
+
+       if ((errorcode = parentnodecontainer(sb, &bh)) == 0 && bh != NULL) {    /* This line also prevents the freeing of the noderoot. */
+               struct fsNodeContainer *nc = (void *) bh->b_data;
+               u16 containerindex = (nodenumber - be32_to_cpu(nc->nodenumber)) / be32_to_cpu(nc->nodes);
+
+               if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(nc->node[containerindex]) >> (sb->s_blocksize_bits - ASFS_BLCKFACCURACY))) == 0) {
+                       u32 *p = nc->node;
+                       s16 n = NODECONT_BLOCK_COUNT;
+
+                       nc->node[containerindex] = 0;
+                       asfs_bstore(sb, bh);
+
+                       while (n-- > 0)
+                               if (*p++ != 0)
+                                       break;
+
+                       if (n < 0) {    /* This container is now completely empty!  Free this NodeIndexContainer too then! */
+                               return freecontainer(sb, bh);
+                       }
+               }
+               asfs_brelse(bh);
+       }
+
+       return errorcode;
+}
+
+static int internaldeletenode(struct super_block *sb, struct buffer_head *bh, struct fsNode *n)
+{
+       struct fsNodeContainer *nc = (void *) bh->b_data;
+       u16 nodecount = (sb->s_blocksize - sizeof(struct fsNodeContainer)) / NODE_STRUCT_SIZE;
+       s16 i = nodecount;
+       s16 empty = 0;
+       int errorcode = 0;
+
+       n->data = 0;
+       n = (struct fsNode *) nc->node;
+
+       while (i-- > 0) {
+               if (n->data == 0)
+                       empty++;
+
+               n = (struct fsNode *) ((u8 *) n + NODE_STRUCT_SIZE);
+       }
+
+       asfs_bstore(sb, bh);
+
+       if (empty == 1)         /* NodeContainer was completely full before, so we need to mark it empty now. */
+               errorcode = markparentempty(sb, bh);
+       else if (empty == nodecount)    /* NodeContainer is now completely empty!  Free it! */
+               errorcode = freecontainer(sb, bh);
+
+       return (errorcode);
+}
+
+int asfs_deletenode(struct super_block *sb, u32 objectnode)
+{
+       struct buffer_head *bh;
+       struct fsObjectNode *on;
+       int errorcode;
+
+       asfs_debug("deletenode: Deleting Node %d\n", objectnode);
+
+       if ((errorcode = asfs_getnode(sb, objectnode, &bh, &on)) == 0)
+               errorcode = internaldeletenode(sb, bh, (struct fsNode *) on);
+
+       asfs_brelse(bh);
+       return (errorcode);
+}
+
+#endif


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 7/9] Amiga SmartFileSystem, revision 2
  2009-02-12 16:38         ` Phillip Lougher
                             ` (5 preceding siblings ...)
  2009-02-13  6:56           ` [PATCH 6/9] " Pavel Fedin
@ 2009-02-13  6:56           ` Pavel Fedin
  2009-02-13  6:57           ` [PATCH 8/9] " Pavel Fedin
  2009-02-13  6:57           ` [PATCH 9/9] " Pavel Fedin
  8 siblings, 0 replies; 15+ messages in thread
From: Pavel Fedin @ 2009-02-13  6:56 UTC (permalink / raw)
  To: Phillip Lougher; +Cc: linux-fsdevel

diff -ruN linux-source-2.6.24.orig/fs/asfs/objects.c linux-source-2.6.24/fs/asfs/objects.c
--- linux-source-2.6.24.orig/fs/asfs/objects.c  1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/objects.c       2008-12-14 23:05:05.000000000 +0300
@@ -0,0 +1,765 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta11
+ *
+ * This file contains some parts of the original amiga version of 
+ * SmartFilesystem source code.
+ *
+ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx, 
+ * Ralph Schmidt, Emmanuel Lesueur, David Gerber, and Marcin Kurek
+ * 
+ * Adapted and modified by Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+
+struct fsObject *asfs_nextobject(struct fsObject *obj)
+{
+       int i;
+       u8 *p = obj->name;
+
+       for (i = 2; i > 0; p++)
+               if (*p == '\0')
+                       i--;
+       if ((p - (u8 *) obj) & 0x01)
+               p++;
+
+       return ((struct fsObject *) p);
+}
+
+struct fsObject *asfs_find_obj_by_name(struct super_block *sb, struct fsObjectContainer *objcont, u8 * name)
+{
+       struct fsObject *obj;
+
+       obj = &(objcont->object[0]);
+       while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj - (char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
+               if (asfs_namecmp(obj->name, name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE, NULL) == 0) {
+                       asfs_debug("Object found! Node %u, Name %s, Type %x, inCont %u\n", be32_to_cpu(obj->objectnode), obj->name, obj->bits, be32_to_cpu(objcont->bheader.ownblock));
+                       return obj;
+               }
+               obj = asfs_nextobject(obj);
+       }
+       return NULL;
+}
+
+#ifdef CONFIG_ASFS_RW
+
+static struct fsObject *find_obj_by_node(struct super_block *sb, struct fsObjectContainer *objcont, u32 objnode)
+{
+       struct fsObject *obj;
+
+       obj = &(objcont->object[0]);
+       while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj - (char *) objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
+               if (be32_to_cpu(obj->objectnode) == objnode) {
+                       return obj;
+               }
+               obj = asfs_nextobject(obj);
+       }
+       return NULL;
+}
+
+int asfs_readobject(struct super_block *sb, u32 objectnode, struct buffer_head **bh, struct fsObject **returned_object)
+{
+       struct fsObjectNode *on;
+       int errorcode;
+       u32 contblock;
+
+       asfs_debug("Seaching object - node %d\n", objectnode);
+
+       if ((errorcode = asfs_getnode(sb, objectnode, bh, &on)) != 0)
+               return errorcode;
+       contblock = be32_to_cpu(on->node.data);
+       asfs_brelse(*bh);
+
+       if (contblock > 0 && (*bh = asfs_breadcheck(sb, contblock, ASFS_OBJECTCONTAINER_ID))) {
+               *returned_object = find_obj_by_node(sb, (void *) (*bh)->b_data, objectnode);
+               if (*returned_object == NULL) {
+                       brelse(*bh);
+                       *bh = NULL;
+                       return -ENOENT;
+               }
+               return 0;
+       } else
+               return -EIO;
+}
+
+static int removeobjectcontainer(struct super_block *sb, struct buffer_head *bh)
+{
+       struct fsObjectContainer *oc = (void *) bh->b_data;
+       int errorcode;
+       struct buffer_head *block;
+
+       asfs_debug("removeobjectcontainer: block %u\n", be32_to_cpu(oc->bheader.ownblock));
+
+       if (oc->next != 0 && oc->next != oc->bheader.ownblock) {
+               struct fsObjectContainer *next_oc;
+
+               if ((block = asfs_breadcheck(sb, be32_to_cpu(oc->next), ASFS_OBJECTCONTAINER_ID)) == NULL)
+                       return -EIO;
+
+               next_oc = (void *) block->b_data;
+               next_oc->previous = oc->previous;
+
+               asfs_bstore(sb, block);
+               asfs_brelse(block);
+       }
+
+       if (oc->previous != 0 && oc->previous != oc->bheader.ownblock) {
+               struct fsObjectContainer *previous_oc;
+
+               if ((block = asfs_breadcheck(sb, be32_to_cpu(oc->previous), ASFS_OBJECTCONTAINER_ID)) == NULL)
+                       return -EIO;
+
+               previous_oc = (void *) block->b_data;
+               previous_oc->next = oc->next;
+
+               asfs_bstore(sb, block);
+               asfs_brelse(block);
+       } else {
+               struct fsObject *parent_o;
+
+               if ((errorcode = asfs_readobject(sb, be32_to_cpu(oc->parent), &block, &parent_o)) != 0)
+                       return (errorcode);
+
+               parent_o->object.dir.firstdirblock = oc->next;
+
+               asfs_bstore(sb, block);
+               asfs_brelse(block);
+       }
+
+       if ((errorcode = asfs_freeadminspace(sb, be32_to_cpu(oc->bheader.ownblock))) != 0)
+               return (errorcode);
+
+       return (0);
+}
+
+static int setrecycledinfodiff(struct super_block *sb, s32 deletedfiles, s32 deletedblocks)
+{
+       struct buffer_head *bh;
+
+       if ((bh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
+               struct fsRootInfo *ri = (struct fsRootInfo *) ((u8 *) bh->b_data + sb->s_blocksize - sizeof(struct fsRootInfo));
+
+               ri->deletedfiles = cpu_to_be32(be32_to_cpu(ri->deletedfiles) + deletedfiles);
+               ri->deletedblocks = cpu_to_be32(be32_to_cpu(ri->deletedblocks) + deletedblocks);
+
+               asfs_bstore(sb, bh);
+               asfs_brelse(bh);
+       } else
+               return -EIO;
+       return 0;
+}
+
+       /* This function removes the fsObject structure passed in from the passed
+          buffer_head.  If the ObjectContainer becomes completely empty it will be 
+          delinked from the ObjectContainer chain and marked free for reuse.
+          This function doesn't delink the object from the hashchain! */
+
+static int simpleremoveobject(struct super_block *sb, struct buffer_head *bh, struct fsObject *o)
+{
+       struct fsObjectContainer *oc = (void *) bh->b_data;
+       int errorcode = 0;
+
+       asfs_debug("simpleremoveobject:\n");
+
+       if (be32_to_cpu(oc->parent) == ASFS_RECYCLEDNODE) {
+               /* This object is removed from the Recycled directory. */
+               if ((errorcode = setrecycledinfodiff(sb, -1, -((be32_to_cpu(o->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits))) != 0)
+                       return errorcode;
+       }
+
+       if ((asfs_nextobject(oc->object))->name[0] == '\0')
+               errorcode = removeobjectcontainer(sb, bh);
+       else {
+               struct fsObject *nexto;
+               int objlen;
+
+               nexto = asfs_nextobject(o);
+               objlen = (u8 *) nexto - (u8 *) o;
+
+               memmove(o, nexto, sb->s_blocksize - ((u8 *) nexto - (u8 *) oc));
+               memset((u8 *) oc + sb->s_blocksize - objlen, 0, objlen);
+
+               asfs_bstore(sb, bh);
+       }
+       return errorcode;
+}
+
+/* This function delinks the passed in ObjectNode from its hash-chain.  Handy when deleting
+   the object, or when renaming/moving it. */
+
+static int dehashobjectquick(struct super_block *sb, u32 objectnode, u8 *name, u32 parentobjectnode)
+{
+       struct fsObject *o;
+       int errorcode = 0;
+       struct buffer_head *block;
+
+       asfs_debug("dehashobject: Delinking object %d (=ObjectNode) from hashchain. Parentnode = %d\n", objectnode, parentobjectnode);
+
+       if ((errorcode = asfs_readobject(sb, parentobjectnode, &block, &o)) == 0 && o->object.dir.hashtable != 0) {
+               u32 hashtable = be32_to_cpu(o->object.dir.hashtable);
+               asfs_brelse(block);
+
+               if ((block = asfs_breadcheck(sb, hashtable, ASFS_HASHTABLE_ID))) {
+                       struct buffer_head *node_bh;
+                       struct fsObjectNode *onptr, on;
+                       struct fsHashTable *ht = (void *) block->b_data;
+                       u32 nexthash;
+
+                       if ((errorcode = asfs_getnode(sb, objectnode, &node_bh, &onptr)) == 0) {
+                               u16 hashchain;
+
+                               asfs_debug("dehashobject: Read HashTable block of parent object of object to be delinked\n");
+
+                               hashchain = HASHCHAIN(asfs_hash(name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE));
+                               nexthash = be32_to_cpu(ht->hashentry[hashchain]);
+
+                               if (nexthash == objectnode) {
+                                       /* The hashtable directly points to the fsObject to be delinked.  We simply
+                                          modify the Hashtable to point to the new nexthash entry. */
+
+                                       asfs_debug("dehashobject: The hashtable points directly to the to be delinked object\n");
+
+                                       ht->hashentry[hashchain] = onptr->next;
+                                       asfs_bstore(sb, block);
+                               } else {
+                                       struct fsObjectNode *onsearch = 0;
+
+                                       on = *onptr;
+
+                                       asfs_debug("dehashobject: Walking through hashchain\n");
+
+                                       while (nexthash != 0 && nexthash != objectnode) {
+                                               asfs_brelse(node_bh);
+                                               if ((errorcode = asfs_getnode(sb, nexthash, &node_bh, &onsearch)) != 0)
+                                                       break;
+                                               nexthash = be32_to_cpu(onsearch->next);
+                                       }
+
+                                       if (errorcode == 0) {
+                                               if (nexthash != 0) {
+                                                       /* Previous fsObjectNode found in hash chain.  Modify the fsObjectNode to 'skip' the
+                                                          ObjectNode which is being delinked from the hash chain. */
+
+                                                       onsearch->next = on.next;
+                                                       asfs_bstore(sb, node_bh);
+                                               } else {
+                                                       printk("ASFS: Hashchain of object %d is corrupt or incorrectly linked.", objectnode);
+
+                                                       /*** This is strange.  We have been looking for the fsObjectNode which is located before the
+                                                            passed in fsObjectNode in the hash-chain.  However, we never found the
+                                                            fsObjectNode reffered to in the hash-chain!  Has to be somekind
+                                                            of internal error... */
+
+                                                       errorcode = -ENOENT;
+                                               }
+                                       }
+                               }
+                               asfs_brelse(node_bh);
+                       }
+                       asfs_brelse(block);
+               }
+       }
+       return errorcode;
+}
+
+
+       /* This function removes an object from any directory.  It takes care
+          of delinking the object from the hashchain and also frees the
+          objectnode number. */
+
+static int removeobject(struct super_block *sb, struct buffer_head *bh, struct fsObject *o)
+{
+       struct fsObjectContainer *oc = (void *) bh->b_data;
+       int errorcode;
+
+       asfs_debug("removeobject\n");
+
+       if ((errorcode = dehashobjectquick(sb, be32_to_cpu(o->objectnode), o->name, be32_to_cpu(oc->parent))) == 0) {
+               u32 objectnode = be32_to_cpu(o->objectnode);
+
+               if ((errorcode = simpleremoveobject(sb, bh, o)) == 0)
+                       errorcode = asfs_deletenode(sb, objectnode);
+       }
+
+       return (errorcode);
+}
+
+       /* This function deletes the specified object. */
+int asfs_deleteobject(struct super_block *sb, struct buffer_head *bh, struct fsObject *o)
+{
+       int errorcode = 0;
+
+       asfs_debug("deleteobject: Entry -- deleting object %d (%s)\n", be32_to_cpu(o->objectnode), o->name);
+
+       if ((o->bits & OTYPE_DIR) == 0 || o->object.dir.firstdirblock == 0) {
+               u8 bits = o->bits;
+               u32 hashblckno = be32_to_cpu(o->object.dir.hashtable);
+               u32 extentbnode = be32_to_cpu(o->object.file.data);
+
+               if ((errorcode = removeobject(sb, bh, o)) == 0) {
+                       if ((bits & OTYPE_LINK) != 0) {
+                               asfs_debug("deleteobject: Object is soft link!\n");
+                               errorcode = asfs_freeadminspace(sb, extentbnode);
+                       } else if ((bits & OTYPE_DIR) != 0) {
+                               asfs_debug("deleteobject: Object is a directory!\n");
+                               errorcode = asfs_freeadminspace(sb, hashblckno);
+                       } else {
+                               asfs_debug("deleteobject: Object is a file\n");
+                               if (extentbnode != 0)
+                                       errorcode = asfs_deleteextents(sb, extentbnode);
+                       }
+               }
+       }
+
+       return (errorcode);
+}
+
+       /* This function takes a HashBlock pointer, an ObjectNode and an ObjectName.
+          If there is a hashblock, then this function will correctly link the object
+          into the hashchain.  If there isn't a hashblock (=0) then this function
+          does nothing.  */
+
+static int hashobject(struct super_block *sb, u32 hashblock, struct fsObjectNode *on, u32 nodeno, u8 *objectname)
+{
+       struct buffer_head *hash_bh;
+
+       asfs_debug("hashobject, using hashblock %d\n", hashblock);
+       if (hashblock == 0)
+               return 0;
+
+       if ((hash_bh = asfs_breadcheck(sb, hashblock, ASFS_HASHTABLE_ID))) {
+               struct fsHashTable *ht = (void *) hash_bh->b_data;
+               u32 nexthash;
+               u16 hashvalue, hashchain;
+
+               hashvalue = asfs_hash(objectname, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE);
+               hashchain = HASHCHAIN(hashvalue);
+               nexthash = be32_to_cpu(ht->hashentry[hashchain]);
+
+               ht->hashentry[hashchain] = cpu_to_be32(nodeno);
+
+               asfs_bstore(sb, hash_bh);
+               asfs_brelse(hash_bh);
+
+               on->next = cpu_to_be32(nexthash);
+               on->hash16 = cpu_to_be16(hashvalue);
+       } else
+               return -EIO;
+
+       return 0;
+}
+
+       /* This function returns a pointer to the first unused byte in
+          an ObjectContainer. */
+
+static u8 *emptyspaceinobjectcontainer(struct super_block *sb, struct fsObjectContainer *oc)
+{
+       struct fsObject *o = oc->object;
+       u8 *endadr;
+
+       endadr = (u8 *) oc + sb->s_blocksize - sizeof(struct fsObject) - 2;
+
+       while ((u8 *) o < endadr && o->name[0] != 0)
+               o = asfs_nextobject(o);
+
+       return (u8 *) o;
+}
+
+       /* This function will look in the directory indicated by io_o
+          for an ObjectContainer block which contains bytesneeded free
+          bytes.  If none is found then this function simply creates a
+          new ObjectContainer and adds that to the indicated directory. */
+
+static int findobjectspace(struct super_block *sb, struct buffer_head **io_bh, struct fsObject **io_o, u32 bytesneeded)
+{
+       struct buffer_head *bhparent = *io_bh;
+       struct fsObject *oparent = *io_o;
+       struct buffer_head *bh;
+       u32 nextblock = be32_to_cpu(oparent->object.dir.firstdirblock);
+       int errorcode = 0;
+
+       asfs_debug("findobjectspace: Looking for %u bytes in directory with ObjectNode number %d (in block %d)\n", bytesneeded, be32_to_cpu((*io_o)->objectnode),
+                  be32_to_cpu(((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock));
+
+       while (nextblock != 0 && (bh = asfs_breadcheck(sb, nextblock, ASFS_OBJECTCONTAINER_ID))) {
+               struct fsObjectContainer *oc = (void *) bh->b_data;
+               u8 *emptyspace;
+
+               /* We need to find out how much free space this ObjectContainer has */
+
+               emptyspace = emptyspaceinobjectcontainer(sb, oc);
+
+               if ((u8 *) oc + sb->s_blocksize - emptyspace >= bytesneeded) {
+                       /* We found enough space in one of the ObjectContainer blocks!!
+                          We return a struct fsObject *. */
+                       *io_bh = bh;
+                       *io_o = (struct fsObject *) emptyspace;
+                       break;
+               }
+               nextblock = be32_to_cpu(oc->next);
+               asfs_brelse(bh);
+       }
+
+       if (nextblock == 0) {
+               u32 newcontblock;
+               /* If we get here, we traversed the *entire* directory (ough!) and found no empty
+                  space large enough for our entry.  We allocate new space and add it to this
+                  directory. */
+
+               if ((errorcode = asfs_allocadminspace(sb, &newcontblock)) == 0 && (bh = asfs_getzeroblk(sb, newcontblock))) {
+                       struct fsObjectContainer *oc = (void *) bh->b_data;
+                       struct buffer_head *bhnext;
+
+                       asfs_debug("findobjectspace: No room was found, allocated new block at %u\n", newcontblock);
+
+                       /* Allocated new block.  We will now link it to the START of the directory chain
+                          so the new free space can be found quickly when more entries need to be added. */
+
+                       oc->bheader.id = cpu_to_be32(ASFS_OBJECTCONTAINER_ID);
+                       oc->bheader.ownblock = cpu_to_be32(newcontblock);
+                       oc->parent = oparent->objectnode;
+                       oc->next = oparent->object.dir.firstdirblock;
+                       oc->previous = 0;
+
+                       oparent->object.dir.firstdirblock = cpu_to_be32(newcontblock);
+
+                       asfs_bstore(sb, bhparent);
+
+                       if (oc->next != 0 && (bhnext = asfs_breadcheck(sb, be32_to_cpu(oc->next), ASFS_OBJECTCONTAINER_ID))) {
+                               struct fsObjectContainer *ocnext = (void *) bhnext->b_data;
+                               ocnext->previous = cpu_to_be32(newcontblock);
+                               asfs_bstore(sb, bhnext);
+                               asfs_brelse(bhnext);
+                       }
+
+                       *io_bh = bh;
+                       *io_o = oc->object;
+               }
+       }
+
+       asfs_debug("findobjectspace: new object will be in container block %u\n", be32_to_cpu(((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock));
+
+       return (errorcode);
+}
+
+/* io_bh & io_o refer to the direct parent of the new object.  Objectname is the
+       name of the new object (name only). Does not realese io_bh !!! */
+
+int asfs_createobject(struct super_block *sb, struct buffer_head **io_bh, struct fsObject **io_o, struct fsObject *src_o, u8 *objectname, int force)
+{
+       int errorcode;
+       u32 object_size;
+       u32 hashblock = be32_to_cpu((*io_o)->object.dir.hashtable);
+
+       asfs_debug("createobject: Creating object '%s' in dir '%s'.\n", objectname, (*io_o)->name);
+
+       if (!force && ASFS_SB(sb)->freeblocks < ASFS_ALWAYSFREE)
+               return -ENOSPC;
+
+       if (!force && be32_to_cpu((*io_o)->objectnode) == ASFS_RECYCLEDNODE)
+               return -EINVAL;
+
+       object_size = sizeof(struct fsObject) + strlen(objectname) + 2;
+
+       if ((errorcode = findobjectspace(sb, io_bh, io_o, object_size)) == 0) {
+               struct fsObject *o2 = *io_o;
+               u8 *name = o2->name;
+               u8 *objname = objectname;
+               struct buffer_head *node_bh;
+               struct fsObjectNode *on;
+               u32 nodeno;
+
+               **io_o = *src_o;        /* Copying whole object data... */
+
+               while (*objname != 0)   /* Copying name */
+                       *name++ = *objname++;
+
+               *name++ = 0;
+               *name = 0;      /* zero byte for comment */
+
+               if (o2->objectnode != 0)        /* ObjectNode reuse or creation */
+                       errorcode = asfs_getnode(sb, o2->objectnode, &node_bh, &on);
+               else {
+                       if ((errorcode = asfs_createnode(sb, &node_bh, (struct fsNode **) &on, &nodeno)) == 0) {
+                               on->hash16 = cpu_to_be16(asfs_hash(o2->name, ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE));
+                               o2->objectnode = cpu_to_be32(nodeno);
+                       }
+                       asfs_debug("createnode returned with errorcode: %d\n", errorcode);
+               }
+
+               if (errorcode == 0) {   /* in io_bh there is a container with created object */
+                       on->node.data = ((struct fsBlockHeader *) (*io_bh)->b_data)->ownblock;
+                       if ((errorcode = hashobject(sb, hashblock, on, be32_to_cpu(o2->objectnode), objectname)) == 0) {
+                               asfs_bstore(sb, node_bh);
+                               asfs_brelse(node_bh);
+                       } else
+                               errorcode = -EIO;
+               }
+
+               if (errorcode == 0) {   /* HashBlock reuse or creation:*/
+
+                       if ((o2->bits & OTYPE_DIR) != 0 && o2->object.dir.hashtable == 0) {
+                               struct buffer_head *hashbh;
+                               u32 hashblock;
+
+                               asfs_debug("creating Hashblock\n");
+
+                               if ((errorcode = asfs_allocadminspace(sb, &hashblock)) == 0 && (hashbh = asfs_getzeroblk(sb, hashblock))) {         
+                                       struct fsHashTable *ht = (void *) hashbh->b_data;
+
+                                       o2->object.dir.hashtable = cpu_to_be32(hashblock);
+
+                                       ht->bheader.id = cpu_to_be32(ASFS_HASHTABLE_ID);
+                                       ht->bheader.ownblock = cpu_to_be32(hashblock);
+                                       ht->parent = o2->objectnode;
+
+                                       asfs_bstore(sb, hashbh);
+                                       asfs_brelse(hashbh);
+                               }
+                       }
+               }
+
+               if (errorcode == 0) {   /* SoftLink creation: */
+                       if ((o2->bits & (OTYPE_LINK | OTYPE_HARDLINK)) == OTYPE_LINK && o2->object.file.data == 0) {
+                               struct buffer_head *bh2;
+                               u32 slinkblock;
+
+                               if ((errorcode = asfs_allocadminspace(sb, &slinkblock)) == 0 && (bh2 = asfs_getzeroblk(sb, slinkblock))) {
+                                       struct fsSoftLink *sl = (void *) bh2->b_data;
+                                       o2->object.file.data = cpu_to_be32(slinkblock);
+                                       sl->bheader.id = cpu_to_be32(ASFS_SOFTLINK_ID);
+                                       sl->bheader.ownblock = cpu_to_be32(slinkblock);
+                                       sl->parent = o2->objectnode;
+                                       sl->next = 0;
+                                       sl->previous = 0;
+                                       asfs_bstore(sb, bh2);
+                                       asfs_brelse(bh2);
+                               }
+                       }
+               }
+       }
+       asfs_debug("createobject: done.\n");
+
+       return (errorcode);
+}
+
+       /* This function extends the file object 'o' with a number  of blocks 
+               (hopefully, if any blocks has been found!). Only new Extents will 
+      be created -- the size of the file will not be altered, and changing 
+               it is left up to the caller.  If the file did not have any blocks 
+               yet, then the o->object.file.data will be set to the first (new) 
+               ExtentBNode. It returns the number of added blocks through 
+               addedblocks pointer */
+
+int asfs_addblockstofile(struct super_block *sb, struct buffer_head *objbh, struct fsObject *o, u32 blocks, u32 * newspace, u32 * addedblocks)
+{
+       u32 lastextentbnode;
+       int errorcode = 0;
+       struct fsExtentBNode *ebnp;
+       struct buffer_head *block = NULL;
+
+
+       asfs_debug("extendblocksinfile: Trying to increasing number of blocks by %d.\n", blocks);
+
+       lastextentbnode = be32_to_cpu(o->object.file.data);
+
+       if (lastextentbnode != 0) {
+               while (lastextentbnode != 0 && errorcode == 0) {
+                       if (block != NULL)
+                               asfs_brelse(block);
+                       errorcode = asfs_getextent(sb, lastextentbnode, &block, &ebnp);
+                       lastextentbnode = be32_to_cpu(ebnp->next);
+               }
+               lastextentbnode = be32_to_cpu(ebnp->key);
+       }
+
+       if (errorcode == 0) {
+               u32 searchstart;
+
+               u32 found_block;
+               u32 found_blocks;
+
+               *addedblocks = 0;
+               *newspace = 0;
+
+               if (lastextentbnode != 0)
+                       searchstart = be32_to_cpu(ebnp->key) + be16_to_cpu(ebnp->blocks);
+               else
+                       searchstart = 0; //ASFS_SB(sb)->block_rovingblockptr;
+
+               if ((errorcode = asfs_findspace(sb, blocks, searchstart, searchstart, &found_block, &found_blocks)) != 0) {
+                       asfs_brelse(block);
+                       asfs_debug("extendblocksinfile: findspace returned %s\n", errorcode == -ENOSPC ? "ENOSPC" : "error");
+                       return errorcode;
+               }
+
+               blocks = found_blocks;
+               errorcode = asfs_markspace(sb, found_block, found_blocks);
+               *addedblocks = found_blocks;
+               *newspace = found_block;
+
+               asfs_debug("extendblocksinfile: block = %u, lastextentbnode = %u, extentblocks = %d\n", found_block, lastextentbnode, blocks);
+
+               if ((errorcode = asfs_addblocks(sb, blocks, found_block, be32_to_cpu(o->objectnode), &lastextentbnode)) != 0) {
+                       asfs_debug("extendblocksinfile: addblocks returned errorcode %d\n", errorcode);
+                       return errorcode;
+               }
+
+               if (o->object.file.data == 0)
+                       o->object.file.data = cpu_to_be32(lastextentbnode);
+       }
+
+       if (block)
+               asfs_brelse(block);
+       asfs_bstore(sb, objbh);
+
+       asfs_debug("addblockstofile: done. added %d blocks\n", *addedblocks);
+
+       return errorcode;
+}
+
+       /* The Object indicated by bh1 & o1, gets renamed to newname and placed
+          in the directory indicated by bhparent & oparent. */
+
+int asfs_renameobject(struct super_block *sb, struct buffer_head *bh1, struct fsObject *o1, struct buffer_head *bhparent, struct fsObject *oparent, u8 * newname)
+{
+       struct fsObject object;
+       u32 oldparentnode = be32_to_cpu(((struct fsObjectContainer *) bh1->b_data)->parent);
+       u8 oldname[107];
+       int errorcode;
+
+       asfs_debug("renameobject: Renaming '%s' to '%s' in dir '%s'\n", o1->name, newname, oparent->name);
+
+       object = *o1;
+       strcpy(oldname, o1->name);
+
+       if ((errorcode = dehashobjectquick(sb, be32_to_cpu(o1->objectnode), o1->name, oldparentnode)) == 0) {
+               u32 parentobjectnode = be32_to_cpu(oparent->objectnode);
+
+               if ((errorcode = simpleremoveobject(sb, bh1, o1)) == 0) {
+                       struct buffer_head *bh2 = bhparent;
+                       struct fsObject *o2;
+
+                       /* oparent might changed after simpleremoveobject */
+                       oparent = o2 = find_obj_by_node(sb, (struct fsObjectContainer *) bhparent->b_data, parentobjectnode);
+
+                       /* In goes the Parent bh & o, out comes the New object's bh & o :-) */
+                       if ((errorcode = asfs_createobject(sb, &bh2, &o2, &object, newname, TRUE)) == 0) {
+                               asfs_bstore(sb, bh2);
+                               if (be32_to_cpu(oparent->objectnode) == ASFS_RECYCLEDNODE) {
+                                       asfs_debug("renameobject: Updating recycled dir info\n");
+                                       if ((errorcode = setrecycledinfodiff(sb, 1, (be32_to_cpu(o2->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits)) != 0) {
+                                               brelse(bh2);
+                                               return errorcode;
+                                       }
+                               }
+                               brelse(bh2);
+                               asfs_debug("renameobject: Succesfully created & stored new object.\n");
+                       } else { /* recreate object in old place, maybe this will not fail, but who knows... */
+                               asfs_debug("renameobject: Creating new object failed. Trying to recreate it in source directory.\n");
+                               if (asfs_readobject(sb, oldparentnode, &bh1, &o1) == 0) {
+                                       struct buffer_head *bh2 = bh1;
+                                       if (asfs_createobject(sb, &bh2, &o1, &object, oldname, TRUE) == 0) {
+                                               asfs_bstore(sb, bh2);
+                                               if (oldparentnode == ASFS_RECYCLEDNODE) {
+                                                       asfs_debug("renameobject: Updating recycled dir info\n");
+                                                       setrecycledinfodiff(sb, 1, (be32_to_cpu(o1->object.file.size) + sb->s_blocksize - 1) >> sb->s_blocksize_bits);
+                                               }
+                                               brelse(bh2);
+                                       }
+                                       brelse(bh1);
+                               }
+                       }
+               }
+       }
+       return errorcode;
+}
+
+               /* Truncates the specified file to /newsize/ bytes */
+
+int asfs_truncateblocksinfile(struct super_block *sb, struct buffer_head *bh, struct fsObject *o, u32 newsize)
+{
+       struct buffer_head *ebh;
+       struct fsExtentBNode *ebn;
+       int errorcode;
+       u32 pos = 0;
+       u32 newblocks = (newsize + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+       u32 filedata = be32_to_cpu(o->object.file.data);
+       u32 eprev, ekey;
+       u16 eblocks;
+
+       asfs_debug("trucateblocksinfile: newsize %u\n", newsize);
+
+       if (filedata == 0)
+               return 0;
+
+       for (;;) {
+               if ((errorcode = asfs_getextent(sb, filedata, &ebh, &ebn)) != 0)
+                       return errorcode;
+               if (pos + be16_to_cpu(ebn->blocks) >= newblocks)
+                       break;
+               pos += be16_to_cpu(ebn->blocks);
+               if ((filedata = be32_to_cpu(ebn->next)) == 0)
+                       break;
+               asfs_brelse(ebh);
+       };
+
+       eblocks = newblocks - pos;
+       ekey = be32_to_cpu(ebn->key);
+       eprev = be32_to_cpu(ebn->prev);
+
+       if (be16_to_cpu(ebn->blocks) < eblocks) {
+               printk("ASFS: Extent chain is too short or damaged!\n");
+               asfs_brelse(ebh);
+               return -ENOENT;
+       }
+       if (be16_to_cpu(ebn->blocks) - eblocks > 0 && (errorcode = asfs_freespace(sb, be32_to_cpu(ebn->key) + eblocks, be16_to_cpu(ebn->blocks) - eblocks)) != 0) {
+               asfs_brelse(ebh);
+               return errorcode;
+       }
+       if (be32_to_cpu(ebn->next) > 0 && (errorcode = asfs_deleteextents(sb, be32_to_cpu(ebn->next))) != 0) {
+               asfs_brelse(ebh);
+               return errorcode;
+       }
+       ebn->blocks = cpu_to_be16(eblocks);
+       ebn->next = 0;
+       asfs_bstore(sb, ebh);
+
+       if (eblocks == 0) {
+               if (eprev & MSB_MASK) {
+                       o->object.file.data = 0;
+                       asfs_bstore(sb, bh);
+               } else {
+                       struct buffer_head *ebhp;
+                       struct fsExtentBNode *ebnp;
+
+                       if ((errorcode = asfs_getextent(sb, eprev & !MSB_MASK, &ebhp, &ebnp)) != 0) {
+                               asfs_brelse(ebh);
+                               return errorcode;
+                       }
+
+                       ebnp->next = 0;
+                       asfs_bstore(sb, ebhp);
+                       asfs_brelse(ebhp);
+               }
+               if ((errorcode = asfs_deletebnode(sb, ebh, ekey)) != 0) {
+                       asfs_brelse(ebh);
+                       return errorcode;
+               }
+       }
+       asfs_brelse(ebh);
+
+       return 0;
+}
+#endif


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 8/9] Amiga SmartFileSystem, revision 2
  2009-02-12 16:38         ` Phillip Lougher
                             ` (6 preceding siblings ...)
  2009-02-13  6:56           ` [PATCH 7/9] " Pavel Fedin
@ 2009-02-13  6:57           ` Pavel Fedin
  2009-02-13  6:57           ` [PATCH 9/9] " Pavel Fedin
  8 siblings, 0 replies; 15+ messages in thread
From: Pavel Fedin @ 2009-02-13  6:57 UTC (permalink / raw)
  To: Phillip Lougher; +Cc: linux-fsdevel

diff -ruN linux-source-2.6.24.orig/fs/asfs/super.c linux-source-2.6.24/fs/asfs/super.c
--- linux-source-2.6.24.orig/fs/asfs/super.c    1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/super.c 2008-12-14 23:41:40.000000000 +0300
@@ -0,0 +1,493 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ *
+ * version: 1.0beta12 for 2.6.19 kernel
+ *  
+ * Copyright (C) 2003,2004,2005,2006  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ * NLS support by Pavel Fedin (C) 2005
+ *
+ *
+ * Thanks to Marcin Kurek (Morgoth/Dreamolers-CAPS) for help and parts 
+ * of original amiga version of SmartFilesystem source code. 
+ *
+ * SmartFilesystem is copyrighted (C) 2003 by: John Hendrikx, 
+ * Ralph Schmidt, Emmanuel Lesueur, David Gerber and Marcin Kurek
+ * 
+ *
+ * ASFS is based on the Amiga FFS filesystem for Linux
+ * Copyright (C) 1993  Ray Burr
+ * Copyright (C) 1996  Hans-Joachim Widmaier
+ *
+ * Earlier versions were based on the Linux implementation of 
+ * the ROMFS file system
+ * Copyright (C) 1997-1999  Janos Farkas <chexum@shadow.banki.hu>
+ *
+ * ASFS used some parts of the smbfs filesystem:
+ * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ * Copyright (C) 1997 by Volker Lendecke
+ *
+ * and parts of the Minix filesystem additionally
+ * Copyright (C) 1991, 1992  Linus Torvalds
+ * Copyright (C) 1996  Gertjan van Wingerde 
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+/* todo:
+ * - remove bugs
+ * - add missing features (maybe safe-delete, other...)
+ * - create other fs tools like mkfs.asfs and fsck.asfs, some data-recovery tools
+ */
+
+#define ASFS_VERSION "1.0beta12 (03.12.2006)"
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include <linux/parser.h>
+#include <linux/nls.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+static void asfs_put_super(struct super_block *sb);
+static int asfs_statfs(struct dentry *dentry, struct kstatfs *buf);
+#ifdef CONFIG_ASFS_RW
+static int asfs_remount(struct super_block *sb, int *flags, char *data);
+#endif
+static struct inode *asfs_alloc_inode(struct super_block *sb);
+static void asfs_destroy_inode(struct inode *inode);
+
+static char asfs_default_codepage[] = CONFIG_ASFS_DEFAULT_CODEPAGE;
+static char asfs_default_iocharset[] = CONFIG_NLS_DEFAULT;
+
+u32 asfs_calcchecksum(void *block, u32 blocksize)
+{
+       u32 *data = block, checksum = 1;
+       while (blocksize > 0) {
+               checksum += be32_to_cpu(*data++);
+               blocksize -= 4;
+       }
+       checksum -= be32_to_cpu(((struct fsBlockHeader *)block)->checksum);
+       return -checksum;
+}
+
+static struct super_operations asfs_ops = {
+       .alloc_inode    = asfs_alloc_inode,
+       .destroy_inode  = asfs_destroy_inode,
+       .put_super              = asfs_put_super,
+       .statfs                 = asfs_statfs,
+#ifdef CONFIG_ASFS_RW
+       .remount_fs             = asfs_remount,
+#endif
+};
+
+extern struct dentry_operations asfs_dentry_operations;
+
+enum {
+       Opt_mode, Opt_setgid, Opt_setuid, Opt_prefix, Opt_volume, 
+       Opt_lcvol, Opt_iocharset, Opt_codepage, Opt_ignore, Opt_err
+};
+
+static match_table_t tokens = {
+       {Opt_mode, "mode=%o"},
+       {Opt_setgid, "setgid=%u"},
+       {Opt_setuid, "setuid=%u"},
+       {Opt_prefix, "prefix=%s"},
+       {Opt_volume, "volume=%s"},
+       {Opt_lcvol, "lowercasevol"},
+       {Opt_iocharset, "iocharset=%s"},
+       {Opt_codepage, "codepage=%s"},
+       {Opt_ignore, "grpquota"},
+       {Opt_ignore, "noquota"},
+       {Opt_ignore, "quota"},
+       {Opt_ignore, "usrquota"},
+       {Opt_err, NULL},
+};
+
+static int asfs_parse_options(char *options, struct super_block *sb)
+{
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+
+       if (!options)
+               return 1;
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token, option;
+               if (!*p)
+                       continue;
+               token = match_token(p, tokens, args);
+
+               switch (token) {
+               case Opt_mode:
+                       if (match_octal(&args[0], &option))
+                               goto no_arg;
+                       ASFS_SB(sb)->mode = option & 0777;
+                       break;
+               case Opt_setgid:
+                       if (match_int(&args[0], &option))
+                               goto no_arg;
+                       ASFS_SB(sb)->gid = option;
+                       break;
+               case Opt_setuid:
+                       if (match_int(&args[0], &option))
+                               goto no_arg;
+                       ASFS_SB(sb)->uid = option;
+                       break;
+               case Opt_prefix:
+                       if (ASFS_SB(sb)->prefix) {
+                               kfree(ASFS_SB(sb)->prefix);
+                               ASFS_SB(sb)->prefix = NULL;
+                       }
+                       ASFS_SB(sb)->prefix = match_strdup(&args[0]);
+                       if (! ASFS_SB(sb)->prefix)
+                               return 0;
+                       break;
+               case Opt_volume:
+                       if (ASFS_SB(sb)->root_volume) {
+                               kfree(ASFS_SB(sb)->root_volume);
+                               ASFS_SB(sb)->root_volume = NULL;
+                       }
+                       ASFS_SB(sb)->root_volume = match_strdup(&args[0]);
+                       if (! ASFS_SB(sb)->root_volume)
+                               return 0;
+                       break;
+               case Opt_lcvol:
+                       ASFS_SB(sb)->flags |= ASFS_VOL_LOWERCASE;
+                       break;
+               case Opt_iocharset:
+                       if (ASFS_SB(sb)->iocharset != asfs_default_iocharset)
+                               kfree(ASFS_SB(sb)->iocharset);
+                       ASFS_SB(sb)->iocharset = match_strdup(&args[0]);
+                       if (!ASFS_SB(sb)->iocharset)
+                               return 0;
+                       break;
+               case Opt_codepage:
+                       if (ASFS_SB(sb)->codepage != asfs_default_codepage)
+                               kfree(ASFS_SB(sb)->codepage);
+                       ASFS_SB(sb)->codepage = match_strdup(&args[0]);
+                       if (!ASFS_SB(sb)->codepage)
+                               return 0;
+               case Opt_ignore:
+                       /* Silently ignore the quota options */
+                       break;
+               default:
+no_arg:
+                       printk("ASFS: Unrecognized mount option \"%s\" "
+                                       "or missing value\n", p);
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+static int asfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+       struct asfs_sb_info *sbi;
+       struct buffer_head *bh;
+       struct fsRootBlock *rootblock;
+       struct inode *rootinode;
+
+       sbi = kzalloc(sizeof(struct asfs_sb_info), GFP_KERNEL);
+       if (!sbi)
+               return -ENOMEM;
+       sb->s_fs_info = sbi;
+
+       /* Fill in defaults */
+       ASFS_SB(sb)->uid = ASFS_DEFAULT_UID;
+       ASFS_SB(sb)->gid = ASFS_DEFAULT_GID;
+       ASFS_SB(sb)->mode = ASFS_DEFAULT_MODE;
+       ASFS_SB(sb)->prefix = NULL;
+       ASFS_SB(sb)->root_volume = NULL;
+       ASFS_SB(sb)->flags = 0;
+       ASFS_SB(sb)->iocharset = asfs_default_iocharset;
+       ASFS_SB(sb)->codepage = asfs_default_codepage;
+
+       if (!asfs_parse_options(data, sb)) {
+               printk(KERN_ERR "ASFS: Error parsing options\n");
+               return -EINVAL;
+       }
+
+       if (!sb_set_blocksize(sb, 512))
+               return -EINVAL;
+       sb->s_maxbytes = ASFS_MAXFILESIZE;
+
+       bh = sb_bread(sb, 0);
+       if (!bh) {
+               printk(KERN_ERR "ASFS: unable to read superblock\n");
+               return -EINVAL;
+       }
+
+       rootblock = (struct fsRootBlock *)bh->b_data;
+
+       if (be32_to_cpu(rootblock->bheader.id) == ASFS_ROOTID && 
+               be16_to_cpu(rootblock->version) == ASFS_STRUCTURE_VERISON) {
+
+               sb->s_blocksize = be32_to_cpu(rootblock->blocksize);
+               ASFS_SB(sb)->totalblocks = be32_to_cpu(rootblock->totalblocks);
+               ASFS_SB(sb)->rootobjectcontainer = be32_to_cpu(rootblock->rootobjectcontainer);
+               ASFS_SB(sb)->extentbnoderoot = be32_to_cpu(rootblock->extentbnoderoot);
+               ASFS_SB(sb)->objectnoderoot = be32_to_cpu(rootblock->objectnoderoot);
+               ASFS_SB(sb)->flags |= 0xff & rootblock->bits;
+               ASFS_SB(sb)->adminspacecontainer = be32_to_cpu(rootblock->adminspacecontainer);
+               ASFS_SB(sb)->bitmapbase = be32_to_cpu(rootblock->bitmapbase);
+               ASFS_SB(sb)->blocks_inbitmap = (sb->s_blocksize - sizeof(struct fsBitmap))<<3;  /* must be a multiple of 32 !! */
+               ASFS_SB(sb)->blocks_bitmap = (ASFS_SB(sb)->totalblocks + ASFS_SB(sb)->blocks_inbitmap - 1) / ASFS_SB(sb)->blocks_inbitmap;
+               ASFS_SB(sb)->block_rovingblockptr = 0;
+               asfs_brelse(bh);
+
+               if (!sb_set_blocksize(sb, sb->s_blocksize)) {
+                       printk(KERN_ERR "ASFS: Found Amiga SFS RootBlock on dev %s, but blocksize %ld is not supported!\n", \
+                              sb->s_id, sb->s_blocksize);
+                       return -EINVAL;
+               }
+
+               bh = sb_bread(sb, 0);
+               if (!bh) {
+                       printk(KERN_ERR "ASFS: unable to read superblock\n");
+                       goto out;
+               }
+               rootblock = (struct fsRootBlock *)bh->b_data;
+
+               if (asfs_check_block((void *)rootblock, sb->s_blocksize, 0, ASFS_ROOTID)) {
+#ifdef CONFIG_ASFS_RW
+                       struct buffer_head *tmpbh;
+                       if ((tmpbh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer, ASFS_OBJECTCONTAINER_ID))) {
+                               struct fsRootInfo *ri = (struct fsRootInfo *)((u8 *)tmpbh->b_data + sb->s_blocksize - sizeof(struct fsRootInfo));
+                               ASFS_SB(sb)->freeblocks = be32_to_cpu(ri->freeblocks);
+                               asfs_brelse(tmpbh);
+                       } else
+                               ASFS_SB(sb)->freeblocks = 0;
+
+                       if ((tmpbh = asfs_breadcheck(sb, ASFS_SB(sb)->rootobjectcontainer+2, ASFS_TRANSACTIONFAILURE_ID))) {
+                               printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s, but it has unfinished transaction. Mounting read-only.\n", sb->s_id);
+                               ASFS_SB(sb)->flags |= ASFS_READONLY;
+                               asfs_brelse(tmpbh);
+                       }
+
+                       if ((tmpbh = asfs_breadcheck(sb, ASFS_SB(sb)->totalblocks-1, ASFS_ROOTID)) == NULL) {
+                               printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s, but there is no second RootBlock! Mounting read-only.\n", sb->s_id);
+                               ASFS_SB(sb)->flags |= ASFS_READONLY;
+                               asfs_brelse(tmpbh);
+                       }
+                       if (!(ASFS_SB(sb)->flags & ASFS_READONLY))
+                               printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s.\n", sb->s_id);
+#else
+                       ASFS_SB(sb)->freeblocks = 0;
+                       ASFS_SB(sb)->flags |= ASFS_READONLY;
+                       printk(KERN_NOTICE "VFS: Found Amiga SFS RootBlock on dev %s.\n", sb->s_id);
+#endif
+               } else {
+                       if (!silent)
+                               printk(KERN_ERR "VFS: Found Amiga SFS RootBlock on dev %s, but it has checksum error!\n", \
+                                      sb->s_id);
+                       goto out;
+               }
+       } else {
+               if (!silent)
+                       printk(KERN_ERR "VFS: Can't find a valid Amiga SFS filesystem on dev %s.\n", \
+                              sb->s_id);
+               goto out;
+       }
+
+       asfs_brelse(bh);
+
+       sb->s_magic = ASFS_MAGIC;
+       sb->s_flags |= MS_NODEV | MS_NOSUID;
+       if (ASFS_SB(sb)->flags & ASFS_READONLY) 
+               sb->s_flags |= MS_RDONLY;
+       sb->s_op = &asfs_ops;
+       asfs_debug("Case sensitive: %s\n", (ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE) ? "yes" : "no");
+
+       if (ASFS_SB(sb)->codepage[0] != '\0' && strcmp(ASFS_SB(sb)->codepage, "none") != 0) {
+               ASFS_SB(sb)->nls_disk = load_nls(ASFS_SB(sb)->codepage);
+               if (!ASFS_SB(sb)->nls_disk) {
+                       printk(KERN_ERR "ASFS: codepage %s not found\n", ASFS_SB(sb)->codepage);
+                       return -EINVAL;
+               }
+               ASFS_SB(sb)->nls_io = load_nls(ASFS_SB(sb)->iocharset);
+               if (!ASFS_SB(sb)->nls_io) {
+                       printk(KERN_ERR "ASFS: IO charset %s not found\n", ASFS_SB(sb)->iocharset);
+                       goto out2;
+               }
+       } else {
+               ASFS_SB(sb)->nls_io = NULL;
+               ASFS_SB(sb)->nls_disk = NULL;
+       }
+
+       if ((rootinode = asfs_get_root_inode(sb))) {
+               if ((sb->s_root = d_alloc_root(rootinode))) {
+                       sb->s_root->d_op = &asfs_dentry_operations;
+                       return 0;
+               }
+               iput(rootinode);
+       }
+       unload_nls(ASFS_SB(sb)->nls_io);
+out2:
+       unload_nls(ASFS_SB(sb)->nls_disk);
+       return -EINVAL;
+
+out:
+       asfs_brelse(bh);
+       return -EINVAL;
+
+}
+
+#ifdef CONFIG_ASFS_RW
+static int asfs_remount(struct super_block *sb, int *flags, char *data)
+{
+       asfs_debug("ASFS: remount (flags=0x%x, opts=\"%s\")\n",*flags,data);
+
+       if (!asfs_parse_options(data,sb))
+               return -EINVAL;
+
+       if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+               return 0;
+
+       if (*flags & MS_RDONLY) {
+               sb->s_flags |= MS_RDONLY;
+       } else if (!(ASFS_SB(sb)->flags & ASFS_READONLY)) {
+               sb->s_flags &= ~MS_RDONLY;
+       } else {
+               printk("VFS: Can't remount Amiga SFS on dev %s read/write because of errors.", sb->s_id);
+               return -EINVAL;
+       }
+       return 0;
+}
+#endif
+
+static void asfs_put_super(struct super_block *sb)
+{
+       struct asfs_sb_info *sbi = ASFS_SB(sb);
+
+       if (ASFS_SB(sb)->prefix)
+               kfree(ASFS_SB(sb)->prefix);
+       if (ASFS_SB(sb)->root_volume)
+               kfree(ASFS_SB(sb)->root_volume);
+       if (ASFS_SB(sb)->nls_disk)
+               unload_nls(ASFS_SB(sb)->nls_disk);
+       if (ASFS_SB(sb)->nls_io)
+               unload_nls(ASFS_SB(sb)->nls_io);
+       if (ASFS_SB(sb)->iocharset != asfs_default_iocharset)
+               kfree(ASFS_SB(sb)->iocharset);
+       if (ASFS_SB(sb)->codepage != asfs_default_codepage)
+               kfree(ASFS_SB(sb)->codepage);
+
+       kfree(sbi);
+       sb->s_fs_info = NULL;
+       return;
+}
+
+/* That's simple too. */
+static int asfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+       struct super_block *sb = dentry->d_sb;
+
+       buf->f_type = ASFS_MAGIC;
+       buf->f_bsize = sb->s_blocksize;
+       buf->f_bfree = buf->f_bavail = ASFS_SB(sb)->freeblocks;
+       buf->f_blocks = ASFS_SB(sb)->totalblocks;
+       buf->f_namelen = ASFS_MAXFN;
+       return 0;
+}
+
+/* --- new in 2.6.x --- */
+static struct kmem_cache * asfs_inode_cachep;
+static struct inode *asfs_alloc_inode(struct super_block *sb)
+{
+       struct asfs_inode_info *ei;
+       ei = (struct asfs_inode_info *)kmem_cache_alloc(asfs_inode_cachep, GFP_KERNEL);
+       if (!ei)
+               return NULL;
+       return &ei->vfs_inode;
+}
+
+static void asfs_destroy_inode(struct inode *inode)
+{
+       kmem_cache_free(asfs_inode_cachep, ASFS_I(inode));
+}
+static void init_once(struct kmem_cache * cachep, void *foo)
+{
+       struct asfs_inode_info *ei = (struct asfs_inode_info *) foo;
+
+       inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+       asfs_inode_cachep = kmem_cache_create("asfs_inode_cache",
+                                            sizeof(struct asfs_inode_info),
+                                            0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+                                            init_once);
+       if (asfs_inode_cachep == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+static void destroy_inodecache(void)
+{
+       kmem_cache_destroy(asfs_inode_cachep);
+}
+
+static int asfs_get_sb(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+{
+       return get_sb_bdev(fs_type, flags, dev_name, data, asfs_fill_super,
+                          mnt);
+}
+
+static struct file_system_type asfs_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "asfs",
+       .get_sb         = asfs_get_sb,
+       .kill_sb        = kill_block_super,
+       .fs_flags       = FS_REQUIRES_DEV,
+};
+
+static int __init init_asfs_fs(void)
+{
+       int err = init_inodecache();
+       if (err)
+               goto out1;
+       err = register_filesystem(&asfs_fs_type);
+       if (err)
+               goto out;
+       return 0;
+out:
+       destroy_inodecache();
+out1:
+       return err;
+}
+
+static void __exit exit_asfs_fs(void)
+{
+       unregister_filesystem(&asfs_fs_type);
+       destroy_inodecache();
+}
+
+/* Yes, works even as a module... :) */
+
+#ifdef CONFIG_ASFS_RW
+MODULE_DESCRIPTION("Amiga Smart File System (read/write) support for Linux kernel 2.6.x v" ASFS_VERSION);
+#else
+MODULE_DESCRIPTION("Amiga Smart File System (read-only) support for Linux kernel 2.6.x v" ASFS_VERSION);
+#endif
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marek Szyprowski <marek@amiga.pl>");
+
+module_init(init_asfs_fs)
+module_exit(exit_asfs_fs)


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 9/9] Amiga SmartFileSystem, revision 2
  2009-02-12 16:38         ` Phillip Lougher
                             ` (7 preceding siblings ...)
  2009-02-13  6:57           ` [PATCH 8/9] " Pavel Fedin
@ 2009-02-13  6:57           ` Pavel Fedin
  8 siblings, 0 replies; 15+ messages in thread
From: Pavel Fedin @ 2009-02-13  6:57 UTC (permalink / raw)
  To: Phillip Lougher; +Cc: linux-fsdevel

diff -ruN linux-source-2.6.24.orig/fs/asfs/symlink.c linux-source-2.6.24/fs/asfs/symlink.c
--- linux-source-2.6.24.orig/fs/asfs/symlink.c  1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/fs/asfs/symlink.c       2008-12-14 23:05:05.000000000 +0300
@@ -0,0 +1,247 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ * version: 1.0beta12
+ *  
+ * Copyright (C) 2003,2004,2005,2006  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include <linux/pagemap.h>
+#include <linux/nls.h>
+#include "asfs_fs.h"
+
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+int asfs_symlink_readpage(struct file *file, struct page *page)
+{
+       struct buffer_head *bh;
+       struct fsSoftLink *slinkcont;
+       struct inode *inode = page->mapping->host;
+       struct super_block *sb = inode->i_sb;
+       struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+       struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
+       char *link = kmap(page);
+       int i = 0, j = 0;
+       char c, lc = 0, *prefix, *lf, *p;
+       wchar_t uni;
+       int clen;
+
+       asfs_debug("asfs_read_symlink from node %d\n", (int)inode->i_ino);
+
+       if (!(bh = asfs_breadcheck(sb, ASFS_I(inode)->firstblock, ASFS_SOFTLINK_ID))) {
+               SetPageError(page);
+               kunmap(page);
+               unlock_page(page);
+               return -EIO;
+       }
+       slinkcont = (struct fsSoftLink *) bh->b_data;
+
+       lf = slinkcont->string;
+       prefix = ASFS_SB(sb)->prefix ? ASFS_SB(sb)->prefix : "/";
+
+       asfs_debug("asfs_read_symlink: link target %s\n", lf);
+
+       if ((p = strchr(lf,':'))) {     /* Handle assign or volume name */
+               if (ASFS_SB(sb)->root_volume &&
+                   strncmp(lf, ASFS_SB(sb)->root_volume, strlen(ASFS_SB(sb)->root_volume)) == 0) {
+                       /* global root volume name found */
+                       link[i++] = '/';
+                       lf = p+1;
+               } else {
+                       /* adding volume prefix */ 
+                       while (i < 1023 && (c = prefix[i]))
+                               link[i++] = c;
+                       while (i < 1023 && lf[j] != ':')
+                       {
+                               c = lf[j++];
+                               if (ASFS_SB(sb)->flags & ASFS_VOL_LOWERCASE)
+                                       c = asfs_lowerchar(c);
+                               if (nls_io)
+                               {
+                                       clen = nls_disk->char2uni(&c, 1, &uni);
+                                       if (clen>0) {
+                                               clen = nls_io->uni2char(uni, &link[i], NLS_MAX_CHARSET_SIZE);
+                                               if (clen>0)
+                                                       i += clen;
+                                       }
+                                       if (clen<0)
+                                               link[i++] = '?';
+                               } else
+                                       link[i++] = c;
+                       }
+                       if (i < 1023)
+                               link[i++] = '/';
+                       j++;
+               }
+               lc = '/';
+       }
+
+       while (i < 1023 && (c = lf[j])) {
+               if (c == '/' && lc == '/' && i < 1020) {        /* parent dir */
+                       link[i++] = '.';
+                       link[i++] = '.';
+               }
+               lc = c;
+               if (nls_io)
+               {
+                       clen = nls_disk->char2uni(&c, 1, &uni);
+                       if (clen>0) {
+                               clen = nls_io->uni2char(uni, &link[i], NLS_MAX_CHARSET_SIZE);
+                               if (clen>0)
+                                       i += clen;
+                       }
+                       if (clen<0)
+                               link[i++] = '?';
+               } else
+                       link[i++] = c;
+               j++;
+       }
+       link[i] = '\0';
+
+       SetPageUptodate(page);
+       kunmap(page);
+       unlock_page(page);
+       asfs_brelse(bh);
+       return 0;
+}
+
+#ifdef CONFIG_ASFS_RW
+
+int asfs_write_symlink(struct inode *symfile, const char *symname)
+{
+       struct super_block *sb = symfile->i_sb;
+       struct buffer_head *bh;
+       struct fsSoftLink *slinkcont;
+       struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+       struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
+       char *p, c, lc;
+       int i, maxlen, pflen;
+       wchar_t uni;
+       int clen, blen;
+
+       asfs_debug("asfs_write_symlink %s to node %d\n", symname, (int)symfile->i_ino);
+
+       if (!(bh = asfs_breadcheck(sb, ASFS_I(symfile)->firstblock, ASFS_SOFTLINK_ID))) {
+               return -EIO;
+       }
+       slinkcont = (struct fsSoftLink *) bh->b_data;
+
+       /* translating symlink target path */
+
+       maxlen = sb->s_blocksize - sizeof(struct fsSoftLink) - 2;
+       i  = 0;
+       p  = slinkcont->string;
+       lc = '/';
+
+       if (*symname == '/') {
+               while (*symname == '/')
+                       symname++;
+               if (ASFS_SB(sb)->prefix &&
+                   strncmp(symname-1, ASFS_SB(sb)->prefix, (pflen = strlen(ASFS_SB(sb)->prefix))) == 0) {
+                       /* found volume prefix, ommiting it */
+                       symname += pflen;
+                       blen = strlen(symname);
+                       while (*symname != '/' && *symname != '\0') {
+                               if (nls_io) {
+                                       clen = nls_io->char2uni(symname, blen, &uni);
+                                       if (clen>0) {
+                                               symname += clen;
+                                               blen -= clen;
+                                               clen = nls_disk->uni2char(uni, p, NLS_MAX_CHARSET_SIZE);
+                                               if (clen>0)
+                                                       p += clen;
+                                       }
+                                       else
+                                       {
+                                               symname++;
+                                               blen--;
+                                       }
+                                       if (clen<0)
+                                               *p++ = '?';
+                               } else {
+                                       *p++ = *symname++;
+                               }
+                               i++;
+                       }
+                       symname++;
+                       *p++ = ':';
+               } else if (ASFS_SB(sb)->root_volume) {  /* adding root volume name */
+                       while (ASFS_SB(sb)->root_volume[i])
+                               *p++ = ASFS_SB(sb)->root_volume[i++];
+                       *p++ = ':';
+               } else {        /* do nothing */
+                       *p++ = '/';
+               }
+               i++;
+       }
+
+       blen = strlen(symname);
+       while (i < maxlen && (c = *symname)) {
+               if (c == '.' && lc == '/' && symname[1] == '.' && symname[2] == '/') {
+                       *p++ = '/';
+                       i++;
+                       symname += 3;
+                       blen -= 3;
+                       lc = '/';
+               } else if (c == '.' && lc == '/' && symname[1] == '/') {
+                       symname += 2;
+                       blen -= 2;
+                       lc = '/';
+               } else {
+                       if (nls_io) {
+                               clen = nls_io->char2uni(symname, blen, &uni);
+                               if (clen>0) {
+                                       symname += clen;
+                                       blen -= clen;
+                                       clen = nls_disk->uni2char(uni, p, NLS_MAX_CHARSET_SIZE);
+                                       if (clen>0)
+                                               lc = *p;
+                                       p += clen;
+                               } else {
+                                       symname++;
+                                       blen--;
+                               }
+                               if (clen<0) {
+                                       *p++ = '?';
+                                       lc = '?';
+                               }
+                       } else {
+                               *p++ = c;
+                               lc = *p;
+                               symname++;
+                               blen--;
+                       }
+                       i++;
+               }
+               if (lc == '/')
+                       while (*symname == '/')
+                       {
+                               symname++;
+                               blen--;
+                       }
+       }
+       *p = 0;
+
+       asfs_debug("asfs_write_symlink: saved %s\n", slinkcont->string);
+
+       asfs_bstore(sb, bh);
+       asfs_brelse(bh);
+
+       return 0;
+}
+
+#endif
diff -ruN linux-source-2.6.24.orig/fs/Kconfig linux-source-2.6.24/fs/Kconfig
--- linux-source-2.6.24.orig/fs/Kconfig 2008-01-25 01:58:37.000000000 +0300
+++ linux-source-2.6.24/fs/Kconfig      2008-12-14 23:05:05.000000000 +0300
@@ -1105,6 +1105,53 @@
          To compile this file system support as a module, choose M here: the
          module will be called ecryptfs.
 
+config ASFS_FS
+       tristate "Amiga SFS file system support (EXPERIMENTAL)"
+       select NLS
+       depends on EXPERIMENTAL
+       help
+
+         The Amiga Smart FileSystem (SFS) is the file system used on hard 
+         disks by Amiga(tm) and MorphOS(tm) systems.  Say Y if you want 
+         to be able to read files from an Amiga SFS partition on your hard 
+         drive.
+
+         For more information read <file:Documentation/filesystems/asfs.txt>
+
+         To compile this file system support as a module, choose M here: the
+         module will be called asfs.
+
+         If unsure, say N.
+
+config ASFS_DEFAULT_CODEPAGE
+       string "Default codepage for SFS"
+       depends on ASFS_FS
+       default ""
+       help
+         This option should be set to the codepage of your SFS filesystems.
+         It can be overridden with the 'codepage' mount option. Leave it blank 
+         or enter 'none' to disable filename converting.
+
+         Use full codepage name (for example 'cp1251' instead of '1251') here, 
+         this allows to specify any character set, not only numbered one (like 
+         'iso8859-2').
+
+         If unsure, leave it blank.
+
+config ASFS_RW
+       bool "Amiga SFS write support (DANGEROUS)"
+       depends on ASFS_FS
+       help
+
+         If you say Y here, you will be able to write to ASFS file
+         systems as well as read from them. The read-write support in ASFS
+         is in beta stage. This means that useing it to write files to SFS 
+         partitions is DANGEROUS and COULD corrupt the filesystem.
+
+         For more information read <file:Documentation/filesystems/asfs.txt>
+
+         If unsure, say N.
+
 config HFS_FS
        tristate "Apple Macintosh file system support (EXPERIMENTAL)"
        depends on BLOCK && EXPERIMENTAL
diff -ruN linux-source-2.6.24.orig/fs/Makefile linux-source-2.6.24/fs/Makefile
--- linux-source-2.6.24.orig/fs/Makefile        2008-01-25 01:58:37.000000000 +0300
+++ linux-source-2.6.24/fs/Makefile     2008-12-14 23:05:05.000000000 +0300
@@ -100,6 +100,7 @@
 obj-$(CONFIG_EFS_FS)           += efs/
 obj-$(CONFIG_JFFS2_FS)         += jffs2/
 obj-$(CONFIG_AFFS_FS)          += affs/
+obj-$(CONFIG_ASFS_FS)          += asfs/
 obj-$(CONFIG_ROMFS_FS)         += romfs/
 obj-$(CONFIG_QNX4FS_FS)                += qnx4/
 obj-$(CONFIG_AUTOFS_FS)                += autofs/
diff -ruN linux-source-2.6.24.orig/include/linux/amigasfs.h linux-source-2.6.24/include/linux/amigasfs.h
--- linux-source-2.6.24.orig/include/linux/amigasfs.h   1970-01-01 03:00:00.000000000 +0300
+++ linux-source-2.6.24/include/linux/amigasfs.h        2008-12-14 23:05:05.000000000 +0300
@@ -0,0 +1,276 @@
+#ifndef __LINUX_AMIGASFS_H
+#define __LINUX_AMIGASFS_H
+
+#include <linux/types.h>
+
+/* some helper macros... */
+#define ASFS_MAKE_ID(a,b,c,d) (((a)&0xff)<<24|((b)&0xff)<<16|((c)&0xff)<<8|((d)&0xff))
+
+/* Amiga SFS block IDs */
+#define ASFS_ROOTID                 ASFS_MAKE_ID('S','F','S','\0')
+#define ASFS_OBJECTCONTAINER_ID     ASFS_MAKE_ID('O','B','J','C')
+#define ASFS_BNODECONTAINER_ID      ASFS_MAKE_ID('B','N','D','C')
+#define ASFS_NODECONTAINER_ID       ASFS_MAKE_ID('N','D','C',' ')
+#define ASFS_HASHTABLE_ID           ASFS_MAKE_ID('H','T','A','B')
+#define ASFS_SOFTLINK_ID            ASFS_MAKE_ID('S','L','N','K')
+#define ASFS_ADMINSPACECONTAINER_ID ASFS_MAKE_ID('A','D','M','C')
+#define ASFS_BITMAP_ID              ASFS_MAKE_ID('B','T','M','P')
+#define ASFS_TRANSACTIONFAILURE_ID  ASFS_MAKE_ID('T','R','F','A')
+
+/* Amiga SFS defines and magic values */
+
+#define ASFS_MAGIC 0xa0ff
+#define ASFS_MAXFN (105u)
+#define ASFS_MAXFILESIZE 0x8FFFFFFE
+
+#define ASFS_STRUCTURE_VERISON (3)
+#define ASFS_BLCKFACCURACY     (5)
+
+#define ASFS_ROOTBITS_CASESENSITIVE (128)
+#define ASFS_READONLY (512)
+#define ASFS_VOL_LOWERCASE (1024)
+
+#define ASFS_ROOTNODE   (1)
+#define ASFS_RECYCLEDNODE (2)
+
+#define OTYPE_HIDDEN      (1)
+#define OTYPE_HARDLINK    (32)
+#define OTYPE_LINK        (64)
+#define OTYPE_DIR         (128)
+
+#define MSB_MASK (1ul << 31)
+
+#define NODE_STRUCT_SIZE (10)  /* (sizeof(struct fsObjectNode)) */
+#define NODECONT_BLOCK_COUNT ((sb->s_blocksize - sizeof(struct fsNodeContainer)) / sizeof(u32))
+
+#define ASFS_ALWAYSFREE (16)           /* keep this amount of blocks free */
+
+#define ASFS_BLOCKCHUNKS (16)          /* try to allocate this number of blocks in one request */
+
+#ifndef TRUE
+#define TRUE           1
+#endif
+#ifndef FALSE
+#define FALSE          0
+#endif
+
+/* amigados protection bits */
+
+#define FIBB_SCRIPT    6       /* program is a script (execute) file */
+#define FIBB_PURE      5       /* program is reentrant and reexecutable */
+#define FIBB_ARCHIVE   4       /* cleared whenever file is changed */
+#define FIBB_READ      3       /* ignored by old filesystem */
+#define FIBB_WRITE     2       /* ignored by old filesystem */
+#define FIBB_EXECUTE   1       /* ignored by system, used by Shell */
+#define FIBB_DELETE    0       /* prevent file from being deleted */
+
+#define FIBF_SCRIPT    (1<<FIBB_SCRIPT)
+#define FIBF_PURE      (1<<FIBB_PURE)
+#define FIBF_ARCHIVE   (1<<FIBB_ARCHIVE)
+#define FIBF_READ      (1<<FIBB_READ)
+#define FIBF_WRITE     (1<<FIBB_WRITE)
+#define FIBF_EXECUTE   (1<<FIBB_EXECUTE)
+#define FIBF_DELETE    (1<<FIBB_DELETE)
+
+/* name hashing macro */
+
+#define HASHCHAIN(x) (u16)(x % (u16)(((sb->s_blocksize) - sizeof(struct fsHashTable))>>2))
+
+/* Each block has its own header with checksum and id, its called fsBlockHeader */
+
+struct fsBlockHeader {
+       __be32 id;                      /* 4 character id string of this block */
+       __be32 checksum;                /* The checksum */
+       __be32 ownblock;                /* The blocknumber of the block this block is stored at */
+};
+
+/* On-disk "super block", called fsRootBlock */
+
+struct fsRootBlock {
+       struct fsBlockHeader bheader;
+
+       __be16 version;                 /* Version number of the filesystem block structure */
+       __be16 sequencenumber;          /* The Root with the highest sequencenumber is valid */
+
+       __be32 datecreated;             /* Creation date (when first formatted).  Cannot be changed. */
+       u8 bits;                        /* various settings, see defines below. */
+       u8 pad1;
+       u16 pad2;
+
+       u32 reserved1[2];
+
+       __be32 firstbyteh;              /* The first byte of our partition from the start of the */
+       __be32 firstbyte;               /* disk.  firstbyteh = upper 32 bits, firstbyte = lower 32 bits. */
+
+       __be32 lastbyteh;               /* The last byte of our partition, excluding this one. */
+       __be32 lastbyte;
+
+       __be32 totalblocks;             /* size of this partition in blocks */
+       __be32 blocksize;               /* blocksize used */
+
+       u32 reserved2[2];
+       u32 reserved3[8];
+
+       __be32 bitmapbase;              /* location of the bitmap */
+       __be32 adminspacecontainer;     /* location of first adminspace container */
+       __be32 rootobjectcontainer;     /* location of the root objectcontainer */
+       __be32 extentbnoderoot;         /* location of the root of the extentbnode B-tree */
+       __be32 objectnoderoot;          /* location of the root of the objectnode tree */
+
+       u32 reserved4[3];
+};
+
+/* On disk inode, called fsObject */
+
+struct fsObject {
+       __be16 owneruid;
+       __be16 ownergid;
+       __be32 objectnode;
+       __be32 protection;
+
+       union {
+               struct {
+                       __be32 data;
+                       __be32 size;
+               } file;
+
+               struct {
+                       __be32 hashtable;       /* for directories & root, 0 means no hashblock */
+                       __be32 firstdirblock;
+               } dir;
+       } object;
+
+       __be32 datemodified;
+       u8 bits;
+
+       u8 name[0];
+       u8 comment[0];
+};
+
+/* On disk block containging a number of fsObjects */
+
+struct fsObjectContainer {
+       struct fsBlockHeader bheader;
+
+       __be32 parent;
+       __be32 next;
+       __be32 previous;        /* 0 for the first block in the directory chain */
+
+       struct fsObject object[0];
+};
+
+/* BTree structures, used to collect file data position on disk */
+
+struct fsExtentBNode {
+       __be32 key;             /* data! */
+       __be32 next;
+       __be32 prev;
+       __be16 blocks;          /* The size in blocks of the region this Extent controls */
+};
+
+struct BNode {
+       __be32 key;
+       __be32 data;
+};
+
+struct BTreeContainer {
+       __be16 nodecount;
+       u8 isleaf;
+       u8 nodesize;            /* Must be a multiple of 2 */
+
+       struct BNode bnode[0];
+};
+
+/* On disk block with BTreeContainer */
+
+struct fsBNodeContainer {
+       struct fsBlockHeader bheader;
+       struct BTreeContainer btc;
+};
+
+/* On disk block  with soft link data */
+
+struct fsSoftLink {
+       struct fsBlockHeader bheader;
+       __be32 parent;
+       __be32 next;
+       __be32 previous;
+       u8 string[0];
+};
+
+/* On disk block with hashtable data */
+
+struct fsHashTable {
+       struct fsBlockHeader bheader;
+       __be32 parent;
+       __be32 hashentry[0];
+};
+
+/* On disk block with node index and some helper structures */
+
+struct fsNodeContainer {
+       struct fsBlockHeader bheader;
+       __be32 nodenumber;
+       __be32 nodes;
+       __be32 node[0];
+};
+
+struct fsNode {
+       __be32 data;
+};
+
+struct fsObjectNode {
+       struct fsNode node;
+       __be32 next;
+       __be16 hash16;
+} __attribute__ ((packed));
+
+/* Some adminspace and bitmap block structures */
+
+struct fsAdminSpace {
+       __be32 space;
+       __be32 bits;            
+/* Set bits are used blocks, bit 31 is the first block in the AdminSpace. */
+};
+
+struct fsAdminSpaceContainer {
+       struct fsBlockHeader bheader;
+
+       __be32 next;
+       __be32 previous;
+
+       u8 bits;
+       u8 pad1;
+       u16 pad2;
+
+       struct fsAdminSpace adminspace[0];
+};
+
+struct fsBitmap {
+       struct fsBlockHeader bheader;
+
+       __be32 bitmap[0];
+
+/* Bits are 1 if the block is free, and 0 if full.
+   Bitmap must consist of an integral number of longwords. */
+};
+
+/* The fsRootInfo structure has all kinds of information about the format
+   of the disk. */
+
+struct fsRootInfo {
+       __be32 deletedblocks;           /* Amount in blocks which deleted files consume. */
+       __be32 deletedfiles;            /* Number of deleted files in recycled. */
+       __be32 freeblocks;              /* Cached number of free blocks on disk. */
+
+       __be32 datecreated;
+
+       __be32 lastallocatedblock;      /* Block which was most recently allocated */
+       __be32 lastallocatedadminspace; /* AdminSpaceContainer which most recently was used to allocate a block */
+       __be32 lastallocatedextentnode; /* ExtentNode which was most recently created */
+       __be32 lastallocatedobjectnode; /* ObjectNode which was most recently created */
+
+       __be32 rovingpointer;
+};
+
+#endif


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2009-02-13  6:58 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-02-09 13:18 Corrupted ASFS patch Pavel Fedin
2009-02-09 13:31 ` maximilian attems
2009-02-12  8:24   ` Re[2]: " Pavel Fedin
2009-02-12  9:42     ` Phillip Lougher
2009-02-12 10:52       ` Re[2]: " Pavel Fedin
2009-02-12 16:38         ` Phillip Lougher
2009-02-13  6:53           ` [PATCH 1/9] Amiga SmartFileSystem, revision 2 Pavel Fedin
2009-02-13  6:54           ` [PATCH 2/9] " Pavel Fedin
2009-02-13  6:55           ` [PATCH 3/9] " Pavel Fedin
2009-02-13  6:55           ` [PATCH 4/9] " Pavel Fedin
2009-02-13  6:56           ` [PATCH 5/9] " Pavel Fedin
2009-02-13  6:56           ` [PATCH 6/9] " Pavel Fedin
2009-02-13  6:56           ` [PATCH 7/9] " Pavel Fedin
2009-02-13  6:57           ` [PATCH 8/9] " Pavel Fedin
2009-02-13  6:57           ` [PATCH 9/9] " Pavel Fedin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).