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@xxxxxxxx>. +Mail me if you have any suggestions or found a bug. + +Copyright (C) 2003,2004,2005 Marek 'March' Szyprowski <marek@xxxxxxxx> + +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@xxxxxxxx> + * + */ + +#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 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html