diff -urN linux-2.3.0/CREDITS linux/CREDITS --- linux-2.3.0/CREDITS Wed May 12 12:55:12 1999 +++ linux/CREDITS Wed May 12 21:08:49 1999 @@ -150,13 +150,12 @@ D: Various bugfixes and changes to sound drivers S: USA -M: Krzysztof G. Baranowski +N: Krzysztof G. Baranowski E: kgb@manjak.knm.org.pl P: 1024/FA6F16D1 96 D1 1A CF 5F CA 69 EC F9 4F 36 1F 6D 60 7B DA -D: Maintainer of the System V file system. -D: System V fs update for 2.1.x dcache. +D: System V file system hacking. D: Forward ported a couple of SCSI drivers. -D: Various bugfixes. +D: Co-author of Unixware disklabel support. S: ul. Koscielna 12a S: 62-300 Wrzesnia S: Poland @@ -1074,6 +1073,12 @@ S: Markham, Ontario S: L3R 8B2 S: Canada + +N: Andrzej M. Krzysztofowicz +E: ankry@mif.pg.gda.pl +D: Some XT disk driver hacking. +D: Co-author of Unixware slices support. +S: Poland N: Russell Kroll E: rkroll@exploits.org diff -urN linux-2.3.0/Documentation/Configure.help linux/Documentation/Configure.help --- linux-2.3.0/Documentation/Configure.help Wed May 12 12:55:13 1999 +++ linux/Documentation/Configure.help Wed May 12 21:08:49 1999 @@ -7188,11 +7188,12 @@ If unsure, say N. -System V and Coherent filesystem support +System V, Version 7, Xenix and Coherent filesystem support CONFIG_SYSV_FS - SCO, Xenix and Coherent are commercial Unix systems for Intel - machines. Saying Y here would allow you to read to and write from - their floppies and hard disk partitions. + SCO , Xenix and Coherent are commercial Unix systems for Intel + machines, and Version 7 was used on the DEC PDP-11. Saying Y + here would allow you to read to and write from their floppies + and hard disk partitions. If you have floppies or hard disk partitions like that, it is likely that they contain binaries from those other Unix systems; in order diff -urN linux-2.3.0/Documentation/filesystems/00-INDEX linux/Documentation/filesystems/00-INDEX --- linux-2.3.0/Documentation/filesystems/00-INDEX Wed May 12 12:55:13 1999 +++ linux/Documentation/filesystems/00-INDEX Wed May 12 21:08:49 1999 @@ -21,7 +21,7 @@ smbfs.txt - info on using filesystems with the SMB protocol (Windows 3.11 and NT) sysv-fs.txt - - info on the SystemV/Coherent filesystem. + - info on the SystemV/V7/Xenix/Coherent filesystem. ufs.txt - info on the ufs filesystem. umsdos.txt diff -urN linux-2.3.0/Documentation/filesystems/sysv-fs.txt linux/Documentation/filesystems/sysv-fs.txt --- linux-2.3.0/Documentation/filesystems/sysv-fs.txt Mon Dec 22 09:07:59 1997 +++ linux/Documentation/filesystems/sysv-fs.txt Wed May 12 21:36:20 1999 @@ -1,37 +1,71 @@ -This is the implementation of the SystemV/Coherent filesystem for Linux. -It implements all of - - Xenix FS, - - SystemV/386 FS, - - Coherent FS. - -This is version beta 4. - -To install: -* Answer the 'System V and Coherent filesystem support' question with 'y' - when configuring the kernel. -* To mount a disk or a partition, use - mount [-r] -t sysv device mountpoint - The file system type names - -t sysv - -t xenix - -t coherent - may be used interchangeably, but the last two will eventually disappear. - -Bugs in the present implementation: -- Coherent FS: - - The "free list interleave" n:m is currently ignored. - - Only file systems with no filesystem name and no pack name are recognized. - (See Coherent "man mkfs" for a description of these features.) -- SystemV Release 2 FS: - The superblock is only searched in the blocks 9, 15, 18, which corresponds to the - beginning of track 1 on floppy disks. No support for this FS on hard disk yet. - - -Please report any bugs and suggestions to - Bruno Haible - Pascal Haible - Krzysztof G. Baranowski -Bruno Haible - + Linux System V File System Project + See linux/MAINTAINERS for address of current maintainer. + + To install: + + * Answer the 'System V, Version 7, Xenix and Coherent filesystem support' + question with 'y' or 'm' when configuring the kernel. + * To mount a disk or a partition, use: + mount [-r] -t fstype device mountpoint + The file system type names are: + -t v7 - Version 7 FS, + -t sysv - all others, ie. Xenix, S5, Coherent, AFS etc. + + History: + + The current Linux System V FS driver grew out of the following + implementations: + + * Xenix FS - Doug Evans (June 1992), + * System V FS - Paul B. Monday (March-June 1993), + * Coherent FS - Bruno Haible (June 1993), + * AFS/EAFS/EFS - Peter Swain, Krzysztof Baranowski (February 1999), + * Version 7 FS - Jonathan Naylor (February 1999). + + It was merged together and as of today supports: + + * AFS/EAFS/EFS - 512, 1024 and 2048 byte blocks, + * Coherent FS - 1024 byte blocks, + * System V/386 FS - 512, 1024 and 2048 byte blocks, + * Version 7 FS - 512 byte blocks, + * Xenix FS - 1024 byte blocks. + + Known issues: + + * Coherent FS: "free list interleave" is currently ignored. Only + file systems with no file system name and no pack name are + recognized. (See Coherent "man mkfs" for a description of these + features) + + * System V Release 2 FS: The superblock is only searched in the + blocks 9, 15, 18, which corresponds to the beginning of track 1 on + floppy disks. No support for this FS on hard disk yet. + + * Extended File Names for System V Release 4 FS and AFS, used in SCO + Open Server. These two filesystems may be extended to handle + filenames up to 255 chars. The similar feature (long file names) + also exists in Interactive UNIX (ISC) Version 4.0/3.x System V FS + implementation, but I don't know how it is related to Extended File + Names used in SCO. As for now the driver forces read only mode in + both cases. + + Contributors: (in alphabetical order by second name) + + * Albert Cranford + * Wolfgang Formann + * Giuseppe Guerrini + * Walter Harms + * Trevor Johnson + * Andrzej Krzysztofowicz + * Wojtek Mitus + * Jonathan Naylor + * Peter Swain + * Alexander Viro + + Thanks ! + + Links: + + * None yet ;) diff -urN linux-2.3.0/MAINTAINERS linux/MAINTAINERS --- linux-2.3.0/MAINTAINERS Wed May 12 12:55:13 1999 +++ linux/MAINTAINERS Wed May 12 21:08:49 1999 @@ -743,6 +743,7 @@ SYSV FILESYSTEM P: Krzysztof G. Baranowski M: kgb@manjak.knm.org.pl +W: http://www.knm.org.pl/prezes/sysv.html S: Maintained TLAN NETWORK DRIVER diff -urN linux-2.3.0/fs/Config.in linux/fs/Config.in --- linux-2.3.0/fs/Config.in Wed Mar 10 21:44:09 1999 +++ linux/fs/Config.in Wed May 12 21:08:49 1999 @@ -49,7 +49,7 @@ fi tristate 'ROM filesystem support' CONFIG_ROMFS_FS tristate 'Second extended fs support' CONFIG_EXT2_FS -tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS +tristate 'System V, Version 7, Xenix and Coherent filesystem support' CONFIG_SYSV_FS tristate 'UFS filesystem support' CONFIG_UFS_FS if [ "$CONFIG_UFS_FS" != "n" ]; then bool ' UFS filesystem write support (experimental)' CONFIG_UFS_FS_WRITE diff -urN linux-2.3.0/fs/sysv/CHANGES linux/fs/sysv/CHANGES --- linux-2.3.0/fs/sysv/CHANGES Mon Mar 29 09:19:01 1999 +++ linux/fs/sysv/CHANGES Wed May 12 21:08:49 1999 @@ -44,6 +44,15 @@ Added detection of expanded s_type field (0x10, 0x20 and 0x30). Forced read-only access in this case. +Thu, 18 Feb 1999 KGB + * all + Preliminary (read-only) support for AFS file system + and Extended File Names to AFS and S51K file system. + +Sun, 21 Feb 1999 Jonathan Naylor + * all + Added V7 Unix file system support. + Sun, 21 Mar 1999 AV * namei.c (sysv_link): Fixed i_count usage that resulted in dcache corruption. diff -urN linux-2.3.0/fs/sysv/INTRO linux/fs/sysv/INTRO --- linux-2.3.0/fs/sysv/INTRO Sat Feb 21 18:05:35 1998 +++ linux/fs/sysv/INTRO Wed May 12 21:08:49 1999 @@ -1,24 +1,19 @@ -This is the implementation of the SystemV/Coherent filesystem for Linux. -It grew out of separate filesystem implementations - - Xenix FS Doug Evans June 1992 - SystemV FS Paul B. Monday March-June 1993 - Coherent FS B. Haible June 1993 - -and was merged together in July 1993. - -These filesystems are rather similar. Here is a comparison with Minix FS: +This is a small comparision between Minix FS and file systems supported +by Linux System V FS driver. Bruno Haible was the original author of +this document. See linux/MAINTAINERS for address of current maintainer. * Linux fdisk reports on partitions - Minix FS 0x81 Linux/Minix - Xenix FS ?? - SystemV FS ?? + - V7 FS ?? - Coherent FS 0x08 AIX bootable * Size of a block or zone (data allocation unit on disk) - Minix FS 1024 - Xenix FS 1024 (also 512 ??) - SystemV FS 1024 (also 512 and 2048) + - V7 FS 512 - Coherent FS 512 * General layout: all have one boot block, one super block and @@ -30,6 +25,7 @@ - Minix FS little endian 0 1 - Xenix FS little endian 0 1 - SystemV FS little endian 0 1 + - V7 FS PDP-11 0 1 - Coherent FS little endian 0 1 Of course, this affects only the file system, not the data of files on it! @@ -37,28 +33,30 @@ - Minix FS little endian 0 1 2 3 - Xenix FS little endian 0 1 2 3 - SystemV FS little endian 0 1 2 3 + - V7 FS PDP-11 2 3 0 1 - Coherent FS PDP-11 2 3 0 1 Of course, this affects only the file system, not the data of files on it! * Inode on disk: "short", 0 means non-existent, the root dir ino is: - - Minix FS 1 - - Xenix FS, SystemV FS, Coherent FS 2 + - Minix FS 1 + - Xenix FS, SystemV FS, V7 FS, Coherent FS 2 * Maximum number of hard links to a file: - Minix FS 250 - Xenix FS ?? - SystemV FS ?? + - V7 FS ?? - Coherent FS >=10000 * Free inode management: - Minix FS a bitmap - - Xenix FS, SystemV FS, Coherent FS + - Xenix FS, SystemV FS, V7 FS, Coherent FS There is a cache of a certain number of free inodes in the super-block. When it is exhausted, new free inodes are found using a linear search. * Free block management: - Minix FS a bitmap - - Xenix FS, SystemV FS, Coherent FS + - Xenix FS, SystemV FS, V7 FS, Coherent FS Free blocks are organized in a "free list". Maybe a misleading term, since it is not true that every free block contains a pointer to the next free block. Rather, the free blocks are organized in chunks @@ -71,6 +69,7 @@ - Minix FS block 1 = bytes 1024..2047 - Xenix FS block 1 = bytes 1024..2047 - SystemV FS bytes 512..1023 + - V7 FS block 1 = bytes 512..1023 - Coherent FS block 1 = bytes 512..1023 * Super-block layout: @@ -99,7 +98,7 @@ unsigned long s_free_zones; unsigned short s_free_inodes; short s_dinfo[4]; -- Xenix FS only - unsigned short s_interleave_m,s_interleave_n; -- Coherent FS only + unsigned short s_interleave_m,s_interleave_n; -- V7 FS and Coherent FS only char s_fname[6]; char s_fpack[6]; then they differ considerably: @@ -115,7 +114,7 @@ long s_type; Coherent FS unsigned long s_unique; - Note that Coherent FS has no magic. + Note that V7 FS and Coherent FS have no magic number. * Inode layout: - Minix FS @@ -126,7 +125,7 @@ unsigned char i_gid; unsigned char i_nlinks; unsigned short i_zone[7+1+1]; - - Xenix FS, SystemV FS, Coherent FS + - Xenix FS, SystemV FS, V7 FS, Coherent FS unsigned short i_mode; unsigned short i_nlink; unsigned short i_uid; @@ -142,7 +141,7 @@ 7 direct blocks 1 indirect block (pointers to blocks) 1 double-indirect block (pointer to pointers to blocks) - - Xenix FS, SystemV FS, Coherent FS + - Xenix FS, SystemV FS, V7 FS, Coherent FS 10 direct blocks 1 indirect block (pointers to blocks) 1 double-indirect block (pointer to pointers to blocks) @@ -152,13 +151,14 @@ - Minix FS 32 32 - Xenix FS 64 16 - SystemV FS 64 16 + - V7 FS 64 8 - Coherent FS 64 8 * Directory entry on disk - Minix FS unsigned short inode; char name[14/30]; - - Xenix FS, SystemV FS, Coherent FS + - Xenix FS, SystemV FS, V7 FS, Coherent FS unsigned short inode; char name[14]; @@ -166,17 +166,16 @@ - Minix FS 16/32 64/32 - Xenix FS 16 64 - SystemV FS 16 64 + - V7 FS 16 32 - Coherent FS 16 32 * How to implement symbolic links such that the host fsck doesn't scream: - Minix FS normal - Xenix FS kludge: as regular files with chmod 1000 - SystemV FS ?? + - V7 FS none - Coherent FS kludge: as regular files with chmod 1000 Notation: We often speak of a "block" but mean a zone (the allocation unit) and not the disk driver's notion of "block". - - -Bruno Haible diff -urN linux-2.3.0/fs/sysv/Makefile linux/fs/sysv/Makefile --- linux-2.3.0/fs/sysv/Makefile Thu Jul 2 09:30:03 1998 +++ linux/fs/sysv/Makefile Wed May 12 21:08:49 1999 @@ -1,5 +1,5 @@ # -# Makefile for the Linux SystemV/Coherent filesystem routines. +# Makefile for the Linux SystemV/Coherent file system routines. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here diff -urN linux-2.3.0/fs/sysv/TODO linux/fs/sysv/TODO --- linux-2.3.0/fs/sysv/TODO Thu Jan 1 01:00:00 1970 +++ linux/fs/sysv/TODO Wed May 12 21:30:32 1999 @@ -0,0 +1,4 @@ +- update INTRO file - afs information +- write parser for sysv_options + +-KGB diff -urN linux-2.3.0/fs/sysv/balloc.c linux/fs/sysv/balloc.c --- linux-2.3.0/fs/sysv/balloc.c Sun Oct 4 23:54:54 1998 +++ linux/fs/sysv/balloc.c Wed May 12 21:08:49 1999 @@ -15,8 +15,11 @@ * * sysv/balloc.c * Copyright (C) 1993 Bruno Haible + * Copyright (C) 1997-1999 Krzysztof G. Baranowski * * This file contains code for allocating/freeing blocks. + * + * See linux/MAINTAINERS for address of current maintainer. */ #include @@ -29,22 +32,24 @@ sb->sv_sbd2->s_tfree = *sb->sv_sb_total_free_blocks but we nevertheless keep it up to date. */ +static struct sysv4_freelist_chunk eafs_flist = {0,}; + void sysv_free_block(struct super_block * sb, unsigned int block) { struct buffer_head * bh; char * bh_data; if (!sb) { - printk("sysv_free_block: trying to free block on nonexistent device\n"); + printk("sysv_free_block: trying to free block on nonexistent device.\n"); return; } if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) { - printk("sysv_free_block: trying to free block not in datazone\n"); + printk("sysv_free_block: trying to free block not in datazone.\n"); return; } lock_super(sb); if (*sb->sv_sb_flc_count > sb->sv_flc_size) { - printk("sysv_free_block: flc_count > flc_size\n"); + printk("sysv_free_block: flc_count > flc_size.\n"); unlock_super(sb); return; } @@ -57,7 +62,7 @@ bh = sv_getblk(sb, sb->s_dev, block); if (!bh) { - printk("sysv_free_block: getblk() failed\n"); + printk("sysv_free_block: getblk() failed.\n"); unlock_super(sb); return; } @@ -67,6 +72,11 @@ flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree; flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0]; break; + case FSTYPE_AFS: + eafs_flist.fl_nfree = 0; + flc_count = &eafs_flist.fl_nfree; + flc_blocks = eafs_flist.fl_free; + break; case FSTYPE_SYSV4: flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree; flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0]; @@ -79,6 +89,10 @@ flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree; flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0]; break; + case FSTYPE_V7: + flc_count = &((struct v7_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct v7_freelist_chunk *) bh_data)->fl_free[0]; + break; default: panic("sysv_free_block: invalid fs type\n"); } *flc_count = *sb->sv_sb_flc_count; /* = sb->sv_flc_size */ @@ -94,7 +108,7 @@ if (*sb->sv_sb_flc_count == 0) { /* Applies only to Coherent FS */ bh = sv_getblk(sb, sb->s_dev, block); if (!bh) { - printk("sysv_free_block: getblk() failed\n"); + printk("sysv_free_block: getblk() failed.\n"); unlock_super(sb); return; } @@ -132,7 +146,7 @@ char * bh_data; if (!sb) { - printk("sysv_new_block: trying to get new block from nonexistent device\n"); + printk("sysv_new_block: trying to get new block from nonexistent device.\n"); return 0; } lock_super(sb); @@ -143,13 +157,13 @@ block = sb->sv_sb_flc_blocks[(*sb->sv_sb_flc_count)-1]; if (sb->sv_convert) block = from_coh_ulong(block); - if (block == 0) { /* Applies only to Xenix FS, SystemV FS */ + if (block == 0) { /* Applies only to Xenix FS, System V FS */ unlock_super(sb); return 0; /* no blocks available */ } (*sb->sv_sb_flc_count)--; if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) { - printk("sysv_new_block: new block %d is not in data zone\n",block); + printk("sysv_new_block: new block %d is not in data zone.\n",block); unlock_super(sb); return 0; } @@ -158,7 +172,7 @@ u32 * flc_blocks; if (!(bh = sv_bread(sb, sb->s_dev, block))) { - printk("sysv_new_block: cannot read free-list block\n"); + printk("sysv_new_block: cannot read free-list block.\n"); /* retry this same block next time */ (*sb->sv_sb_flc_count)++; unlock_super(sb); @@ -182,10 +196,14 @@ flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree; flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0]; break; + case FSTYPE_V7: + flc_count = &((struct v7_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct v7_freelist_chunk *) bh_data)->fl_free[0]; + break; default: panic("sysv_new_block: invalid fs type\n"); } if (*flc_count > sb->sv_flc_size) { - printk("sysv_new_block: free-list block with >flc_size entries\n"); + printk("sysv_new_block: free-list block with >flc_size entries.\n"); brelse(bh); unlock_super(sb); return 0; @@ -197,12 +215,12 @@ /* Now the free list head in the superblock is valid again. */ bh = sv_getblk(sb, sb->s_dev, block); if (!bh) { - printk("sysv_new_block: getblk() failed\n"); + printk("sysv_new_block: getblk() failed.\n"); unlock_super(sb); return 0; } if (bh->b_count != 1) { - printk("sysv_new_block: block already in use\n"); + printk("sysv_new_block: block already in use.\n"); unlock_super(sb); return 0; } @@ -224,13 +242,19 @@ unsigned long sysv_count_free_blocks(struct super_block * sb) { -#if 1 /* test */ int count, old_count; unsigned int block; struct buffer_head * bh; char * bh_data; int i; + if (!sysv_opt[check].val) { + count = *sb->sv_sb_total_free_blocks; + if (sb->sv_convert) + count = from_coh_ulong(count); + return count; + } + /* this causes a lot of disk traffic ... */ count = 0; lock_super(sb); @@ -251,11 +275,11 @@ u32 * flc_blocks; if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) { - printk("sysv_count_free_blocks: new block %d is not in data zone\n",block); + printk("sysv_count_free_blocks: new block %d is not in data zone.\n",block); break; } if (!(bh = sv_bread(sb, sb->s_dev, block))) { - printk("sysv_count_free_blocks: cannot read free-list block\n"); + printk("sysv_count_free_blocks: cannot read free-list block.\n"); break; } bh_data = bh->b_data; @@ -264,6 +288,11 @@ flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree; flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0]; break; + case FSTYPE_AFS: + eafs_flist.fl_nfree = 0; + flc_count = &eafs_flist.fl_nfree; + flc_blocks = eafs_flist.fl_free; + break; case FSTYPE_SYSV4: flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree; flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0]; @@ -276,18 +305,23 @@ flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree; flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0]; break; - default: panic("sysv_count_free_blocks: invalid fs type\n"); + case FSTYPE_V7: + flc_count = &((struct v7_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct v7_freelist_chunk *) bh_data)->fl_free[0]; + break; + default: panic("sysv_count_free_blocks: invalid fs type.\n"); } if (*flc_count > sb->sv_flc_size) { - printk("sysv_count_free_blocks: free-list block with >flc_size entries\n"); + printk("sysv_count_free_blocks: free-list block with >flc_size entries.\n"); brelse(bh); break; } - if (*flc_count == 0) { /* Applies only to Coherent FS */ + if (*flc_count == 0) { + /* Applies only to Coherent FS or AFS(ro) */ brelse(bh); break; } - for (i = *flc_count ; /* i > 0 */ ; ) { + for (i = *flc_count; i > 0; ) { block = flc_blocks[--i]; if (sb->sv_convert) block = from_coh_ulong(block); @@ -299,7 +333,7 @@ } /* block = flc_blocks[0], the last block continues the free list */ brelse(bh); - if (block == 0) /* Applies only to Xenix FS and SystemV FS */ + if (block == 0) /* Applies only to Xenix FS and System V FS */ break; } done: ; @@ -308,7 +342,7 @@ if (sb->sv_convert) old_count = from_coh_ulong(old_count); if (count != old_count) { - printk("sysv_count_free_blocks: free block count was %d, correcting to %d\n",old_count,count); + printk("sysv_count_free_blocks: free block count was %d, correcting to %d.\n", old_count, count); if (!(sb->s_flags & MS_RDONLY)) { *sb->sv_sb_total_free_blocks = (sb->sv_convert ? to_coh_ulong(count) : count); mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified */ @@ -317,13 +351,4 @@ } unlock_super(sb); return count; -#else - int count; - - count = *sb->sv_sb_total_free_blocks; - if (sb->sv_convert) - count = from_coh_ulong(count); - return count; -#endif } - diff -urN linux-2.3.0/fs/sysv/dir.c linux/fs/sysv/dir.c --- linux-2.3.0/fs/sysv/dir.c Wed Apr 28 21:44:08 1999 +++ linux/fs/sysv/dir.c Wed May 12 21:08:49 1999 @@ -9,8 +9,12 @@ * * sysv/dir.c * Copyright (C) 1993 Bruno Haible + * Copyright (C) 1995-1996 Peter Swain + * Copyright (C) 1997-2000 Krzysztof G. Baranowski * - * SystemV/Coherent directory handling functions + * Directory handling functions. + * + * See linux/MAINTAINERS for address of current maintainer. */ #include @@ -74,6 +78,10 @@ struct buffer_head * bh; char* bh_data; struct sysv_dir_entry * de, sde; + char bigbuf[SYSV_LONG_NAMELEN+1]; /* EAFS extended names built here */ + unsigned int biglen = 0; /* size of bigbuf contents */ + loff_t bigpos = 0; /* filp->f_pos of start of name */ + if ((unsigned long)(filp->f_pos) % SYSV_DIRSIZE) return -EBADF; @@ -82,28 +90,70 @@ bh = sysv_file_bread(inode, filp->f_pos >> sb->sv_block_size_bits, 0); if (!bh) { filp->f_pos += sb->sv_block_size - offset; + if (biglen) + printk("sysv_readdir: long name spans dir blocks [%.*s].\n", (int)biglen, bigbuf); + continue; } bh_data = bh->b_data; while (offset < sb->sv_block_size && filp->f_pos < inode->i_size) { de = (struct sysv_dir_entry *) (offset + bh_data); - if (de->inode) { + if (de->inode == SYSV_PARTIAL_NAME) { + if ((char *)&de[1] >= bh_data + sb->sv_block_size) { + printk("sysv_readdir: partial long name crosses block.\n"); + biglen = 0; + } else if (!de[1].inode) { + printk("sysv_readdir: zapping partial long name with zero inode.\n"); + sysv_clear_entry(bh, de); + mark_buffer_dirty(bh, 1); + biglen = 0; + } + if (!biglen) + bigpos = filp->f_pos; + memcpy(bigbuf+biglen, de->name, SYSV_NAMELEN); + biglen += SYSV_NAMELEN; + bigbuf[biglen] = 0; + if (biglen > SYSV_LONG_NAMELEN) { + printk("sysv_readdir: zeroing huge biglen %d.\n", biglen); + biglen = 0; + } + } else if (!de->inode) { + biglen = 0; + } else { /* Copy the directory entry first, because the directory * might be modified while we sleep in filldir()... */ + int err = 0; + memcpy(&sde, de, sizeof(struct sysv_dir_entry)); if (sde.inode > inode->i_sb->sv_ninodes) printk("sysv_readdir: Bad inode number on dev " - "%s, ino %ld, offset 0x%04lx: %d is out of range\n", - kdevname(inode->i_dev), + "%s, ino %ld, offset 0x%04lx: %d is out of range.\n", + bdevname(inode->i_dev), inode->i_ino, (off_t) filp->f_pos, sde.inode); i = strnlen(sde.name, SYSV_NAMELEN); - if (filldir(dirent, sde.name, i, filp->f_pos, sde.inode) < 0) { + if (biglen+i > SYSV_LONG_NAMELEN) { + printk("sysv_readdir: zeroing huge biglen %d.\n", biglen); + biglen = 0; + } + if (biglen > 0) { + memcpy(bigbuf+biglen, sde.name, i); + biglen += i; + bigbuf[biglen] = 0; + err = filldir(dirent, bigbuf, biglen, + bigpos, sde.inode); + if (err < 0) + filp->f_pos = bigpos; + } else + err = filldir(dirent, sde.name, i, + filp->f_pos, sde.inode); + if (err < 0) { brelse(bh); return 0; } + biglen = 0; } offset += SYSV_DIRSIZE; filp->f_pos += SYSV_DIRSIZE; diff -urN linux-2.3.0/fs/sysv/file.c linux/fs/sysv/file.c --- linux-2.3.0/fs/sysv/file.c Sun Oct 4 23:54:07 1998 +++ linux/fs/sysv/file.c Wed May 12 21:08:49 1999 @@ -10,7 +10,9 @@ * sysv/file.c * Copyright (C) 1993 Bruno Haible * - * SystemV/Coherent regular file handling primitives + * Regular file handling primitives. + * + * See linux/MAINTAINERS for address of current maintainer. */ #include @@ -30,14 +32,11 @@ #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) -#include -#include - static ssize_t sysv_file_write(struct file *, const char *, size_t, loff_t *); /* * We have mostly NULLs here: the current defaults are OK for - * the coh filesystem. + * the coh file system. */ static struct file_operations sysv_file_operations = { NULL, /* lseek - default */ @@ -88,11 +87,11 @@ size_t size; if (!inode) { - printk("sysv_file_read: inode = NULL\n"); + printk("sysv_file_read: inode = NULL.\n"); return -EINVAL; } if (!S_ISREG(inode->i_mode)) { - printk("sysv_file_read: mode = %07o\n",inode->i_mode); + printk("sysv_file_read: mode = %07o.\n",inode->i_mode); return -EINVAL; } offset = *ppos; @@ -121,7 +120,7 @@ as many blocks as we can, then we wait for the first one to complete, and then we try to wrap up as many as are actually done. This routine is rather generic, in that it can be used - in a filesystem by substituting the appropriate function in + in a file system by substituting the appropriate function in for getblk. This routine is optimized to make maximum use of the various @@ -213,11 +212,11 @@ char * p; if (!inode) { - printk("sysv_file_write: inode = NULL\n"); + printk("sysv_file_write: inode = NULL.\n"); return -EINVAL; } if (!S_ISREG(inode->i_mode)) { - printk("sysv_file_write: mode = %07o\n",inode->i_mode); + printk("sysv_file_write: mode = %07o.\n",inode->i_mode); return -EINVAL; } /* diff -urN linux-2.3.0/fs/sysv/fsync.c linux/fs/sysv/fsync.c --- linux-2.3.0/fs/sysv/fsync.c Sun Oct 4 23:54:54 1998 +++ linux/fs/sysv/fsync.c Wed May 12 21:08:49 1999 @@ -11,7 +11,9 @@ * sysv/fsync.c * Copyright (C) 1993 Bruno Haible * - * SystemV/Coherent fsync primitive + * Fsync primitive. + * + * See linux/MAINTAINERS for address of current maintainer. */ #include diff -urN linux-2.3.0/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c --- linux-2.3.0/fs/sysv/ialloc.c Wed Mar 24 00:04:35 1999 +++ linux/fs/sysv/ialloc.c Wed May 12 21:08:49 1999 @@ -15,8 +15,11 @@ * * sysv/ialloc.c * Copyright (C) 1993 Bruno Haible + * Copyright (C) 1997-2000 Krzysztof G. Baranowski * * This file contains code for allocating/freeing inodes. + * + * See linux/MAINTAINERS for address of current maintainer. */ #include @@ -59,29 +62,29 @@ if (!inode) return; if (!inode->i_dev) { - printk("sysv_free_inode: inode has no device\n"); + printk("sysv_free_inode: inode has no device.\n"); return; } if (inode->i_count != 1) { - printk("sysv_free_inode: inode has count=%d\n", inode->i_count); + printk("sysv_free_inode: inode has count=%d.\n", inode->i_count); return; } if (inode->i_nlink) { - printk("sysv_free_inode: inode has nlink=%d\n", inode->i_nlink); + printk("sysv_free_inode: inode has nlink=%d.\n", inode->i_nlink); return; } if (!(sb = inode->i_sb)) { - printk("sysv_free_inode: inode on nonexistent device\n"); + printk("sysv_free_inode: inode on nonexistent device.\n"); return; } ino = inode->i_ino; if (ino <= SYSV_ROOT_INO || ino > sb->sv_ninodes) { - printk("sysv_free_inode: inode 0,1,2 or nonexistent inode\n"); + printk("sysv_free_inode: inode 0,1,2 or nonexistent inode %d.\n", ino); return; } if (!(bh = sv_bread(sb, inode->i_dev, sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits)))) { printk("sysv_free_inode: unable to read inode block on device " - "%s\n", kdevname(inode->i_dev)); + "%s.\n", bdevname(inode->i_dev)); clear_inode(inode); return; } @@ -115,7 +118,7 @@ inode->i_flags = 0; lock_super(sb); /* protect against task switches */ if ((*sb->sv_sb_fic_count == 0) - || (*sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)-1) == 0) /* Applies only to SystemV2 FS */ + || (*sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)-1) == 0) /* Applies only to System V2 FS */ ) { /* Rebuild cache of free inodes: */ /* i : index into cache slot being filled */ @@ -126,7 +129,7 @@ /* raw_inode : pointer to inode ino in the block */ for (i = 0, ino = SYSV_ROOT_INO+1, block = sb->sv_firstinodezone, j = SYSV_ROOT_INO ; i < sb->sv_fic_size && block < sb->sv_firstdatazone ; block++, j = 0) { if (!(bh = sv_bread(sb, sb->s_dev, block))) { - printk("sysv_new_inode: unable to read inode table\n"); + printk("sysv_new_inode: unable to read inode table.\n"); break; /* go with what we've got */ /* FIXME: Perhaps try the next block? */ } @@ -176,11 +179,13 @@ unsigned long sysv_count_free_inodes(struct super_block * sb) { -#if 1 /* test */ struct buffer_head * bh; struct sysv_inode * raw_inode; int j,block,count; + if (!sysv_opt[check].val) + return *sb->sv_sb_total_free_inodes; + /* this causes a lot of disk traffic ... */ count = 0; lock_super(sb); @@ -192,7 +197,7 @@ /* raw_inode : pointer to inode ino in the block */ for (block = sb->sv_firstinodezone, j = SYSV_ROOT_INO ; block < sb->sv_firstdatazone ; block++, j = 0) { if (!(bh = sv_bread(sb, sb->s_dev, block))) { - printk("sysv_count_free_inodes: unable to read inode table\n"); + printk("sysv_count_free_inodes: unable to read inode table.\n"); break; /* go with what we've got */ /* FIXME: Perhaps try the next block? */ } @@ -203,7 +208,7 @@ brelse(bh); } if (count != *sb->sv_sb_total_free_inodes) { - printk("sysv_count_free_inodes: free inode count was %d, correcting to %d\n",(short)(*sb->sv_sb_total_free_inodes),count); + printk("sysv_count_free_inodes: free inode count was %d, correcting to %d.\n", (short)(*sb->sv_sb_total_free_inodes), count); if (!(sb->s_flags & MS_RDONLY)) { *sb->sv_sb_total_free_inodes = count; mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified */ @@ -212,8 +217,4 @@ } unlock_super(sb); return count; -#else - return *sb->sv_sb_total_free_inodes; -#endif } - diff -urN linux-2.3.0/fs/sysv/inode.c linux/fs/sysv/inode.c --- linux-2.3.0/fs/sysv/inode.c Wed Mar 24 00:04:35 1999 +++ linux/fs/sysv/inode.c Wed May 12 21:51:45 1999 @@ -15,14 +15,16 @@ * * sysv/inode.c * Copyright (C) 1993 Bruno Haible - * Copyright (C) 1997, 1998 Krzysztof G. Baranowski + * Copyright (C) 1995-1996 Peter Swain + * Copyright (C) 1997-2000 Krzysztof G. Baranowski * * This file contains code for allocating/freeing inodes and for read/writing * the superblock. + * + * See linux/MAINTAINERS for address of current maintainer. */ #include - #include #include #include @@ -37,7 +39,7 @@ #if 0 void sysv_print_inode(struct inode * inode) { - printk("ino %lu mode 0%6.6o lk %d uid %d gid %d" + printk("sysv ino %lu mode 0%6.6o lk %d uid %d gid %d" " sz %lu blks %lu cnt %u\n", inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid, inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count); @@ -55,6 +57,15 @@ } #endif +iopt sysv_opt[max_opt] = { + Iopt(debug, 0), + Iopt(bsize, BLOCK_SIZE), + Iopt(blk0, 0), + Iopt(trunc, 0), + Iopt(check, 0), + Iopt(convert_afs, 0), +}; + static void sysv_delete_inode(struct inode *inode) { inode->i_size = 0; @@ -75,15 +86,26 @@ NULL /* remount_fs */ }; -/* The following functions try to recognize specific filesystems. +/* + * The following functions try to recognize specific file systems. * We recognize: * - Xenix FS by its magic number. - * - SystemV FS by its magic number. + * - System V FS by its magic number. * - Coherent FS by its funny fname/fpack field. - * We discriminate among SystemV4 and SystemV2 FS by the assumption that + * - V7 FS has no distinguishing features. + * - SCO EFS by its magic number (SysV + 1). + * - SCO AFS by s_nfree == SYSV_BITMAP_FREELIST. + * - SCO EAFS (usual SCO3) has both EFS and AFS mods. + * We discriminate among System V4 and System V2 FS by the assumption that * the time stamp is not < 01-01-1980. */ +enum { + JAN_1_1970_GMT = 0, + JAN_1_1980 = JAN_1_1970_GMT + 10 * (365 * 24 + 24/4) * 60 * 60, +}; + + static void detected_bs (u_char type, struct super_block *sb) { u_char n_bits = type+8; @@ -126,8 +148,9 @@ return NULL; detected_bs(sbd->s_type, sb); sb->sv_type = FSTYPE_XENIX; - return "Xenix"; + return "Xenix(R)"; } + static struct super_block * detected_xenix (struct super_block *sb, struct buffer_head *bh1, struct buffer_head *bh2) { struct xenix_super_block * sbd1; @@ -147,7 +170,7 @@ sb->sv_convert = 0; sb->sv_kludge_symlinks = 1; - sb->sv_truncate = 1; + sb->sv_truncate = sysv_opt[trunc].val; sb->sv_link_max = XENIX_LINK_MAX; sb->sv_fic_size = XENIX_NICINOD; sb->sv_flc_size = XENIX_NICFREE; @@ -160,24 +183,59 @@ sb->sv_sb_total_free_inodes = &sbd2->s_tinode; sb->sv_sb_flc_count = &sbd1->s_nfree; sb->sv_sb_flc_blocks = &sbd1->s_free[0]; - sb->sv_sb_total_free_blocks = &sbd2->s_tfree; + sb->sv_sb_total_free_blocks = &sbd2->s_tfree; sb->sv_sb_time = &sbd2->s_time; sb->sv_firstinodezone = 2; sb->sv_firstdatazone = sbd1->s_isize; sb->sv_nzones = sbd1->s_fsize; sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; + sb->sv_namelen = SYSV_NAMELEN; return sb; } -static const char* detect_sysv4 (struct super_block *sb, struct buffer_head *bh) +static const char* detect_sysv4(struct super_block *sb, struct buffer_head *bh) { struct sysv4_super_block * sbd; + char *fsname; + int fstype; - sbd = (struct sysv4_super_block *) (bh->b_data + BLOCK_SIZE/2); - if (sbd->s_magic != 0xfd187e20) - return NULL; - if (sbd->s_time < 315532800) /* this is likely to happen on SystemV2 FS */ + sbd = ((struct sysv4_super_block *) (bh->b_data + bh->b_size)) - 1; + + if (sysv_opt[debug].val) + printk("detect_sysv4: at %ld s_magic %x s_time %d s_type %x s_nfree %d.\n", + bh->b_blocknr, sbd->s_magic, sbd->s_time, + sbd->s_type, sbd->s_nfree); + + if (sbd->s_magic == SYSV_FSMAGIC || sbd->s_magic == SYSV_FSEMAGIC) { + if (sbd->s_nfree != SYSV_BITMAP_FREELIST || sysv_opt[convert_afs].val) { + fstype = FSTYPE_SYSV4; + fsname = "System V"; + if (sbd->s_time < JAN_1_1980) + return NULL; + if (sbd->s_nfree == SYSV_BITMAP_FREELIST) { + /* authorised to convert from AFS to SYSV, + should reconstruct free list, but for + now we just zap it... let fsck.sysv fill + it out later. */ + int n; + + for (n = 0; n < SYSV_NICFREE; n++) + sbd->s_free[n] = 0; + sbd->s_nfree = 0; + } + } else { + fstype = FSTYPE_AFS; + fsname = "Extended Acer Fast"; + if (!(sb->s_flags & MS_RDONLY)) + printk("SysV FS: SCO EAFS on %s detected, " + "forcing read-only mode.\n", + bdevname(sb->s_dev)); + sb->s_flags |= MS_RDONLY; + } + + } else return NULL; + if ((sbd->s_type > 3 || sbd->s_type < 1) && (sbd->s_type > 0x30 || sbd->s_type < 0x10)) return NULL; @@ -188,33 +246,44 @@ if (sbd->s_type >= 0x10) { printk("SysV FS: can't handle long file names on %s, " - "forcing read-only mode.\n", kdevname(sb->s_dev)); + "forcing read-only mode.\n", bdevname(sb->s_dev)); sb->s_flags |= MS_RDONLY; } detected_bs(sbd->s_type >= 0x10 ? (sbd->s_type >> 4) : sbd->s_type, sb); - sb->sv_type = FSTYPE_SYSV4; - return "SystemV"; + sb->sv_type = fstype; + return fsname; } static struct super_block * detected_sysv4 (struct super_block *sb, struct buffer_head *bh) { struct sysv4_super_block * sbd; - if (sb->sv_block_size >= BLOCK_SIZE) - sbd = (struct sysv4_super_block *) (bh->b_data + BLOCK_SIZE/2); - else { - sbd = (struct sysv4_super_block *) bh->b_data; - /* sanity check */ - if (sbd->s_magic != 0xfd187e20) - return NULL; - if (sbd->s_time < 315532800) + + sbd = ((struct sysv4_super_block *) (bh->b_data + bh->b_size)) - 1; + + if (sysv_opt[debug].val) + printk("detected_sysv4: s_magic %x s_time %d s_type %x.\n", + sbd->s_magic, sbd->s_time, sbd->s_type); + + /* sanity check */ + switch (sbd->s_magic) { + case SYSV_FSMAGIC: + sb->sv_namelen = SYSV_NAMELEN; + break; + case SYSV_FSEMAGIC: + sb->sv_namelen = SYSV_LONG_NAMELEN; + break; + default: return NULL; } + if (sbd->s_time < JAN_1_1980) + return NULL; + sb->sv_convert = 0; sb->sv_kludge_symlinks = 0; /* ?? */ - sb->sv_truncate = 1; + sb->sv_truncate = sysv_opt[trunc].val; sb->sv_link_max = SYSV_LINK_MAX; sb->sv_fic_size = SYSV_NICINOD; sb->sv_flc_size = SYSV_NICFREE; @@ -241,35 +310,48 @@ { struct sysv2_super_block * sbd; - sbd = (struct sysv2_super_block *) (bh->b_data + BLOCK_SIZE/2); - if (sbd->s_magic != 0xfd187e20) + sbd = ((struct sysv2_super_block *) (bh->b_data + bh->b_size)) - 1; + + if (sysv_opt[debug].val) + printk("detect_sysv2: at %ld s_magic %x s_time %d s_type %x s_nfree %d.\n", + bh->b_blocknr, sbd->s_magic, sbd->s_time, sbd->s_type, + sbd->s_nfree); + + if (sbd->s_magic != SYSV_FSMAGIC && sbd->s_magic != SYSV_FSEMAGIC) return NULL; - if (sbd->s_time < 315532800) /* this is likely to happen on SystemV4 FS */ + + if (sbd->s_nfree == SYSV_BITMAP_FREELIST) + return NULL; + + if (sbd->s_time >= JAN_1_1980) return NULL; + if (sbd->s_type > 3 || sbd->s_type < 1) return NULL; detected_bs(sbd->s_type, sb); sb->sv_type = FSTYPE_SYSV2; - return "SystemV Release 2"; + return "System V Release 2"; } + static struct super_block * detected_sysv2 (struct super_block *sb, struct buffer_head *bh) { struct sysv2_super_block * sbd; - if (sb->sv_block_size >= BLOCK_SIZE) - sbd = (struct sysv2_super_block *) (bh->b_data + BLOCK_SIZE/2); - else { - sbd = (struct sysv2_super_block *) bh->b_data; - /* sanity check */ - if (sbd->s_magic != 0xfd187e20) - return NULL; - if (sbd->s_time < 315532800) - return NULL; - } + sbd = ((struct sysv2_super_block *) (bh->b_data + bh->b_size)) - 1; + + if (sysv_opt[debug].val) + printk("detected_sysv2: s_magic %x s_time %d s_type %x.\n", + sbd->s_magic, sbd->s_time, sbd->s_type); + + /* sanity check */ + if (sbd->s_magic != SYSV_FSMAGIC || sbd->s_nfree == SYSV_BITMAP_FREELIST) + return NULL; + if (sbd->s_time >= JAN_1_1980) + return NULL; sb->sv_convert = 0; - sb->sv_kludge_symlinks = 0; /* ?? */ - sb->sv_truncate = 1; + sb->sv_kludge_symlinks = 1; + sb->sv_truncate = sysv_opt[trunc].val; sb->sv_link_max = SYSV_LINK_MAX; sb->sv_fic_size = SYSV_NICINOD; sb->sv_flc_size = SYSV_NICFREE; @@ -289,6 +371,7 @@ sb->sv_firstdatazone = sbd->s_isize; sb->sv_nzones = sbd->s_fsize; sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; + sb->sv_namelen = SYSV_NAMELEN; return sb; } @@ -297,6 +380,7 @@ struct coh_super_block * sbd; sbd = (struct coh_super_block *) (bh->b_data + BLOCK_SIZE/2); + if ((memcmp(sbd->s_fname,"noname",6) && memcmp(sbd->s_fname,"xxxxx ",6)) || (memcmp(sbd->s_fpack,"nopack",6) && memcmp(sbd->s_fpack,"xxxxx\n",6))) return NULL; @@ -304,6 +388,7 @@ sb->sv_type = FSTYPE_COH; return "Coherent"; } + static struct super_block * detected_coherent (struct super_block *sb, struct buffer_head *bh) { struct coh_super_block * sbd; @@ -316,7 +401,7 @@ sb->sv_convert = 1; sb->sv_kludge_symlinks = 1; - sb->sv_truncate = 1; + sb->sv_truncate = sysv_opt[trunc].val; sb->sv_link_max = COH_LINK_MAX; sb->sv_fic_size = COH_NICINOD; sb->sv_flc_size = COH_NICFREE; @@ -335,9 +420,122 @@ sb->sv_firstdatazone = sbd->s_isize; sb->sv_nzones = from_coh_ulong(sbd->s_fsize); sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; + sb->sv_namelen = SYSV_NAMELEN; return sb; } +/* i hate parsers ;) */ +static int sysv_parse_options(char *options, int silent) +{ + int i; + + for (i = min_opt; i < max_opt; i++) + sysv_opt[i].val = sysv_opt[i].deflt; + + /* !! TODO !! */ + return 1; +} + +struct super_block *v7_read_super(struct super_block *sb,void *data, + int silent) +{ + struct v7_super_block *sbd; + struct buffer_head *bh; + kdev_t dev = sb->s_dev; + struct inode *root_inode; + unsigned long blocknr; + int block_size = BLOCK_SIZE; + + if (sysv_opt[bsize].val) + block_size = sysv_opt[bsize].val; + + if (440 != sizeof (struct v7_super_block)) + panic("V7 FS: bad super-block size"); + if (64 != sizeof (struct sysv_inode)) + panic("sysv fs: bad i-node size"); + MOD_INC_USE_COUNT; + lock_super(sb); + set_blocksize(dev, block_size); + sb->sv_block_base = sysv_opt[blk0].val; + + if ((bh = bread(dev, 0, block_size)) == NULL) { + sb->s_dev = 0; + unlock_super(sb); + if (!silent) + printk("VFS: unable to read V7 FS superblock on device " + "%s.\n", bdevname(dev)); + goto failed; + } + + detected_bs(1, sb); + sb->sv_type = FSTYPE_V7; + /* Change to 512 byte block mode */ + blocknr = (bh->b_blocknr << sb->sv_block_size_dec_bits) >> sb->sv_block_size_inc_bits; + brelse(bh); + set_blocksize(dev,sb->sv_block_size); + + if ((bh = bread(dev, blocknr+1, sb->sv_block_size)) == NULL) { + set_blocksize(sb->s_dev, block_size); + sb->s_dev = 0; + unlock_super(sb); + printk("SysV FS: cannot read superblock in 512 byte mode.\n"); + goto failed; + } + + sbd = (struct v7_super_block *)bh->b_data; + + sb->sv_convert = 1; + sb->sv_kludge_symlinks = 1; /* V7 doesn't have them at all */ + sb->sv_truncate = sysv_opt[trunc].val; + sb->sv_link_max = V7_LINK_MAX; + sb->sv_fic_size = V7_NICINOD; + sb->sv_flc_size = V7_NICFREE; + sb->sv_bh1 = bh; + sb->sv_bh2 = bh; + sb->sv_sbd1 = (char *)sbd; + sb->sv_sbd2 = (char *)sbd; + sb->sv_sb_fic_count = &sbd->s_ninode; + sb->sv_sb_fic_inodes = &sbd->s_inode[0]; + sb->sv_sb_total_free_inodes = &sbd->s_tinode; + sb->sv_sb_flc_count = &sbd->s_nfree; + sb->sv_sb_flc_blocks = &sbd->s_free[0]; + sb->sv_sb_total_free_blocks = &sbd->s_tfree; + sb->sv_sb_time = &sbd->s_time; + sb->sv_firstinodezone = 2; + sb->sv_firstdatazone = sbd->s_isize; + sb->sv_nzones = from_coh_ulong(sbd->s_fsize); + sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; + sb->sv_namelen = SYSV_NAMELEN; + sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone) << sb->sv_inodes_per_block_bits; + if (!silent) + printk("VFS: Found a V7 FS (block size = %d) on device %s.\n", + sb->sv_block_size, bdevname(dev)); + sb->s_magic = SYSV_MAGIC_BASE + FSTYPE_V7; + /* The buffer code now supports block size 512 as well as 1024. */ + sb->s_blocksize = sb->sv_block_size; + sb->s_blocksize_bits = sb->sv_block_size_bits; + /* set up enough so that it can read an inode */ + sb->s_dev = dev; + sb->s_op = &sysv_sops; + root_inode = iget(sb, SYSV_ROOT_INO); + sb->s_root = d_alloc_root(root_inode, NULL); + if (!sb->s_root) { + printk("SysV FS: get V7 FS root inode failed.\n"); + sysv_put_super(sb); + sb->s_dev = 0; + unlock_super(sb); + return NULL; + } + unlock_super(sb); + sb->s_dirt = 1; + /* brelse(bh); occurs when the disk is unmounted. */ + return sb; + +failed: + MOD_DEC_USE_COUNT; + return NULL; +} + struct super_block *sysv_read_super(struct super_block *sb,void *data, int silent) { @@ -346,29 +544,43 @@ kdev_t dev = sb->s_dev; struct inode *root_inode; unsigned long blocknr; + int block_size = BLOCK_SIZE; + + if (!sysv_parse_options((char *) data, silent)) { + printk("sysv_read_super: parse_options(sb, %s, %d) failed.\n", + (char *)data ? (char *)data : "(NULL)", silent); + return NULL; + } + + if (sysv_opt[bsize].val) + block_size = sysv_opt[bsize].val; if (1024 != sizeof (struct xenix_super_block)) - panic("Xenix FS: bad super-block size"); + panic("Xenix FS: bad super-block size."); if ((512 != sizeof (struct sysv4_super_block)) || (512 != sizeof (struct sysv2_super_block))) - panic("SystemV FS: bad super-block size"); + panic("System V FS: bad super-block size."); if (500 != sizeof (struct coh_super_block)) - panic("Coherent FS: bad super-block size"); + panic("Coherent FS: bad super-block size."); if (64 != sizeof (struct sysv_inode)) - panic("sysv fs: bad i-node size"); + panic("sysv_read_super: bad i-node size."); MOD_INC_USE_COUNT; lock_super(sb); - set_blocksize(dev,BLOCK_SIZE); - sb->sv_block_base = 0; + set_blocksize(dev, block_size); + sb->sv_block_base = sysv_opt[blk0].val; /* Try to read Xenix superblock */ - if ((bh = bread(dev, 1, BLOCK_SIZE)) != NULL) { + if ((bh = bread(dev, sb->sv_block_base + 1, block_size)) != NULL) { if ((found = detect_xenix(sb,bh)) != NULL) goto ok; brelse(bh); } - if ((bh = bread(dev, 0, BLOCK_SIZE)) != NULL) { - /* Try to recognize SystemV superblock */ + if ((bh = bread(dev, sb->sv_block_base + 0, block_size)) != NULL) { + + if (sysv_opt[debug].val >= 2) + printk("sysv_read_super: at %d*%d.\n", sb->sv_block_base, block_size); + + /* Try to recognize System V superblock */ if ((found = detect_sysv4(sb,bh)) != NULL) goto ok; if ((found = detect_sysv2(sb,bh)) != NULL) @@ -378,23 +590,23 @@ goto ok; brelse(bh); } - /* Try to recognize SystemV superblock */ + /* Try to recognize System V superblock */ /* Offset by 1 track, i.e. most probably 9, 15, or 18 kilobytes. */ /* 2kB blocks with offset of 9 and 15 kilobytes are not supported. */ /* Maybe we should also check the device geometry ? */ { static int offsets[] = { 9, 15, 18, }; int i; for (i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) - if ((bh = bread(dev, offsets[i], BLOCK_SIZE)) != NULL) { - /* Try to recognize SystemV superblock */ + if ((bh = bread(dev, offsets[i], block_size)) != NULL) { + /* Try to recognize System V superblock */ if ((found = detect_sysv4(sb,bh)) != NULL) { - if (sb->sv_block_size>BLOCK_SIZE && (offsets[i] % 2)) + if (sb->sv_block_size>block_size && (offsets[i] % 2)) goto bad_shift; sb->sv_block_base = (offsets[i] << sb->sv_block_size_dec_bits) >> sb->sv_block_size_inc_bits; goto ok; } if ((found = detect_sysv2(sb,bh)) != NULL) { - if (sb->sv_block_size>BLOCK_SIZE && (offsets[i] % 2)) + if (sb->sv_block_size>block_size && (offsets[i] % 2)) goto bad_shift; sb->sv_block_base = (offsets[i] << sb->sv_block_size_dec_bits) >> sb->sv_block_size_inc_bits; goto ok; @@ -406,15 +618,15 @@ sb->s_dev = 0; unlock_super(sb); if (!silent) - printk("VFS: unable to read Xenix/SystemV/Coherent superblock on device " - "%s\n", kdevname(dev)); + printk("SysV FS: unable to read superblock on device %s.\n", + bdevname(dev)); failed: MOD_DEC_USE_COUNT; return NULL; ok: - if (sb->sv_block_size >= BLOCK_SIZE) { - if (sb->sv_block_size != BLOCK_SIZE) { + if (sb->sv_block_size >= block_size) { + if (sb->sv_block_size != block_size) { brelse(bh); set_blocksize(dev, sb->sv_block_size); blocknr = (bh->b_blocknr << sb->sv_block_size_dec_bits) >> sb->sv_block_size_inc_bits; @@ -426,6 +638,7 @@ if (!detected_xenix(sb,bh,bh)) goto bad_superblock; break; + case FSTYPE_AFS: case FSTYPE_SYSV4: if (!detected_sysv4(sb,bh)) goto bad_superblock; @@ -440,7 +653,7 @@ brelse(bh); sb->s_dev = 0; unlock_super(sb); - printk("SysV FS: cannot read superblock in %d byte mode\n", sb->sv_block_size); + printk("SysV FS: cannot read superblock in %d byte mode..\n", sb->sv_block_size); goto failed; superblock_ok: } @@ -462,6 +675,7 @@ if (!detected_xenix(sb,bh1,bh2)) goto bad_superblock2; break; + case FSTYPE_AFS: case FSTYPE_SYSV4: if ((bh2 = bread(dev, blocknr+1, sb->sv_block_size)) == NULL) goto bad_superblock2; @@ -484,17 +698,19 @@ bad_superblock2: brelse(bh1); brelse(bh2); - set_blocksize(sb->s_dev,BLOCK_SIZE); + set_blocksize(sb->s_dev,block_size); sb->s_dev = 0; unlock_super(sb); - printk("SysV FS: cannot read superblock in 512 byte mode\n"); + printk("SysV FS: cannot read superblock in 512 byte mode.\n"); goto failed; } } sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone) << sb->sv_inodes_per_block_bits; if (!silent) - printk("VFS: Found a %s FS (block size = %d) on device %s\n", - found, sb->sv_block_size, kdevname(dev)); + printk("VFS: Found %s Filesystem (block size = %d, name length = %d) " + "on device %s.\n", found, sb->sv_block_size, + sb->sv_namelen, bdevname(dev)); + sb->s_magic = SYSV_MAGIC_BASE + sb->sv_type; /* The buffer code now supports block size 512 as well as 1024. */ sb->s_blocksize = sb->sv_block_size; @@ -505,7 +721,7 @@ root_inode = iget(sb,SYSV_ROOT_INO); sb->s_root = d_alloc_root(root_inode, NULL); if (!sb->s_root) { - printk("SysV FS: get root inode failed\n"); + printk("sysv_read_super: get root inode failed.\n"); sysv_put_super(sb); sb->s_dev = 0; unlock_super(sb); @@ -521,29 +737,67 @@ /* This is only called on sync() and umount(), when s_dirt=1. */ void sysv_write_super (struct super_block *sb) { + unsigned long time = CURRENT_TIME; + + if (sb->sv_sb_state) { + long state = 0; + int fix = 0; + + switch (sb->sv_type) { + case FSTYPE_AFS: + case FSTYPE_SYSV4: + if (sb->s_root) + state = FS_ACTIVE; + else + state = FS_OKAY - time; + fix++; + break; + case FSTYPE_SYSV2: + if (sb->s_root) + state = FS_ACTIVE; + else + state = FS_OKAY - (time + 1); + fix++; + break; + } + + if (fix && *sb->sv_sb_state != state) { + *sb->sv_sb_state = state; + mark_buffer_dirty(sb->sv_bh2, 1); + } + } + lock_super(sb); if (buffer_dirty(sb->sv_bh1) || buffer_dirty(sb->sv_bh2)) { /* If we are going to write out the super block, then attach current time stamp. - But if the filesystem was marked clean, keep it clean. */ - unsigned long time = CURRENT_TIME; - unsigned long old_time = *sb->sv_sb_time; - if (sb->sv_convert) - old_time = from_coh_ulong(old_time); - if (sb->sv_type == FSTYPE_SYSV4) - if (*sb->sv_sb_state == 0x7c269d38 - old_time) - *sb->sv_sb_state = 0x7c269d38 - time; + But if the file system was marked clean, keep it clean. */ if (sb->sv_convert) time = to_coh_ulong(time); *sb->sv_sb_time = time; + mark_buffer_dirty(sb->sv_bh2, 1); } + + if (sysv_opt[debug].val > 1) + printk("sysv_write_super: mounted=%c, state %x, time %x.\n", + (sb->s_root ? 'y' : 'n'), + (sb->sv_sb_state ? *sb->sv_sb_state : 0), + *sb->sv_sb_time); + sb->s_dirt = 0; unlock_super(sb); } void sysv_put_super(struct super_block *sb) { + + /* tried explicit write here, just to flush s_state of FS_OKAY, + but that *still* didn't convince SCO S51K/fsck (running under iBCS2) + that it was unmounted & safe to check */ + if (0) + sysv_write_super(sb); + /* we can assume sysv_write_super() has already been called, and that the superblock is locked */ brelse(sb->sv_bh1); @@ -559,14 +813,14 @@ { struct statfs tmp; - tmp.f_type = sb->s_magic; /* type of filesystem */ + tmp.f_type = sb->s_magic; /* type of file system */ tmp.f_bsize = sb->sv_block_size; /* block size */ tmp.f_blocks = sb->sv_ndatazones; /* total data blocks in file system */ tmp.f_bfree = sysv_count_free_blocks(sb); /* free blocks in fs */ tmp.f_bavail = tmp.f_bfree; /* free blocks available to non-superuser */ tmp.f_files = sb->sv_ninodes; /* total file nodes in file system */ tmp.f_ffree = sysv_count_free_inodes(sb); /* free file nodes in fs */ - tmp.f_namelen = SYSV_NAMELEN; + tmp.f_namelen = sb->sv_namelen; /* max length of directory entry */ /* Don't know what value to put in tmp.f_fsid */ /* file system id */ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; } @@ -645,10 +899,10 @@ return block_bmap(sb, bh, block & sb->sv_ind_per_block_1, convert); } if ((int)block<0) { - printk("sysv_bmap: block<0"); + printk("sysv_bmap: block < 0.\n"); return 0; } - printk("sysv_bmap: block>big"); + printk("sysv_bmap: block > big.\n"); return 0; } @@ -772,10 +1026,10 @@ return block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create); } if ((int)block<0) { - printk("sysv_getblk: block<0"); + printk("sysv_getblk: block < 0.\n"); return NULL; } - printk("sysv_getblk: block>big"); + printk("sysv_getblk: block > big.\n"); return NULL; } @@ -848,23 +1102,22 @@ inode->i_op = NULL; inode->i_mode = 0; if (!ino || ino > sb->sv_ninodes) { - printk("Bad inode number on dev %s" - ": %d is out of range\n", - kdevname(inode->i_dev), ino); + printk("sysv_read_inode: bad inode number on dev %s" + ": %d is out of range.\n", + bdevname(inode->i_dev), ino); return; } block = sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits); if (!(bh = sv_bread(sb,inode->i_dev,block))) { - printk("Major problem: unable to read inode from dev " - "%s\n", - kdevname(inode->i_dev)); + printk("sysv_read_inode: unable to read inode from %s.\n", + bdevname(inode->i_dev)); return; } raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1); mode = raw_inode->i_mode; if (sb->sv_kludge_symlinks) mode = from_coh_imode(mode); - /* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */ + /* System V FS: kludge permissions if ino==SYSV_ROOT_INO ?? */ inode->i_mode = mode; inode->i_uid = raw_inode->i_uid; inode->i_gid = raw_inode->i_gid; @@ -936,14 +1189,13 @@ ino = inode->i_ino; if (!ino || ino > sb->sv_ninodes) { - printk("Bad inode number on dev %s" - ": %d is out of range\n", - kdevname(inode->i_dev), ino); + printk("sysv_update_inode: bad inode number on dev %s" + ": %d is out of range.\n", bdevname(inode->i_dev), ino); return 0; } block = sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits); if (!(bh = sv_bread(sb,inode->i_dev,block))) { - printk("unable to read i-node block\n"); + printk("sysv_update_inode: unable to read i-node block.\n"); return 0; } raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1); @@ -996,9 +1248,9 @@ wait_on_buffer(bh); if (buffer_req(bh) && !buffer_uptodate(bh)) { - printk ("IO error syncing sysv inode [" - "%s:%08lx]\n", - kdevname(inode->i_dev), inode->i_ino); + printk ("sysv_sync_inode: IO error syncing inode %s, " + "%08lx.\n", + bdevname(inode->i_dev), inode->i_ino); err = -1; } } @@ -1008,24 +1260,21 @@ return err; } -/* Every kernel module contains stuff like this. */ - -static struct file_system_type sysv_fs_type[3] = { - {"xenix", FS_REQUIRES_DEV, sysv_read_super, NULL}, - {"sysv", FS_REQUIRES_DEV, sysv_read_super, NULL}, - {"coherent", FS_REQUIRES_DEV, sysv_read_super, NULL} +static struct file_system_type sysv_fs_type[2] = { + { "sysv", FS_REQUIRES_DEV, sysv_read_super, NULL }, + { "v7", FS_REQUIRES_DEV, v7_read_super, NULL }, }; -__initfunc(int init_sysv_fs(void)) +int __init init_sysv_fs(void) { int i; int ouch; - for (i = 0; i < 3; i++) { + for (i = 0; i < 2; i++) { if ((ouch = register_filesystem(&sysv_fs_type[i])) != 0) break; } - return ouch; + return ouch; } #ifdef MODULE @@ -1040,8 +1289,7 @@ { int i; - for (i = 0; i < 3; i++) - /* No error message if this breaks... that's OK... */ + for (i = 0; i < 2; i++) unregister_filesystem(&sysv_fs_type[i]); } diff -urN linux-2.3.0/fs/sysv/namei.c linux/fs/sysv/namei.c --- linux-2.3.0/fs/sysv/namei.c Wed May 12 12:55:19 1999 +++ linux/fs/sysv/namei.c Wed May 12 21:08:49 1999 @@ -9,7 +9,10 @@ * * sysv/namei.c * Copyright (C) 1993 Bruno Haible - * Copyright (C) 1997, 1998 Krzysztof G. Baranowski + * Copyright (C) 1995-1996 Peter Swain + * Copyright (C) 1997-2000 Krzysztof G. Baranowski + * + * See linux/MAINTAINERS for address of current maintainer. */ @@ -21,17 +24,22 @@ #include #include -/* compare strings: name[0..len-1] (not zero-terminated) and +/* + * compare strings: name[0..len-1] (not zero-terminated) and * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1]) */ static inline int namecompare(int len, int maxlen, - const char * name, const char * buffer) + const char * name, const struct sysv_dir_entry * de) { + int ret; + if (len > maxlen) - return 0; - if (len < maxlen && buffer[len]) - return 0; - return !memcmp(name, buffer, len); + ret = 0; + else if (len < maxlen && de->name[len]) + ret = 0; + else + ret = !memcmp(name, de->name, len); + return ret; } /* @@ -43,12 +51,44 @@ */ static int sysv_match(int len, const char * name, struct sysv_dir_entry * de) { - if (!de->inode || len > SYSV_NAMELEN) + struct sysv_dir_entry * final_de = de; + + if (!de->inode || de->inode == SYSV_PARTIAL_NAME) return 0; /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) return 1; - return namecompare(len, SYSV_NAMELEN, name, de->name); + + /* + * Process leading fragments in a EAFS multi-fragment name. + * Assumes inode -1 not used in non-EAFS, and chunks are all in + * one dir block. jump de[] back to putative beginning of name, + * and check all SYSV_NAMELEN-sized prefix fragments. + * Final chunk is checked by common code below. + */ + if (len > SYSV_NAMELEN) { + /* wind back to 0th chunk */ + de -= (len - 1) / SYSV_NAMELEN; + + do { + /* non-last chunks must have magic inum */ + if (de->inode != SYSV_PARTIAL_NAME) + return 0; + if (!namecompare(SYSV_NAMELEN,SYSV_NAMELEN,name,de)) + return 0; + + /* move to next chunk */ + len -= SYSV_NAMELEN; + name += SYSV_NAMELEN; + de++; + } while (len > SYSV_NAMELEN); + } + + if (final_de != de) + panic("SysV FS: match extended names out of sync: %p != %p\n", + final_de, de); + + return namecompare(len, SYSV_NAMELEN, name,de); } /* @@ -68,9 +108,9 @@ *res_dir = NULL; sb = dir->i_sb; - if (namelen > SYSV_NAMELEN) { + if (namelen > sb->sv_namelen) { if (sb->sv_truncate) - namelen = SYSV_NAMELEN; + namelen = sb->sv_namelen; else return NULL; } @@ -122,6 +162,27 @@ } /* + * Clear a dir entry, even if it is a multi-chunk EAFS long name. + */ +void sysv_clear_entry(struct buffer_head *bh, struct sysv_dir_entry *de) +{ + struct sysv_dir_entry *de0 = (struct sysv_dir_entry *) bh->b_data; + /*int blk = dir->i_sb->sv_block_size;*/ + int blk = 1024; + + if (!de || !bh || ((int)de - (int)de0) >= blk) { + printk("sysv_clear_entry: %p/%p.\n", de, de0); + return; + } + + do { + de->inode = 0; + } while (--de >= de0 && de->inode == SYSV_PARTIAL_NAME); + mark_buffer_dirty(bh, 1); +} + + +/* * sysv_add_entry() * * adds a file entry to the specified directory, returning a possible @@ -140,43 +201,81 @@ int i; unsigned long pos, block, offset; /* pos = block * block_size + offset */ struct buffer_head * bh; - struct sysv_dir_entry * de; + int skipchunks = 0; *res_buf = NULL; *res_dir = NULL; if (!dir) return -ENOENT; sb = dir->i_sb; - if (namelen > SYSV_NAMELEN) { + if (!sb) + return -ENOENT; + if (!namelen) + return -ENOENT; + + if (namelen > sb->sv_namelen) { if (sb->sv_truncate) - namelen = SYSV_NAMELEN; + namelen = sb->sv_namelen; else return -ENAMETOOLONG; } - if (!namelen) - return -ENOENT; + skipchunks = (namelen - 1) / SYSV_NAMELEN; + bh = NULL; - pos = block = offset = 0; + block = 0; + pos = offset = 0 * SYSV_NAMELEN; while (1) { + struct sysv_dir_entry *de; + struct sysv_dir_entry *de0; + if (!bh) { bh = sysv_file_bread(dir, block, 1); if (!bh) return -ENOSPC; } - de = (struct sysv_dir_entry *) (bh->b_data + offset); + de0 = (struct sysv_dir_entry *)bh->b_data; + de = de0 + offset/SYSV_DIRSIZE; + + /* pre-increment pos,offset for next time */ pos += SYSV_DIRSIZE; offset += SYSV_DIRSIZE; if (pos > dir->i_size) { - de->inode = 0; + sysv_clear_entry(bh, de); dir->i_size = pos; mark_inode_dirty(dir); } if (de->inode) { - if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) { + if (sysv_match(namelen, name, de)) { brelse(bh); return -EEXIST; } } else { + if (skipchunks > 0) { + int toobig = (skipchunks > offset/SYSV_DIRSIZE); + + /* + * SCO EAFS puts long names in SYSV_NAMELEN chunks + * chunks with all but the last having inum + * SYSV_PARTIAL_NAME. We don't split such a name over + * block boundaries. When created, it will span + * de[-(skipchunks-1) .. 0]. So must check for + * skipchunks non-empty slots. + */ + for (i = 0; !toobig && i <= skipchunks; i++) + if (de[-i].inode) + toobig++; + if (toobig) + continue; + + while (skipchunks > 0) { + for (i = 0; i < SYSV_NAMELEN ; i++) + de[-skipchunks].name[i] = name[i]; + de[-skipchunks].inode = SYSV_PARTIAL_NAME; + name += SYSV_NAMELEN; + namelen -= SYSV_NAMELEN; + skipchunks--; + } + } dir->i_mtime = dir->i_ctime = CURRENT_TIME; mark_inode_dirty(dir); for (i = 0; i < SYSV_NAMELEN ; i++) @@ -189,7 +288,8 @@ continue; brelse(bh); bh = NULL; - offset = 0; block++; + offset = 0; + block++; } *res_buf = bh; return 0; @@ -379,8 +479,8 @@ return 1; bad_dir: brelse(bh); - printk("Bad directory on device %s\n", - kdevname(inode->i_dev)); + printk("sysv_empty_dir: bad directory on device %s.\n", + bdevname(inode->i_dev)); return 1; } @@ -412,8 +512,8 @@ goto end_rmdir; } if (inode->i_nlink != 2) - printk("empty directory has nlink!=2 (%d)\n", inode->i_nlink); - de->inode = 0; + printk("sysv_rmdir: empty directory has nlink != 2 (%d).\n", inode->i_nlink); + sysv_clear_entry(bh, de); mark_buffer_dirty(bh, 1); inode->i_nlink=0; mark_inode_dirty(inode); @@ -450,16 +550,12 @@ schedule(); goto repeat; } - if (de->inode != inode->i_ino) { - retval = -ENOENT; - goto end_unlink; - } if (!inode->i_nlink) { - printk("Deleting nonexistent file (%s:%lu), %d\n", - kdevname(inode->i_dev), inode->i_ino, inode->i_nlink); + printk("sysv_unlink: deleting nonexistent file %s, %lu, %d.\n", + bdevname(inode->i_dev), inode->i_ino, inode->i_nlink); inode->i_nlink=1; } - de->inode = 0; + sysv_clear_entry(bh, de); mark_buffer_dirty(bh, 1); dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); @@ -645,7 +741,7 @@ if (old_de->inode != old_inode->i_ino) goto try_again; /* ok, that's it */ - old_de->inode = 0; + sysv_clear_entry(old_bh, old_de); new_de->inode = old_inode->i_ino; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; mark_inode_dirty(old_dir); diff -urN linux-2.3.0/fs/sysv/symlink.c linux/fs/sysv/symlink.c --- linux-2.3.0/fs/sysv/symlink.c Sun Oct 4 23:55:03 1998 +++ linux/fs/sysv/symlink.c Wed May 12 21:08:49 1999 @@ -10,7 +10,9 @@ * sysv/symlink.c * Copyright (C) 1993 Bruno Haible * - * SystemV/Coherent symlink handling code + * Symlink handling code. + * + * See linux/MAINTAINERS for address of current maintainer. */ #include diff -urN linux-2.3.0/fs/sysv/truncate.c linux/fs/sysv/truncate.c --- linux-2.3.0/fs/sysv/truncate.c Sun Oct 4 23:54:54 1998 +++ linux/fs/sysv/truncate.c Wed May 12 21:08:49 1999 @@ -9,6 +9,8 @@ * * sysv/truncate.c * Copyright (C) 1993 Bruno Haible + * + * See linux/MAINTAINERS for address of current maintainer. */ #include @@ -17,13 +19,14 @@ #include -/* Linus' implementation of truncate. +/* + * Linus' implementation of truncate. * It doesn't need locking because it can tell from looking at bh->b_count * whether a given block is in use elsewhere. */ /* - * Truncate has the most races in the whole filesystem: coding it is + * Truncate has the most races in the whole file system: coding it is * a pain in the a**, especially as I don't do any locking. * * The code may look a bit weird, but that's just because I've tried to @@ -269,7 +272,8 @@ void sysv_truncate(struct inode * inode) { - /* If this is called from sysv_put_inode, we needn't worry about + /* + * If this is called from sysv_put_inode, we needn't worry about * races as we are just losing the last reference to the inode. * If this is called from another place, let's hope it's a regular * file. @@ -278,7 +282,7 @@ * a regular file we are just writing to, by use of a lock. */ if (S_ISLNK(inode->i_mode)) - printk("sysv_truncate: truncating symbolic link\n"); + printk("sysv_truncate: truncating symbolic link.\n"); else if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) return; while (trunc_all(inode)) { diff -urN linux-2.3.0/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h --- linux-2.3.0/include/linux/sysv_fs.h Wed Apr 28 21:44:10 1999 +++ linux/include/linux/sysv_fs.h Wed May 12 21:08:49 1999 @@ -2,7 +2,7 @@ #define _LINUX_SYSV_FS_H /* - * The SystemV/Coherent filesystem constants/structures/macros + * The SystemV/V7/Coherent filesystem constants/structures/macros */ @@ -22,6 +22,26 @@ #include /* declares wake_up() */ #include /* defines the sv_... shortcuts */ +typedef struct { + const char *name; + int deflt; + int val; +} iopt; + +#define Iopt(name, dflt) [name] {#name, dflt} + +enum { + min_opt = 0, + debug, + bsize, + blk0, + trunc, + check, + convert_afs, + max_opt +}; + +extern iopt sysv_opt[max_opt]; /* Layout on disk */ /* ============== */ @@ -61,7 +81,7 @@ typedef u32 sysv_zone_t; /* Among the blocks ... */ -/* Xenix FS, Coherent FS: block 0 is the boot block, block 1 the super-block. +/* Xenix FS, V7 FS, Coherent FS: block 0 is the boot block, block 1 the super-block. SystemV FS: block 0 contains both the boot sector and the super-block. */ /* The first inode zone is sb->sv_firstinodezone (1 or 2). */ @@ -188,6 +208,41 @@ u32 fl_free[SYSV_NICFREE] __packed2__; }; +/* V7 super-block data on disk */ +#define V7_NICINOD 100 /* number of inode cache entries */ +#define V7_NICFREE 50 /* number of free block list chunk entries */ +struct v7_super_block { + u16 s_isize; /* index of first data zone */ + u32 s_fsize __packed2__; /* total number of zones of this fs */ + /* the start of the free block list: */ + u16 s_nfree; /* number of free blocks in s_free, <= V7_NICFREE */ + u32 s_free[V7_NICFREE]; /* first free block list chunk */ + /* the cache of free inodes: */ + u16 s_ninode; /* number of free inodes in s_inode, <= V7_NICINOD */ + sysv_ino_t s_inode[V7_NICINOD]; /* some free inodes */ + /* locks, not used by Linux or V7: */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ + u32 s_time __packed2__; /* time of last super block update */ + /* the following fields are not maintained by V7: */ + u32 s_tfree __packed2__; /* total number of free zones */ + u16 s_tinode; /* total number of free inodes */ + u16 s_m; /* interleave factor */ + u16 s_n; /* interleave factor */ + char s_fname[6]; /* file system name */ + char s_fpack[6]; /* file system pack name */ +}; + +/* V7 free list block on disk */ +struct v7_freelist_chunk { + u16 fl_nfree; /* number of free blocks in fl_free, <= +V7_NICFREE] */ + u32 fl_free[V7_NICFREE] __packed2__; +}; + + /* Coherent super-block data on disk */ #define COH_NICINOD 100 /* number of inode cache entries */ #define COH_NICFREE 64 /* number of free block list chunk entries */ @@ -222,7 +277,7 @@ }; -/* SystemV/Coherent inode data on disk */ +/* SystemV/V7/Coherent inode data on disk */ struct sysv_inode { u16 i_mode; @@ -302,6 +357,7 @@ /* Admissible values for i_nlink: 0.._LINK_MAX */ #define XENIX_LINK_MAX 126 /* ?? */ #define SYSV_LINK_MAX 126 /* 127? 251? */ +#define V7_LINK_MAX 126 /* ?? */ #define COH_LINK_MAX 10000 /* max number of hard links to an inode */ /* The number of inodes per block is @@ -310,7 +366,7 @@ sb->sv_ind_per_block = block_size / sizeof(u32) */ -/* SystemV/Coherent directory entry on disk */ +/* SystemV/V7/Coherent directory entry on disk */ #define SYSV_NAMELEN 14 /* max size of name in struct sysv_dir_entry */ @@ -321,26 +377,33 @@ #define SYSV_DIRSIZE sizeof(struct sysv_dir_entry) /* size of every directory entry */ +#define SYSV_LONG_NAMELEN 255 /* max size of EAFS multi-chunk names */ +#define SYSV_PARTIAL_NAME ((sysv_ino_t) -1) /* this name continues */ -/* Operations */ -/* ========== */ - - -/* identify the FS in memory */ -#define FSTYPE_XENIX 1 -#define FSTYPE_SYSV4 2 -#define FSTYPE_SYSV2 3 -#define FSTYPE_COH 4 - -#define SYSV_MAGIC_BASE 0x012FF7B3 - -#define XENIX_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_XENIX) -#define SYSV4_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_SYSV4) -#define SYSV2_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_SYSV2) -#define COH_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_COH) +enum { + FSTYPE_NONE = 0, + FSTYPE_XENIX, + FSTYPE_SYSV4, + FSTYPE_SYSV2, + FSTYPE_COH, + FSTYPE_AFS, + FSTYPE_V7, + FSTYPE_END, + + SYSV_MAGIC_BASE = 0x012FF7B3, + + SYSV_FSMAGIC = 0xfd187e20, + SYSV_FSEMAGIC = 0xfd187e21, + SYSV_BITMAP_FREELIST = 0xffff, + FS_OKAY = 0x7c269d38, + FS_ACTIVE = 0x5e72d81a, +}; #ifdef __KERNEL__ +/* Operations */ +/* ========== */ + /* sv_get_hash_table(sb,dev,block) is equivalent to get_hash_table(dev,block,block_size) */ static inline struct buffer_head * sv_get_hash_table (struct super_block *sb, kdev_t dev, unsigned int block) @@ -402,6 +465,7 @@ extern int sysv_sync_inode(struct inode *); extern int sysv_sync_file(struct file *, struct dentry *); extern int sysv_mmap(struct file *, struct vm_area_struct *); +extern void sysv_clear_entry(struct buffer_head *bh, struct sysv_dir_entry *de); extern struct inode_operations sysv_file_inode_operations; extern struct inode_operations sysv_file_inode_operations_with_bmap; diff -urN linux-2.3.0/include/linux/sysv_fs_i.h linux/include/linux/sysv_fs_i.h --- linux-2.3.0/include/linux/sysv_fs_i.h Sun Oct 4 23:54:55 1998 +++ linux/include/linux/sysv_fs_i.h Wed May 12 21:08:49 1999 @@ -2,7 +2,7 @@ #define _SYSV_FS_I /* - * SystemV/Coherent FS inode data in memory + * SystemV/V7/Coherent FS inode data in memory */ struct sysv_inode_info { u32 i_data[10+1+1+1]; /* zone numbers: max. 10 data blocks, diff -urN linux-2.3.0/include/linux/sysv_fs_sb.h linux/include/linux/sysv_fs_sb.h --- linux-2.3.0/include/linux/sysv_fs_sb.h Sun Oct 4 23:54:55 1998 +++ linux/include/linux/sysv_fs_sb.h Wed May 12 21:08:49 1999 @@ -2,8 +2,8 @@ #define _SYSV_FS_SB /* - * SystemV/Coherent super-block data in memory - * The SystemV/Coherent superblock contains dynamic data (it gets modified + * SystemV/V7/Coherent super-block data in memory + * The SystemV/V7/Coherent superblock contains dynamic data (it gets modified * while the system is running). This is in contrast to the Minix and Berkeley * filesystems (where the superblock is never modified). This affects the * sync() operation: we must keep the superblock in a disk buffer and use this @@ -65,6 +65,7 @@ u32 s_ninodes; /* total number of inodes */ u32 s_ndatazones; /* total number of data zones */ u32 s_nzones; /* same as s_sbd->s_fsize */ + u16 s_namelen; /* max length of dir entry */ }; /* The fields s_ind_per_block_2_1, s_toobig_block are currently unused. */ @@ -117,6 +118,6 @@ #define sv_ninodes u.sysv_sb.s_ninodes #define sv_ndatazones u.sysv_sb.s_ndatazones #define sv_nzones u.sysv_sb.s_nzones +#define sv_namelen u.sysv_sb.s_namelen #endif -