You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(6) |
Sep
(2) |
Oct
(43) |
Nov
(4) |
Dec
(12) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(78) |
Feb
(97) |
Mar
(29) |
Apr
(2) |
May
(22) |
Jun
(38) |
Jul
(11) |
Aug
(27) |
Sep
(40) |
Oct
(2) |
Nov
(17) |
Dec
(8) |
2002 |
Jan
|
Feb
(2) |
Mar
(1) |
Apr
(480) |
May
(456) |
Jun
(12) |
Jul
|
Aug
(1) |
Sep
|
Oct
(18) |
Nov
(3) |
Dec
(6) |
2003 |
Jan
|
Feb
(18) |
Mar
(1) |
Apr
|
May
(6) |
Jun
(147) |
Jul
(7) |
Aug
(3) |
Sep
(235) |
Oct
(10) |
Nov
(2) |
Dec
(1) |
2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Andy P. <at...@us...> - 2002-04-09 15:08:11
|
Update of /cvsroot/linux-vax/kernel-2.4/fs/ncpfs In directory usw-pr-cvs1:/tmp/cvs-serv29245/ncpfs Modified Files: dir.c file.c inode.c ioctl.c mmap.c ncplib_kernel.c ncpsign_kernel.c Log Message: synch 2.4.15 commit 13 Index: dir.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/ncpfs/dir.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- dir.c 25 Feb 2001 23:14:46 -0000 1.1.1.2 +++ dir.c 9 Apr 2002 13:19:35 -0000 1.2 @@ -326,56 +326,15 @@ return res; } -/* most parts from nfsd_d_validate() */ -static int -ncp_d_validate(struct dentry *dentry) -{ - unsigned long dent_addr = (unsigned long) dentry; - unsigned long min_addr = PAGE_OFFSET; - unsigned long align_mask = 0x0F; - unsigned int len; - int valid = 0; - - if (dent_addr < min_addr) - goto bad_addr; - if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry)) - goto bad_addr; - if ((dent_addr & ~align_mask) != dent_addr) - goto bad_align; - if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 + - sizeof(struct dentry)))) - goto bad_addr; - /* - * Looks safe enough to dereference ... - */ - len = dentry->d_name.len; - if (len > NCP_MAXPATHLEN) - goto out; - /* - * Note: d_validate doesn't dereference the parent pointer ... - * just combines it with the name hash to find the hash chain. - */ - valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len); -out: - return valid; - -bad_addr: - PRINTK("ncp_d_validate: invalid address %lx\n", dent_addr); - goto out; -bad_align: - PRINTK("ncp_d_validate: unaligned address %lx\n", dent_addr); - goto out; -} - static struct dentry * ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) { struct dentry *dent = dentry; struct list_head *next; - if (ncp_d_validate(dent)) { - if (dent->d_parent == parent && - (unsigned long)dent->d_fsdata == fpos) { + if (d_validate(dent, parent)) { + if (dent->d_name.len <= NCP_MAXPATHLEN && + (unsigned long)dent->d_fsdata == fpos) { if (!dent->d_inode) { dput(dent); dent = NULL; @@ -580,6 +539,7 @@ struct ncp_cache_control ctl = *ctrl; struct qstr qname; int valid = 0; + int hashed = 0; ino_t ino = 0; __u8 __name[256]; @@ -602,9 +562,11 @@ newdent = d_alloc(dentry, &qname); if (!newdent) goto end_advance; - } else + } else { + hashed = 1; memcpy((char *) newdent->d_name.name, qname.name, newdent->d_name.len); + } if (!newdent->d_inode) { entry->opened = 0; @@ -612,7 +574,9 @@ newino = ncp_iget(inode->i_sb, entry); if (newino) { newdent->d_op = &ncp_dentry_operations; - d_add(newdent, newino); + d_instantiate(newdent, newino); + if (!hashed) + d_rehash(newdent); } } else ncp_update_inode2(newdent->d_inode, entry); Index: file.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/ncpfs/file.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- file.c 25 Feb 2001 23:14:46 -0000 1.1.1.2 +++ file.c 9 Apr 2002 13:19:35 -0000 1.2 @@ -22,11 +22,6 @@ #include <linux/ncp_fs.h> #include "ncplib_kernel.h" -static inline unsigned int min(unsigned int a, unsigned int b) -{ - return a < b ? a : b; -} - static int ncp_fsync(struct file *file, struct dentry *dentry, int datasync) { return 0; @@ -157,8 +152,9 @@ /* First read in as much as possible for each bufsize. */ while (already_read < count) { int read_this_time; - size_t to_read = min(bufsize - (pos % bufsize), - count - already_read); + size_t to_read = min_t(unsigned int, + bufsize - (pos % bufsize), + count - already_read); error = ncp_read_bounce(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, @@ -238,8 +234,9 @@ } while (already_written < count) { int written_this_time; - size_t to_write = min(bufsize - (pos % bufsize), - count - already_written); + size_t to_write = min_t(unsigned int, + bufsize - (pos % bufsize), + count - already_written); if (copy_from_user(bouncebuffer, buf, to_write)) { errno = -EFAULT; @@ -284,6 +281,7 @@ struct file_operations ncp_file_operations = { + llseek: generic_file_llseek, read: ncp_file_read, write: ncp_file_write, ioctl: ncp_ioctl, Index: inode.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/ncpfs/inode.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- inode.c 25 Feb 2001 23:14:46 -0000 1.1.1.2 +++ inode.c 9 Apr 2002 13:19:35 -0000 1.2 @@ -692,7 +692,7 @@ ncp_inode_close(inode); result = ncp_make_closed(inode); if (!result) - vmtruncate(inode, attr->ia_size); + result = vmtruncate(inode, attr->ia_size); } out: return result; @@ -730,3 +730,4 @@ module_init(init_ncp_fs) module_exit(exit_ncp_fs) +MODULE_LICENSE("GPL"); Index: ioctl.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/ncpfs/ioctl.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- ioctl.c 14 Jan 2001 16:28:42 -0000 1.1.1.1 +++ ioctl.c 9 Apr 2002 13:19:35 -0000 1.2 @@ -378,7 +378,7 @@ } { struct ncp_objectname_ioctl user; - int outl; + size_t outl; if (copy_from_user(&user, (struct ncp_objectname_ioctl*)arg, @@ -448,7 +448,7 @@ } { struct ncp_privatedata_ioctl user; - int outl; + size_t outl; if (copy_from_user(&user, (struct ncp_privatedata_ioctl*)arg, Index: mmap.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/ncpfs/mmap.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- mmap.c 25 Feb 2001 23:14:46 -0000 1.1.1.2 +++ mmap.c 9 Apr 2002 13:19:35 -0000 1.2 @@ -22,11 +22,6 @@ #include <asm/uaccess.h> #include <asm/system.h> -static inline int min(int a, int b) -{ - return a < b ? a : b; -} - /* * Fill in the supplied page for mmap */ @@ -43,7 +38,7 @@ int bufsize; int pos; - page = alloc_page(GFP_HIGHMEM); /* ncpfs has nothing against GFP_HIGHMEM + page = alloc_page(GFP_HIGHUSER); /* ncpfs has nothing against high pages as long as recvmsg and memset works on it */ if (!page) return page; @@ -66,7 +61,7 @@ to_read = bufsize - (pos % bufsize); - to_read = min(to_read, count - already_read); + to_read = min_t(unsigned int, to_read, count - already_read); if (ncp_read_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, Index: ncplib_kernel.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/ncpfs/ncplib_kernel.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- ncplib_kernel.c 14 Jan 2001 16:28:48 -0000 1.1.1.1 +++ ncplib_kernel.c 9 Apr 2002 13:19:35 -0000 1.2 @@ -13,11 +13,6 @@ #include "ncplib_kernel.h" -static inline int min(int a, int b) -{ - return a < b ? a : b; -} - static inline void assert_server_locked(struct ncp_server *server) { if (server->lock == 0) { @@ -132,7 +127,7 @@ ncp_unlock_server(server); return result; } - *target = min(ntohs(ncp_reply_word(server, 0)), size); + *target = min_t(unsigned int, ntohs(ncp_reply_word(server, 0)), size); ncp_unlock_server(server); return 0; @@ -163,7 +158,8 @@ /* NCP over UDP returns 0 (!!!) */ result = ntohs(ncp_reply_word(server, 0)); - if (result >= NCP_BLOCK_SIZE) size=min(result, size); + if (result >= NCP_BLOCK_SIZE) + size = min(result, size); *ret_size = size; *ret_options = ncp_reply_byte(server, 4); Index: ncpsign_kernel.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/ncpfs/ncpsign_kernel.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- ncpsign_kernel.c 14 Jan 2001 16:28:50 -0000 1.1.1.1 +++ ncpsign_kernel.c 9 Apr 2002 13:19:35 -0000 1.2 @@ -52,8 +52,6 @@ #define PUT_LE32(p,v) DSET_LH(p,0,v) #endif -#define min(a,b) ((a)<(b)?(a):(b)) - static void nwsign(char *r_data1, char *r_data2, char *outdata) { int i; unsigned int w0,w1,w2,w3; @@ -102,7 +100,7 @@ memcpy(data,server->sign_root,8); PUT_LE32(data+8,(*size)); memcpy(data+12,server->packet+sizeof(struct ncp_request_header)-1, - min((*size)-sizeof(struct ncp_request_header)+1,52)); + min_t(unsigned int,(*size)-sizeof(struct ncp_request_header)+1,52)); nwsign(server->sign_last,data,server->sign_last); |
From: Andy P. <at...@us...> - 2002-04-09 14:55:24
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/arm/mach-epxa10db In directory usw-pr-cvs1:/tmp/cvs-serv1225/arch/arm/mach-epxa10db Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/arm/mach-epxa10db added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:55:15
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/arm/mach-anakin In directory usw-pr-cvs1:/tmp/cvs-serv1161/arch/arm/mach-anakin Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/arm/mach-anakin added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:55:04
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/arm/mach-ebsa110 In directory usw-pr-cvs1:/tmp/cvs-serv1024/arch/arm/mach-ebsa110 Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/arm/mach-ebsa110 added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:54:53
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/arm/mach-integrator In directory usw-pr-cvs1:/tmp/cvs-serv926/arch/arm/mach-integrator Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/arm/mach-integrator added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:51:06
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/sh/stboards In directory usw-pr-cvs1:/tmp/cvs-serv32002/arch/sh/stboards Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/sh/stboards added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:48:32
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/mips64/mips-boards/generic In directory usw-pr-cvs1:/tmp/cvs-serv30954/generic Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/mips64/mips-boards/generic added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:48:32
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/mips64/mips-boards/malta In directory usw-pr-cvs1:/tmp/cvs-serv30954/malta Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/mips64/mips-boards/malta added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:48:32
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/mips64/mips-boards/atlas In directory usw-pr-cvs1:/tmp/cvs-serv30954/atlas Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/mips64/mips-boards/atlas added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:46:45
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/mips64/sgi-ip32 In directory usw-pr-cvs1:/tmp/cvs-serv30209/arch/mips64/sgi-ip32 Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/mips64/sgi-ip32 added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:46:44
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/mips64/math-emu In directory usw-pr-cvs1:/tmp/cvs-serv30209/arch/mips64/math-emu Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/mips64/math-emu added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:46:44
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/mips64/mips-boards In directory usw-pr-cvs1:/tmp/cvs-serv30209/arch/mips64/mips-boards Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/mips64/mips-boards added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:39:37
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/cris/drivers/lpslave In directory usw-pr-cvs1:/tmp/cvs-serv27501/arch/cris/drivers/lpslave Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/cris/drivers/lpslave added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:37:50
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/cris/boot/tools In directory usw-pr-cvs1:/tmp/cvs-serv26742/arch/cris/boot/tools Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/cris/boot/tools added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:37:42
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/cris/boot/rescue In directory usw-pr-cvs1:/tmp/cvs-serv26669/arch/cris/boot/rescue Log Message: Directory /cvsroot/linux-vax/kernel-2.4/arch/cris/boot/rescue added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:32:37
|
Update of /cvsroot/linux-vax/kernel-2.4/Documentation/mips In directory usw-pr-cvs1:/tmp/cvs-serv24993/Documentation/mips Log Message: Directory /cvsroot/linux-vax/kernel-2.4/Documentation/mips added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:19:00
|
Update of /cvsroot/linux-vax/kernel-2.4/drivers/acpi/kdb In directory usw-pr-cvs1:/tmp/cvs-serv19932/acpi/kdb Added Files: README.txt kdbm_acpi.c Log Message: synch 2.4.15 commit 17 --- NEW FILE --- Using the ACPI debugger with kdb -------------------------------- ACPI CA includes a full-featured debugger, which allows the examination of a running system's ACPI tables, as well as running and stepping through control methods. Configuration ------------- 1) Edit the main acpi Makefile. On the ACPI_CFLAGS line, remove the '#', thus enabling the debugger. 2) Download the latest kdb patch from: ftp://oss.sgi.com/www/projects/kdb/download/ix86/ Follow the instructions at http://oss.sgi.com/projects/kdb/ on how to install the patch and configure KDB. 3) This would probably be a good time to recompile the kernel, and make sure kdb works (Hitting the Pause key should drop you into it. Type "go" to exit it. 4) The kdb <--> ACPI debugger interface is a module. Type "make modules", and it will be built and placed in drivers/acpi/kdb. 5) Change to that directory and type "insmod kdbm_acpi.o". This loads the module we just built. 6) Break back into kdb. If you type help, you should now see "acpi" listed as a command, at the bottom. 7) Type "acpi". You are now in the ACPI debugger. While hosted by kdb, it is wholly separate, and has many ACPI-specific commands. Type "?" or "help" to get a listing of the command categories, and then "help <category>" for a list of commands and their descriptions --- NEW FILE --- /* * kdbm_acpi.c - kdb debugger module interface for ACPI debugger * * Copyright (C) 2000 Andrew Grover * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/types.h> #include <linux/kdb.h> #include <linux/module.h> #include "acpi.h" #include "acdebug.h" extern int acpi_in_debugger; static int kdbm_acpi(int argc, const char **argv, const char **envp, struct pt_regs *regs) { acpi_in_debugger = 1; acpi_db_user_commands(DB_COMMAND_PROMPT, NULL); acpi_in_debugger = 0; return 0; } int init_module(void) { kdb_register("acpi", kdbm_acpi, "", "Enter ACPI debugger", 0); return 0; } void cleanup_module(void) { kdb_unregister("acpi"); } |
From: Andy P. <at...@us...> - 2002-04-09 14:11:27
|
Update of /cvsroot/linux-vax/kernel-2.4/drivers/message/fusion/lsi In directory usw-pr-cvs1:/tmp/cvs-serv17320/lsi Log Message: Directory /cvsroot/linux-vax/kernel-2.4/drivers/message/fusion/lsi added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:10:44
|
Update of /cvsroot/linux-vax/kernel-2.4/drivers/message/fusion In directory usw-pr-cvs1:/tmp/cvs-serv17041/fusion Log Message: Directory /cvsroot/linux-vax/kernel-2.4/drivers/message/fusion added to the repository |
From: Andy P. <at...@us...> - 2002-04-09 14:10:44
|
Update of /cvsroot/linux-vax/kernel-2.4/drivers/message/i2o In directory usw-pr-cvs1:/tmp/cvs-serv17041/i2o Log Message: Directory /cvsroot/linux-vax/kernel-2.4/drivers/message/i2o added to the repository |
Update of /cvsroot/linux-vax/kernel-2.4/fs/jffs2 In directory usw-pr-cvs1:/tmp/cvs-serv29245/jffs2 Added Files: Makefile TODO background.c build.c compr.c compr_rtime.c compr_rubin.c compr_rubin.h compr_zlib.c comprtest.c crc32.c crc32.h dir.c erase.c file.c gc.c histo.h histo_mips.h ioctl.c malloc.c nodelist.c nodelist.h nodemgmt.c pushpull.c pushpull.h read.c readinode.c scan.c super.c symlink.c write.c zlib.c zlib.h Log Message: synch 2.4.15 commit 13 --- NEW FILE --- # # Makefile for the linux Journalling Flash FileSystem (JFFS) routines. # # $Id: Makefile,v 1.1 2002/04/09 13:19:33 atp Exp $ # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). # # Note 2! The CFLAGS definitions are now in the main makefile... COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o pushpull.o \ compr_zlib.o zlib.o JFFS2_OBJS := crc32.o dir.o file.o ioctl.o nodelist.o malloc.o \ read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \ symlink.o build.o erase.o background.o O_TARGET := jffs2.o obj-y := $(COMPR_OBJS) $(JFFS2_OBJS) obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make --- NEW FILE --- $Id: TODO,v 1.1 2002/04/09 13:19:33 atp Exp $ - disable compression in commit_write()? Or at least optimise the 'always write whole page' bit. - fix zlib. It's ugly as hell and there are at least three copies in the kernel tree - fine-tune the allocation / GC thresholds - chattr support - turning on/off and tuning compression per-inode - checkpointing (do we need this? scan is quite fast) - make the scan code populate real inodes so read_inode just after mount doesn't have to read the flash twice for large files. Make this a per-inode option, changable with chattr, so you can decide which inodes should be in-core immediately after mount. - stop it depending on a block device. mount(8) needs a change for this. - make it work on NAND flash. We need to know when we can GC deletion dirents, etc. And think about holes/truncation. It can all be done reasonably simply, but it need implementing. - NAND flash will require new dirent/dnode structures on the medium with ECC data in rather than just the CRC we're using ATM. - test, test, test --- NEW FILE --- /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright (C) 2001 Red Hat, Inc. * * Created by David Woodhouse <dw...@ca...> * * The original JFFS, from which the design for JFFS2 was derived, * was designed and implemented by Axis Communications AB. * * The contents of this file are subject to the Red Hat eCos Public * License Version 1.1 (the "Licence"); you may not use this file * except in compliance with the Licence. You may obtain a copy of * the Licence at http://www.redhat.com/ * * Software distributed under the Licence is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the Licence for the specific language governing rights and * limitations under the Licence. * * The Original Code is JFFS2 - Journalling Flash File System, version 2 * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License version 2 (the "GPL"), in * which case the provisions of the GPL are applicable instead of the * above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the RHEPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * * $Id: background.c,v 1.1 2002/04/09 13:19:33 atp Exp $ * */ #define __KERNEL_SYSCALLS__ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/unistd.h> #include <linux/jffs2.h> #include <linux/mtd/mtd.h> #include <linux/interrupt.h> #include <linux/completion.h> #include "nodelist.h" static int jffs2_garbage_collect_thread(void *); static int thread_should_wake(struct jffs2_sb_info *c); void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) { spin_lock_bh(&c->erase_completion_lock); if (c->gc_task && thread_should_wake(c)) send_sig(SIGHUP, c->gc_task, 1); spin_unlock_bh(&c->erase_completion_lock); } /* This must only ever be called when no GC thread is currently running */ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) { pid_t pid; int ret = 0; if (c->gc_task) BUG(); init_MUTEX_LOCKED(&c->gc_thread_start); init_completion(&c->gc_thread_exit); pid = kernel_thread(jffs2_garbage_collect_thread, c, CLONE_FS|CLONE_FILES); if (pid < 0) { printk(KERN_WARNING "fork failed for JFFS2 garbage collect thread: %d\n", -pid); complete(&c->gc_thread_exit); ret = pid; } else { /* Wait for it... */ D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid)); down(&c->gc_thread_start); } return ret; } void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) { spin_lock_bh(&c->erase_completion_lock); if (c->gc_task) { D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid)); send_sig(SIGKILL, c->gc_task, 1); } spin_unlock_bh(&c->erase_completion_lock); wait_for_completion(&c->gc_thread_exit); } static int jffs2_garbage_collect_thread(void *_c) { struct jffs2_sb_info *c = _c; daemonize(); current->tty = NULL; c->gc_task = current; up(&c->gc_thread_start); sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index); /* FIXME in the 2.2 backport */ current->nice = 10; for (;;) { spin_lock_irq(¤t->sigmask_lock); siginitsetinv (¤t->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); if (!thread_should_wake(c)) { set_current_state (TASK_INTERRUPTIBLE); D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); /* Yes, there's a race here; we checked thread_should_wake() before setting current->state to TASK_INTERRUPTIBLE. But it doesn't matter - We don't care if we miss a wakeup, because the GC thread is only an optimisation anyway. */ schedule(); } if (current->need_resched) schedule(); /* Put_super will send a SIGKILL and then wait on the sem. */ while (signal_pending(current)) { siginfo_t info; unsigned long signr; spin_lock_irq(¤t->sigmask_lock); signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); switch(signr) { case SIGSTOP: D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGSTOP received.\n")); set_current_state(TASK_STOPPED); schedule(); break; case SIGKILL: D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n")); spin_lock_bh(&c->erase_completion_lock); c->gc_task = NULL; spin_unlock_bh(&c->erase_completion_lock); complete_and_exit(&c->gc_thread_exit, 0); case SIGHUP: D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGHUP received.\n")); break; default: D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): signal %ld received\n", signr)); } } /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */ spin_lock_irq(¤t->sigmask_lock); siginitsetinv (¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n")); jffs2_garbage_collect_pass(c); } } static int thread_should_wake(struct jffs2_sb_info *c) { D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x\n", c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size)); if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER && c->dirty_size > c->sector_size) return 1; else return 0; } --- NEW FILE --- /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright (C) 2001 Red Hat, Inc. * * Created by David Woodhouse <dw...@ca...> * * The original JFFS, from which the design for JFFS2 was derived, * was designed and implemented by Axis Communications AB. * * The contents of this file are subject to the Red Hat eCos Public * License Version 1.1 (the "Licence"); you may not use this file * except in compliance with the Licence. You may obtain a copy of * the Licence at http://www.redhat.com/ * * Software distributed under the Licence is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the Licence for the specific language governing rights and * limitations under the Licence. * * The Original Code is JFFS2 - Journalling Flash File System, version 2 * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License version 2 (the "GPL"), in * which case the provisions of the GPL are applicable instead of the * above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the RHEPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * * $Id: build.c,v 1.1 2002/04/09 13:19:33 atp Exp $ * */ #include <linux/kernel.h> #include <linux/jffs2.h> #include <linux/slab.h> #include "nodelist.h" int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *); int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *); #define for_each_inode(i, c, ic) for (i=0; i<INOCACHE_HASHSIZE; i++) for (ic=c->inocache_list[i]; ic; ic=ic->next) /* Scan plan: - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go - Scan directory tree from top down, setting nlink in inocaches - Scan inocaches for inodes with nlink==0 */ int jffs2_build_filesystem(struct jffs2_sb_info *c) { int ret; int i; struct jffs2_inode_cache *ic; /* First, scan the medium and build all the inode caches with lists of physical nodes */ ret = jffs2_scan_medium(c); if (ret) return ret; D1(printk(KERN_DEBUG "Scanned flash completely\n")); /* Now build the data map for each inode, marking obsoleted nodes as such, and also increase nlink of any children. */ for_each_inode(i, c, ic) { D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino)); ret = jffs2_build_inode_pass1(c, ic); if (ret) { D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret)); return ret; } } D1(printk(KERN_DEBUG "Pass 1 complete\n")); /* Next, scan for inodes with nlink == 0 and remove them. If they were directories, then decrement the nlink of their children too, and repeat the scan. As that's going to be a fairly uncommon occurrence, it's not so evil to do it this way. Recursion bad. */ do { D1(printk(KERN_DEBUG "Pass 2 (re)starting\n")); ret = 0; for_each_inode(i, c, ic) { D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes)); if (ic->nlink) continue; ret = jffs2_build_remove_unlinked_inode(c, ic); if (ret) break; /* -EAGAIN means the inode's nlink was zero, so we deleted it, and furthermore that it had children and their nlink has now gone to zero too. So we have to restart the scan. */ } } while(ret == -EAGAIN); D1(printk(KERN_DEBUG "Pass 2 complete\n")); /* Finally, we can scan again and free the dirent nodes and scan_info structs */ for_each_inode(i, c, ic) { struct jffs2_scan_info *scan = ic->scan; struct jffs2_full_dirent *fd; D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes)); if (!scan) { if (ic->nlink) { D1(printk(KERN_WARNING "Why no scan struct for ino #%u which has nlink %d?\n", ic->ino, ic->nlink)); } continue; } ic->scan = NULL; while(scan->dents) { fd = scan->dents; scan->dents = fd->next; jffs2_free_full_dirent(fd); } kfree(scan); } D1(printk(KERN_DEBUG "Pass 3 complete\n")); return ret; } int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) { struct jffs2_tmp_dnode_info *tn; struct jffs2_full_dirent *fd; struct jffs2_node_frag *fraglist = NULL; struct jffs2_tmp_dnode_info *metadata = NULL; D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino)); if (ic->ino > c->highest_ino) c->highest_ino = ic->ino; if (!ic->scan->tmpnodes && ic->ino != 1) { D1(printk(KERN_DEBUG "jffs2_build_inode: ino #%u has no data nodes!\n", ic->ino)); } /* Build the list to make sure any obsolete nodes are marked as such */ while(ic->scan->tmpnodes) { tn = ic->scan->tmpnodes; ic->scan->tmpnodes = tn->next; if (metadata && tn->version > metadata->version) { D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring old metadata at 0x%08x\n", metadata->fn->raw->flash_offset &~3)); jffs2_free_full_dnode(metadata->fn); jffs2_free_tmp_dnode_info(metadata); metadata = NULL; } if (tn->fn->size) { jffs2_add_full_dnode_to_fraglist (c, &fraglist, tn->fn); jffs2_free_tmp_dnode_info(tn); } else { if (!metadata) { metadata = tn; } else { D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring new metadata at 0x%08x\n", tn->fn->raw->flash_offset &~3)); jffs2_free_full_dnode(tn->fn); jffs2_free_tmp_dnode_info(tn); } } } /* OK. Now clear up */ if (metadata) { jffs2_free_full_dnode(metadata->fn); jffs2_free_tmp_dnode_info(metadata); } metadata = NULL; while (fraglist) { struct jffs2_node_frag *frag; frag = fraglist; fraglist = fraglist->next; if (frag->node && !(--frag->node->frags)) { jffs2_free_full_dnode(frag->node); } jffs2_free_node_frag(frag); } /* Now for each child, increase nlink */ for(fd=ic->scan->dents; fd; fd = fd->next) { struct jffs2_inode_cache *child_ic; if (!fd->ino) continue; child_ic = jffs2_get_ino_cache(c, fd->ino); if (!child_ic) { printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", fd->name, fd->ino, ic->ino); continue; } if (child_ic->nlink++ && fd->type == DT_DIR) { printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino); /* What do we do about it? */ } D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino)); /* Can't free them. We might need them in pass 2 */ } return 0; } int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) { struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *fd; int ret = 0; if(!ic->scan) { D1(printk(KERN_DEBUG "ino #%u was already removed\n", ic->ino)); return 0; } D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino)); for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) { D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", raw->flash_offset&~3)); jffs2_mark_node_obsolete(c, raw); } if (ic->scan->dents) { printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino); while(ic->scan->dents) { struct jffs2_inode_cache *child_ic; fd = ic->scan->dents; ic->scan->dents = fd->next; D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n", fd->name, fd->ino)); child_ic = jffs2_get_ino_cache(c, fd->ino); if (!child_ic) { printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino); continue; } jffs2_free_full_dirent(fd); child_ic->nlink--; } ret = -EAGAIN; } kfree(ic->scan); ic->scan = NULL; // jffs2_del_ino_cache(c, ic); // jffs2_free_inode_cache(ic); return ret; } --- NEW FILE --- /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright (C) 2001 Red Hat, Inc. * * Created by Arjan van de Ven <ar...@re...> * * The original JFFS, from which the design for JFFS2 was derived, * was designed and implemented by Axis Communications AB. * * The contents of this file are subject to the Red Hat eCos Public * License Version 1.1 (the "Licence"); you may not use this file * except in compliance with the Licence. You may obtain a copy of * the Licence at http://www.redhat.com/ * * Software distributed under the Licence is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the Licence for the specific language governing rights and * limitations under the Licence. * * The Original Code is JFFS2 - Journalling Flash File System, version 2 * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License version 2 (the "GPL"), in * which case the provisions of the GPL are applicable instead of the * above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the RHEPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * * $Id: compr.c,v 1.1 2002/04/09 13:19:34 atp Exp $ * */ #include <linux/kernel.h> #include <linux/string.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/jffs2.h> int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen); void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen); int rtime_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen); void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen); int rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen); void rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen); int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen); void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen); /* jffs2_compress: * @data: Pointer to uncompressed data * @cdata: Pointer to buffer for compressed data * @datalen: On entry, holds the amount of data available for compression. * On exit, expected to hold the amount of data actually compressed. * @cdatalen: On entry, holds the amount of space available for compressed * data. On exit, expected to hold the actual size of the compressed * data. * * Returns: Byte to be stored with data indicating compression type used. * Zero is used to show that the data could not be compressed - the * compressed version was actually larger than the original. * * If the cdata buffer isn't large enough to hold all the uncompressed data, * jffs2_compress should compress as much as will fit, and should set * *datalen accordingly to show the amount of data which were compressed. */ unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *datalen, __u32 *cdatalen) { int ret; ret = zlib_compress(data_in, cpage_out, datalen, cdatalen); if (!ret) { return JFFS2_COMPR_ZLIB; } #if 0 /* Disabled 23/9/1. With zlib it hardly ever gets a look in */ ret = dynrubin_compress(data_in, cpage_out, datalen, cdatalen); if (!ret) { return JFFS2_COMPR_DYNRUBIN; } #endif #if 0 /* Disabled 26/2/1. Obsoleted by dynrubin */ ret = rubinmips_compress(data_in, cpage_out, datalen, cdatalen); if (!ret) { return JFFS2_COMPR_RUBINMIPS; } #endif /* rtime does manage to recompress already-compressed data */ ret = rtime_compress(data_in, cpage_out, datalen, cdatalen); if (!ret) { return JFFS2_COMPR_RTIME; } #if 0 /* We don't need to copy. Let the caller special-case the COMPR_NONE case. */ /* If we get here, no compression is going to work */ /* But we might want to use the fragmentation part -- Arjan */ memcpy(cpage_out,data_in,min(*datalen,*cdatalen)); if (*datalen > *cdatalen) *datalen = *cdatalen; #endif return JFFS2_COMPR_NONE; /* We failed to compress */ } int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, unsigned char *data_out, __u32 cdatalen, __u32 datalen) { switch (comprtype) { case JFFS2_COMPR_NONE: /* This should be special-cased elsewhere, but we might as well deal with it */ memcpy(data_out, cdata_in, datalen); break; case JFFS2_COMPR_ZERO: memset(data_out, 0, datalen); break; case JFFS2_COMPR_ZLIB: zlib_decompress(cdata_in, data_out, cdatalen, datalen); break; case JFFS2_COMPR_RTIME: rtime_decompress(cdata_in, data_out, cdatalen, datalen); break; case JFFS2_COMPR_RUBINMIPS: #if 0 /* Disabled 23/9/1 */ rubinmips_decompress(cdata_in, data_out, cdatalen, datalen); #else printk(KERN_WARNING "JFFS2: Rubinmips compression encountered but support not compiled in!\n"); #endif break; case JFFS2_COMPR_DYNRUBIN: #if 1 /* Phase this one out */ dynrubin_decompress(cdata_in, data_out, cdatalen, datalen); #else printk(KERN_WARNING "JFFS2: Dynrubin compression encountered but support not compiled in!\n"); #endif break; default: printk(KERN_NOTICE "Unknown JFFS2 compression type 0x%02x\n", comprtype); return -EIO; } return 0; } --- NEW FILE --- /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright (C) 2001 Red Hat, Inc. * * Created by Arjan van de Ven <ar...@re...> * * The original JFFS, from which the design for JFFS2 was derived, * was designed and implemented by Axis Communications AB. * * The contents of this file are subject to the Red Hat eCos Public * License Version 1.1 (the "Licence"); you may not use this file * except in compliance with the Licence. You may obtain a copy of * the Licence at http://www.redhat.com/ * * Software distributed under the Licence is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the Licence for the specific language governing rights and * limitations under the Licence. * * The Original Code is JFFS2 - Journalling Flash File System, version 2 * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License version 2 (the "GPL"), in * which case the provisions of the GPL are applicable instead of the * above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the RHEPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * * $Id: compr_rtime.c,v 1.1 2002/04/09 13:19:34 atp Exp $ * * * Very simple lz77-ish encoder. * * Theory of operation: Both encoder and decoder have a list of "last * occurances" for every possible source-value; after sending the * first source-byte, the second byte indicated the "run" length of * matches * * The algorithm is intended to only send "whole bytes", no bit-messing. * */ #include <linux/kernel.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/string.h> /* _compress returns the compressed size, -1 if bigger */ int rtime_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen) { int positions[256]; int outpos = 0; int pos=0; memset(positions,0,sizeof(positions)); while (pos < (*sourcelen) && outpos <= (*dstlen)-2) { int backpos, runlen=0; unsigned char value; value = data_in[pos]; cpage_out[outpos++] = data_in[pos++]; backpos = positions[value]; positions[value]=pos; while ((backpos < pos) && (pos < (*sourcelen)) && (data_in[pos]==data_in[backpos++]) && (runlen<255)) { pos++; runlen++; } cpage_out[outpos++] = runlen; } if (outpos >= pos) { /* We failed */ return -1; } /* Tell the caller how much we managed to compress, and how much space it took */ *sourcelen = pos; *dstlen = outpos; return 0; } void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen) { int positions[256]; int outpos = 0; int pos=0; memset(positions,0,sizeof(positions)); while (outpos<destlen) { unsigned char value; int backoffs; int repeat; value = data_in[pos++]; cpage_out[outpos++] = value; /* first the verbatim copied byte */ repeat = data_in[pos++]; backoffs = positions[value]; positions[value]=outpos; if (repeat) { if (backoffs + repeat >= outpos) { while(repeat) { cpage_out[outpos++] = cpage_out[backoffs++]; repeat--; } } else { memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat); outpos+=repeat; } } } } --- NEW FILE --- /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright (C) 2001 Red Hat, Inc. * * Created by Arjan van de Ven <ar...@re...> * * The original JFFS, from which the design for JFFS2 was derived, * was designed and implemented by Axis Communications AB. * * The contents of this file are subject to the Red Hat eCos Public * License Version 1.1 (the "Licence"); you may not use this file * except in compliance with the Licence. You may obtain a copy of * the Licence at http://www.redhat.com/ * * Software distributed under the Licence is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the Licence for the specific language governing rights and * limitations under the Licence. * * The Original Code is JFFS2 - Journalling Flash File System, version 2 * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License version 2 (the "GPL"), in * which case the provisions of the GPL are applicable instead of the * above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the RHEPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * * $Id: compr_rubin.c,v 1.1 2002/04/09 13:19:34 atp Exp $ * */ #include <linux/string.h> #include <linux/types.h> #include "compr_rubin.h" #include "histo_mips.h" void init_rubin(struct rubin_state *rs, int div, int *bits) { int c; rs->q = 0; rs->p = (long) (2 * UPPER_BIT_RUBIN); rs->bit_number = (long) 0; rs->bit_divider = div; for (c=0; c<8; c++) rs->bits[c] = bits[c]; } int encode(struct rubin_state *rs, long A, long B, int symbol) { long i0, i1; int ret; while ((rs->q >= UPPER_BIT_RUBIN) || ((rs->p + rs->q) <= UPPER_BIT_RUBIN)) { rs->bit_number++; ret = pushbit(&rs->pp, (rs->q & UPPER_BIT_RUBIN) ? 1 : 0, 0); if (ret) return ret; rs->q &= LOWER_BITS_RUBIN; rs->q <<= 1; rs->p <<= 1; } i0 = A * rs->p / (A + B); if (i0 <= 0) { i0 = 1; } if (i0 >= rs->p) { i0 = rs->p - 1; } i1 = rs->p - i0; if (symbol == 0) rs->p = i0; else { rs->p = i1; rs->q += i0; } return 0; } void end_rubin(struct rubin_state *rs) { int i; for (i = 0; i < RUBIN_REG_SIZE; i++) { pushbit(&rs->pp, (UPPER_BIT_RUBIN & rs->q) ? 1 : 0, 1); rs->q &= LOWER_BITS_RUBIN; rs->q <<= 1; } } void init_decode(struct rubin_state *rs, int div, int *bits) { init_rubin(rs, div, bits); /* behalve lower */ rs->rec_q = 0; for (rs->bit_number = 0; rs->bit_number++ < RUBIN_REG_SIZE; rs->rec_q = rs->rec_q * 2 + (long) (pullbit(&rs->pp))) ; } static void __do_decode(struct rubin_state *rs, unsigned long p, unsigned long q) { register unsigned long lower_bits_rubin = LOWER_BITS_RUBIN; unsigned long rec_q; int c, bits = 0; /* * First, work out how many bits we need from the input stream. * Note that we have already done the initial check on this * loop prior to calling this function. */ do { bits++; q &= lower_bits_rubin; q <<= 1; p <<= 1; } while ((q >= UPPER_BIT_RUBIN) || ((p + q) <= UPPER_BIT_RUBIN)); rs->p = p; rs->q = q; rs->bit_number += bits; /* * Now get the bits. We really want this to be "get n bits". */ rec_q = rs->rec_q; do { c = pullbit(&rs->pp); rec_q &= lower_bits_rubin; rec_q <<= 1; rec_q += c; } while (--bits); rs->rec_q = rec_q; } int decode(struct rubin_state *rs, long A, long B) { unsigned long p = rs->p, q = rs->q; long i0, threshold; int symbol; if (q >= UPPER_BIT_RUBIN || ((p + q) <= UPPER_BIT_RUBIN)) __do_decode(rs, p, q); i0 = A * rs->p / (A + B); if (i0 <= 0) { i0 = 1; } if (i0 >= rs->p) { i0 = rs->p - 1; } threshold = rs->q + i0; symbol = rs->rec_q >= threshold; if (rs->rec_q >= threshold) { rs->q += i0; i0 = rs->p - i0; } rs->p = i0; return symbol; } static int out_byte(struct rubin_state *rs, unsigned char byte) { int i, ret; struct rubin_state rs_copy; rs_copy = *rs; for (i=0;i<8;i++) { ret = encode(rs, rs->bit_divider-rs->bits[i],rs->bits[i],byte&1); if (ret) { /* Failed. Restore old state */ *rs = rs_copy; return ret; } byte=byte>>1; } return 0; } static int in_byte(struct rubin_state *rs) { int i, result = 0, bit_divider = rs->bit_divider; for (i = 0; i < 8; i++) result |= decode(rs, bit_divider - rs->bits[i], rs->bits[i]) << i; return result; } int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen) { int outpos = 0; int pos=0; struct rubin_state rs; init_pushpull(&rs.pp, cpage_out, *dstlen * 8, 0, 32); init_rubin(&rs, bit_divider, bits); while (pos < (*sourcelen) && !out_byte(&rs, data_in[pos])) pos++; end_rubin(&rs); if (outpos > pos) { /* We failed */ return -1; } /* Tell the caller how much we managed to compress, * and how much space it took */ outpos = (pushedbits(&rs.pp)+7)/8; if (outpos >= pos) return -1; /* We didn't actually compress */ *sourcelen = pos; *dstlen = outpos; return 0; } #if 0 /* _compress returns the compressed size, -1 if bigger */ int rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen) { return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); } #endif int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen) { int bits[8]; unsigned char histo[256]; int i; int ret; __u32 mysrclen, mydstlen; mysrclen = *sourcelen; mydstlen = *dstlen - 8; if (*dstlen <= 12) return -1; memset(histo, 0, 256); for (i=0; i<mysrclen; i++) { histo[data_in[i]]++; } memset(bits, 0, sizeof(int)*8); for (i=0; i<256; i++) { if (i&128) bits[7] += histo[i]; if (i&64) bits[6] += histo[i]; if (i&32) bits[5] += histo[i]; if (i&16) bits[4] += histo[i]; if (i&8) bits[3] += histo[i]; if (i&4) bits[2] += histo[i]; if (i&2) bits[1] += histo[i]; if (i&1) bits[0] += histo[i]; } for (i=0; i<8; i++) { bits[i] = (bits[i] * 256) / mysrclen; if (!bits[i]) bits[i] = 1; if (bits[i] > 255) bits[i] = 255; cpage_out[i] = bits[i]; } ret = rubin_do_compress(256, bits, data_in, cpage_out+8, &mysrclen, &mydstlen); if (ret) return ret; /* Add back the 8 bytes we took for the probabilities */ mydstlen += 8; if (mysrclen <= mydstlen) { /* We compressed */ return -1; } *sourcelen = mysrclen; *dstlen = mydstlen; return 0; } void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in, unsigned char *page_out, __u32 srclen, __u32 destlen) { int outpos = 0; struct rubin_state rs; init_pushpull(&rs.pp, cdata_in, srclen, 0, 0); init_decode(&rs, bit_divider, bits); while (outpos < destlen) { page_out[outpos++] = in_byte(&rs); } } void rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 sourcelen, __u32 dstlen) { rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); } void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 sourcelen, __u32 dstlen) { int bits[8]; int c; for (c=0; c<8; c++) bits[c] = data_in[c]; rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen); } --- NEW FILE --- /* Rubin encoder/decoder header */ /* work started at : aug 3, 1994 */ /* last modification : aug 15, 1994 */ /* $Id: compr_rubin.h,v 1.1 2002/04/09 13:19:34 atp Exp $ */ #include "pushpull.h" #define RUBIN_REG_SIZE 16 #define UPPER_BIT_RUBIN (((long) 1)<<(RUBIN_REG_SIZE-1)) #define LOWER_BITS_RUBIN ((((long) 1)<<(RUBIN_REG_SIZE-1))-1) struct rubin_state { unsigned long p; unsigned long q; unsigned long rec_q; long bit_number; struct pushpull pp; int bit_divider; int bits[8]; }; void init_rubin (struct rubin_state *rs, int div, int *bits); int encode (struct rubin_state *, long, long, int); void end_rubin (struct rubin_state *); void init_decode (struct rubin_state *, int div, int *bits); int decode (struct rubin_state *, long, long); --- NEW FILE --- /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright (C) 2001 Red Hat, Inc. * * Created by David Woodhouse <dw...@ca...> * * The original JFFS, from which the design for JFFS2 was derived, * was designed and implemented by Axis Communications AB. * * The contents of this file are subject to the Red Hat eCos Public * License Version 1.1 (the "Licence"); you may not use this file * except in compliance with the Licence. You may obtain a copy of * the Licence at http://www.redhat.com/ * * Software distributed under the Licence is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the Licence for the specific language governing rights and * limitations under the Licence. * * The Original Code is JFFS2 - Journalling Flash File System, version 2 * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License version 2 (the "GPL"), in * which case the provisions of the GPL are applicable instead of the * above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the RHEPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * * $Id: compr_zlib.c,v 1.1 2002/04/09 13:19:34 atp Exp $ * */ #include "zlib.h" #ifdef __KERNEL__ #include <linux/kernel.h> #include <linux/mtd/compatmac.h> /* for min() */ #include <linux/slab.h> #include <linux/jffs2.h> #include "nodelist.h" static void *zalloc(void *opaque, unsigned nr, unsigned size) { /* How much does it request? Should we use vmalloc? Or be dynamic? */ return kmalloc(nr * size, GFP_KERNEL); } static void zfree(void *opaque, void *addr) { kfree(addr); } #else #define min(x,y) ((x)<(y)?(x):(y)) #ifndef D1 #define D1(x) #endif #define KERN_DEBUG #define KERN_NOTICE #define KERN_WARNING #define printk printf #include <stdio.h> #include <asm/types.h> #endif /* Plan: call deflate() with avail_in == *sourcelen, avail_out = *dstlen - 12 and flush == Z_FINISH. If it doesn't manage to finish, call it again with avail_in == 0 and avail_out set to the remaining 12 bytes for it to clean up. Q: Is 12 bytes sufficient? */ #define STREAM_END_SPACE 12 int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen) { z_stream strm; int ret; if (*dstlen <= STREAM_END_SPACE) return -1; #ifdef __KERNEL__ strm.zalloc = zalloc; strm.zfree = zfree; #else strm.zalloc = (void *)0; strm.zfree = (void *)0; #endif if (Z_OK != deflateInit(&strm, 3)) { printk(KERN_WARNING "deflateInit failed\n"); return -1; } strm.next_in = data_in; strm.total_in = 0; strm.next_out = cpage_out; strm.total_out = 0; while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) { strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE); strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out); D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n", strm.avail_in, strm.avail_out)); ret = deflate(&strm, Z_PARTIAL_FLUSH); D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", strm.avail_in, strm.avail_out, strm.total_in, strm.total_out)); if (ret != Z_OK) { D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret)); deflateEnd(&strm); return -1; } } strm.avail_out += STREAM_END_SPACE; strm.avail_in = 0; ret = deflate(&strm, Z_FINISH); if (ret != Z_STREAM_END) { D1(printk(KERN_DEBUG "final deflate returned %d\n", ret)); deflateEnd(&strm); return -1; } deflateEnd(&strm); D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", strm.total_in, strm.total_out)); if (strm.total_out >= strm.total_in) return -1; *dstlen = strm.total_out; *sourcelen = strm.total_in; return 0; } void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen) { z_stream strm; int ret; #ifdef __KERNEL__ strm.zalloc = zalloc; strm.zfree = zfree; #else strm.zalloc = (void *)0; strm.zfree = (void *)0; #endif if (Z_OK != inflateInit(&strm)) { printk(KERN_WARNING "inflateInit failed\n"); return; } strm.next_in = data_in; strm.avail_in = srclen; strm.total_in = 0; strm.next_out = cpage_out; strm.avail_out = destlen; strm.total_out = 0; while((ret = inflate(&strm, Z_FINISH)) == Z_OK) ; if (ret != Z_STREAM_END) { printk(KERN_NOTICE "inflate returned %d\n", ret); } inflateEnd(&strm); } --- NEW FILE --- /* $Id: comprtest.c,v 1.1 2002/04/09 13:19:34 atp Exp $ */ #include <linux/kernel.h> #include <linux/string.h> #include <linux/module.h> #include <asm/types.h> #if 0 #define TESTDATA_LEN 512 static unsigned char testdata[TESTDATA_LEN] = { 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x83, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, 0xb0, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x06, 0x00, 0x28, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x06, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x80, 0x04, 0x08, 0x34, 0x80, 0x04, 0x08, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf4, 0x80, 0x04, 0x08, 0xf4, 0x80, 0x04, 0x08, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x08, 0x00, 0x80, 0x04, 0x08, 0x0d, 0x05, 0x00, 0x00, 0x0d, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x10, 0x95, 0x04, 0x08, 0x10, 0x95, 0x04, 0x08, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x58, 0x05, 0x00, 0x00, 0x58, 0x95, 0x04, 0x08, 0x58, 0x95, 0x04, 0x08, 0xa0, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x81, 0x04, 0x08, 0x08, 0x81, 0x04, 0x08, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2e, 0x73, 0x6f, 0x2e, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x0c, 0x83, 0x04, 0x08, 0x81, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x1c, 0x83, 0x04, 0x08, 0xac, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x2c, 0x83, 0x04, 0x08, 0xdd, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x3c, 0x83, 0x04, 0x08, 0x2e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x4c, 0x83, 0x04, 0x08, 0x7d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x85, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x67, 0x6d, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x5f, 0x00, 0x6c, 0x69, 0x62, 0x63, 0x2e, 0x73, 0x6f, 0x2e, 0x36, 0x00, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x00, 0x5f, 0x5f, 0x63}; #else #define TESTDATA_LEN 3481 static unsigned char testdata[TESTDATA_LEN] = { 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x22, 0x64, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x20, 0x31, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x62, 0x75, 0x66, 0x5b, 0x37, 0x30, 0x30, 0x30, 0x30, 0x5d, 0x3b, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x3b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x3b, 0x0a, 0x7d, 0x20, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x5d, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x28, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x3b, 0x0a, 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x4d, 0x49, 0x4e, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x6f, 0x66, 0x28, 0x62, 0x75, 0x66, 0x29, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x2d, 0x3d, 0x20, 0x73, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x2c, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x3d, 0x20, 0x4f, 0x5f, 0x52, 0x44, 0x57, 0x52, 0x7c, 0x4f, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x20, 0x73, 0x74, 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x7c, 0x3d, 0x20, 0x4f, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x43, 0x3b, 0x0a, 0x0a, 0x09, 0x66, 0x64, 0x20, 0x3d, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2c, 0x20, 0x30, 0x36, 0x30, 0x30, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x64, 0x20, 0x3d, 0x3d, 0x20, 0x2d, 0x31, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x73, 0x74, 0x61, 0x74, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x26, 0x73, 0x74, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3e, 0x20, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x44, 0x45, 0x42, 0x55, 0x47, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x25, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x25, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, 0x74, 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x09, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x2d, 0x20, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3c, 0x20, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x25, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x25, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, 0x74, 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x66, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x25, 0x73, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x65, 0x78, 0x69, 0x74, 0x28, 0x31, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x3b, 0x0a, 0x09, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x64, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x20, 0x25, 0x20, 0x31, 0x30, 0x30, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x2e, 0x22, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x62, 0x75, 0x66, 0x5b, 0x30, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x6d, 0x65, 0x6d, 0x73, 0x65, 0x74, 0x28, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x6f, 0x66, 0x28, 0x62, 0x75, 0x66, 0x29, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x31, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, 0x64, 0x20, 0x6f, 0x66, 0x73, 0x3d, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x73, 0x65, 0x65, 0x6b, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2c, 0x20, 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x28, 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, 0x64, 0x20, 0x6f, 0x66, 0x73, 0x3d, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x73, 0x65, 0x65, 0x6b, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2c, 0x20, 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x29, 0x3b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x29, 0x3b, 0x0a, 0x09, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x30, 0x37, 0x30, 0x30, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x44, 0x45, 0x42, 0x55, 0x47, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x6f, 0x6c, 0x64, 0x2c, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x6e, 0x65, 0x77, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x6f, 0x6c, 0x64, 0x29, 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x6e, 0x65, 0x77, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6f, 0x6c, 0x64, 0x2c, 0x20, 0x6e, 0x65, 0x77, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x6... [truncated message content] |
From: Andy P. <at...@us...> - 2002-04-09 14:08:31
|
Update of /cvsroot/linux-vax/kernel-2.4/fs/isofs In directory usw-pr-cvs1:/tmp/cvs-serv27691/isofs Modified Files: Makefile inode.c joliet.c rock.c rock.h util.c Added Files: compress.c zisofs.h Log Message: sync 2.4.15 commit 11 --- NEW FILE --- /* -*- linux-c -*- ------------------------------------------------------- * * * Copyright 2001 H. Peter Anvin - All Rights Reserved * * 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, Inc., 675 Mass Ave, Cambridge MA 02139, * USA; either version 2 of the License, or (at your option) any later * version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ /* * linux/fs/isofs/compress.c * * Transparent decompression of files on an iso9660 filesystem */ #include <linux/config.h> #include <linux/module.h> #include <linux/stat.h> #include <linux/sched.h> #include <linux/iso_fs.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/locks.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/cdrom.h> #include <linux/init.h> #include <linux/nls.h> #include <linux/ctype.h> #include <linux/smp_lock.h> #include <linux/blkdev.h> #include <linux/vmalloc.h> #include <linux/zlib_fs.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/semaphore.h> #include "zisofs.h" /* This should probably be global. */ static char zisofs_sink_page[PAGE_CACHE_SIZE]; /* * This contains the zlib memory allocation and the mutex for the * allocation; this avoids failures at block-decompression time. */ static void *zisofs_zlib_workspace; static struct semaphore zisofs_zlib_semaphore; /* * When decompressing, we typically obtain more than one page * per reference. We inject the additional pages into the page * cache as a form of readahead. */ static int zisofs_readpage(struct file *file, struct page *page) { struct inode *inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; unsigned int maxpage, xpage, fpage, blockindex; unsigned long offset; unsigned long blockptr, blockendptr, cstart, cend, csize; struct buffer_head *bh, *ptrbh[2]; unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); unsigned int bufshift = ISOFS_BUFFER_BITS(inode); unsigned long bufmask = bufsize - 1; int err = -EIO; int i; unsigned int header_size = inode->u.isofs_i.i_format_parm[0]; unsigned int zisofs_block_shift = inode->u.isofs_i.i_format_parm[1]; /* unsigned long zisofs_block_size = 1UL << zisofs_block_shift; */ unsigned int zisofs_block_page_shift = zisofs_block_shift-PAGE_CACHE_SHIFT; unsigned long zisofs_block_pages = 1UL << zisofs_block_page_shift; unsigned long zisofs_block_page_mask = zisofs_block_pages-1; struct page *pages[zisofs_block_pages]; unsigned long index = page->index; int indexblocks; /* We have already been given one page, this is the one we must do. */ xpage = index & zisofs_block_page_mask; pages[xpage] = page; /* The remaining pages need to be allocated and inserted */ offset = index & ~zisofs_block_page_mask; blockindex = offset >> zisofs_block_page_shift; maxpage = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; maxpage = min(zisofs_block_pages, maxpage-offset); for ( i = 0 ; i < maxpage ; i++, offset++ ) { if ( i != xpage ) { pages[i] = grab_cache_page_nowait(mapping, offset); } page = pages[i]; if ( page ) { ClearPageError(page); kmap(page); } } /* This is the last page filled, plus one; used in case of abort. */ fpage = 0; /* Find the pointer to this specific chunk */ /* Note: we're not using isonum_731() here because the data is known aligned */ /* Note: header_size is in 32-bit words (4 bytes) */ blockptr = (header_size + blockindex) << 2; blockendptr = blockptr + 4; indexblocks = ((blockptr^blockendptr) >> bufshift) ? 2 : 1; ptrbh[0] = ptrbh[1] = 0; if ( isofs_get_blocks(inode, blockptr >> bufshift, ptrbh, indexblocks) != indexblocks ) { if ( ptrbh[0] ) brelse(ptrbh[0]); printk(KERN_DEBUG "zisofs: Null buffer on reading block table, inode = %lu, block = %lu\n", inode->i_ino, blockptr >> bufshift); goto eio; } ll_rw_block(READ, indexblocks, ptrbh); bh = ptrbh[0]; if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) { printk(KERN_DEBUG "zisofs: Failed to read block table, inode = %lu, block = %lu\n", inode->i_ino, blockptr >> bufshift); if ( ptrbh[1] ) brelse(ptrbh[1]); goto eio; } cstart = le32_to_cpu(*(u32 *)(bh->b_data + (blockptr & bufmask))); if ( indexblocks == 2 ) { /* We just crossed a block boundary. Switch to the next block */ brelse(bh); bh = ptrbh[1]; if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) { printk(KERN_DEBUG "zisofs: Failed to read block table, inode = %lu, block = %lu\n", inode->i_ino, blockendptr >> bufshift); goto eio; } } cend = le32_to_cpu(*(u32 *)(bh->b_data + (blockendptr & bufmask))); brelse(bh); csize = cend-cstart; /* Now page[] contains an array of pages, any of which can be NULL, and the locks on which we hold. We should now read the data and release the pages. If the pages are NULL the decompressed data for that particular page should be discarded. */ if ( csize == 0 ) { /* This data block is empty. */ for ( fpage = 0 ; fpage < maxpage ; fpage++ ) { if ( (page = pages[fpage]) != NULL ) { memset(page_address(page), 0, PAGE_CACHE_SIZE); flush_dcache_page(page); SetPageUptodate(page); kunmap(page); UnlockPage(page); if ( fpage == xpage ) err = 0; /* The critical page */ else page_cache_release(page); } } } else { /* This data block is compressed. */ z_stream stream; int bail = 0, left_out = -1; int zerr; int needblocks = (csize + (cstart & bufmask) + bufmask) >> bufshift; int haveblocks; struct buffer_head *bhs[needblocks+1]; struct buffer_head **bhptr; /* Because zlib is not thread-safe, do all the I/O at the top. */ blockptr = cstart >> bufshift; memset(bhs, 0, (needblocks+1)*sizeof(struct buffer_head *)); haveblocks = isofs_get_blocks(inode, blockptr, bhs, needblocks); ll_rw_block(READ, haveblocks, bhs); bhptr = &bhs[0]; bh = *bhptr++; /* First block is special since it may be fractional. We also wait for it before grabbing the zlib semaphore; odds are that the subsequent blocks are going to come in in short order so we don't hold the zlib semaphore longer than necessary. */ if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) { printk(KERN_DEBUG "zisofs: Hit null buffer, fpage = %d, xpage = %d, csize = %ld\n", fpage, xpage, csize); goto b_eio; } stream.next_in = bh->b_data + (cstart & bufmask); stream.avail_in = min(bufsize-(cstart & bufmask), csize); csize -= stream.avail_in; stream.workspace = zisofs_zlib_workspace; down(&zisofs_zlib_semaphore); zerr = zlib_fs_inflateInit(&stream); if ( zerr != Z_OK ) { if ( err && zerr == Z_MEM_ERROR ) err = -ENOMEM; printk(KERN_DEBUG "zisofs: zisofs_inflateInit returned %d\n", zerr); goto z_eio; } while ( !bail && fpage < maxpage ) { page = pages[fpage]; if ( page ) stream.next_out = page_address(page); else stream.next_out = (void *)&zisofs_sink_page; stream.avail_out = PAGE_CACHE_SIZE; while ( stream.avail_out ) { int ao, ai; if ( stream.avail_in == 0 && left_out ) { if ( !csize ) { printk(KERN_WARNING "zisofs: ZF read beyond end of input\n"); bail = 1; break; } else { bh = *bhptr++; if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) { /* Reached an EIO */ printk(KERN_DEBUG "zisofs: Hit null buffer, fpage = %d, xpage = %d, csize = %ld\n", fpage, xpage, csize); bail = 1; break; } stream.next_in = bh->b_data; stream.avail_in = min(csize,bufsize); csize -= stream.avail_in; } } ao = stream.avail_out; ai = stream.avail_in; zerr = zlib_fs_inflate(&stream, Z_SYNC_FLUSH); left_out = stream.avail_out; if ( zerr == Z_BUF_ERROR && stream.avail_in == 0 ) continue; if ( zerr != Z_OK ) { /* EOF, error, or trying to read beyond end of input */ if ( err && zerr == Z_MEM_ERROR ) err = -ENOMEM; if ( zerr != Z_STREAM_END ) printk(KERN_DEBUG "zisofs: zisofs_inflate returned %d, inode = %lu, index = %lu, fpage = %d, xpage = %d, avail_in = %d, avail_out = %d, ai = %d, ao = %d\n", zerr, inode->i_ino, index, fpage, xpage, stream.avail_in, stream.avail_out, ai, ao); bail = 1; break; } } if ( stream.avail_out && zerr == Z_STREAM_END ) { /* Fractional page written before EOF. This may be the last page in the file. */ memset(stream.next_out, 0, stream.avail_out); stream.avail_out = 0; } if ( !stream.avail_out ) { /* This page completed */ if ( page ) { flush_dcache_page(page); SetPageUptodate(page); kunmap(page); UnlockPage(page); if ( fpage == xpage ) err = 0; /* The critical page */ else page_cache_release(page); } fpage++; } } zlib_fs_inflateEnd(&stream); z_eio: up(&zisofs_zlib_semaphore); b_eio: for ( i = 0 ; i < haveblocks ; i++ ) { if ( bhs[i] ) brelse(bhs[i]); } } eio: /* Release any residual pages, do not SetPageUptodate */ while ( fpage < maxpage ) { page = pages[fpage]; if ( page ) { flush_dcache_page(page); if ( fpage == xpage ) SetPageError(page); kunmap(page); UnlockPage(page); if ( fpage != xpage ) page_cache_release(page); } fpage++; } /* At this point, err contains 0 or -EIO depending on the "critical" page */ return err; } struct address_space_operations zisofs_aops = { readpage: zisofs_readpage, /* No sync_page operation supported? */ /* No bmap operation supported */ }; static int initialized = 0; int __init zisofs_init(void) { if ( initialized ) { printk("zisofs_init: called more than once\n"); return 0; } zisofs_zlib_workspace = vmalloc(zlib_fs_inflate_workspacesize()); if ( !zisofs_zlib_workspace ) return -ENOMEM; init_MUTEX(&zisofs_zlib_semaphore); initialized = 1; return 0; } void __exit zisofs_cleanup(void) { if ( !initialized ) { printk("zisofs_cleanup: called without initialization\n"); return; } vfree(zisofs_zlib_workspace); initialized = 0; } --- NEW FILE --- /* ----------------------------------------------------------------------- * * * Copyright 2001 H. Peter Anvin - All Rights Reserved * * 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, Inc., 675 Mass Ave, Cambridge MA 02139, * USA; either version 2 of the License, or (at your option) any later * version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ /* * Prototypes for functions exported from the compressed isofs subsystem */ #ifdef CONFIG_ZISOFS extern struct address_space_operations zisofs_aops; extern int __init zisofs_init(void); extern void __exit zisofs_cleanup(void); #endif Index: Makefile =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/isofs/Makefile,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- Makefile 14 Jan 2001 16:26:08 -0000 1.1.1.1 +++ Makefile 9 Apr 2002 13:11:18 -0000 1.2 @@ -11,7 +11,10 @@ obj-y := namei.o inode.o dir.o util.o rock.o obj-$(CONFIG_JOLIET) += joliet.o +obj-$(CONFIG_ZISOFS) += compress.o obj-m := $(O_TARGET) + +CFLAGS_compress.o := -I $(TOPDIR)/fs/inflate_fs include $(TOPDIR)/Rules.make Index: inode.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/isofs/inode.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- inode.c 25 Feb 2001 23:14:46 -0000 1.1.1.2 +++ inode.c 9 Apr 2002 13:11:18 -0000 1.2 @@ -27,10 +27,13 @@ #include <linux/nls.h> #include <linux/ctype.h> #include <linux/smp_lock.h> +#include <linux/blkdev.h> #include <asm/system.h> #include <asm/uaccess.h> +#include "zisofs.h" + /* * We have no support for "multi volume" CDs, but more and more disks carry * wrong information within the volume descriptors. @@ -108,6 +111,7 @@ char joliet; char cruft; char unhide; + char nocompress; unsigned char check; unsigned int blocksize; mode_t mode; @@ -277,6 +281,7 @@ popt->cruft = 'n'; popt->unhide = 'n'; popt->check = 'u'; /* unset */ + popt->nocompress = 0; popt->blocksize = 1024; popt->mode = S_IRUGO | S_IXUGO; /* r-x for all. The disc could be shared with DOS machines so @@ -310,6 +315,10 @@ popt->utf8 = 1; continue; } + if (strncmp(this_char,"nocompress",10) == 0) { + popt->nocompress = 1; + continue; + } if ((value = strchr(this_char,'=')) != NULL) *value++ = 0; @@ -493,21 +502,21 @@ printk("iocharset = %s\n", opt.iocharset); #endif - /* - * First of all, get the hardware blocksize for this device. - * If we don't know what it is, or the hardware blocksize is - * larger than the blocksize the user specified, then use - * that value. - */ - blocksize = get_hardblocksize(dev); - if(blocksize > opt.blocksize) { - /* - * Force the blocksize we are going to use to be the - * hardware blocksize. - */ - opt.blocksize = blocksize; + /* + * First of all, get the hardware blocksize for this device. + * If we don't know what it is, or the hardware blocksize is + * larger than the blocksize the user specified, then use + * that value. + */ + blocksize = get_hardsect_size(dev); + if(blocksize > opt.blocksize) { + /* + * Force the blocksize we are going to use to be the + * hardware blocksize. + */ + opt.blocksize = blocksize; } - + blocksize_bits = 0; { int i = opt.blocksize; @@ -616,7 +625,7 @@ #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (isonum_723 (h_pri->volume_set_size) != 1) goto out_no_support; -#endif IGNORE_WRONG_MULTI_VOLUME_SPECS +#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */ s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size); s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size); @@ -625,7 +634,7 @@ #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (isonum_723 (pri->volume_set_size) != 1) goto out_no_support; -#endif IGNORE_WRONG_MULTI_VOLUME_SPECS +#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */ s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size); s->u.isofs_sb.s_max_size = isonum_733(pri->volume_space_size); @@ -663,6 +672,9 @@ s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */; + /* Set this for reference. Its not currently used except on write + which we don't have .. */ + /* RDE: data zone now byte offset! */ first_data_zone = ((isonum_733 (rootp->extent) + @@ -740,7 +752,7 @@ if (! s->u.isofs_sb.s_nls_iocharset) { /* Fail only if explicit charset specified */ if (opt.iocharset) - goto out_freebh; + goto out_unlock; s->u.isofs_sb.s_nls_iocharset = load_nls_default(); } } @@ -748,11 +760,13 @@ s->s_op = &isofs_sops; s->u.isofs_sb.s_mapping = opt.map; s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 2 : 0); + s->u.isofs_sb.s_rock_offset = -1; /* initial offset, will guess until SP is found*/ s->u.isofs_sb.s_cruft = opt.cruft; s->u.isofs_sb.s_unhide = opt.unhide; s->u.isofs_sb.s_uid = opt.uid; s->u.isofs_sb.s_gid = opt.gid; s->u.isofs_sb.s_utf8 = opt.utf8; + s->u.isofs_sb.s_nocompress = opt.nocompress; /* * It would be incredibly stupid to allow people to mark every file * on the disk as suid, so we merely allow them to set the default @@ -869,93 +883,108 @@ return 0; } -/* Life is simpler than for other filesystem since we never - * have to create a new block, only find an existing one. +/* + * Get a set of blocks; filling in buffer_heads if already allocated + * or getblk() if they are not. Returns the number of blocks inserted + * (0 == error.) */ -static int isofs_get_block(struct inode *inode, long iblock, - struct buffer_head *bh_result, int create) +int isofs_get_blocks(struct inode *inode, long iblock, + struct buffer_head **bh_result, unsigned long nblocks) { unsigned long b_off; unsigned offset, sect_size; unsigned int firstext; unsigned long nextino; - int i, err; + int section, rv; + unsigned int blocksize = inode->i_sb->s_blocksize; lock_kernel(); - err = -EROFS; - if (create) - goto abort_create_attempted; - - err = -EIO; - if (iblock < 0) - goto abort_negative; + rv = 0; + if (iblock < 0) { + printk("isofs_get_blocks: block < 0\n"); + goto abort; + } b_off = iblock; - - /* If we are *way* beyond the end of the file, print a message. - * Access beyond the end of the file up to the next page boundary - * is normal, however because of the way the page cache works. - * In this case, we just return 0 so that we can properly fill - * the page with useless information without generating any - * I/O errors. - */ - if (b_off > ((inode->i_size + PAGE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) - goto abort_beyond_end; - + offset = 0; firstext = inode->u.isofs_i.i_first_extent; sect_size = inode->u.isofs_i.i_section_size >> ISOFS_BUFFER_BITS(inode); nextino = inode->u.isofs_i.i_next_section_ino; + section = 0; - i = 0; - if (nextino) { - while (b_off >= (offset + sect_size)) { - struct inode *ninode; - - offset += sect_size; - if (nextino == 0) - goto abort; - ninode = iget(inode->i_sb, nextino); - if (!ninode) + while ( nblocks ) { + /* If we are *way* beyond the end of the file, print a message. + * Access beyond the end of the file up to the next page boundary + * is normal, however because of the way the page cache works. + * In this case, we just return 0 so that we can properly fill + * the page with useless information without generating any + * I/O errors. + */ + if (b_off > ((inode->i_size + PAGE_CACHE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) { + printk("isofs_get_blocks: block >= EOF (%ld, %ld)\n", + iblock, (unsigned long) inode->i_size); + goto abort; + } + + if (nextino) { + while (b_off >= (offset + sect_size)) { + struct inode *ninode; + + offset += sect_size; + if (nextino == 0) + goto abort; + ninode = iget(inode->i_sb, nextino); + if (!ninode) + goto abort; + firstext = ninode->u.isofs_i.i_first_extent; + sect_size = ninode->u.isofs_i.i_section_size; + nextino = ninode->u.isofs_i.i_next_section_ino; + iput(ninode); + + if (++section > 100) { + printk("isofs_get_blocks: More than 100 file sections ?!?, aborting...\n"); + printk("isofs_get_blocks: ino=%lu block=%ld firstext=%u sect_size=%u nextino=%lu\n", + inode->i_ino, iblock, firstext, (unsigned) sect_size, nextino); + goto abort; + } + } + } + + if ( *bh_result ) { + (*bh_result)->b_dev = inode->i_dev; + (*bh_result)->b_blocknr = firstext + b_off - offset; + (*bh_result)->b_state |= (1UL << BH_Mapped); + } else { + *bh_result = getblk(inode->i_dev, firstext+b_off-offset, blocksize); + if ( !*bh_result ) goto abort; - firstext = ninode->u.isofs_i.i_first_extent; - sect_size = ninode->u.isofs_i.i_section_size; - nextino = ninode->u.isofs_i.i_next_section_ino; - iput(ninode); - - if (++i > 100) - goto abort_too_many_sections; } + bh_result++; /* Next buffer head */ + b_off++; /* Next buffer offset */ + nblocks--; + rv++; } - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = firstext + b_off - offset; - bh_result->b_state |= (1UL << BH_Mapped); - err = 0; abort: unlock_kernel(); - return err; + return rv; +} -abort_create_attempted: - printk("isofs_get_block: Kernel tries to allocate a block\n"); - goto abort; - -abort_negative: - printk("isofs_get_block: block < 0\n"); - goto abort; - -abort_beyond_end: - printk("isofs_get_block: block >= EOF (%ld, %ld)\n", - iblock, (unsigned long) inode->i_size); - goto abort; - -abort_too_many_sections: - printk("isofs_get_block: More than 100 file sections ?!?, aborting...\n"); - printk("isofs_get_block: ino=%lu block=%ld firstext=%u sect_size=%u nextino=%lu\n", - inode->i_ino, iblock, firstext, (unsigned) sect_size, nextino); - goto abort; +/* + * Used by the standard interfaces. + */ +static int isofs_get_block(struct inode *inode, long iblock, + struct buffer_head *bh_result, int create) +{ + if ( create ) { + printk("isofs_get_block: Kernel tries to allocate a block\n"); + return -EROFS; + } + + return isofs_get_blocks(inode, iblock, &bh_result, 1) ? 0 : -EIO; } static int isofs_bmap(struct inode *inode, int block) @@ -1146,6 +1175,9 @@ de = tmpde; } + /* Assume it is a normal-format file unless told otherwise */ + inode->u.isofs_i.i_file_format = isofs_file_normal; + if (de->flags[-high_sierra] & 2) { inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR; inode->i_nlink = 1; /* Set to 1. We know there are 2, but @@ -1179,11 +1211,14 @@ inode->i_size = isonum_733 (de->size); } - /* There are defective discs out there - we do this to protect - ourselves. A cdrom will never contain more than 800Mb - .. but a DVD may be up to 1Gig (Ulrich Habel) */ - - if ((inode->i_size < 0 || inode->i_size > 1073741824) && + /* + * The ISO-9660 filesystem only stores 32 bits for file size. + * mkisofs handles files up to 2GB-2 = 2147483646 = 0x7FFFFFFE bytes + * in size. This is according to the large file summit paper from 1996. + * WARNING: ISO-9660 filesystems > 1 GB and even > 2 GB are fully + * legal. Do not prevent to use DVD's sch...@fo... + */ + if ((inode->i_size < 0 || inode->i_size > 0x7FFFFFFE) && inode->i_sb->u.isofs_sb.s_cruft == 'n') { printk(KERN_WARNING "Warning: defective CD-ROM. " "Enabling \"cruft\" mount option.\n"); @@ -1229,6 +1264,10 @@ inode->u.isofs_i.i_first_extent = (isonum_733 (de->extent) + isonum_711 (de->ext_attr_length)); + /* Set the number of blocks for stat() - should be done before RR */ + inode->i_blksize = PAGE_CACHE_SIZE; /* For stat() only */ + inode->i_blocks = (inode->i_size + 511) >> 9; + /* * Now test for possible Rock Ridge extensions which will override * some of these numbers in the inode structure. @@ -1268,7 +1307,16 @@ { if (S_ISREG(inode->i_mode)) { inode->i_fop = &generic_ro_fops; - inode->i_data.a_ops = &isofs_aops; + switch ( inode->u.isofs_i.i_file_format ) { +#ifdef CONFIG_ZISOFS + case isofs_file_compressed: + inode->i_data.a_ops = &zisofs_aops; + break; +#endif + default: + inode->i_data.a_ops = &isofs_aops; + break; + } } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &isofs_dir_inode_operations; inode->i_fop = &isofs_dir_operations; @@ -1328,15 +1376,27 @@ static int __init init_iso9660_fs(void) { +#ifdef CONFIG_ZISOFS + int err; + + err = zisofs_init(); + if ( err ) + return err; +#endif return register_filesystem(&iso9660_fs_type); } static void __exit exit_iso9660_fs(void) { unregister_filesystem(&iso9660_fs_type); +#ifdef CONFIG_ZISOFS + zisofs_cleanup(); +#endif } EXPORT_NO_SYMBOLS; module_init(init_iso9660_fs) module_exit(exit_iso9660_fs) +MODULE_LICENSE("GPL"); + Index: joliet.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/isofs/joliet.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- joliet.c 25 Feb 2001 23:14:46 -0000 1.1.1.2 +++ joliet.c 9 Apr 2002 13:11:18 -0000 1.2 @@ -10,6 +10,7 @@ #include <linux/nls.h> #include <linux/slab.h> #include <linux/iso_fs.h> +#include <asm/unaligned.h> /* * Convert Unicode 16 to UTF8 or ASCII. @@ -17,15 +18,15 @@ static int uni16_to_x8(unsigned char *ascii, u16 *uni, int len, struct nls_table *nls) { - wchar_t *ip; + wchar_t *ip, ch; unsigned char *op; ip = uni; op = ascii; - while (*ip && len) { + while ((ch = get_unaligned(ip)) && len) { int llen; - wchar_t ch = be16_to_cpu(*ip); + ch = be16_to_cpu(ch); if ((llen = nls->uni2char(ch, op, NLS_MAX_CHARSET_SIZE)) > 0) op += llen; else Index: rock.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/isofs/rock.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- rock.c 25 Feb 2001 23:14:46 -0000 1.1.1.2 +++ rock.c 9 Apr 2002 13:11:18 -0000 1.2 @@ -24,15 +24,15 @@ * returns a symbolic link name, and a fourth one returns the extent number * for the file. */ -#define SIG(A,B) ((A << 8) | B) +#define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ /* This is a way of ensuring that we have something in the system use fields that is compatible with Rock Ridge */ #define CHECK_SP(FAIL) \ if(rr->u.SP.magic[0] != 0xbe) FAIL; \ - if(rr->u.SP.magic[1] != 0xef) FAIL; - + if(rr->u.SP.magic[1] != 0xef) FAIL; \ + inode->i_sb->u.isofs_sb.s_rock_offset=rr->u.SP.skip; /* We define a series of macros because each function must do exactly the same thing in certain places. We use the macros to ensure that everything is done correctly */ @@ -50,7 +50,14 @@ {LEN= sizeof(struct iso_directory_record) + DE->name_len[0]; \ if(LEN & 1) LEN++; \ CHR = ((unsigned char *) DE) + LEN; \ - LEN = *((unsigned char *) DE) - LEN;} + LEN = *((unsigned char *) DE) - LEN; \ + if (inode->i_sb->u.isofs_sb.s_rock_offset!=-1) \ + { \ + LEN-=inode->i_sb->u.isofs_sb.s_rock_offset; \ + CHR+=inode->i_sb->u.isofs_sb.s_rock_offset; \ + if (LEN<0) LEN=0; \ + } \ +} #define MAYBE_CONTINUE(LABEL,DEV) \ {if (buffer) kfree(buffer); \ @@ -106,7 +113,7 @@ while (len > 1){ /* There may be one byte for padding somewhere */ rr = (struct rock_ridge *) chr; if (rr->len == 0) goto out; /* Something got screwed up here */ - sig = (chr[0] << 8) + chr[1]; + sig = isonum_721(chr); chr += rr->len; len -= rr->len; @@ -167,7 +174,7 @@ while (len > 1){ /* There may be one byte for padding somewhere */ rr = (struct rock_ridge *) chr; if (rr->len == 0) goto out; /* Something got screwed up here */ - sig = (chr[0] << 8) + chr[1]; + sig = isonum_721(chr); chr += rr->len; len -= rr->len; @@ -220,8 +227,8 @@ return 0; } -int parse_rock_ridge_inode(struct iso_directory_record * de, - struct inode * inode){ +int parse_rock_ridge_inode_internal(struct iso_directory_record * de, + struct inode * inode,int regard_xa){ int len; unsigned char * chr; int symlink_len = 0; @@ -230,6 +237,13 @@ if (!inode->i_sb->u.isofs_sb.s_rock) return 0; SETUP_ROCK_RIDGE(de, chr, len); + if (regard_xa) + { + chr+=14; + len-=14; + if (len<0) len=0; + }; + repeat: { int cnt, sig; @@ -240,15 +254,17 @@ while (len > 1){ /* There may be one byte for padding somewhere */ rr = (struct rock_ridge *) chr; if (rr->len == 0) goto out; /* Something got screwed up here */ - sig = (chr[0] << 8) + chr[1]; + sig = isonum_721(chr); chr += rr->len; len -= rr->len; switch(sig){ +#ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ case SIG('R','R'): if((rr->u.RR.flags[0] & (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) goto out; break; +#endif case SIG('S','P'): CHECK_SP(goto out); break; @@ -361,11 +377,36 @@ inode->i_gid = reloc->i_gid; inode->i_rdev = reloc->i_rdev; inode->i_size = reloc->i_size; + inode->i_blocks = reloc->i_blocks; inode->i_atime = reloc->i_atime; inode->i_ctime = reloc->i_ctime; inode->i_mtime = reloc->i_mtime; iput(reloc); break; +#ifdef CONFIG_ZISOFS + case SIG('Z','F'): + if ( !inode->i_sb->u.isofs_sb.s_nocompress ) { + int algo; + algo = isonum_721(rr->u.ZF.algorithm); + if ( algo == SIG('p','z') ) { + int block_shift = isonum_711(&rr->u.ZF.parms[1]); + if ( block_shift < PAGE_CACHE_SHIFT || block_shift > 17 ) { + printk(KERN_WARNING "isofs: Can't handle ZF block size of 2^%d\n", block_shift); + } else { + /* Note: we don't change i_blocks here */ + inode->u.isofs_i.i_file_format = isofs_file_compressed; + /* Parameters to compression algorithm (header size, block size) */ + inode->u.isofs_i.i_format_parm[0] = isonum_711(&rr->u.ZF.parms[0]); + inode->u.isofs_i.i_format_parm[1] = isonum_711(&rr->u.ZF.parms[1]); + inode->i_size = isonum_733(rr->u.ZF.real_size); + } + } else { + printk(KERN_WARNING "isofs: Unknown ZF compression algorithm: %c%c\n", + rr->u.ZF.algorithm[0], rr->u.ZF.algorithm[1]); + } + } + break; +#endif default: break; } @@ -416,7 +457,7 @@ * If there is another SL record, and this component * record isn't continued, then add a slash. */ - if ((rr->u.SL.flags & 1) && !(oldslp->flags & 1)) + if ((!rootflag) && (rr->u.SL.flags & 1) && !(oldslp->flags & 1)) *rpnt++='/'; break; } @@ -431,6 +472,19 @@ return rpnt; } +int parse_rock_ridge_inode(struct iso_directory_record * de, + struct inode * inode) +{ + int result=parse_rock_ridge_inode_internal(de,inode,0); + /* if rockridge flag was reset and we didn't look for attributes + * behind eventual XA attributes, have a look there */ + if ((inode->i_sb->u.isofs_sb.s_rock_offset==-1) + &&(inode->i_sb->u.isofs_sb.s_rock==2)) + { + result=parse_rock_ridge_inode_internal(de,inode,14); + }; + return result; +}; /* readpage() for symlinks: reads symlink contents into the page and either makes it uptodate and returns 0 or returns error (-EIO) */ @@ -481,7 +535,7 @@ rr = (struct rock_ridge *) chr; if (rr->len == 0) goto out; /* Something got screwed up here */ - sig = (chr[0] << 8) + chr[1]; + sig = isonum_721(chr); chr += rr->len; len -= rr->len; Index: rock.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/isofs/rock.h,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- rock.h 14 Jan 2001 16:26:17 -0000 1.1.1.1 +++ rock.h 9 Apr 2002 13:11:18 -0000 1.2 @@ -6,7 +6,7 @@ struct SU_SP{ unsigned char magic[2]; unsigned char skip; -}; +} __attribute__((packed)); struct SU_CE{ char extent[8]; @@ -20,11 +20,11 @@ unsigned char len_src; unsigned char ext_ver; char data[0]; -}; +} __attribute__((packed)); struct RR_RR{ char flags[1]; -}; +} __attribute__((packed)); struct RR_PX{ char mode[8]; @@ -43,17 +43,17 @@ unsigned char flags; unsigned char len; char text[0]; -}; +} __attribute__((packed)); struct RR_SL{ unsigned char flags; struct SL_component link; -}; +} __attribute__((packed)); struct RR_NM{ unsigned char flags; char name[0]; -}; +} __attribute__((packed)); struct RR_CL{ char location[8]; @@ -65,11 +65,18 @@ struct stamp{ char time[7]; -}; +} __attribute__((packed)); struct RR_TF{ char flags; struct stamp times[0]; /* Variable number of these beasts */ +} __attribute__((packed)); + +/* Linux-specific extension for transparent decompression */ +struct RR_ZF{ + char algorithm[2]; + char parms[2]; + char real_size[8]; }; /* These are the bits and their meanings for flags in the TF structure. */ @@ -98,6 +105,7 @@ struct RR_CL CL; struct RR_PL PL; struct RR_TF TF; + struct RR_ZF ZF; } u; }; Index: util.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/isofs/util.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- util.c 14 Jan 2001 16:26:17 -0000 1.1.1.1 +++ util.c 9 Apr 2002 13:11:18 -0000 1.2 @@ -1,90 +1,9 @@ /* * linux/fs/isofs/util.c - * - * The special functions in the file are numbered according to the section - * of the iso 9660 standard in which they are described. isonum_733 will - * convert numbers according to section 7.3.3, etc. - * - * isofs special functions. This file was lifted in its entirety from - * the 386BSD iso9660 filesystem, by Pace Willisson <pa...@bl...>. */ #include <linux/time.h> - -int -isonum_711 (char * p) -{ - return (*p & 0xff); -} - -int -isonum_712 (char * p) -{ - int val; - - val = *p; - if (val & 0x80) - val |= 0xffffff00; - return (val); -} - -int -isonum_721 (char * p) -{ - return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); -} - -int -isonum_722 (char * p) -{ - return (((p[0] & 0xff) << 8) | (p[1] & 0xff)); -} - -int -isonum_723 (char * p) -{ -#if 0 - if (p[0] != p[3] || p[1] != p[2]) { - fprintf (stderr, "invalid format 7.2.3 number\n"); - exit (1); - } -#endif - return (isonum_721 (p)); -} - -int -isonum_731 (char * p) -{ - return ((p[0] & 0xff) - | ((p[1] & 0xff) << 8) - | ((p[2] & 0xff) << 16) - | ((p[3] & 0xff) << 24)); -} - -int -isonum_732 (char * p) -{ - return (((p[0] & 0xff) << 24) - | ((p[1] & 0xff) << 16) - | ((p[2] & 0xff) << 8) - | (p[3] & 0xff)); -} - -int -isonum_733 (char * p) -{ -#if 0 - int i; - - for (i = 0; i < 4; i++) { - if (p[i] != p[7-i]) { - fprintf (stderr, "bad format 7.3.3 number\n"); - exit (1); - } - } -#endif - return (isonum_731 (p)); -} +#include <linux/iso_fs.h> /* * We have to convert from a MM/DD/YY format to the Unix ctime format. |
Update of /cvsroot/linux-vax/kernel-2.4/fs/minix In directory usw-pr-cvs1:/tmp/cvs-serv29245/minix Modified Files: bitmap.c dir.c file.c inode.c itree_common.c itree_v1.c itree_v2.c namei.c Log Message: synch 2.4.15 commit 13 Index: bitmap.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/minix/bitmap.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- bitmap.c 14 Jan 2001 16:26:02 -0000 1.1.1.1 +++ bitmap.c 9 Apr 2002 13:19:34 -0000 1.2 @@ -11,13 +11,9 @@ /* bitmap.c contains the code that handles the inode and block bitmaps */ -#include <linux/sched.h> +#include <linux/fs.h> #include <linux/minix_fs.h> -#include <linux/stat.h> -#include <linux/kernel.h> -#include <linux/string.h> #include <linux/locks.h> -#include <linux/quotaops.h> #include <asm/bitops.h> @@ -68,10 +64,6 @@ printk("trying to free block not in datazone\n"); return; } - bh = get_hash_table(sb->s_dev,block,BLOCK_SIZE); - if (bh) - clear_bit(BH_Dirty, &bh->b_state); - brelse(bh); zone = block - sb->u.minix_sb.s_firstdatazone + 1; bit = zone & 8191; zone >>= 13; @@ -126,60 +118,53 @@ << sb->u.minix_sb.s_log_zone_size); } -static struct buffer_head *V1_minix_clear_inode(struct inode *inode) +struct minix_inode * +minix_V1_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh) { - struct buffer_head *bh; - struct minix_inode *raw_inode; - int ino, block; - - ino = inode->i_ino; - if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) { - printk("Bad inode number on dev %s: %d is out of range\n", - kdevname(inode->i_dev), ino); + int block; + struct minix_sb_info *sbi = &sb->u.minix_sb; + struct minix_inode *p; + + if (!ino || ino > sbi->s_ninodes) { + printk("Bad inode number on dev %s: %ld is out of range\n", + bdevname(sb->s_dev), ino); return NULL; } - block = (2 + inode->i_sb->u.minix_sb.s_imap_blocks + - inode->i_sb->u.minix_sb.s_zmap_blocks + - (ino - 1) / MINIX_INODES_PER_BLOCK); - bh = bread(inode->i_dev, block, BLOCK_SIZE); - if (!bh) { + ino--; + block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks + + ino / MINIX_INODES_PER_BLOCK; + *bh = bread(sb->s_dev, block, BLOCK_SIZE); + if (!*bh) { printk("unable to read i-node block\n"); return NULL; } - raw_inode = ((struct minix_inode *)bh->b_data + - (ino - 1) % MINIX_INODES_PER_BLOCK); - raw_inode->i_nlinks = 0; - raw_inode->i_mode = 0; - mark_buffer_dirty(bh); - return bh; + p = (void *)(*bh)->b_data; + return p + ino % MINIX_INODES_PER_BLOCK; } -static struct buffer_head *V2_minix_clear_inode(struct inode *inode) +struct minix2_inode * +minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh) { - struct buffer_head *bh; - struct minix2_inode *raw_inode; - int ino, block; + int block; + struct minix_sb_info *sbi = &sb->u.minix_sb; + struct minix2_inode *p; - ino = inode->i_ino; - if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) { - printk("Bad inode number on dev %s: %d is out of range\n", - kdevname(inode->i_dev), ino); + *bh = NULL; + if (!ino || ino > sbi->s_ninodes) { + printk("Bad inode number on dev %s: %ld is out of range\n", + bdevname(sb->s_dev), ino); return NULL; } - block = (2 + inode->i_sb->u.minix_sb.s_imap_blocks + - inode->i_sb->u.minix_sb.s_zmap_blocks + - (ino - 1) / MINIX2_INODES_PER_BLOCK); - bh = bread(inode->i_dev, block, BLOCK_SIZE); - if (!bh) { + ino--; + block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks + + ino / MINIX2_INODES_PER_BLOCK; + *bh = bread(sb->s_dev, block, BLOCK_SIZE); + if (!*bh) { printk("unable to read i-node block\n"); return NULL; } - raw_inode = ((struct minix2_inode *) bh->b_data + - (ino - 1) % MINIX2_INODES_PER_BLOCK); - raw_inode->i_nlinks = 0; - raw_inode->i_mode = 0; - mark_buffer_dirty(bh); - return bh; + p = (void *)(*bh)->b_data; + return p + ino % MINIX2_INODES_PER_BLOCK; } /* Clear the link count and mode of a deleted inode on disk. */ @@ -187,11 +172,25 @@ static void minix_clear_inode(struct inode *inode) { struct buffer_head *bh; - if (INODE_VERSION(inode) == MINIX_V1) - bh = V1_minix_clear_inode(inode); - else - bh = V2_minix_clear_inode(inode); - brelse (bh); + if (INODE_VERSION(inode) == MINIX_V1) { + struct minix_inode *raw_inode; + raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh); + if (raw_inode) { + raw_inode->i_nlinks = 0; + raw_inode->i_mode = 0; + } + } else { + struct minix2_inode *raw_inode; + raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh); + if (raw_inode) { + raw_inode->i_nlinks = 0; + raw_inode->i_mode = 0; + } + } + if (bh) { + mark_buffer_dirty(bh); + brelse (bh); + } } void minix_free_inode(struct inode * inode) Index: dir.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/minix/dir.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- dir.c 14 Jan 2001 16:26:07 -0000 1.1.1.1 +++ dir.c 9 Apr 2002 13:19:34 -0000 1.2 @@ -6,53 +6,368 @@ * minix directory handling functions */ -#include <linux/string.h> -#include <linux/errno.h> #include <linux/fs.h> #include <linux/minix_fs.h> -#include <linux/stat.h> +#include <linux/pagemap.h> + +typedef struct minix_dir_entry minix_dirent; static int minix_readdir(struct file *, void *, filldir_t); struct file_operations minix_dir_operations = { read: generic_read_dir, readdir: minix_readdir, - fsync: file_fsync, + fsync: minix_sync_file, }; -static int minix_readdir(struct file * filp, - void * dirent, filldir_t filldir) +static inline void dir_put_page(struct page *page) { - unsigned int offset; - struct buffer_head * bh; - struct minix_dir_entry * de; - struct minix_sb_info * info; + kunmap(page); + page_cache_release(page); +} + +static inline unsigned long dir_pages(struct inode *inode) +{ + return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; +} + +static int dir_commit_chunk(struct page *page, unsigned from, unsigned to) +{ + struct inode *dir = (struct inode *)page->mapping->host; + int err = 0; + page->mapping->a_ops->commit_write(NULL, page, from, to); + if (IS_SYNC(dir)) + err = waitfor_one_page(page); + return err; +} + +static struct page * dir_get_page(struct inode *dir, unsigned long n) +{ + struct address_space *mapping = dir->i_mapping; + struct page *page = read_cache_page(mapping, n, + (filler_t*)mapping->a_ops->readpage, NULL); + if (!IS_ERR(page)) { + wait_on_page(page); + kmap(page); + if (!Page_Uptodate(page)) + goto fail; + } + return page; + +fail: + dir_put_page(page); + return ERR_PTR(-EIO); +} + +static inline void *minix_next_entry(void *de, struct minix_sb_info *sbi) +{ + return (void*)((char*)de + sbi->s_dirsize); +} + +static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir) +{ + unsigned long pos = filp->f_pos; struct inode *inode = filp->f_dentry->d_inode; + struct super_block *sb = inode->i_sb; + unsigned offset = pos & ~PAGE_CACHE_MASK; + unsigned long n = pos >> PAGE_CACHE_SHIFT; + unsigned long npages = dir_pages(inode); + struct minix_sb_info *sbi = &sb->u.minix_sb; + unsigned chunk_size = sbi->s_dirsize; - info = &inode->i_sb->u.minix_sb; - if (filp->f_pos & (info->s_dirsize - 1)) - return -EBADF; - while (filp->f_pos < inode->i_size) { - offset = filp->f_pos & 1023; - bh = minix_bread(inode,(filp->f_pos)>>BLOCK_SIZE_BITS,0); - if (!bh) { - filp->f_pos += 1024-offset; + pos = (pos + chunk_size-1) & ~(chunk_size-1); + if (pos >= inode->i_size) + goto done; + + for ( ; n < npages; n++, offset = 0) { + char *p, *kaddr, *limit; + struct page *page = dir_get_page(inode, n); + + if (IS_ERR(page)) continue; - } - do { - de = (struct minix_dir_entry *) (offset + bh->b_data); + kaddr = (char *)page_address(page); + p = kaddr+offset; + limit = kaddr + PAGE_CACHE_SIZE - chunk_size; + for ( ; p <= limit ; p = minix_next_entry(p, sbi)) { + minix_dirent *de = (minix_dirent *)p; if (de->inode) { - int size = strnlen(de->name, info->s_namelen); - if (filldir(dirent, de->name, size, filp->f_pos, de->inode, DT_UNKNOWN) < 0) { - brelse(bh); - return 0; + int over; + unsigned l = strnlen(de->name,sbi->s_namelen); + + offset = p - kaddr; + over = filldir(dirent, de->name, l, + (n<<PAGE_CACHE_SHIFT) | offset, + de->inode, DT_UNKNOWN); + if (over) { + dir_put_page(page); + goto done; } } - offset += info->s_dirsize; - filp->f_pos += info->s_dirsize; - } while (offset < 1024 && filp->f_pos < inode->i_size); - brelse(bh); + } + dir_put_page(page); } + +done: + filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; UPDATE_ATIME(inode); return 0; +} + +static inline int namecompare(int len, int maxlen, + const char * name, const char * buffer) +{ + if (len < maxlen && buffer[len]) + return 0; + return !memcmp(name, buffer, len); +} + +/* + * minix_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + */ +minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page) +{ + const char * name = dentry->d_name.name; + int namelen = dentry->d_name.len; + struct inode * dir = dentry->d_parent->d_inode; + struct super_block * sb = dir->i_sb; + struct minix_sb_info * sbi = &sb->u.minix_sb; + unsigned long n; + unsigned long npages = dir_pages(dir); + struct page *page = NULL; + struct minix_dir_entry *de; + + *res_page = NULL; + + for (n = 0; n < npages; n++) { + char *kaddr; + page = dir_get_page(dir, n); + if (IS_ERR(page)) + continue; + + kaddr = (char*)page_address(page); + de = (struct minix_dir_entry *) kaddr; + kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize; + for ( ; (char *) de <= kaddr ; de = minix_next_entry(de,sbi)) { + if (!de->inode) + continue; + if (namecompare(namelen,sbi->s_namelen,name,de->name)) + goto found; + } + dir_put_page(page); + } + return NULL; + +found: + *res_page = page; + return de; +} + +int minix_add_link(struct dentry *dentry, struct inode *inode) +{ + struct inode *dir = dentry->d_parent->d_inode; + const char * name = dentry->d_name.name; + int namelen = dentry->d_name.len; + struct super_block * sb = dir->i_sb; + struct minix_sb_info * sbi = &sb->u.minix_sb; + struct page *page = NULL; + struct minix_dir_entry * de; + unsigned long npages = dir_pages(dir); + unsigned long n; + char *kaddr; + unsigned from, to; + int err; + + /* We take care of directory expansion in the same loop */ + for (n = 0; n <= npages; n++) { + page = dir_get_page(dir, n); + err = PTR_ERR(page); + if (IS_ERR(page)) + goto out; + kaddr = (char*)page_address(page); + de = (minix_dirent *)kaddr; + kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize; + while ((char *)de <= kaddr) { + if (!de->inode) + goto got_it; + err = -EEXIST; + if (namecompare(namelen,sbi->s_namelen,name,de->name)) + goto out_page; + de = minix_next_entry(de, sbi); + } + dir_put_page(page); + } + BUG(); + return -EINVAL; + +got_it: + from = (char*)de - (char*)page_address(page); + to = from + sbi->s_dirsize; + lock_page(page); + err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + if (err) + goto out_unlock; + memcpy (de->name, name, namelen); + memset (de->name + namelen, 0, sbi->s_dirsize - namelen - 2); + de->inode = inode->i_ino; + err = dir_commit_chunk(page, from, to); + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + mark_inode_dirty(dir); +out_unlock: + UnlockPage(page); +out_page: + dir_put_page(page); +out: + return err; +} + +int minix_delete_entry(struct minix_dir_entry *de, struct page *page) +{ + struct address_space *mapping = page->mapping; + struct inode *inode = (struct inode*)mapping->host; + char *kaddr = (char*)page_address(page); + unsigned from = (char*)de - kaddr; + unsigned to = from + inode->i_sb->u.minix_sb.s_dirsize; + int err; + + lock_page(page); + err = mapping->a_ops->prepare_write(NULL, page, from, to); + if (err) + BUG(); + de->inode = 0; + err = dir_commit_chunk(page, from, to); + UnlockPage(page); + dir_put_page(page); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + mark_inode_dirty(inode); + return err; +} + +int minix_make_empty(struct inode *inode, struct inode *dir) +{ + struct address_space *mapping = inode->i_mapping; + struct page *page = grab_cache_page(mapping, 0); + struct minix_sb_info * sbi = &inode->i_sb->u.minix_sb; + struct minix_dir_entry * de; + char *base; + int err; + + if (!page) + return -ENOMEM; + err = mapping->a_ops->prepare_write(NULL, page, 0, 2 * sbi->s_dirsize); + if (err) + goto fail; + + base = (char*)page_address(page); + memset(base, 0, PAGE_CACHE_SIZE); + + de = (struct minix_dir_entry *) base; + de->inode = inode->i_ino; + strcpy(de->name,"."); + de = minix_next_entry(de, sbi); + de->inode = dir->i_ino; + strcpy(de->name,".."); + + err = dir_commit_chunk(page, 0, 2 * sbi->s_dirsize); +fail: + UnlockPage(page); + page_cache_release(page); + return err; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +int minix_empty_dir(struct inode * inode) +{ + struct page *page = NULL; + unsigned long i, npages = dir_pages(inode); + struct minix_sb_info *sbi = &inode->i_sb->u.minix_sb; + + for (i = 0; i < npages; i++) { + char *kaddr; + minix_dirent * de; + page = dir_get_page(inode, i); + + if (IS_ERR(page)) + continue; + + kaddr = (char *)page_address(page); + de = (minix_dirent *)kaddr; + kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize; + + while ((char *)de <= kaddr) { + if (de->inode != 0) { + /* check for . and .. */ + if (de->name[0] != '.') + goto not_empty; + if (!de->name[1]) { + if (de->inode != inode->i_ino) + goto not_empty; + } else if (de->name[1] != '.') + goto not_empty; + else if (de->name[2]) + goto not_empty; + } + de = minix_next_entry(de, sbi); + } + dir_put_page(page); + } + return 1; + +not_empty: + dir_put_page(page); + return 0; +} + +/* Releases the page */ +void minix_set_link(struct minix_dir_entry *de, struct page *page, + struct inode *inode) +{ + struct inode *dir = (struct inode*)page->mapping->host; + struct minix_sb_info *sbi = &dir->i_sb->u.minix_sb; + unsigned from = (char *)de-(char*)page_address(page); + unsigned to = from + sbi->s_dirsize; + int err; + + lock_page(page); + err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + if (err) + BUG(); + de->inode = inode->i_ino; + err = dir_commit_chunk(page, from, to); + UnlockPage(page); + dir_put_page(page); + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + mark_inode_dirty(dir); +} + +struct minix_dir_entry * minix_dotdot (struct inode *dir, struct page **p) +{ + struct page *page = dir_get_page(dir, 0); + struct minix_sb_info *sbi = &dir->i_sb->u.minix_sb; + struct minix_dir_entry *de = NULL; + + if (!IS_ERR(page)) { + de = minix_next_entry(page_address(page), sbi); + *p = page; + } + return de; +} + +ino_t minix_inode_by_name(struct dentry *dentry) +{ + struct page *page; + struct minix_dir_entry *de = minix_find_entry(dentry, &page); + ino_t res = 0; + + if (de) { + res = de->inode; + dir_put_page(page); + } + return res; } Index: file.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/minix/file.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- file.c 14 Jan 2001 16:26:06 -0000 1.1.1.1 +++ file.c 9 Apr 2002 13:19:34 -0000 1.2 @@ -13,9 +13,10 @@ * We have mostly NULLs here: the current defaults are OK for * the minix filesystem. */ -static int minix_sync_file(struct file *, struct dentry *, int); +int minix_sync_file(struct file *, struct dentry *, int); struct file_operations minix_file_operations = { + llseek: generic_file_llseek, read: generic_file_read, write: generic_file_write, mmap: generic_file_mmap, @@ -26,14 +27,18 @@ truncate: minix_truncate, }; -static int minix_sync_file(struct file * file, - struct dentry *dentry, - int datasync) +int minix_sync_file(struct file * file, struct dentry *dentry, int datasync) { struct inode *inode = dentry->d_inode; + int err; - if (INODE_VERSION(inode) == MINIX_V1) - return V1_minix_sync_file(inode); - else - return V2_minix_sync_file(inode); + err = fsync_inode_buffers(inode); + err |= fsync_inode_data_buffers(inode); + if (!(inode->i_state & I_DIRTY)) + return err; + if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) + return err; + + err |= minix_sync_inode(inode); + return err ? -EIO : 0; } Index: inode.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/minix/inode.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- inode.c 25 Feb 2001 23:14:46 -0000 1.1.1.2 +++ inode.c 9 Apr 2002 13:19:34 -0000 1.2 @@ -11,21 +11,14 @@ #include <linux/module.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> +#include <linux/fs.h> +#include <linux/minix_fs.h> #include <linux/slab.h> -#include <linux/string.h> -#include <linux/stat.h> #include <linux/locks.h> #include <linux/init.h> #include <linux/smp_lock.h> #include <linux/highuid.h> - -#include <asm/system.h> -#include <asm/bitops.h> - -#include <linux/minix_fs.h> +#include <linux/blkdev.h> static void minix_read_inode(struct inode * inode); static void minix_write_inode(struct inode * inode, int wait); @@ -126,48 +119,6 @@ return 0; } -/* - * Check the root directory of the filesystem to make sure - * it really _is_ a Minix filesystem, and to check the size - * of the directory entry. - */ -static const char * minix_checkroot(struct super_block *s, struct inode *dir) -{ - struct buffer_head *bh; - struct minix_dir_entry *de; - const char * errmsg; - int dirsize; - - if (!S_ISDIR(dir->i_mode)) - return "root directory is not a directory"; - - bh = minix_bread(dir, 0, 0); - if (!bh) - return "unable to read root directory"; - - de = (struct minix_dir_entry *) bh->b_data; - errmsg = "bad root directory '.' entry"; - dirsize = BLOCK_SIZE; - if (de->inode == MINIX_ROOT_INO && strcmp(de->name, ".") == 0) { - errmsg = "bad root directory '..' entry"; - dirsize = 8; - } - - while ((dirsize <<= 1) < BLOCK_SIZE) { - de = (struct minix_dir_entry *) (bh->b_data + dirsize); - if (de->inode != MINIX_ROOT_INO) - continue; - if (strcmp(de->name, "..")) - continue; - s->u.minix_sb.s_dirsize = dirsize; - s->u.minix_sb.s_namelen = dirsize - 2; - errmsg = NULL; - break; - } - brelse(bh); - return errmsg; -} - static struct super_block *minix_read_super(struct super_block *s, void *data, int silent) { @@ -176,10 +127,10 @@ struct minix_super_block *ms; int i, block; kdev_t dev = s->s_dev; - const char * errmsg; struct inode *root_inode; unsigned int hblock; - + struct minix_sb_info *sbi = &s->u.minix_sb; + /* N.B. These should be compile-time tests. Unfortunately that is impossible. */ if (32 != sizeof (struct minix_inode)) @@ -187,8 +138,8 @@ if (64 != sizeof(struct minix2_inode)) panic("bad V2 i-node size"); - hblock = get_hardblocksize(dev); - if (hblock && hblock > BLOCK_SIZE) + hblock = get_hardsect_size(dev); + if (hblock > BLOCK_SIZE) goto out_bad_hblock; set_blocksize(dev, BLOCK_SIZE); @@ -196,103 +147,96 @@ goto out_bad_sb; ms = (struct minix_super_block *) bh->b_data; - s->u.minix_sb.s_ms = ms; - s->u.minix_sb.s_sbh = bh; - s->u.minix_sb.s_mount_state = ms->s_state; + sbi->s_ms = ms; + sbi->s_sbh = bh; + sbi->s_mount_state = ms->s_state; s->s_blocksize = BLOCK_SIZE; s->s_blocksize_bits = BLOCK_SIZE_BITS; - s->u.minix_sb.s_ninodes = ms->s_ninodes; - s->u.minix_sb.s_nzones = ms->s_nzones; - s->u.minix_sb.s_imap_blocks = ms->s_imap_blocks; - s->u.minix_sb.s_zmap_blocks = ms->s_zmap_blocks; - s->u.minix_sb.s_firstdatazone = ms->s_firstdatazone; - s->u.minix_sb.s_log_zone_size = ms->s_log_zone_size; - s->u.minix_sb.s_max_size = ms->s_max_size; + sbi->s_ninodes = ms->s_ninodes; + sbi->s_nzones = ms->s_nzones; + sbi->s_imap_blocks = ms->s_imap_blocks; + sbi->s_zmap_blocks = ms->s_zmap_blocks; + sbi->s_firstdatazone = ms->s_firstdatazone; + sbi->s_log_zone_size = ms->s_log_zone_size; + sbi->s_max_size = ms->s_max_size; s->s_magic = ms->s_magic; if (s->s_magic == MINIX_SUPER_MAGIC) { - s->u.minix_sb.s_version = MINIX_V1; - s->u.minix_sb.s_dirsize = 16; - s->u.minix_sb.s_namelen = 14; - s->u.minix_sb.s_link_max = MINIX_LINK_MAX; + sbi->s_version = MINIX_V1; + sbi->s_dirsize = 16; + sbi->s_namelen = 14; + sbi->s_link_max = MINIX_LINK_MAX; } else if (s->s_magic == MINIX_SUPER_MAGIC2) { - s->u.minix_sb.s_version = MINIX_V1; - s->u.minix_sb.s_dirsize = 32; - s->u.minix_sb.s_namelen = 30; - s->u.minix_sb.s_link_max = MINIX_LINK_MAX; + sbi->s_version = MINIX_V1; + sbi->s_dirsize = 32; + sbi->s_namelen = 30; + sbi->s_link_max = MINIX_LINK_MAX; } else if (s->s_magic == MINIX2_SUPER_MAGIC) { - s->u.minix_sb.s_version = MINIX_V2; - s->u.minix_sb.s_nzones = ms->s_zones; - s->u.minix_sb.s_dirsize = 16; - s->u.minix_sb.s_namelen = 14; - s->u.minix_sb.s_link_max = MINIX2_LINK_MAX; + sbi->s_version = MINIX_V2; + sbi->s_nzones = ms->s_zones; + sbi->s_dirsize = 16; + sbi->s_namelen = 14; + sbi->s_link_max = MINIX2_LINK_MAX; } else if (s->s_magic == MINIX2_SUPER_MAGIC2) { - s->u.minix_sb.s_version = MINIX_V2; - s->u.minix_sb.s_nzones = ms->s_zones; - s->u.minix_sb.s_dirsize = 32; - s->u.minix_sb.s_namelen = 30; - s->u.minix_sb.s_link_max = MINIX2_LINK_MAX; + sbi->s_version = MINIX_V2; + sbi->s_nzones = ms->s_zones; + sbi->s_dirsize = 32; + sbi->s_namelen = 30; + sbi->s_link_max = MINIX2_LINK_MAX; } else goto out_no_fs; /* * Allocate the buffer map to keep the superblock small. */ - i = (s->u.minix_sb.s_imap_blocks + s->u.minix_sb.s_zmap_blocks) * sizeof(bh); + i = (sbi->s_imap_blocks + sbi->s_zmap_blocks) * sizeof(bh); map = kmalloc(i, GFP_KERNEL); if (!map) goto out_no_map; memset(map, 0, i); - s->u.minix_sb.s_imap = &map[0]; - s->u.minix_sb.s_zmap = &map[s->u.minix_sb.s_imap_blocks]; + sbi->s_imap = &map[0]; + sbi->s_zmap = &map[sbi->s_imap_blocks]; block=2; - for (i=0 ; i < s->u.minix_sb.s_imap_blocks ; i++) { - if (!(s->u.minix_sb.s_imap[i]=bread(dev,block,BLOCK_SIZE))) + for (i=0 ; i < sbi->s_imap_blocks ; i++) { + if (!(sbi->s_imap[i]=bread(dev,block,BLOCK_SIZE))) goto out_no_bitmap; block++; } - for (i=0 ; i < s->u.minix_sb.s_zmap_blocks ; i++) { - if (!(s->u.minix_sb.s_zmap[i]=bread(dev,block,BLOCK_SIZE))) + for (i=0 ; i < sbi->s_zmap_blocks ; i++) { + if (!(sbi->s_zmap[i]=bread(dev,block,BLOCK_SIZE))) goto out_no_bitmap; block++; } - minix_set_bit(0,s->u.minix_sb.s_imap[0]->b_data); - minix_set_bit(0,s->u.minix_sb.s_zmap[0]->b_data); + minix_set_bit(0,sbi->s_imap[0]->b_data); + minix_set_bit(0,sbi->s_zmap[0]->b_data); + /* set up enough so that it can read an inode */ s->s_op = &minix_sops; root_inode = iget(s, MINIX_ROOT_INO); if (!root_inode) goto out_no_root; - /* - * Check the fs before we get the root dentry ... - */ - errmsg = minix_checkroot(s, root_inode); - if (errmsg) - goto out_bad_root; s->s_root = d_alloc_root(root_inode); if (!s->s_root) goto out_iput; - s->s_root->d_op = &minix_dentry_operations; + if (!NO_TRUNCATE) + s->s_root->d_op = &minix_dentry_operations; if (!(s->s_flags & MS_RDONLY)) { ms->s_state &= ~MINIX_VALID_FS; mark_buffer_dirty(bh); s->s_dirt = 1; } - if (!(s->u.minix_sb.s_mount_state & MINIX_VALID_FS)) + if (!(sbi->s_mount_state & MINIX_VALID_FS)) printk ("MINIX-fs: mounting unchecked file system, " "running fsck is recommended.\n"); - else if (s->u.minix_sb.s_mount_state & MINIX_ERROR_FS) + else if (sbi->s_mount_state & MINIX_ERROR_FS) printk ("MINIX-fs: mounting file system with errors, " "running fsck is recommended.\n"); return s; -out_bad_root: - if (!silent) - printk("MINIX-fs: %s\n", errmsg); out_iput: iput(root_inode); goto out_freemap; @@ -305,11 +249,11 @@ out_no_bitmap: printk("MINIX-fs: bad superblock or unable to read bitmaps\n"); out_freemap: - for (i = 0; i < s->u.minix_sb.s_imap_blocks; i++) - brelse(s->u.minix_sb.s_imap[i]); - for (i = 0; i < s->u.minix_sb.s_zmap_blocks; i++) - brelse(s->u.minix_sb.s_zmap[i]); - kfree(s->u.minix_sb.s_imap); + for (i = 0; i < sbi->s_imap_blocks; i++) + brelse(sbi->s_imap[i]); + for (i = 0; i < sbi->s_zmap_blocks; i++) + brelse(sbi->s_zmap[i]); + kfree(sbi->s_imap); goto out_release; out_no_map: @@ -357,45 +301,6 @@ return V2_minix_get_block(inode, block, bh_result, create); } -/* - * the global minix fs getblk function. - */ -struct buffer_head *minix_getblk(struct inode *inode, int block, int create) -{ - struct buffer_head dummy; - int error; - - dummy.b_state = 0; - dummy.b_blocknr = -1000; - error = minix_get_block(inode, block, &dummy, create); - if (!error && buffer_mapped(&dummy)) { - struct buffer_head *bh; - bh = getblk(dummy.b_dev, dummy.b_blocknr, BLOCK_SIZE); - if (buffer_new(&dummy)) { - memset(bh->b_data, 0, BLOCK_SIZE); - mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh); - } - return bh; - } - return NULL; -} - -struct buffer_head * minix_bread(struct inode * inode, int block, int create) -{ - struct buffer_head * bh; - - bh = minix_getblk(inode, block, create); - if (!bh || buffer_uptodate(bh)) - return bh; - ll_rw_block(READ, 1, &bh); - wait_on_buffer(bh); - if (buffer_uptodate(bh)) - return bh; - brelse(bh); - return NULL; -} - static int minix_writepage(struct page *page) { return block_write_full_page(page,minix_get_block); @@ -412,7 +317,7 @@ { return generic_block_bmap(mapping,block,minix_get_block); } -struct address_space_operations minix_aops = { +static struct address_space_operations minix_aops = { readpage: minix_readpage, writepage: minix_writepage, sync_page: block_sync_page, @@ -421,6 +326,23 @@ bmap: minix_bmap }; +void minix_set_inode(struct inode *inode, dev_t rdev) +{ + if (S_ISREG(inode->i_mode)) { + inode->i_op = &minix_file_inode_operations; + inode->i_fop = &minix_file_operations; + inode->i_mapping->a_ops = &minix_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &minix_dir_inode_operations; + inode->i_fop = &minix_dir_operations; + inode->i_mapping->a_ops = &minix_aops; + } else if (S_ISLNK(inode->i_mode)) { + inode->i_op = &page_symlink_inode_operations; + inode->i_mapping->a_ops = &minix_aops; + } else + init_special_inode(inode, inode->i_mode, rdev); +} + /* * The minix V1 function to read an inode. */ @@ -428,26 +350,11 @@ { struct buffer_head * bh; struct minix_inode * raw_inode; - int block, ino; + int i; - ino = inode->i_ino; - inode->i_mode = 0; - if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) { - printk("Bad inode number on dev %s" - ": %d is out of range\n", - kdevname(inode->i_dev), ino); + raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh); + if (!raw_inode) return; - } - block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + - inode->i_sb->u.minix_sb.s_zmap_blocks + - (ino-1)/MINIX_INODES_PER_BLOCK; - if (!(bh=bread(inode->i_dev,block, BLOCK_SIZE))) { - printk("Major problem: unable to read inode from dev " - "%s\n", kdevname(inode->i_dev)); - return; - } - raw_inode = ((struct minix_inode *) bh->b_data) + - (ino-1)%MINIX_INODES_PER_BLOCK; inode->i_mode = raw_inode->i_mode; inode->i_uid = (uid_t)raw_inode->i_uid; inode->i_gid = (gid_t)raw_inode->i_gid; @@ -455,20 +362,9 @@ inode->i_size = raw_inode->i_size; inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time; inode->i_blocks = inode->i_blksize = 0; - for (block = 0; block < 9; block++) - inode->u.minix_i.u.i1_data[block] = raw_inode->i_zone[block]; - if (S_ISREG(inode->i_mode)) { - inode->i_op = &minix_file_inode_operations; - inode->i_fop = &minix_file_operations; - inode->i_mapping->a_ops = &minix_aops; - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &minix_dir_inode_operations; - inode->i_fop = &minix_dir_operations; - } else if (S_ISLNK(inode->i_mode)) { - inode->i_op = &page_symlink_inode_operations; - inode->i_mapping->a_ops = &minix_aops; - } else - init_special_inode(inode, inode->i_mode, raw_inode->i_zone[0]); + for (i = 0; i < 9; i++) + inode->u.minix_i.u.i1_data[i] = raw_inode->i_zone[i]; + minix_set_inode(inode, raw_inode->i_zone[0]); brelse(bh); } @@ -479,26 +375,11 @@ { struct buffer_head * bh; struct minix2_inode * raw_inode; - int block, ino; + int i; - ino = inode->i_ino; - inode->i_mode = 0; - if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) { - printk("Bad inode number on dev %s" - ": %d is out of range\n", - kdevname(inode->i_dev), ino); - return; - } - block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + - inode->i_sb->u.minix_sb.s_zmap_blocks + - (ino-1)/MINIX2_INODES_PER_BLOCK; - if (!(bh=bread(inode->i_dev,block, BLOCK_SIZE))) { - printk("Major problem: unable to read inode from dev " - "%s\n", kdevname(inode->i_dev)); + raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh); + if (!raw_inode) return; - } - raw_inode = ((struct minix2_inode *) bh->b_data) + - (ino-1)%MINIX2_INODES_PER_BLOCK; inode->i_mode = raw_inode->i_mode; inode->i_uid = (uid_t)raw_inode->i_uid; inode->i_gid = (gid_t)raw_inode->i_gid; @@ -508,20 +389,9 @@ inode->i_atime = raw_inode->i_atime; inode->i_ctime = raw_inode->i_ctime; inode->i_blocks = inode->i_blksize = 0; - for (block = 0; block < 10; block++) - inode->u.minix_i.u.i2_data[block] = raw_inode->i_zone[block]; - if (S_ISREG(inode->i_mode)) { - inode->i_op = &minix_file_inode_operations; - inode->i_fop = &minix_file_operations; - inode->i_mapping->a_ops = &minix_aops; - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &minix_dir_inode_operations; - inode->i_fop = &minix_dir_operations; - } else if (S_ISLNK(inode->i_mode)) { - inode->i_op = &page_symlink_inode_operations; - inode->i_mapping->a_ops = &minix_aops; - } else - init_special_inode(inode, inode->i_mode, raw_inode->i_zone[0]); + for (i = 0; i < 10; i++) + inode->u.minix_i.u.i2_data[i] = raw_inode->i_zone[i]; + minix_set_inode(inode, raw_inode->i_zone[0]); brelse(bh); } @@ -543,23 +413,11 @@ { struct buffer_head * bh; struct minix_inode * raw_inode; - int ino, block; + int i; - ino = inode->i_ino; - if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) { - printk("Bad inode number on dev %s" - ": %d is out of range\n", - kdevname(inode->i_dev), ino); + raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh); + if (!raw_inode) return 0; - } - block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + inode->i_sb->u.minix_sb.s_zmap_blocks + - (ino-1)/MINIX_INODES_PER_BLOCK; - if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE))) { - printk("unable to read i-node block\n"); - return 0; - } - raw_inode = ((struct minix_inode *)bh->b_data) + - (ino-1)%MINIX_INODES_PER_BLOCK; raw_inode->i_mode = inode->i_mode; raw_inode->i_uid = fs_high2lowuid(inode->i_uid); raw_inode->i_gid = fs_high2lowgid(inode->i_gid); @@ -568,8 +426,8 @@ raw_inode->i_time = inode->i_mtime; if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev); - else for (block = 0; block < 9; block++) - raw_inode->i_zone[block] = inode->u.minix_i.u.i1_data[block]; + else for (i = 0; i < 9; i++) + raw_inode->i_zone[i] = inode->u.minix_i.u.i1_data[i]; mark_buffer_dirty(bh); return bh; } @@ -581,23 +439,11 @@ { struct buffer_head * bh; struct minix2_inode * raw_inode; - int ino, block; + int i; - ino = inode->i_ino; - if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) { - printk("Bad inode number on dev %s" - ": %d is out of range\n", - kdevname(inode->i_dev), ino); - return 0; - } - block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + inode->i_sb->u.minix_sb.s_zmap_blocks + - (ino-1)/MINIX2_INODES_PER_BLOCK; - if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE))) { - printk("unable to read i-node block\n"); + raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh); + if (!raw_inode) return 0; - } - raw_inode = ((struct minix2_inode *)bh->b_data) + - (ino-1)%MINIX2_INODES_PER_BLOCK; raw_inode->i_mode = inode->i_mode; raw_inode->i_uid = fs_high2lowuid(inode->i_uid); raw_inode->i_gid = fs_high2lowgid(inode->i_gid); @@ -608,8 +454,8 @@ raw_inode->i_ctime = inode->i_ctime; if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev); - else for (block = 0; block < 10; block++) - raw_inode->i_zone[block] = inode->u.minix_i.u.i2_data[block]; + else for (i = 0; i < 10; i++) + raw_inode->i_zone[i] = inode->u.minix_i.u.i2_data[i]; mark_buffer_dirty(bh); return bh; } @@ -683,3 +529,5 @@ module_init(init_minix_fs) module_exit(exit_minix_fs) +MODULE_LICENSE("GPL"); + Index: itree_common.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/minix/itree_common.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- itree_common.c 14 Jan 2001 16:26:08 -0000 1.1.1.1 +++ itree_common.c 9 Apr 2002 13:19:34 -0000 1.2 @@ -80,14 +80,14 @@ break; branch[n].key = cpu_to_block(nr); bh = getblk(inode->i_dev, parent, BLOCK_SIZE); - if (!buffer_uptodate(bh)) - wait_on_buffer(bh); + lock_buffer(bh); memset(bh->b_data, 0, BLOCK_SIZE); branch[n].bh = bh; branch[n].p = (block_t*) bh->b_data + offsets[n]; *branch[n].p = branch[n].key; mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh); + unlock_buffer(bh); + mark_buffer_dirty_inode(bh, inode); parent = nr; } if (n == num) @@ -127,7 +127,7 @@ /* had we spliced it onto indirect block? */ if (where->bh) - mark_buffer_dirty(where->bh); + mark_buffer_dirty_inode(where->bh, inode); mark_inode_dirty(inode); return 0; @@ -201,7 +201,7 @@ changed: while (partial > chain) { - bforget(partial->bh); + brelse(partial->bh); partial--; } goto reread; @@ -320,14 +320,14 @@ if (partial == chain) mark_inode_dirty(inode); else - mark_buffer_dirty(partial->bh); + mark_buffer_dirty_inode(partial->bh, inode); free_branches(inode, &nr, &nr+1, (chain+n-1) - partial); } /* Clear the ends of indirect blocks on the shared branch */ while (partial > chain) { free_branches(inode, partial->p + 1, block_end(partial->bh), (chain+n-1) - partial); - mark_buffer_dirty(partial->bh); + mark_buffer_dirty_inode(partial->bh, inode); brelse (partial->bh); partial--; } @@ -344,74 +344,4 @@ } inode->i_mtime = inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); -} - -static int sync_block (struct inode * inode, block_t block, int wait) -{ - struct buffer_head * bh; - - if (!block) - return 0; - bh = get_hash_table(inode->i_dev, block_to_cpu(block), BLOCK_SIZE); - if (!bh) - return 0; - if (wait && buffer_req(bh) && !buffer_uptodate(bh)) { - brelse(bh); - return -1; - } - if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) - { - brelse(bh); - return 0; - } - ll_rw_block(WRITE, 1, &bh); - atomic_dec(&bh->b_count); - return 0; -} - -static int sync_indirect(struct inode *inode, block_t iblock, int depth, - int wait) -{ - struct buffer_head * ind_bh = NULL; - int rc, err = 0; - - if (!iblock) - return 0; - - rc = sync_block (inode, iblock, wait); - if (rc) - return rc; - - ind_bh = bread(inode->i_dev, block_to_cpu(iblock), BLOCK_SIZE); - if (!ind_bh) - return -1; - - if (--depth) { - block_t *p = (block_t*)ind_bh->b_data; - block_t *end = block_end(ind_bh); - while (p < end) { - rc = sync_indirect (inode, *p++, depth, wait); - if (rc > 0) - break; - if (rc) - err = rc; - } - } - brelse(ind_bh); - return err; -} - -static inline int sync_file(struct inode * inode) -{ - int wait, err = 0, i; - block_t *idata = i_data(inode); - - lock_kernel(); - err = generic_buffer_fdatasync(inode, 0, ~0UL); - for (wait=0; wait<=1; wait++) - for (i=1; i<DEPTH; i++) - err |= sync_indirect(inode, idata[DIRECT+i-1], i, wait); - err |= minix_sync_inode (inode); - unlock_kernel(); - return (err < 0) ? -EIO : 0; } Index: itree_v1.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/minix/itree_v1.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- itree_v1.c 14 Jan 2001 16:26:08 -0000 1.1.1.1 +++ itree_v1.c 9 Apr 2002 13:19:34 -0000 1.2 @@ -1,6 +1,6 @@ -#include <linux/sched.h> -#include <linux/locks.h> +#include <linux/fs.h> #include <linux/minix_fs.h> +#include <linux/locks.h> #include <linux/smp_lock.h> enum {DEPTH = 3, DIRECT = 7}; /* Only double indirect */ @@ -55,9 +55,4 @@ void V1_minix_truncate(struct inode * inode) { truncate(inode); -} - -int V1_minix_sync_file(struct inode * inode) -{ - return sync_file(inode); } Index: itree_v2.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/minix/itree_v2.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- itree_v2.c 14 Jan 2001 16:26:08 -0000 1.1.1.1 +++ itree_v2.c 9 Apr 2002 13:19:34 -0000 1.2 @@ -1,6 +1,6 @@ -#include <linux/sched.h> -#include <linux/locks.h> +#include <linux/fs.h> #include <linux/minix_fs.h> +#include <linux/locks.h> #include <linux/smp_lock.h> enum {DIRECT = 7, DEPTH = 4}; /* Have triple indirect */ @@ -60,9 +60,4 @@ void V2_minix_truncate(struct inode * inode) { truncate(inode); -} - -int V2_minix_sync_file(struct inode * inode) -{ - return sync_file(inode); } Index: namei.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/minix/namei.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- namei.c 14 Jan 2001 16:26:04 -0000 1.1.1.1 +++ namei.c 9 Apr 2002 13:19:34 -0000 1.2 @@ -4,84 +4,33 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#include <linux/sched.h> +#include <linux/fs.h> #include <linux/minix_fs.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/stat.h> -#include <linux/fcntl.h> -#include <linux/errno.h> -#include <linux/quotaops.h> - -#include <asm/uaccess.h> - -/* - * comment out this line if you want names > info->s_namelen chars to be - * truncated. Else they will be disallowed (ENAMETOOLONG). - */ -/* #define NO_TRUNCATE */ +#include <linux/pagemap.h> -static inline int namecompare(int len, int maxlen, - const char * name, const char * buffer) +static inline void inc_count(struct inode *inode) { - if (len < maxlen && buffer[len]) - return 0; - return !memcmp(name, buffer, len); + inode->i_nlink++; + mark_inode_dirty(inode); } -/* - * minix_find_entry() - * - * finds an entry in the specified directory with the wanted name. It - * returns the cache buffer in which the entry was found, and the entry - * itself (as a parameter - res_dir). It does NOT read the inode of the - * entry - you'll have to do that yourself if you want to. - */ -static struct buffer_head * minix_find_entry(struct inode * dir, - const char * name, int namelen, struct minix_dir_entry ** res_dir) -{ - unsigned long block, offset; - struct buffer_head * bh; - struct minix_sb_info * info; - struct minix_dir_entry *de; - - *res_dir = NULL; - info = &dir->i_sb->u.minix_sb; - if (namelen > info->s_namelen) { -#ifdef NO_TRUNCATE - return NULL; -#else - namelen = info->s_namelen; -#endif - } - bh = NULL; - block = offset = 0; - while (block*BLOCK_SIZE+offset < dir->i_size) { - if (!bh) { - bh = minix_bread(dir,block,0); - if (!bh) { - block++; - continue; - } - } - de = (struct minix_dir_entry *) (bh->b_data + offset); - offset += info->s_dirsize; - if (de->inode && namecompare(namelen,info->s_namelen,name,de->name)) { - *res_dir = de; - return bh; - } - if (offset < bh->b_size) - continue; - brelse(bh); - bh = NULL; - offset = 0; - block++; - } - brelse(bh); - return NULL; +static inline void dec_count(struct inode *inode) +{ + inode->i_nlink--; + mark_inode_dirty(inode); } -#ifndef NO_TRUNCATE +static int add_nondir(struct dentry *dentry, struct inode *inode) +{ + int err = minix_add_link(dentry, inode); + if (!err) { + d_instantiate(dentry, inode); + return 0; + } + dec_count(inode); + iput(inode); + return err; +} static int minix_hash(struct dentry *dentry, struct qstr *qstr) { @@ -103,27 +52,22 @@ return 0; } -#endif - struct dentry_operations minix_dentry_operations = { -#ifndef NO_TRUNCATE d_hash: minix_hash, -#endif }; static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry) { struct inode * inode = NULL; - struct minix_dir_entry * de; - struct buffer_head * bh; + ino_t ino; + + dentry->d_op = dir->i_sb->s_root->d_op; -#ifndef NO_TRUNCATE - dentry->d_op = &minix_dentry_operations; -#endif - bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); - if (bh) { - int ino = de->inode; - brelse (bh); + if (dentry->d_name.len > dir->i_sb->u.minix_sb.s_namelen) + return ERR_PTR(-ENAMETOOLONG); + + ino = minix_inode_by_name(dentry); + if (ino) { inode = iget(dir->i_sb, ino); if (!inode) @@ -133,481 +77,226 @@ return NULL; } -/* - * minix_add_entry() - * - * adds a file entry to the specified directory, returning a possible - * error value if it fails. - * - * NOTE!! The inode part of 'de' is left at 0 - which means you - * may not sleep between calling this and putting something into - * the entry, as someone else might have used it while you slept. - */ -static int minix_add_entry(struct inode * dir, - const char * name, int namelen, - struct buffer_head ** res_buf, - struct minix_dir_entry ** res_dir) +static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev) { - int i; - unsigned long block, offset; - struct buffer_head * bh; - struct minix_dir_entry * de; - struct minix_sb_info * info; + int error; + struct inode * inode = minix_new_inode(dir, &error); - *res_buf = NULL; - *res_dir = NULL; - info = &dir->i_sb->u.minix_sb; - if (namelen > info->s_namelen) { -#ifdef NO_TRUNCATE - return -ENAMETOOLONG; -#else - namelen = info->s_namelen; -#endif - } - if (!namelen) - return -ENOENT; - bh = NULL; - block = offset = 0; - while (1) { - if (!bh) { - bh = minix_bread(dir,block,1); - if (!bh) - return -ENOSPC; - } - de = (struct minix_dir_entry *) (bh->b_data + offset); - offset += info->s_dirsize; - if (block*bh->b_size + offset > dir->i_size) { - de->inode = 0; - dir->i_size = block*bh->b_size + offset; - mark_inode_dirty(dir); - } - if (!de->inode) { - dir->i_mtime = dir->i_ctime = CURRENT_TIME; - mark_inode_dirty(dir); - for (i = 0; i < info->s_namelen ; i++) - de->name[i] = (i < namelen) ? name[i] : 0; - dir->i_version = ++event; - mark_buffer_dirty(bh); - *res_dir = de; - break; - } - if (offset < bh->b_size) - continue; - brelse(bh); - bh = NULL; - offset = 0; - block++; + if (inode) { + inode->i_mode = mode; + minix_set_inode(inode, rdev); + mark_inode_dirty(inode); + error = add_nondir(dentry, inode); } - *res_buf = bh; - return 0; + return error; } static int minix_create(struct inode * dir, struct dentry *dentry, int mode) { - int error; - struct inode * inode; - struct buffer_head * bh; - struct minix_dir_entry * de; - - inode = minix_new_inode(dir, &error); - if (!inode) - return error; - inode->i_op = &minix_file_inode_operations; - inode->i_fop = &minix_file_operations; - inode->i_mapping->a_ops = &minix_aops; - inode->i_mode = mode; - mark_inode_dirty(inode); - error = minix_add_entry(dir, dentry->d_name.name, - dentry->d_name.len, &bh ,&de); - if (error) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput(inode); - return error; - } - de->inode = inode->i_ino; - mark_buffer_dirty(bh); - brelse(bh); - d_instantiate(dentry, inode); - return 0; + return minix_mknod(dir, dentry, mode, 0); } -static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev) +static int minix_symlink(struct inode * dir, struct dentry *dentry, + const char * symname) { - int error; + int err = -ENAMETOOLONG; + int i = strlen(symname)+1; struct inode * inode; - struct buffer_head * bh; - struct minix_dir_entry * de; - inode = minix_new_inode(dir, &error); + if (i > dir->i_sb->s_blocksize) + goto out; + + inode = minix_new_inode(dir, &err); if (!inode) - return error; - inode->i_uid = current->fsuid; - init_special_inode(inode, mode, rdev); - mark_inode_dirty(inode); - error = minix_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de); - if (error) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput(inode); - return error; - } - de->inode = inode->i_ino; - mark_buffer_dirty(bh); - brelse(bh); - d_instantiate(dentry, inode); - return 0; -} + goto out; -static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode) -{ - int error; - struct inode * inode; - struct buffer_head * bh, *dir_block; - struct minix_dir_entry * de; - struct minix_sb_info * info; + inode->i_mode = S_IFLNK | 0777; + minix_set_inode(inode, 0); + err = block_symlink(inode, symname, i); + if (err) + goto out_fail; - info = &dir->i_sb->u.minix_sb; - if (dir->i_nlink >= info->s_link_max) - return -EMLINK; - inode = minix_new_inode(dir, &error); - if (!inode) - return error; - inode->i_op = &minix_dir_inode_operations; - inode->i_fop = &minix_dir_operations; - inode->i_size = 2 * info->s_dirsize; - dir_block = minix_bread(inode,0,1); - if (!dir_block) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput(inode); - return -ENOSPC; - } - de = (struct minix_dir_entry *) dir_block->b_data; - de->inode=inode->i_ino; - strcpy(de->name,"."); - de = (struct minix_dir_entry *) (dir_block->b_data + info->s_dirsize); - de->inode = dir->i_ino; - strcpy(de->name,".."); - inode->i_nlink = 2; - mark_buffer_dirty(dir_block); - brelse(dir_block); - inode->i_mode = S_IFDIR | mode; - if (dir->i_mode & S_ISGID) - inode->i_mode |= S_ISGID; - mark_inode_dirty(inode); - error = minix_add_entry(dir, dentry->d_name.name, - dentry->d_name.len, &bh, &de); - if (error) { - inode->i_nlink=0; - iput(inode); - return error; - } - de->inode = inode->i_ino; - mark_buffer_dirty(bh); - dir->i_nlink++; - mark_inode_dirty(dir); - brelse(bh); - d_instantiate(dentry, inode); - return 0; + err = add_nondir(dentry, inode); +out: + return err; + +out_fail: + dec_count(inode); + iput(inode); + goto out; } -/* - * routine to check that the specified directory is empty (for rmdir) - */ -static int empty_dir(struct inode * inode) +static int minix_link(struct dentry * old_dentry, struct inode * dir, + struct dentry *dentry) { - unsigned int block, offset; - struct buffer_head * bh; - struct minix_dir_entry * de; - struct minix_sb_info * info; + struct inode *inode = old_dentry->d_inode; - info = &inode->i_sb->u.minix_sb; - block = 0; - bh = NULL; - offset = 2*info->s_dirsize; - if (inode->i_size & (info->s_dirsize-1)) - goto bad_dir; - if (inode->i_size < offset) - goto bad_dir; - bh = minix_bread(inode,0,0); - if (!bh) - goto bad_dir; - de = (struct minix_dir_entry *) bh->b_data; - if (!de->inode || strcmp(de->name,".")) - goto bad_dir; - de = (struct minix_dir_entry *) (bh->b_data + info->s_dirsize); - if (!de->inode || strcmp(de->name,"..")) - goto bad_dir; - while (block*BLOCK_SIZE+offset < inode->i_size) { - if (!bh) { - bh = minix_bread(inode,block,0); - if (!bh) { - block++; - continue; - } - } - de = (struct minix_dir_entry *) (bh->b_data + offset); - offset += info->s_dirsize; - if (de->inode) { - brelse(bh); - return 0; - } - if (offset < bh->b_size) - continue; - brelse(bh); - bh = NULL; - offset = 0; - block++; - } - brelse(bh); - return 1; -bad_dir: - brelse(bh); - printk("Bad directory on device %s\n", - kdevname(inode->i_dev)); - return 1; -} + if (S_ISDIR(inode->i_mode)) + return -EPERM; -static int minix_rmdir(struct inode * dir, struct dentry *dentry) -{ - int retval; - struct inode * inode; - struct buffer_head * bh; - struct minix_dir_entry * de; + if (inode->i_nlink >= inode->i_sb->u.minix_sb.s_link_max) + return -EMLINK; - inode = NULL; - bh = minix_find_entry(dir, dentry->d_name.name, - dentry->d_name.len, &de); - retval = -ENOENT; - if (!bh) - goto end_rmdir; - inode = dentry->d_inode; - - if (!empty_dir(inode)) { - retval = -ENOTEMPTY; - goto end_rmdir; - } - if (de->inode != inode->i_ino) { - retval = -ENOENT; - goto end_rmdir; - } - if (inode->i_nlink != 2) - printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink); - de->inode = 0; - dir->i_version = ++event; - mark_buffer_dirty(bh); - inode->i_nlink=0; - mark_inode_dirty(inode); - inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; - dir->i_nlink--; - mark_inode_dirty(dir); - retval = 0; -end_rmdir: - brelse(bh); - return retval; + inode->i_ctime = CURRENT_TIME; + inc_count(inode); + atomic_inc(&inode->i_count); + return add_nondir(dentry, inode); } -static int minix_unlink(struct inode * dir, struct dentry *dentry) +static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode) { - int retval; struct inode * inode; - struct buffer_head * bh; - struct minix_dir_entry * de; + int err = -EMLINK; - retval = -ENOENT; - inode = dentry->d_inode; - bh = minix_find_entry(dir, dentry->d_name.name, - dentry->d_name.len, &de); - if (!bh || de->inode != inode->i_ino) - 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); - inode->i_nlink=1; - } - de->inode = 0; - dir->i_version = ++event; - mark_buffer_dirty(bh); - dir->i_ctime = dir->i_mtime = CURRENT_TIME; - mark_inode_dirty(dir); - inode->i_nlink--; - inode->i_ctime = dir->i_ctime; - mark_inode_dirty(inode); - retval = 0; -end_unlink: - brelse(bh); - return retval; -} + if (dir->i_nlink >= dir->i_sb->u.minix_sb.s_link_max) + goto out; -static int minix_symlink(struct inode * dir, struct dentry *dentry, - const char * symname) -{ - struct minix_dir_entry * de; - struct inode * inode = NULL; - struct buffer_head * bh = NULL; - int i; - int err; + inc_count(dir); - err = -ENAMETOOLONG; - i = strlen(symname)+1; - if (i>1024) - goto out; inode = minix_new_inode(dir, &err); if (!inode) - goto out; + goto out_dir; - inode->i_mode = S_IFLNK | 0777; - inode->i_op = &page_symlink_inode_operations; - inode->i_mapping->a_ops = &minix_aops; - err = block_symlink(inode, symname, i); + inode->i_mode = S_IFDIR | mode; + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + minix_set_inode(inode, 0); + + inc_count(inode); + + err = minix_make_empty(inode, dir); if (err) - goto fail; + goto out_fail; - err = minix_add_entry(dir, dentry->d_name.name, - dentry->d_name.len, &bh, &de); + err = minix_add_link(dentry, inode); if (err) - goto fail; + goto out_fail; - de->inode = inode->i_ino; - mark_buffer_dirty(bh); - brelse(bh); d_instantiate(dentry, inode); out: return err; -fail: - inode->i_nlink--; - mark_inode_dirty(inode); + +out_fail: + dec_count(inode); + dec_count(inode); iput(inode); +out_dir: + dec_count(dir); goto out; } -static int minix_link(struct dentry * old_dentry, struct inode * dir, - struct dentry *dentry) +static int minix_unlink(struct inode * dir, struct dentry *dentry) { - int error; - struct inode *inode = old_dentry->d_inode; + int err = -ENOENT; + struct inode * inode = dentry->d_inode; + struct page * page; struct minix_dir_entry * de; - struct buffer_head * bh; - if (S_ISDIR(inode->i_mode)) - return -EPERM; + de = minix_find_entry(dentry, &page); + if (!de) + goto end_unlink; - if (inode->i_nlink >= inode->i_sb->u.minix_sb.s_link_max) - return -EMLINK; + err = minix_delete_entry(de, page); + if (err) + goto end_unlink; - error = minix_add_entry(dir, dentry->d_name.name, - dentry->d_name.len, &bh, &de); - if (error) { - brelse(bh); - return error; - } - de->inode = inode->i_ino; - mark_buffer_dirty(bh); - brelse(bh); - inode->i_nlink++; - inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); - atomic_inc(&inode->i_count); - d_instantiate(dentry, inode); - return 0; + inode->i_ctime = dir->i_ctime; + dec_count(inode); +end_unlink: + return err; } -#define PARENT_INO(buffer) \ -(((struct minix_dir_entry *) ((buffer)+info->s_dirsize))->inode) +static int minix_rmdir(struct inode * dir, struct dentry *dentry) +{ + struct inode * inode = dentry->d_inode; + int err = -ENOTEMPTY; + + if (minix_empty_dir(inode)) { + err = minix_unlink(dir, dentry); + if (!err) { + dec_count(dir); + dec_count(inode); + } + } + return err; +} -/* - * Anybody can rename anything with this: the permission checks are left to the - * higher-level routines. - */ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir, struct dentry *new_dentry) { - struct inode * old_inode, * new_inode; - struct buffer_head * old_bh, * new_bh, * dir_bh; - struct minix_dir_entry * old_de, * new_de; - struct minix_sb_info * info; - int retval; - - info = &old_dir->i_sb->u.minix_sb; - new_bh = dir_bh = NULL; - old_inode = old_dentry->d_inode; - new_inode = new_dentry->d_inode; - old_bh = minix_find_entry(old_dir, old_dentry->d_name.name, - old_dentry->d_name.len, &old_de); - retval = -ENOENT; - if (!old_bh || old_de->inode != old_inode->i_ino) - goto end_rename; - retval = -EPERM; - new_bh = minix_find_entry(new_dir, new_dentry->d_name.name, - new_dentry->d_name.len, &new_de); - if (new_bh) { - if (!new_inode) { - brelse(new_bh); - new_bh = NULL; - } - } + struct minix_sb_info * info = &old_dir->i_sb->u.minix_sb; + struct inode * old_inode = old_dentry->d_inode; + struct inode * new_inode = new_dentry->d_inode; + struct page * dir_page = NULL; + struct minix_dir_entry * dir_de = NULL; + struct page * old_page; + struct minix_dir_entry * old_de; + int err = -ENOENT; + + old_de = minix_find_entry(old_dentry, &old_page); + if (!old_de) + goto out; + if (S_ISDIR(old_inode->i_mode)) { - if (new_inode) { - retval = -ENOTEMPTY; - if (!empty_dir(new_inode)) - goto end_rename; - } - retval = -EIO; - dir_bh = minix_bread(old_inode,0,0); - if (!dir_bh) - goto end_rename; - if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) - goto end_rename; - retval = -EMLINK; - if (!new_inode && new_dir != old_dir && - new_dir->i_nlink >= info->s_link_max) - goto end_rename; + err = -EIO; + dir_de = minix_dotdot(old_inode, &dir_page); + if (!dir_de) + goto out_old; } - if (!new_bh) { - retval = minix_add_entry(new_dir, - new_dentry->d_name.name, - new_dentry->d_name.len, - &new_bh, &new_de); - if (retval) - goto end_rename; - } -/* ok, that's it */ - new_de->inode = old_inode->i_ino; - old_de->inode = 0; - old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; - old_dir->i_version = ++event; - mark_inode_dirty(old_dir); - new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME; - new_dir->i_version = ++event; - mark_inode_dirty(new_dir); + if (new_inode) { - new_inode->i_nlink--; + struct page * new_page; + struct minix_dir_entry * new_de; + + err = -ENOTEMPTY; + if (dir_de && !minix_empty_dir(new_inode)) + goto out_dir; + + err = -ENOENT; + new_de = minix_find_entry(new_dentry, &new_page); + if (!new_de) + goto out_dir; + inc_count(old_inode); + minix_set_link(new_de, new_page, old_inode); new_inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(new_inode); - } - mark_buffer_dirty(old_bh); - mark_buffer_dirty(new_bh); - if (dir_bh) { - PARENT_INO(dir_bh->b_data) = new_dir->i_ino; - mark_buffer_dirty(dir_bh); - old_dir->i_nlink--; - mark_inode_dirty(old_dir); - if (new_inode) { + if (dir_de) new_inode->i_nlink--; - mark_inode_dirty(new_inode); - } else { - new_dir->i_nlink++; - mark_inode_dirty(new_dir); + dec_count(new_inode); + } else { + if (dir_de) { + err = -EMLINK; + if (new_dir->i_nlink >= info->s_link_max) + goto out_dir; + } + inc_count(old_inode); + err = minix_add_link(new_dentry, old_inode); + if (err) { + dec_count(old_inode); + goto out_dir; } + if (dir_de) + inc_count(new_dir); + } + + minix_delete_entry(old_de, old_page); + dec_count(old_inode); + + if (dir_de) { + minix_set_link(dir_de, dir_page, new_dir); + dec_count(old_dir); } - retval = 0; -end_rename: - brelse(dir_bh); - brelse(old_bh); - brelse(new_bh); - return retval; + return 0; + +out_dir: + if (dir_de) { + kunmap(dir_page); + page_cache_release(dir_page); + } +out_old: + kunmap(old_page); + page_cache_release(old_page); +out: + return err; } /* |
From: Andy P. <at...@us...> - 2002-04-09 14:08:27
|
Update of /cvsroot/linux-vax/kernel-2.4/fs/openpromfs In directory usw-pr-cvs1:/tmp/cvs-serv29245/openpromfs Modified Files: inode.c Log Message: synch 2.4.15 commit 13 Index: inode.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/openpromfs/inode.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- inode.c 25 Feb 2001 23:14:48 -0000 1.1.1.2 +++ inode.c 9 Apr 2002 13:19:36 -0000 1.2 @@ -1053,3 +1053,4 @@ module_init(init_openprom_fs) module_exit(exit_openprom_fs) +MODULE_LICENSE("GPL"); |
From: Andy P. <at...@us...> - 2002-04-09 14:08:27
|
Update of /cvsroot/linux-vax/kernel-2.4/drivers/acorn/net In directory usw-pr-cvs1:/tmp/cvs-serv12544/acorn/net Modified Files: ether1.c ether3.c etherh.c Log Message: synch 2.4.15 commit 16 Index: ether1.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/acorn/net/ether1.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- ether1.c 25 Feb 2001 23:15:12 -0000 1.1.1.2 +++ ether1.c 9 Apr 2002 14:00:57 -0000 1.2 @@ -75,7 +75,7 @@ /* ------------------------------------------------------------------------- */ -static const char version[] __initdata = KERN_INFO "ether1 ethernet driver (c) 2000 Russell King v1.07\n"; +static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n"; #define BUS_16 16 #define BUS_8 8 @@ -990,7 +990,7 @@ static unsigned int version_printed = 0; if (net_debug && version_printed++ == 0) - printk (version); + printk(KERN_INFO "%s", version); } static struct net_device * __init ether1_init_one(struct expansion_card *ec) @@ -1045,7 +1045,6 @@ release: release_region(dev->base_addr, 16); release_region(dev->base_addr + 0x800, 4096); -free: unregister_netdev(dev); kfree(dev); out: @@ -1103,3 +1102,5 @@ module_init(ether1_init); module_exit(ether1_exit); + +MODULE_LICENSE("GPL"); Index: ether3.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/acorn/net/ether3.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- ether3.c 25 Feb 2001 23:15:12 -0000 1.1.1.2 +++ ether3.c 9 Apr 2002 14:00:57 -0000 1.2 @@ -70,7 +70,7 @@ #include <asm/io.h> #include <asm/irq.h> -static const char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n"; +static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n"; #include "ether3.h" @@ -777,7 +777,7 @@ static unsigned version_printed = 0; if (net_debug && version_printed++ == 0) - printk(version); + printk(KERN_INFO "%s", version); } static const char * __init @@ -938,3 +938,5 @@ module_init(ether3_init); module_exit(ether3_exit); + +MODULE_LICENSE("GPL"); Index: etherh.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/acorn/net/etherh.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- etherh.c 25 Feb 2001 23:15:12 -0000 1.1.1.2 +++ etherh.c 9 Apr 2002 14:00:57 -0000 1.2 @@ -7,10 +7,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * NS8390 ANT etherh specific driver - * For Acorn machines - * + * NS8390 I-cubed EtherH and ANT EtherM specific driver * Thanks to I-Cubed for information on their cards. + * EtherM conversion (C) 1999 Chris Kemp and Tim Watterton + * EtherM integration (C) 2000 Aleph One Ltd (Tak-Shing Chan) + * EtherM integration re-engineered by Russell King. * * Changelog: * 08-12-1996 RMK 1.00 Created @@ -19,12 +20,9 @@ * 16-04-1998 RMK 1.05 Improved media autodetection * 10-02-2000 RMK 1.06 Updated for 2.3.43 * 13-05-2000 RMK 1.07 Updated for 2.3.99-pre8 - * - * Insmod Module Parameters - * ------------------------ - * io=<io_base> - * irq=<irqno> - * xcvr=<0|1> 0 = 10bT, 1=10b2 (Lan600/600A only) + * 12-10-1999 CK/TEW EtherM driver first release + * 21-12-2000 TTC EtherH/EtherM integration + * 25-12-2000 RMK 1.08 Clean integration of EtherM into this driver. */ #include <linux/module.h> @@ -57,18 +55,22 @@ #define DEBUG_INIT 2 static unsigned int net_debug = NET_DEBUG; + static const card_ids __init etherh_cids[] = { - { MANU_I3, PROD_I3_ETHERLAN500 }, - { MANU_I3, PROD_I3_ETHERLAN600 }, - { MANU_I3, PROD_I3_ETHERLAN600A }, - { 0xffff, 0xffff } + { MANU_ANT, PROD_ANT_ETHERM }, + { MANU_I3, PROD_I3_ETHERLAN500 }, + { MANU_I3, PROD_I3_ETHERLAN600 }, + { MANU_I3, PROD_I3_ETHERLAN600A }, + { 0xffff, 0xffff } }; + MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("i3 EtherH driver"); +MODULE_DESCRIPTION("EtherH/EtherM driver"); +MODULE_LICENSE("GPL"); -static const char version[] __initdata = - "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King v1.07\n"; +static char version[] __initdata = + "EtherH/EtherM Driver (c) 2000 Russell King v1.08\n"; #define ETHERH500_DATAPORT 0x200 /* MEMC */ #define ETHERH500_NS8390 0x000 /* MEMC */ @@ -83,13 +85,24 @@ #define ETHERH_CP_HEARTBEAT 2 #define ETHERH_TX_START_PAGE 1 -#define ETHERH_STOP_PAGE 0x7f +#define ETHERH_STOP_PAGE 127 + +/* + * These came from CK/TEW + */ +#define ETHERM_DATAPORT 0x080 /* MEMC */ +#define ETHERM_NS8390 0x200 /* MEMC */ +#define ETHERM_CTRLPORT 0x08f /* MEMC */ + +#define ETHERM_TX_START_PAGE 64 +#define ETHERM_STOP_PAGE 127 /* --------------------------------------------------------------------------- */ static void etherh_setif(struct net_device *dev) { + struct ei_device *ei_local = (struct ei_device *) dev->priv; unsigned long addr, flags; save_flags_cli(flags); @@ -133,6 +146,7 @@ static int etherh_getifstat(struct net_device *dev) { + struct ei_device *ei_local = (struct ei_device *) dev->priv; int stat = 0; switch (dev->mem_end) { @@ -199,6 +213,8 @@ static void etherh_reset(struct net_device *dev) { + struct ei_device *ei_local = (struct ei_device *) dev->priv; + outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, dev->base_addr); /* @@ -206,8 +222,8 @@ * Note that we use 'interface_num' as a flag * to indicate that we need to change the media. */ - if (dev->flags & IFF_AUTOMEDIA && ei_status.interface_num) { - ei_status.interface_num = 0; + if (dev->flags & IFF_AUTOMEDIA && ei_local->interface_num) { + ei_local->interface_num = 0; if (dev->if_port == IF_PORT_10BASET) dev->if_port = IF_PORT_10BASE2; @@ -224,17 +240,18 @@ static void etherh_block_output (struct net_device *dev, int count, const unsigned char *buf, int start_page) { + struct ei_device *ei_local = (struct ei_device *) dev->priv; unsigned int addr, dma_addr; unsigned long dma_start; - - if (ei_status.dmaing) { - printk ("%s: DMAing conflict in etherh_block_input: " + + if (ei_local->dmaing) { + printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: " " DMAstat %d irqlock %d\n", dev->name, - ei_status.dmaing, ei_status.irqlock); + ei_local->dmaing, ei_local->irqlock); return; } - ei_status.dmaing |= 1; + ei_local->dmaing |= 1; addr = dev->base_addr; dma_addr = dev->mem_start; @@ -257,7 +274,7 @@ outb (start_page, addr + EN0_RSARHI); outb (E8390_RWRITE | E8390_START, addr + E8390_CMD); - if (ei_status.word16) + if (ei_local->word16) outsw (dma_addr, buf, count >> 1); else outsb (dma_addr, buf, count); @@ -266,14 +283,15 @@ while ((inb (addr + EN0_ISR) & ENISR_RDC) == 0) if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ - printk ("%s: timeout waiting for TX RDC\n", dev->name); + printk(KERN_ERR "%s: timeout waiting for TX RDC\n", + dev->name); etherh_reset (dev); NS8390_init (dev, 1); break; } outb (ENISR_RDC, addr + EN0_ISR); - ei_status.dmaing &= ~1; + ei_local->dmaing &= ~1; } /* @@ -282,17 +300,18 @@ static void etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) { + struct ei_device *ei_local = (struct ei_device *) dev->priv; unsigned int addr, dma_addr; unsigned char *buf; - if (ei_status.dmaing) { - printk ("%s: DMAing conflict in etherh_block_input: " + if (ei_local->dmaing) { + printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: " " DMAstat %d irqlock %d\n", dev->name, - ei_status.dmaing, ei_status.irqlock); + ei_local->dmaing, ei_local->irqlock); return; } - ei_status.dmaing |= 1; + ei_local->dmaing |= 1; addr = dev->base_addr; dma_addr = dev->mem_start; @@ -305,7 +324,7 @@ outb (ring_offset >> 8, addr + EN0_RSARHI); outb (E8390_RREAD | E8390_START, addr + E8390_CMD); - if (ei_status.word16) { + if (ei_local->word16) { insw (dma_addr, buf, count >> 1); if (count & 1) buf[count - 1] = inb (dma_addr); @@ -313,7 +332,7 @@ insb (dma_addr, buf, count); outb (ENISR_RDC, addr + EN0_ISR); - ei_status.dmaing &= ~1; + ei_local->dmaing &= ~1; } /* @@ -322,16 +341,17 @@ static void etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { + struct ei_device *ei_local = (struct ei_device *) dev->priv; unsigned int addr, dma_addr; - if (ei_status.dmaing) { - printk ("%s: DMAing conflict in etherh_get_header: " + if (ei_local->dmaing) { + printk(KERN_ERR "%s: DMAing conflict in etherh_get_header: " " DMAstat %d irqlock %d\n", dev->name, - ei_status.dmaing, ei_status.irqlock); + ei_local->dmaing, ei_local->irqlock); return; } - ei_status.dmaing |= 1; + ei_local->dmaing |= 1; addr = dev->base_addr; dma_addr = dev->mem_start; @@ -343,13 +363,13 @@ outb (ring_page, addr + EN0_RSARHI); outb (E8390_RREAD | E8390_START, addr + E8390_CMD); - if (ei_status.word16) + if (ei_local->word16) insw (dma_addr, hdr, sizeof (*hdr) >> 1); else insb (dma_addr, hdr, sizeof (*hdr)); outb (ENISR_RDC, addr + EN0_ISR); - ei_status.dmaing &= ~1; + ei_local->dmaing &= ~1; } /* @@ -363,7 +383,9 @@ static int etherh_open(struct net_device *dev) { - if (request_irq(dev->irq, ei_interrupt, 0, "etherh", dev)) + struct ei_device *ei_local = (struct ei_device *) dev->priv; + + if (request_irq(dev->irq, ei_interrupt, 0, dev->name, dev)) return -EAGAIN; /* @@ -371,7 +393,7 @@ * media type on the next reset - we are about to * do automedia manually now. */ - ei_status.interface_num = 0; + ei_local->interface_num = 0; /* * If we are doing automedia detection, do it now. @@ -431,36 +453,7 @@ static int version_printed; if (net_debug && version_printed++ == 0) - printk(version); -} - -static int __init etherh_check_presence(struct net_device *dev) -{ - unsigned int addr = dev->base_addr, reg0, tmp; - - reg0 = inb(addr); - if (reg0 == 0xff) { - if (net_debug & DEBUG_INIT) - printk("%s: etherh error: NS8390 command register wrong\n", - dev->name); - return -ENODEV; - } - - outb(E8390_NODMA | E8390_PAGE1 | E8390_STOP, addr + E8390_CMD); - tmp = inb(addr + 13); - outb(0xff, addr + 13); - outb(E8390_NODMA | E8390_PAGE0, addr + E8390_CMD); - inb(addr + EN0_COUNTER0); - if (inb(addr + EN0_COUNTER0) != 0) { - if (net_debug & DEBUG_INIT) - printk("%s: etherh error: NS8390 not found\n", - dev->name); - outb(reg0, addr); - outb(tmp, addr + 13); - return -ENODEV; - } - - return 0; + printk(KERN_INFO "%s", version); } /* @@ -485,11 +478,36 @@ return ENODEV; } +/* + * Create an ethernet address from the system serial number. + */ +static int __init etherm_addr(char *addr) +{ + unsigned int serial; + + if (system_serial_low == 0 && system_serial_high == 0) + return ENODEV; + + serial = system_serial_low | system_serial_high; + + addr[0] = 0; + addr[1] = 0; + addr[2] = 0xa4; + addr[3] = 0x10 + (serial >> 24); + addr[4] = serial >> 16; + addr[5] = serial >> 8; + return 0; +} + +static u32 etherh_regoffsets[16]; +static u32 etherm_regoffsets[16]; + static struct net_device * __init etherh_init_one(struct expansion_card *ec) { + struct ei_device *ei_local; struct net_device *dev; const char *dev_type; - int i; + int i, size; etherh_banner(); @@ -501,8 +519,6 @@ SET_MODULE_OWNER(dev); - etherh_addr(dev->dev_addr, ec); - dev->open = etherh_open; dev->stop = etherh_close; dev->set_config = etherh_set_config; @@ -512,7 +528,17 @@ ec->ops = ðerh_ops; switch (ec->cid.product) { + case PROD_ANT_ETHERM: + if (etherm_addr(dev->dev_addr)) + goto free; + dev->base_addr += ETHERM_NS8390; + dev->mem_start = dev->base_addr + ETHERM_DATAPORT; + ec->irq_data = (void *)(dev->base_addr + ETHERM_CTRLPORT); + break; + case PROD_I3_ETHERLAN500: + if (etherh_addr(dev->dev_addr, ec)) + goto free; dev->base_addr += ETHERH500_NS8390; dev->mem_start = dev->base_addr + ETHERH500_DATAPORT; dev->rmem_start = (unsigned long) @@ -522,34 +548,54 @@ case PROD_I3_ETHERLAN600: case PROD_I3_ETHERLAN600A: + if (etherh_addr(dev->dev_addr, ec)) + goto free; dev->base_addr += ETHERH600_NS8390; dev->mem_start = dev->base_addr + ETHERH600_DATAPORT; ec->irq_data = (void *)(dev->base_addr + ETHERH600_CTRLPORT); break; default: - printk("%s: etherh error: unknown card type %x\n", + printk(KERN_ERR "%s: unknown card type %x\n", dev->name, ec->cid.product); - goto out; + goto free; } - if (!request_region(dev->base_addr, 16, dev->name)) - goto region_not_free; + size = 16; + if (ec->cid.product == PROD_ANT_ETHERM) + size <<= 3; + + if (!request_region(dev->base_addr, size, dev->name)) + goto free; - if (etherh_check_presence(dev) || ethdev_init(dev)) + if (ethdev_init(dev)) goto release; + /* + * Unfortunately, ethdev_init eventually calls + * ether_setup, which re-writes dev->flags. + */ switch (ec->cid.product) { + case PROD_ANT_ETHERM: + dev_type = "ANT EtherM"; + dev->if_port = IF_PORT_UNKNOWN; + break; + case PROD_I3_ETHERLAN500: - dev_type = "500"; + dev_type = "i3 EtherH 500"; + dev->if_port = IF_PORT_UNKNOWN; break; case PROD_I3_ETHERLAN600: - dev_type = "600"; + dev_type = "i3 EtherH 600"; + dev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA; + dev->if_port = IF_PORT_10BASET; break; case PROD_I3_ETHERLAN600A: - dev_type = "600A"; + dev_type = "i3 EtherH 600A"; + dev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA; + dev->if_port = IF_PORT_10BASET; break; default: @@ -557,39 +603,31 @@ break; } - printk("%s: etherh %s at %lx, IRQ%d, ether address ", - dev->name, dev_type, dev->base_addr, dev->irq); + printk(KERN_INFO "%s: %s in slot %d, ", + dev->name, dev_type, ec->slot_no); for (i = 0; i < 6; i++) - printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]); + printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); - /* - * Unfortunately, ethdev_init eventually calls - * ether_setup, which re-writes dev->flags. - */ - switch (ec->cid.product) { - case PROD_I3_ETHERLAN500: - dev->if_port = IF_PORT_UNKNOWN; - break; - - case PROD_I3_ETHERLAN600: - case PROD_I3_ETHERLAN600A: - dev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA; - dev->if_port = IF_PORT_10BASET; - break; - } - - ei_status.name = dev->name; - ei_status.word16 = 1; - ei_status.tx_start_page = ETHERH_TX_START_PAGE; - ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES; - ei_status.stop_page = ETHERH_STOP_PAGE; - - ei_status.reset_8390 = etherh_reset; - ei_status.block_input = etherh_block_input; - ei_status.block_output = etherh_block_output; - ei_status.get_8390_hdr = etherh_get_header; - ei_status.interface_num = 0; + ei_local = (struct ei_device *) dev->priv; + if (ec->cid.product == PROD_ANT_ETHERM) { + ei_local->tx_start_page = ETHERM_TX_START_PAGE; + ei_local->stop_page = ETHERM_STOP_PAGE; + ei_local->reg_offset = etherm_regoffsets; + } else { + ei_local->tx_start_page = ETHERH_TX_START_PAGE; + ei_local->stop_page = ETHERH_STOP_PAGE; + ei_local->reg_offset = etherh_regoffsets; + } + + ei_local->name = dev->name; + ei_local->word16 = 1; + ei_local->rx_start_page = ei_local->tx_start_page + TX_PAGES; + ei_local->reset_8390 = etherh_reset; + ei_local->block_input = etherh_block_input; + ei_local->block_output = etherh_block_output; + ei_local->get_8390_hdr = etherh_get_header; + ei_local->interface_num = 0; etherh_reset(dev); NS8390_init(dev, 0); @@ -597,7 +635,7 @@ release: release_region(dev->base_addr, 16); -region_not_free: +free: unregister_netdev(dev); kfree(dev); out: @@ -614,6 +652,11 @@ { int i, ret = -ENODEV; + for (i = 0; i < 16; i++) { + etherh_regoffsets[i] = i; + etherm_regoffsets[i] = i << 3; + } + ecard_startfind(); for (i = 0; i < MAX_ECARDS; i++) { @@ -642,8 +685,12 @@ for (i = 0; i < MAX_ETHERH_CARDS; i++) { if (e_dev[i]) { + int size; unregister_netdev(e_dev[i]); - release_region(e_dev[i]->base_addr, 16); + size = 16; + if (e_card[i]->cid.product == PROD_ANT_ETHERM) + size <<= 3; + release_region(e_dev[i]->base_addr, size); kfree(e_dev[i]); e_dev[i] = NULL; } |