summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in9
-rw-r--r--fs/Makefile392
-rw-r--r--fs/adfs/adfs.h1
-rw-r--r--fs/adfs/dir.c10
-rw-r--r--fs/adfs/dir_f.c8
-rw-r--r--fs/adfs/dir_f.h10
-rw-r--r--fs/adfs/dir_fplus.c6
-rw-r--r--fs/adfs/dir_fplus.h10
-rw-r--r--fs/adfs/file.c1
-rw-r--r--fs/adfs/inode.c6
-rw-r--r--fs/adfs/map.c6
-rw-r--r--fs/adfs/super.c9
-rw-r--r--fs/affs/amigaffs.c8
-rw-r--r--fs/affs/bitmap.c4
-rw-r--r--fs/affs/file.c16
-rw-r--r--fs/affs/inode.c8
-rw-r--r--fs/affs/namei.c4
-rw-r--r--fs/affs/super.c8
-rw-r--r--fs/attr.c29
-rw-r--r--fs/autofs/waitq.c4
-rw-r--r--fs/autofs4/waitq.c4
-rw-r--r--fs/bfs/dir.c6
-rw-r--r--fs/bfs/file.c6
-rw-r--r--fs/bfs/inode.c12
-rw-r--r--fs/binfmt_elf.c2
-rw-r--r--fs/block_dev.c52
-rw-r--r--fs/buffer.c168
-rw-r--r--fs/coda/cache.c172
-rw-r--r--fs/coda/cnode.c96
-rw-r--r--fs/coda/coda_linux.c7
-rw-r--r--fs/coda/dir.c43
-rw-r--r--fs/coda/file.c9
-rw-r--r--fs/coda/inode.c130
-rw-r--r--fs/coda/pioctl.c5
-rw-r--r--fs/coda/psdev.c93
-rw-r--r--fs/coda/symlink.c1
-rw-r--r--fs/coda/sysctl.c11
-rw-r--r--fs/coda/upcall.c29
-rw-r--r--fs/cramfs/uncompress.c2
-rw-r--r--fs/dcache.c27
-rw-r--r--fs/devices.c4
-rw-r--r--fs/dnotify.c140
-rw-r--r--fs/dquot.c29
-rw-r--r--fs/exec.c2
-rw-r--r--fs/ext2/Makefile2
-rw-r--r--fs/ext2/balloc.c13
-rw-r--r--fs/ext2/bitmap.c2
-rw-r--r--fs/ext2/dir.c1
-rw-r--r--fs/ext2/file.c1
-rw-r--r--fs/ext2/fsync.c1
-rw-r--r--fs/ext2/ialloc.c24
-rw-r--r--fs/ext2/inode.c374
-rw-r--r--fs/ext2/ioctl.c1
-rw-r--r--fs/ext2/namei.c22
-rw-r--r--fs/ext2/super.c15
-rw-r--r--fs/ext2/symlink.c1
-rw-r--r--fs/ext2/truncate.c382
-rw-r--r--fs/fat/buffer.c15
-rw-r--r--fs/fat/cache.c6
-rw-r--r--fs/fat/cvf.c4
-rw-r--r--fs/fat/dir.c2
-rw-r--r--fs/fat/inode.c2
-rw-r--r--fs/fat/misc.c4
-rw-r--r--fs/fat/msbuffer.h3
-rw-r--r--fs/fcntl.c71
-rw-r--r--fs/file_table.c57
-rw-r--r--fs/filesystems.c48
-rw-r--r--fs/hfs/file.c2
-rw-r--r--fs/hpfs/anode.c34
-rw-r--r--fs/hpfs/buffer.c8
-rw-r--r--fs/hpfs/dnode.c4
-rw-r--r--fs/hpfs/ea.c6
-rw-r--r--fs/hpfs/inode.c2
-rw-r--r--fs/hpfs/namei.c12
-rw-r--r--fs/hpfs/super.c6
-rw-r--r--fs/inode.c30
-rw-r--r--fs/jffs/inode-v23.c514
-rw-r--r--fs/jffs/intrep.c503
-rw-r--r--fs/jffs/intrep.h16
-rw-r--r--fs/jffs/jffs_fm.c28
-rw-r--r--fs/jffs/jffs_fm.h8
-rw-r--r--fs/lockd/clntlock.c2
-rw-r--r--fs/lockd/clntproc.c18
-rw-r--r--fs/lockd/host.c4
-rw-r--r--fs/lockd/svc.c12
-rw-r--r--fs/lockd/svclock.c4
-rw-r--r--fs/lockd/svcshare.c1
-rw-r--r--fs/lockd/xdr.c4
-rw-r--r--fs/lockd/xdr4.c4
-rw-r--r--fs/locks.c788
-rw-r--r--fs/minix/Makefile2
-rw-r--r--fs/minix/bitmap.c29
-rw-r--r--fs/minix/file.c14
-rw-r--r--fs/minix/fsync.c344
-rw-r--r--fs/minix/inode.c591
-rw-r--r--fs/minix/itree_common.c417
-rw-r--r--fs/minix/itree_v1.c63
-rw-r--r--fs/minix/itree_v2.c68
-rw-r--r--fs/minix/namei.c28
-rw-r--r--fs/minix/truncate.c420
-rw-r--r--fs/msdos/namei.c12
-rw-r--r--fs/namei.c44
-rw-r--r--fs/ncpfs/dir.c3
-rw-r--r--fs/ncpfs/file.c2
-rw-r--r--fs/ncpfs/ioctl.c3
-rw-r--r--fs/nfs/Makefile2
-rw-r--r--fs/nfs/dir.c30
-rw-r--r--fs/nfs/file.c7
-rw-r--r--fs/nfs/inode.c1
-rw-r--r--fs/nfs/nfs3proc.c34
-rw-r--r--fs/nfs/nfsroot.c1
-rw-r--r--fs/nfs/proc.c27
-rw-r--r--fs/nfs/unlink.c216
-rw-r--r--fs/nfsd/export.c14
-rw-r--r--fs/nfsd/nfs3proc.c1
-rw-r--r--fs/nfsd/nfs3xdr.c2
-rw-r--r--fs/nfsd/nfsctl.c10
-rw-r--r--fs/nfsd/nfsfh.c2
-rw-r--r--fs/nfsd/nfssvc.c10
-rw-r--r--fs/nfsd/nfsxdr.c2
-rw-r--r--fs/nfsd/vfs.c46
-rw-r--r--fs/ntfs/support.c2
-rw-r--r--fs/open.c14
-rw-r--r--fs/partitions/acorn.c11
-rw-r--r--fs/partitions/check.c51
-rw-r--r--fs/partitions/mac.c10
-rw-r--r--fs/proc/array.c4
-rw-r--r--fs/proc/generic.c2
-rw-r--r--fs/proc/kcore.c87
-rw-r--r--fs/proc/proc_misc.c46
-rw-r--r--fs/proc/procfs_syms.c4
-rw-r--r--fs/qnx4/bitmap.c2
-rw-r--r--fs/qnx4/inode.c4
-rw-r--r--fs/qnx4/namei.c4
-rw-r--r--fs/ramfs/inode.c2
-rw-r--r--fs/read_write.c15
-rw-r--r--fs/smbfs/inode.c9
-rw-r--r--fs/smbfs/sock.c8
-rw-r--r--fs/super.c60
-rw-r--r--fs/sysv/balloc.c16
-rw-r--r--fs/sysv/ialloc.c14
-rw-r--r--fs/sysv/inode.c10
-rw-r--r--fs/sysv/namei.c24
-rw-r--r--fs/sysv/truncate.c6
-rw-r--r--fs/udf/balloc.c12
-rw-r--r--fs/udf/file.c4
-rw-r--r--fs/udf/ialloc.c9
-rw-r--r--fs/udf/inode.c22
-rw-r--r--fs/udf/namei.c10
-rw-r--r--fs/udf/super.c4
-rw-r--r--fs/udf/truncate.c4
-rw-r--r--fs/ufs/balloc.c20
-rw-r--r--fs/ufs/cylinder.c2
-rw-r--r--fs/ufs/ialloc.c12
-rw-r--r--fs/ufs/inode.c6
-rw-r--r--fs/ufs/namei.c24
-rw-r--r--fs/ufs/super.c10
-rw-r--r--fs/ufs/truncate.c8
-rw-r--r--fs/ufs/util.c4
-rw-r--r--fs/ufs/util.h2
-rw-r--r--fs/umsdos/dir.c3
-rw-r--r--fs/umsdos/emd.c8
-rw-r--r--fs/umsdos/ioctl.c3
-rw-r--r--fs/vfat/namei.c10
164 files changed, 4042 insertions, 3645 deletions
diff --git a/fs/Config.in b/fs/Config.in
index 183aab8f8..d728d2166 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -76,7 +76,7 @@ if [ "$CONFIG_NET" = "y" ]; then
dep_tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS $CONFIG_INET
dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET
- dep_mbool ' Provide NFSv3 client support (EXPERIMENTAL)' CONFIG_NFS_V3 $CONFIG_NFS_FS
+ dep_mbool ' Provide NFSv3 client support' CONFIG_NFS_V3 $CONFIG_NFS_FS
dep_bool ' Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP
dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET
@@ -100,8 +100,11 @@ if [ "$CONFIG_NET" = "y" ]; then
dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET
if [ "$CONFIG_SMB_FS" != "n" ]; then
- string 'Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE ""
- fi
+ bool ' Use a default NLS' CONFIG_SMB_NLS_DEFAULT
+ if [ "$CONFIG_SMB_NLS_DEFAULT" = "y" ]; then
+ string ' Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE "cp437"
+ fi
+ fi
if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS
source fs/ncpfs/Config.in
diff --git a/fs/Makefile b/fs/Makefile
index 4e67ec808..5bed63c84 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -1,347 +1,91 @@
#
# Makefile for the Linux filesystems.
#
-# 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 (not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile.
+# 14 Sep 2000, Christoph Hellwig <hch@caldera.de>
+# Rewritten to use lists instead of if-statements.
+#
-FILESYSTEMS = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
O_TARGET := fs.o
-O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \
- super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
- ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \
- dcache.o inode.o attr.o bad_inode.o file.o iobuf.o \
- $(BINFMTS) $(FILESYSTEMS)
-ALL_SUB_DIRS := coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
- hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \
- nfsd nls devpts devfs adfs partitions qnx4 udf bfs cramfs \
- openpromfs autofs4 ramfs jffs
+export-objs := filesystems.o
+mod-subdirs := nls
-SUB_DIRS :=
+obj-y := open.o read_write.o devices.o file_table.o buffer.o \
+ super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
+ ioctl.o readdir.o select.o fifo.o locks.o \
+ dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
+ filesystems.o
ifeq ($(CONFIG_QUOTA),y)
-O_OBJS += dquot.o
+obj-y += dquot.o
else
-O_OBJS += noquot.o
-endif
-
-ifdef CONFIG_PROC_FS
-SUB_DIRS += proc
+obj-y += noquot.o
endif
-SUB_DIRS += partitions
+subdir-$(CONFIG_PROC_FS) += proc
+subdir-y += partitions
# Do not add any filesystems before this line
+subdir-$(CONFIG_EXT2_FS) += ext2
+subdir-$(CONFIG_CRAMFS) += cramfs
+subdir-$(CONFIG_RAMFS) += ramfs
+subdir-$(CONFIG_CODA_FS) += coda
+subdir-$(CONFIG_MINIX_FS) += minix
+subdir-$(CONFIG_FAT_FS) += fat
+subdir-$(CONFIG_MSDOS_FS) += msdos
+subdir-$(CONFIG_VFAT_FS) += vfat
+subdir-$(CONFIG_BFS_FS) += bfs
+subdir-$(CONFIG_ISO9660_FS) += isofs
+subdir-$(CONFIG_DEVFS_FS) += devfs
+subdir-$(CONFIG_HFS_FS) += hfs
+subdir-$(CONFIG_NFS_FS) += nfs
+subdir-$(CONFIG_NFSD) += nfsd
+subdir-$(CONFIG_LOCKD) += lockd
+subdir-$(CONFIG_NLS) += nls
+subdir-$(CONFIG_UMSDOS_FS) += umsdos
+subdir-$(CONFIG_SYSV_FS) += sysv
+subdir-$(CONFIG_SMB_FS) += smbfs
+subdir-$(CONFIG_NCP_FS) += ncpfs
+subdir-$(CONFIG_HPFS_FS) += hpfs
+subdir-$(CONFIG_NTFS_FS) += ntfs
+subdir-$(CONFIG_UFS_FS) += ufs
+subdir-$(CONFIG_EFS_FS) += efs
+subdir-$(CONFIG_JFFS_FS) += jffs
+subdir-$(CONFIG_AFFS_FS) += affs
+subdir-$(CONFIG_ROMFS_FS) += romfs
+subdir-$(CONFIG_QNX4FS_FS) += qnx4
+subdir-$(CONFIG_UDF_FS) += udf
+subdir-$(CONFIG_AUTOFS_FS) += autofs
+subdir-$(CONFIG_AUTOFS4_FS) += autofs4
+subdir-$(CONFIG_ADFS_FS) += adfs
+subdir-$(CONFIG_DEVPTS_FS) += devpts
+subdir-$(CONFIG_SUN_OPENPROMFS) += openpromfs
+
+
+obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o
+obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o
+obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o
-ifeq ($(CONFIG_EXT2_FS),y)
-SUB_DIRS += ext2
-else
- ifeq ($(CONFIG_EXT2_FS),m)
- MOD_SUB_DIRS += ext2
- endif
-endif
-
-ifeq ($(CONFIG_CRAMFS),y)
-SUB_DIRS += cramfs
-else
- ifeq ($(CONFIG_CRAMFS),m)
- MOD_SUB_DIRS += cramfs
- endif
-endif
-
-ifeq ($(CONFIG_RAMFS),y)
-SUB_DIRS += ramfs
-else
- ifeq ($(CONFIG_RAMFS),m)
- MOD_SUB_DIRS += ramfs
- endif
-endif
-
-ifeq ($(CONFIG_CODA_FS),y)
-SUB_DIRS += coda
-else
- ifeq ($(CONFIG_CODA_FS),m)
- MOD_SUB_DIRS += coda
- endif
-endif
-
-ifeq ($(CONFIG_MINIX_FS),y)
-SUB_DIRS += minix
-else
- ifeq ($(CONFIG_MINIX_FS),m)
- MOD_SUB_DIRS += minix
- endif
-endif
-
-ifeq ($(CONFIG_FAT_FS),y)
-SUB_DIRS += fat
-else
- ifeq ($(CONFIG_FAT_FS),m)
- MOD_SUB_DIRS += fat
- endif
-endif
-
-ifeq ($(CONFIG_MSDOS_FS),y)
-SUB_DIRS += msdos
-else
- ifeq ($(CONFIG_MSDOS_FS),m)
- MOD_SUB_DIRS += msdos
- endif
-endif
-
-ifeq ($(CONFIG_VFAT_FS),y)
-SUB_DIRS += vfat
-else
- ifeq ($(CONFIG_VFAT_FS),m)
- MOD_SUB_DIRS += vfat
- endif
-endif
-
-ifeq ($(CONFIG_BFS_FS),y)
-SUB_DIRS += bfs
-else
- ifeq ($(CONFIG_BFS_FS),m)
- MOD_SUB_DIRS += bfs
- endif
-endif
-
-ifeq ($(CONFIG_ISO9660_FS),y)
-SUB_DIRS += isofs
-else
- ifeq ($(CONFIG_ISO9660_FS),m)
- MOD_SUB_DIRS += isofs
- endif
-endif
-
-ifdef CONFIG_DEVFS_FS
-SUB_DIRS += devfs
-endif
-
-ifeq ($(CONFIG_HFS_FS),y)
-SUB_DIRS += hfs
-else
- ifeq ($(CONFIG_HFS_FS),m)
- MOD_SUB_DIRS += hfs
- endif
-endif
-
-ifeq ($(CONFIG_NFS_FS),y)
-SUB_DIRS += nfs
-else
- ifeq ($(CONFIG_NFS_FS),m)
- MOD_SUB_DIRS += nfs
- endif
-endif
-
-ifeq ($(CONFIG_NFSD),y)
-CONFIG_LOCKD := y
-SUB_DIRS += nfsd
-else
- ifeq ($(CONFIG_NFSD),m)
- MOD_SUB_DIRS += nfsd
- endif
-endif
-
-ifeq ($(CONFIG_LOCKD),y)
-SUB_DIRS += lockd
-else
- ifeq ($(CONFIG_LOCKD),m)
- MOD_SUB_DIRS := lockd $(MOD_SUB_DIRS)
- endif
-endif
-
-# Since CONFIG_NLS might be set to y while there are modules
-# to be build in the nls/ directory, we need to enter the nls
-# directory every time, but with different rules.
-ifeq ($(CONFIG_NLS),y)
-SUB_DIRS += nls
-MOD_IN_SUB_DIRS += nls
-else
- ifeq ($(CONFIG_NLS),m)
- MOD_SUB_DIRS += nls
- endif
-endif
-
-ifeq ($(CONFIG_UMSDOS_FS),y)
-SUB_DIRS += umsdos
-else
- ifeq ($(CONFIG_UMSDOS_FS),m)
- MOD_SUB_DIRS += umsdos
- endif
-endif
-
-ifeq ($(CONFIG_SYSV_FS),y)
-SUB_DIRS += sysv
-else
- ifeq ($(CONFIG_SYSV_FS),m)
- MOD_SUB_DIRS += sysv
- endif
-endif
-
-ifeq ($(CONFIG_SMB_FS),y)
-SUB_DIRS += smbfs
-else
- ifeq ($(CONFIG_SMB_FS),m)
- MOD_SUB_DIRS += smbfs
- endif
-endif
-
-ifeq ($(CONFIG_NCP_FS),y)
-SUB_DIRS += ncpfs
-else
- ifeq ($(CONFIG_NCP_FS),m)
- MOD_SUB_DIRS += ncpfs
- endif
-endif
-
-ifeq ($(CONFIG_HPFS_FS),y)
-SUB_DIRS += hpfs
-else
- ifeq ($(CONFIG_HPFS_FS),m)
- MOD_SUB_DIRS += hpfs
- endif
-endif
-
-ifeq ($(CONFIG_NTFS_FS),y)
-SUB_DIRS += ntfs
-else
- ifeq ($(CONFIG_NTFS_FS),m)
- MOD_SUB_DIRS += ntfs
- endif
-endif
-
-ifeq ($(CONFIG_UFS_FS),y)
-SUB_DIRS += ufs
-else
- ifeq ($(CONFIG_UFS_FS),m)
- MOD_SUB_DIRS += ufs
- endif
-endif
-
-ifeq ($(CONFIG_EFS_FS),y)
-SUB_DIRS += efs
-else
- ifeq ($(CONFIG_EFS_FS),m)
- MOD_SUB_DIRS += efs
- endif
-endif
-
-ifeq ($(CONFIG_JFFS_FS),y)
-SUB_DIRS += jffs
-else
- ifeq ($(CONFIG_JFFS_FS),m)
- MOD_SUB_DIRS += jffs
- endif
-endif
-
-ifeq ($(CONFIG_AFFS_FS),y)
-SUB_DIRS += affs
-else
- ifeq ($(CONFIG_AFFS_FS),m)
- MOD_SUB_DIRS += affs
- endif
-endif
-
-ifeq ($(CONFIG_ROMFS_FS),y)
-SUB_DIRS += romfs
-else
- ifeq ($(CONFIG_ROMFS_FS),m)
- MOD_SUB_DIRS += romfs
- endif
-endif
-
-ifeq ($(CONFIG_QNX4FS_FS),y)
-SUB_DIRS += qnx4
-else
- ifeq ($(CONFIG_QNX4FS_FS),m)
- MOD_SUB_DIRS += qnx4
- endif
-endif
-
-ifeq ($(CONFIG_UDF_FS),y)
-SUB_DIRS += udf
-else
- ifeq ($(CONFIG_UDF_FS),m)
- MOD_SUB_DIRS += udf
- endif
-endif
-
-ifeq ($(CONFIG_AUTOFS_FS),y)
-SUB_DIRS += autofs
-else
- ifeq ($(CONFIG_AUTOFS_FS),m)
- MOD_SUB_DIRS += autofs
- endif
-endif
-
-ifeq ($(CONFIG_AUTOFS4_FS),y)
-SUB_DIRS += autofs4
-else
- ifeq ($(CONFIG_AUTOFS4_FS),m)
- MOD_SUB_DIRS += autofs4
- endif
-endif
-
-ifeq ($(CONFIG_ADFS_FS),y)
-SUB_DIRS += adfs
-else
- ifeq ($(CONFIG_ADFS_FS),m)
- MOD_SUB_DIRS += adfs
- endif
-endif
-
-ifeq ($(CONFIG_DEVPTS_FS),y)
-SUB_DIRS += devpts
-else
- ifeq ($(CONFIG_DEVPTS_FS),m)
- MOD_SUB_DIRS += devpts
- endif
-endif
+# binfmt_script is always there
+obj-y += binfmt_script.o
-ifeq ($(CONFIG_SUN_OPENPROMFS),y)
-SUB_DIRS += openpromfs
-else
- ifeq ($(CONFIG_SUN_OPENPROMFS),m)
- MOD_SUB_DIRS += openpromfs
- endif
-endif
+obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o
-ifeq ($(CONFIG_BINFMT_AOUT),y)
-BINFMTS += binfmt_aout.o
-else
- ifeq ($(CONFIG_BINFMT_AOUT),m)
- M_OBJS += binfmt_aout.o
- endif
-endif
+# persistent filesystems
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
-ifeq ($(CONFIG_BINFMT_EM86),y)
-BINFMTS += binfmt_em86.o
-else
- ifeq ($(CONFIG_BINFMT_EM86),m)
- M_OBJS += binfmt_em86.o
- endif
-endif
-ifeq ($(CONFIG_BINFMT_MISC),y)
-BINFMTS += binfmt_misc.o
-else
- ifeq ($(CONFIG_BINFMT_MISC),m)
- M_OBJS += binfmt_misc.o
- endif
-endif
+# Subdirectories that should be entered when MAKING_MODULES=1, even if set to 'y'.
+both-m := $(filter $(mod-subdirs), $(subdir-y))
-# binfmt_script is always there
-BINFMTS += binfmt_script.o
+# Translate to Rules.make lists.
+O_OBJS := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS := $(filter $(export-objs), $(obj-y))
+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-ifeq ($(CONFIG_BINFMT_ELF),y)
-BINFMTS += binfmt_elf.o
-else
- ifeq ($(CONFIG_BINFMT_ELF),m)
- M_OBJS += binfmt_elf.o
- endif
-endif
+SUB_DIRS := $(subdir-y)
+MOD_SUB_DIRS := $(sort $(subdir-m) $(both-m))
+ALL_SUB_DIRS := $(sort $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-))
include $(TOPDIR)/Rules.make
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index e88beb5f3..30c400e5b 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -97,6 +97,7 @@ extern struct dentry *adfs_lookup(struct inode *dir, struct dentry *dentry);
/* dir_*.c */
extern struct inode_operations adfs_dir_inode_operations;
extern struct file_operations adfs_dir_operations;
+extern struct dentry_operations adfs_dentry_operations;
extern struct adfs_dir_ops adfs_f_dir_ops;
extern struct adfs_dir_ops adfs_fplus_dir_ops;
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index b650f421f..51828c605 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -1,9 +1,13 @@
/*
- * linux/fs/adfs/dir.c
+ * linux/fs/adfs/dir.c
*
- * Copyright (C) 1999-2000 Russell King
+ * Copyright (C) 1999-2000 Russell King
*
- * Common directory handling for ADFS
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Common directory handling for ADFS
*/
#include <linux/config.h>
#include <linux/version.h>
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index bdcce1c51..ef7715c44 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -3,7 +3,11 @@
*
* Copyright (C) 1997-1999 Russell King
*
- * E and F format directory handling
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * E and F format directory handling
*/
#include <linux/version.h>
#include <linux/errno.h>
@@ -437,7 +441,7 @@ adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
}
#endif
for (i = dir->nr_buffers - 1; i >= 0; i--)
- mark_buffer_dirty(dir->bh[i], 1);
+ mark_buffer_dirty(dir->bh[i]);
ret = 0;
out:
diff --git a/fs/adfs/dir_f.h b/fs/adfs/dir_f.h
index 8df158739..e47134040 100644
--- a/fs/adfs/dir_f.h
+++ b/fs/adfs/dir_f.h
@@ -1,9 +1,13 @@
/*
- * linux/fs/adfs/dir_f.h
+ * linux/fs/adfs/dir_f.h
*
- * Copyright (C) 1999 Russell King
+ * Copyright (C) 1999 Russell King
*
- * Structures of directories on the F format disk
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Structures of directories on the F format disk
*/
#ifndef ADFS_DIR_F_H
#define ADFS_DIR_F_H
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 21d719ba7..329bbd5f9 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -1,7 +1,11 @@
/*
* linux/fs/adfs/dir_fplus.c
*
- * Copyright (C) 1997-1999 Russell King
+ * Copyright (C) 1997-1999 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
*/
#include <linux/version.h>
#include <linux/errno.h>
diff --git a/fs/adfs/dir_fplus.h b/fs/adfs/dir_fplus.h
index 5b3adefca..a65f65348 100644
--- a/fs/adfs/dir_fplus.h
+++ b/fs/adfs/dir_fplus.h
@@ -1,9 +1,13 @@
/*
- * linux/fs/adfs/dir_fplus.h
+ * linux/fs/adfs/dir_fplus.h
*
- * Copyright (C) 1999 Russell King
+ * Copyright (C) 1999 Russell King
*
- * Structures of directories on the F+ format disk
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Structures of directories on the F+ format disk
*/
#define ADFS_FPLUS_NAME_LEN 255
diff --git a/fs/adfs/file.c b/fs/adfs/file.c
index bdd2a4f18..aa5bf69c6 100644
--- a/fs/adfs/file.c
+++ b/fs/adfs/file.c
@@ -22,7 +22,6 @@
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/stat.h>
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index e55362eb7..c1c621179 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -1,7 +1,11 @@
/*
* linux/fs/adfs/inode.c
*
- * Copyright (C) 1997-1999 Russell King
+ * Copyright (C) 1997-1999 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
*/
#include <linux/version.h>
#include <linux/errno.h>
diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index e74458e45..6bda94ed3 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -1,7 +1,11 @@
/*
* linux/fs/adfs/map.c
*
- * Copyright (C) 1997-1999 Russell King
+ * Copyright (C) 1997-1999 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
*/
#include <linux/version.h>
#include <linux/errno.h>
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 7e56aeec7..a53c2b8e1 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -1,7 +1,11 @@
/*
* linux/fs/adfs/super.c
*
- * Copyright (C) 1997-1999 Russell King
+ * Copyright (C) 1997-1999 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
*/
#include <linux/version.h>
#include <linux/module.h>
@@ -425,7 +429,8 @@ struct super_block *adfs_read_super(struct super_block *sb, void *data, int sile
kfree(sb->u.adfs_sb.s_map);
adfs_error(sb, "get root inode failed\n");
goto error;
- }
+ } else
+ sb->s_root->d_op = &adfs_dentry_operations;
return sb;
error_free_bh:
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index d01f618c8..5c4ec8e6b 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -79,7 +79,7 @@ affs_insert_hash(unsigned long next, struct buffer_head *file, struct inode *ino
DIR_END(file->b_data,inode)->hash_chain = cpu_to_be32(next);
((s32 *)bh->b_data)[offset] = cpu_to_be32(ino);
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
- mark_buffer_dirty(bh,1);
+ mark_buffer_dirty(bh);
affs_brelse(bh);
return 0;
@@ -130,7 +130,7 @@ affs_remove_hash(struct buffer_head *dbh, struct inode *inode)
if (ownkey == key) {
((s32 *)bh->b_data)[offset] = FILE_END(dbh->b_data,inode)->hash_chain;
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
- mark_buffer_dirty(bh,1);
+ mark_buffer_dirty(bh);
affs_brelse(bh);
retval = 0;
break;
@@ -178,7 +178,7 @@ affs_remove_link(struct buffer_head *dbh, struct inode *inode)
FILE_END(bh->b_data,inode)->link_chain =
FILE_END(dbh->b_data,inode)->link_chain;
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
- mark_buffer_dirty(bh,1);
+ mark_buffer_dirty(bh);
affs_brelse(bh);
retval = 0;
break;
@@ -261,7 +261,7 @@ affs_remove_header(struct buffer_head *bh, struct inode *inode)
return error;
}
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
- mark_buffer_dirty(bh,1);
+ mark_buffer_dirty(bh);
affs_brelse(link_bh);
affs_free_block(inode->i_sb,link_ino);
/* Mark the link's parent dir as changed, too. */
diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c
index 3382a82f9..de477b331 100644
--- a/fs/affs/bitmap.c
+++ b/fs/affs/bitmap.c
@@ -93,7 +93,7 @@ affs_free_block(struct super_block *sb, s32 block)
else {
sb->u.affs_sb.s_alloc[zone_no].az_free++;
((u32 *)bm->bm_bh->b_data)[0] = cpu_to_be32(be32_to_cpu(((u32 *)bm->bm_bh->b_data)[0]) - blk);
- mark_buffer_dirty(bm->bm_bh,1);
+ mark_buffer_dirty(bm->bm_bh);
sb->s_dirt = 1;
}
if (--bm->bm_count == 0) {
@@ -176,7 +176,7 @@ found:
w = ~w - be32_to_cpu(bm[i]);
bm[0] = cpu_to_be32(be32_to_cpu(bm[0]) + w);
unlock_super(sb);
- mark_buffer_dirty(zone->z_bm->bm_bh,1);
+ mark_buffer_dirty(zone->z_bm->bm_bh);
sb->s_dirt = 1;
zone->z_lru_time = jiffies;
diff --git a/fs/affs/file.c b/fs/affs/file.c
index cd31491b0..de0808b9e 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -447,12 +447,12 @@ static struct buffer_head * affs_getblock(struct inode *inode, s32 block)
DATA_FRONT(ebh)->header_key = cpu_to_be32(inode->i_ino);
DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1);
affs_fix_checksum(AFFS_I2BSIZE(inode), ebh->b_data, 5);
- mark_buffer_dirty(ebh, 0);
+ mark_buffer_dirty(ebh);
if (pbh) {
DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24);
DATA_FRONT(pbh)->next_data = cpu_to_be32(nkey);
affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5);
- mark_buffer_dirty(pbh,0);
+ mark_buffer_dirty(pbh);
affs_brelse(pbh);
}
pbh = ebh;
@@ -466,7 +466,7 @@ static struct buffer_head * affs_getblock(struct inode *inode, s32 block)
fdp->first_data = AFFS_BLOCK(bh->b_data,inode,0);
fdp->block_count = cpu_to_be32(j);
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
- mark_buffer_dirty(bh,1);
+ mark_buffer_dirty(bh);
}
if (block < j) {
@@ -495,10 +495,10 @@ static struct buffer_head * affs_getblock(struct inode *inode, s32 block)
FILE_END(ebh->b_data,inode)->secondary_type = cpu_to_be32(ST_FILE);
FILE_END(ebh->b_data,inode)->parent = cpu_to_be32(inode->i_ino);
affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
- mark_buffer_dirty(ebh, 1);
+ mark_buffer_dirty(ebh);
FILE_END(bh->b_data,inode)->extension = cpu_to_be32(key);
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
- mark_buffer_dirty(bh,1);
+ mark_buffer_dirty(bh);
affs_brelse(bh);
bh = ebh;
}
@@ -678,7 +678,7 @@ affs_truncate(struct inode *inode)
rem = do_div(tmp, net_blocksize);
DATA_FRONT(bh)->data_size = cpu_to_be32(rem ? rem : net_blocksize);
affs_fix_checksum(blocksize,bh->b_data,5);
- mark_buffer_dirty(bh,0);
+ mark_buffer_dirty(bh);
}
goto out_truncate;
}
@@ -733,7 +733,7 @@ affs_truncate(struct inode *inode)
first = 0;
*keyp = 0;
affs_fix_checksum(blocksize,bh->b_data,5);
- mark_buffer_dirty(bh,1);
+ mark_buffer_dirty(bh);
} else
first -= AFFS_I2HSIZE(inode);
affs_brelse(bh);
@@ -766,7 +766,7 @@ affs_truncate(struct inode *inode)
((struct data_front *)bh->b_data)->next_data = 0;
affs_fix_checksum(blocksize,bh->b_data,5);
}
- mark_buffer_dirty(bh,1);
+ mark_buffer_dirty(bh);
} else
affs_error(inode->i_sb,"truncate","Cannot read block %d",block);
}
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index f98a2cd0b..2f8c36aa5 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -232,7 +232,7 @@ affs_write_inode(struct inode *inode, int unused)
}
}
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
- mark_buffer_dirty(bh,1);
+ mark_buffer_dirty(bh);
brelse(bh);
unlock_kernel();
}
@@ -392,7 +392,7 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
link->i_version = ++event;
mark_inode_dirty(link);
- mark_buffer_dirty(link_bh,1);
+ mark_buffer_dirty(link_bh);
}
affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5);
affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5);
@@ -402,8 +402,8 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
mark_inode_dirty(dir);
mark_inode_dirty(inode);
- mark_buffer_dirty(dir_bh,1);
- mark_buffer_dirty(inode_bh,1);
+ mark_buffer_dirty(dir_bh);
+ mark_buffer_dirty(inode_bh);
addentry_done:
affs_brelse(dir_bh);
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index 8ad7b07a2..a73e60618 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -440,7 +440,7 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
symname++;
}
*p = 0;
- mark_buffer_dirty(bh,1);
+ mark_buffer_dirty(bh);
affs_brelse(bh);
mark_inode_dirty(inode);
@@ -592,7 +592,7 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
retval = 0;
mark_inode_dirty(new_dir);
mark_inode_dirty(old_dir);
- mark_buffer_dirty(old_bh,1);
+ mark_buffer_dirty(old_bh);
end_rename:
affs_brelse(old_bh);
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 46c11a8e2..32ad74eb9 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -52,7 +52,7 @@ affs_put_super(struct super_block *sb)
secs_to_datestamp(CURRENT_TIME,
&ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5);
- mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1);
+ mark_buffer_dirty(sb->u.affs_sb.s_root_bh);
}
if (sb->u.affs_sb.s_prefix)
@@ -88,7 +88,7 @@ affs_write_super(struct super_block *sb)
secs_to_datestamp(CURRENT_TIME,
&ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5);
- mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1);
+ mark_buffer_dirty(sb->u.affs_sb.s_root_bh);
sb->s_dirt = !clean; /* redo until bitmap synced */
} else
sb->s_dirt = 0;
@@ -491,7 +491,7 @@ got_root:
chksum = cpu_to_be32(0x7FFFFFFF >> (31 - key));
((u32 *)bb->b_data)[ptype] &= chksum;
affs_fix_checksum(s->s_blocksize,bb->b_data,0);
- mark_buffer_dirty(bb,1);
+ mark_buffer_dirty(bb);
bmalt = 1;
}
ptype = (size + 31) & ~0x1F;
@@ -553,7 +553,7 @@ nobitmap:
secs_to_datestamp(CURRENT_TIME,&ROOT_END(
s->u.affs_sb.s_root_bh->b_data,root_inode)->disk_altered);
affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5);
- mark_buffer_dirty(s->u.affs_sb.s_root_bh,1);
+ mark_buffer_dirty(s->u.affs_sb.s_root_bh);
}
affs_make_zones(s);
}
diff --git a/fs/attr.c b/fs/attr.c
index 9af530c8b..c4849d324 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -9,6 +9,8 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
+#include <linux/dnotify.h>
+#include <linux/fcntl.h>
/* Taken over from the old code... */
@@ -79,6 +81,28 @@ void inode_setattr(struct inode * inode, struct iattr * attr)
mark_inode_dirty(inode);
}
+static int setattr_mask(unsigned int ia_valid)
+{
+ unsigned long dn_mask = 0;
+
+ if (ia_valid & ATTR_UID)
+ dn_mask |= DN_ATTRIB;
+ if (ia_valid & ATTR_GID)
+ dn_mask |= DN_ATTRIB;
+ if (ia_valid & ATTR_SIZE)
+ dn_mask |= DN_MODIFY;
+ /* both times implies a utime(s) call */
+ if ((ia_valid & (ATTR_ATIME|ATTR_MTIME)) == (ATTR_ATIME|ATTR_MTIME))
+ dn_mask |= DN_ATTRIB;
+ else if (ia_valid & ATTR_ATIME)
+ dn_mask |= DN_ACCESS;
+ else if (ia_valid & ATTR_MTIME)
+ dn_mask |= DN_MODIFY;
+ if (ia_valid & ATTR_MODE)
+ dn_mask |= DN_ATTRIB;
+ return dn_mask;
+}
+
int notify_change(struct dentry * dentry, struct iattr * attr)
{
struct inode *inode = dentry->d_inode;
@@ -101,5 +125,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
inode_setattr(inode, attr);
}
unlock_kernel();
+ if (!error) {
+ unsigned long dn_mask = setattr_mask(ia_valid);
+ if (dn_mask)
+ inode_dir_notify(dentry->d_parent->d_inode, dn_mask);
+ }
return error;
}
diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c
index 7b6573dd7..7c7c8baf2 100644
--- a/fs/autofs/waitq.c
+++ b/fs/autofs/waitq.c
@@ -53,7 +53,7 @@ static int autofs_write(struct file *file, const void *addr, int bytes)
/** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/
- sigpipe = sigismember(&current->signal, SIGPIPE);
+ sigpipe = sigismember(&current->pending.signal, SIGPIPE);
/* Save pointer to user space and point back to kernel space */
fs = get_fs();
@@ -71,7 +71,7 @@ static int autofs_write(struct file *file, const void *addr, int bytes)
SIGPIPE unless it was already supposed to get one */
if (wr == -EPIPE && !sigpipe) {
spin_lock_irqsave(&current->sigmask_lock, flags);
- sigdelset(&current->signal, SIGPIPE);
+ sigdelset(&current->pending.signal, SIGPIPE);
recalc_sigpending(current);
spin_unlock_irqrestore(&current->sigmask_lock, flags);
}
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index f49f213e0..a76cde227 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -57,7 +57,7 @@ static int autofs4_write(struct file *file, const void *addr, int bytes)
/** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/
- sigpipe = sigismember(&current->signal, SIGPIPE);
+ sigpipe = sigismember(&current->pending.signal, SIGPIPE);
/* Save pointer to user space and point back to kernel space */
fs = get_fs();
@@ -75,7 +75,7 @@ static int autofs4_write(struct file *file, const void *addr, int bytes)
SIGPIPE unless it was already supposed to get one */
if (wr == -EPIPE && !sigpipe) {
spin_lock_irqsave(&current->sigmask_lock, flags);
- sigdelset(&current->signal, SIGPIPE);
+ sigdelset(&current->pending.signal, SIGPIPE);
recalc_sigpending(current);
spin_unlock_irqrestore(&current->sigmask_lock, flags);
}
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 721739e31..9ebea1ca7 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -177,7 +177,7 @@ static int bfs_unlink(struct inode * dir, struct dentry * dentry)
}
de->ino = 0;
dir->i_version = ++event;
- mark_buffer_dirty(bh, 0);
+ mark_buffer_dirty(bh);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
inode->i_nlink--;
@@ -236,7 +236,7 @@ static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry,
new_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(new_inode);
}
- mark_buffer_dirty(old_bh, 0);
+ mark_buffer_dirty(old_bh);
error = 0;
end_rename:
@@ -288,7 +288,7 @@ static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int
de->ino = ino;
for (i=0; i<BFS_NAMELEN; i++)
de->name[i] = (i < namelen) ? name[i] : 0;
- mark_buffer_dirty(bh, 0);
+ mark_buffer_dirty(bh);
brelse(bh);
return 0;
}
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index 1335d301b..1da12e6ae 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -33,7 +33,7 @@ static int bfs_move_block(unsigned long from, unsigned long to, kdev_t dev)
return -EIO;
new = getblk(dev, to, BFS_BSIZE);
memcpy(new->b_data, bh->b_data, bh->b_size);
- mark_buffer_dirty(new, 0);
+ mark_buffer_dirty(new);
bforget(bh);
brelse(new);
return 0;
@@ -98,7 +98,7 @@ static int bfs_get_block(struct inode * inode, long block,
bh_result->b_state |= (1UL << BH_Mapped);
s->su_lf_eblk = inode->iu_eblock = inode->iu_sblock + block;
mark_inode_dirty(inode);
- mark_buffer_dirty(s->su_sbh, 1);
+ mark_buffer_dirty(s->su_sbh);
err = 0;
goto out;
}
@@ -118,7 +118,7 @@ static int bfs_get_block(struct inode * inode, long block,
inode->iu_sblock = next_free_block;
s->su_lf_eblk = inode->iu_eblock = next_free_block + block;
mark_inode_dirty(inode);
- mark_buffer_dirty(s->su_sbh, 1);
+ mark_buffer_dirty(s->su_sbh);
bh_result->b_dev = inode->i_dev;
bh_result->b_blocknr = inode->iu_sblock + block;
bh_result->b_state |= (1UL << BH_Mapped);
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 9f53cbcd3..fe1396497 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -127,7 +127,7 @@ static void bfs_write_inode(struct inode * inode, int unused)
di->i_eblock = inode->iu_eblock;
di->i_eoffset = di->i_sblock * BFS_BSIZE + inode->i_size - 1;
- mark_buffer_dirty(bh, 0);
+ mark_buffer_dirty(bh);
brelse(bh);
unlock_kernel();
}
@@ -169,7 +169,7 @@ static void bfs_delete_inode(struct inode * inode)
}
di->i_ino = 0;
di->i_sblock = 0;
- mark_buffer_dirty(bh, 0);
+ mark_buffer_dirty(bh);
brelse(bh);
/* if this was the last file, make the previous
@@ -177,7 +177,7 @@ static void bfs_delete_inode(struct inode * inode)
saves us 1 gap */
if (s->su_lf_eblk == inode->iu_eblock) {
s->su_lf_eblk = inode->iu_sblock - 1;
- mark_buffer_dirty(s->su_sbh, 1);
+ mark_buffer_dirty(s->su_sbh);
}
unlock_kernel();
clear_inode(inode);
@@ -197,7 +197,7 @@ static int bfs_statfs(struct super_block *s, struct statfs *buf)
buf->f_bfree = buf->f_bavail = s->su_freeb;
buf->f_files = s->su_lasti + 1 - BFS_ROOT_INO;
buf->f_ffree = s->su_freei;
- buf->f_fsid.val[0] = s->s_dev;
+ buf->f_fsid.val[0] = kdev_t_to_nr(s->s_dev);
buf->f_namelen = BFS_NAMELEN;
return 0;
}
@@ -205,7 +205,7 @@ static int bfs_statfs(struct super_block *s, struct statfs *buf)
static void bfs_write_super(struct super_block *s)
{
if (!(s->s_flags & MS_RDONLY))
- mark_buffer_dirty(s->su_sbh, 1);
+ mark_buffer_dirty(s->su_sbh);
s->s_dirt = 0;
}
@@ -314,7 +314,7 @@ static struct super_block * bfs_read_super(struct super_block * s,
iput(inode);
}
if (!(s->s_flags & MS_RDONLY)) {
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
s->s_dirt = 1;
}
dump_imap("read_super", s);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 422531158..445c47aa6 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1045,7 +1045,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
notes[0].datasz = sizeof(prstatus);
notes[0].data = &prstatus;
prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
- prstatus.pr_sigpend = current->signal.sig[0];
+ prstatus.pr_sigpend = current->pending.signal.sig[0];
prstatus.pr_sighold = current->blocked.sig[0];
psinfo.pr_pid = prstatus.pr_pid = current->pid;
psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 21bc086e3..103332fc4 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -30,17 +30,17 @@ ssize_t block_write(struct file * filp, const char * buf,
ssize_t block, blocks;
loff_t offset;
ssize_t chars;
- ssize_t written = 0;
+ ssize_t written;
struct buffer_head * bhlist[NBUF];
size_t size;
- kdev_t dev;
+ kdev_t dev = inode->i_rdev;
struct buffer_head * bh, *bufferlist[NBUF];
register char * p;
- write_error = buffercount = 0;
- dev = inode->i_rdev;
- if ( is_read_only( inode->i_rdev ))
+ if (is_read_only(dev))
return -EPERM;
+
+ written = write_error = buffercount = 0;
blocksize = BLOCK_SIZE;
if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)])
blocksize = blksize_size[MAJOR(dev)][MINOR(dev)];
@@ -129,7 +129,7 @@ ssize_t block_write(struct file * filp, const char * buf,
p += chars;
buf += chars;
mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh, 0);
+ mark_buffer_dirty(bh);
if (filp->f_flags & O_SYNC)
bufferlist[buffercount++] = bh;
else
@@ -311,6 +311,39 @@ ssize_t block_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
}
/*
+ * private llseek:
+ * for a block special file file->f_dentry->d_inode->i_size is zero
+ * so we compute the size by hand (just as in block_read/write above)
+ */
+static loff_t block_llseek(struct file *file, loff_t offset, int origin)
+{
+ long long retval;
+ kdev_t dev;
+
+ switch (origin) {
+ case 2:
+ dev = file->f_dentry->d_inode->i_rdev;
+ if (blk_size[MAJOR(dev)])
+ offset += (loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS;
+ /* else? return -EINVAL? */
+ break;
+ case 1:
+ offset += file->f_pos;
+ }
+ retval = -EINVAL;
+ if (offset >= 0) {
+ if (offset != file->f_pos) {
+ file->f_pos = offset;
+ file->f_reada = 0;
+ file->f_version = ++event;
+ }
+ retval = offset;
+ }
+ return retval;
+}
+
+
+/*
* Filp may be NULL when we are called by an msync of a vma
* since the vma has no handle.
*/
@@ -435,9 +468,7 @@ void bdput(struct block_device *bdev)
static struct {
const char *name;
struct block_device_operations *bdops;
-} blkdevs[MAX_BLKDEV] = {
- { NULL, NULL },
-};
+} blkdevs[MAX_BLKDEV];
int get_blkdev_list(char * p)
{
@@ -612,7 +643,7 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind)
int blkdev_open(struct inode * inode, struct file * filp)
{
- int ret = -ENODEV;
+ int ret = -ENXIO;
struct block_device *bdev = inode->i_bdev;
down(&bdev->bd_sem);
lock_kernel();
@@ -678,6 +709,7 @@ static int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
struct file_operations def_blk_fops = {
open: blkdev_open,
release: blkdev_close,
+ llseek: block_llseek,
read: block_read,
write: block_write,
fsync: block_fsync,
diff --git a/fs/buffer.c b/fs/buffer.c
index ca6e2f919..145e11793 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -35,6 +35,7 @@
#include <linux/locks.h>
#include <linux/errno.h>
#include <linux/swap.h>
+#include <linux/swapctl.h>
#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/blkdev.h>
@@ -409,8 +410,9 @@ out:
*/
#define _hashfn(dev,block) \
((((dev)<<(bh_hash_shift - 6)) ^ ((dev)<<(bh_hash_shift - 9))) ^ \
- (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ ((block) << (bh_hash_shift - 12))))
-#define hash(dev,block) hash_table[(_hashfn(dev,block) & bh_hash_mask)]
+ (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ \
+ ((block) << (bh_hash_shift - 12))))
+#define hash(dev,block) hash_table[(_hashfn(HASHDEV(dev),block) & bh_hash_mask)]
static __inline__ void __hash_link(struct buffer_head *bh, struct buffer_head **head)
{
@@ -856,23 +858,35 @@ repeat:
/* -1 -> no need to flush
0 -> async flush
1 -> sync flush (wait for I/O completation) */
-static int balance_dirty_state(kdev_t dev)
+int balance_dirty_state(kdev_t dev)
{
unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit;
+ int shortage;
dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
tot = nr_free_buffer_pages();
- tot -= size_buffers_type[BUF_PROTECTED] >> PAGE_SHIFT;
dirty *= 200;
soft_dirty_limit = tot * bdf_prm.b_un.nfract;
hard_dirty_limit = soft_dirty_limit * 2;
+ /* First, check for the "real" dirty limit. */
if (dirty > soft_dirty_limit) {
if (dirty > hard_dirty_limit)
return 1;
return 0;
}
+
+ /*
+ * If we are about to get low on free pages and
+ * cleaning the inactive_dirty pages would help
+ * fix this, wake up bdflush.
+ */
+ shortage = free_shortage();
+ if (shortage && nr_inactive_dirty_pages > shortage &&
+ nr_inactive_dirty_pages > freepages.high)
+ return 0;
+
return -1;
}
@@ -892,7 +906,7 @@ void balance_dirty(kdev_t dev)
wakeup_bdflush(state);
}
-static __inline__ void __mark_dirty(struct buffer_head *bh, int flag)
+static __inline__ void __mark_dirty(struct buffer_head *bh)
{
bh->b_flushtime = jiffies + bdf_prm.b_un.age_buffer;
refile_buffer(bh);
@@ -900,15 +914,15 @@ static __inline__ void __mark_dirty(struct buffer_head *bh, int flag)
/* atomic version, the user must call balance_dirty() by hand
as soon as it become possible to block */
-void __mark_buffer_dirty(struct buffer_head *bh, int flag)
+void __mark_buffer_dirty(struct buffer_head *bh)
{
if (!atomic_set_buffer_dirty(bh))
- __mark_dirty(bh, flag);
+ __mark_dirty(bh);
}
-void mark_buffer_dirty(struct buffer_head *bh, int flag)
+void mark_buffer_dirty(struct buffer_head *bh)
{
- __mark_buffer_dirty(bh, flag);
+ __mark_buffer_dirty(bh);
balance_dirty(bh->b_dev);
}
@@ -1380,6 +1394,19 @@ static void unmap_underlying_metadata(struct buffer_head * bh)
}
/*
+ * NOTE! All mapped/uptodate combinations are valid:
+ *
+ * Mapped Uptodate Meaning
+ *
+ * No No "unknown" - must do get_block()
+ * No Yes "hole" - zero-filled
+ * Yes No "allocated" - allocated on disk, not read in
+ * Yes Yes "valid" - allocated and up-to-date in memory.
+ *
+ * "Dirty" is valid only with the last case (mapped+uptodate).
+ */
+
+/*
* block_write_full_page() is SMP-safe - currently it's still
* being called with the kernel lock held, but the code is ready.
*/
@@ -1419,7 +1446,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b
}
set_bit(BH_Uptodate, &bh->b_state);
if (!atomic_set_buffer_dirty(bh)) {
- __mark_dirty(bh, 0);
+ __mark_dirty(bh);
need_balance_dirty = 1;
}
@@ -1471,6 +1498,10 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
goto out;
if (buffer_new(bh)) {
unmap_underlying_metadata(bh);
+ if (Page_Uptodate(page)) {
+ set_bit(BH_Uptodate, &bh->b_state);
+ continue;
+ }
if (block_end > to)
memset(kaddr+to, 0, block_end-to);
if (block_start < from)
@@ -1480,6 +1511,10 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
continue;
}
}
+ if (Page_Uptodate(page)) {
+ set_bit(BH_Uptodate, &bh->b_state);
+ continue;
+ }
if (!buffer_uptodate(bh) &&
(block_start < from || block_end > to)) {
ll_rw_block(READ, 1, &bh);
@@ -1520,7 +1555,7 @@ static int __block_commit_write(struct inode *inode, struct page *page,
} else {
set_bit(BH_Uptodate, &bh->b_state);
if (!atomic_set_buffer_dirty(bh)) {
- __mark_dirty(bh, 0);
+ __mark_dirty(bh);
need_balance_dirty = 1;
}
}
@@ -1574,8 +1609,10 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
continue;
if (!buffer_mapped(bh)) {
- if (iblock < lblock)
- get_block(inode, iblock, bh, 0);
+ if (iblock < lblock) {
+ if (get_block(inode, iblock, bh, 0))
+ continue;
+ }
if (!buffer_mapped(bh)) {
if (!kaddr)
kaddr = kmap(page);
@@ -1721,6 +1758,82 @@ int generic_commit_write(struct file *file, struct page *page,
return 0;
}
+int block_truncate_page(struct address_space *mapping, loff_t from, get_block_t *get_block)
+{
+ unsigned long index = from >> PAGE_CACHE_SHIFT;
+ unsigned offset = from & (PAGE_CACHE_SIZE-1);
+ unsigned blocksize, iblock, length, pos;
+ struct inode *inode = (struct inode *)mapping->host;
+ struct page *page;
+ struct buffer_head *bh;
+ int err;
+
+ blocksize = inode->i_sb->s_blocksize;
+ length = offset & (blocksize - 1);
+
+ /* Block boundary? Nothing to do */
+ if (!length)
+ return 0;
+
+ length = blocksize - length;
+ iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
+
+ page = grab_cache_page(mapping, index);
+ err = PTR_ERR(page);
+ if (IS_ERR(page))
+ goto out;
+
+ if (!page->buffers)
+ create_empty_buffers(page, inode, blocksize);
+
+ /* Find the buffer that contains "offset" */
+ bh = page->buffers;
+ pos = blocksize;
+ while (offset >= pos) {
+ bh = bh->b_this_page;
+ iblock++;
+ pos += blocksize;
+ }
+
+ err = 0;
+ if (!buffer_mapped(bh)) {
+ /* Hole? Nothing to do */
+ if (buffer_uptodate(bh))
+ goto unlock;
+ get_block(inode, iblock, bh, 0);
+ /* Still unmapped? Nothing to do */
+ if (!buffer_mapped(bh))
+ goto unlock;
+ }
+
+ /* Ok, it's mapped. Make sure it's up-to-date */
+ if (Page_Uptodate(page))
+ set_bit(BH_Uptodate, &bh->b_state);
+
+ bh->b_end_io = end_buffer_io_sync;
+ if (!buffer_uptodate(bh)) {
+ err = -EIO;
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ /* Uhhuh. Read error. Complain and punt. */
+ if (!buffer_uptodate(bh))
+ goto unlock;
+ }
+
+ memset((char *) kmap(page) + offset, 0, length);
+ flush_dcache_page(page);
+ kunmap(page);
+
+ mark_buffer_dirty(bh);
+ err = 0;
+
+unlock:
+ UnlockPage(page);
+ page_cache_release(page);
+out:
+ return err;
+}
+
int block_write_full_page(struct page *page, get_block_t *get_block)
{
struct inode *inode = (struct inode*)page->mapping->host;
@@ -2086,6 +2199,7 @@ static int grow_buffers(int size)
page = alloc_page(GFP_BUFFER);
if (!page)
goto out;
+ LockPage(page);
bh = create_buffers(page, size, 0);
if (!bh)
goto no_buffer_head;
@@ -2118,10 +2232,12 @@ static int grow_buffers(int size)
page->buffers = bh;
page->flags &= ~(1 << PG_referenced);
lru_cache_add(page);
+ UnlockPage(page);
atomic_inc(&buffermem_pages);
return 1;
no_buffer_head:
+ UnlockPage(page);
page_cache_release(page);
out:
return 0;
@@ -2178,7 +2294,9 @@ int try_to_free_buffers(struct page * page, int wait)
{
struct buffer_head * tmp, * bh = page->buffers;
int index = BUFSIZE_INDEX(bh->b_size);
+ int loop = 0;
+cleaned_buffers_try_again:
spin_lock(&lru_list_lock);
write_lock(&hash_table_lock);
spin_lock(&free_list[index].lock);
@@ -2224,8 +2342,14 @@ busy_buffer_page:
spin_unlock(&free_list[index].lock);
write_unlock(&hash_table_lock);
spin_unlock(&lru_list_lock);
- if (wait)
+ if (wait) {
sync_page_buffers(bh, wait);
+ /* We waited synchronously, so we can free the buffers. */
+ if (wait > 1 && !loop) {
+ loop = 1;
+ goto cleaned_buffers_try_again;
+ }
+ }
return 0;
}
@@ -2543,6 +2667,8 @@ int bdflush(void *sem)
CHECK_EMERGENCY_SYNC
flushed = flush_dirty_buffers(0);
+ if (free_shortage())
+ flushed += page_launder(GFP_BUFFER, 0);
/* If wakeup_bdflush will wakeup us
after our bdflush_done wakeup, then
@@ -2553,14 +2679,16 @@ int bdflush(void *sem)
(as we would be sleeping) and so it would
deadlock in SMP. */
__set_current_state(TASK_INTERRUPTIBLE);
- wake_up(&bdflush_done);
+ wake_up_all(&bdflush_done);
/*
* If there are still a lot of dirty buffers around,
* skip the sleep and flush some more. Otherwise, we
* go to sleep waiting a wakeup.
*/
- if (!flushed || balance_dirty_state(NODEV) < 0)
+ if (!flushed || balance_dirty_state(NODEV) < 0) {
+ run_task_queue(&tq_disk);
schedule();
+ }
/* Remember to mark us as running otherwise
the next schedule will block. */
__set_current_state(TASK_RUNNING);
@@ -2606,8 +2734,8 @@ int kupdate(void *sem)
if (signal_pending(tsk)) {
int stopped = 0;
spin_lock_irq(&tsk->sigmask_lock);
- if (sigismember(&tsk->signal, SIGSTOP)) {
- sigdelset(&tsk->signal, SIGSTOP);
+ if (sigismember(&tsk->pending.signal, SIGSTOP)) {
+ sigdelset(&tsk->pending.signal, SIGSTOP);
stopped = 1;
}
recalc_sigpending(tsk);
@@ -2625,9 +2753,9 @@ int kupdate(void *sem)
static int __init bdflush_init(void)
{
DECLARE_MUTEX_LOCKED(sem);
- kernel_thread(bdflush, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ kernel_thread(bdflush, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
down(&sem);
- kernel_thread(kupdate, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ kernel_thread(kupdate, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
down(&sem);
return 0;
}
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index e837db96a..db7fbb4ec 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -24,168 +24,60 @@
#include <linux/coda_fs_i.h>
#include <linux/coda_cache.h>
-/* create a new acl cache entry and enlist it */
-static struct coda_cache *coda_cache_create(struct inode *inode)
-{
- struct coda_inode_info *cii = ITOC(inode);
- struct coda_sb_info *sbi = coda_sbp(inode->i_sb);
- struct coda_cache *cc = NULL;
- ENTRY;
-
- if ( !sbi || !cii ) {
- printk("coda_cache_create: NULL sbi or cii!\n");
- return NULL;
- }
-
- CODA_ALLOC(cc, struct coda_cache *, sizeof(*cc));
-
- if ( !cc ) {
- printk("Out of memory in coda_cache_create!\n");
- return NULL;
- }
-
- coda_load_creds(&cc->cc_cred);
- cc->cc_mask = 0;
-
- INIT_LIST_HEAD(&cc->cc_cclist);
- INIT_LIST_HEAD(&cc->cc_cnlist);
- list_add(&cc->cc_cclist, &sbi->sbi_cchead);
- list_add(&cc->cc_cnlist, &cii->c_cnhead);
-
- return cc;
-}
-
-/* destroy an acl cache entry */
-static void coda_cache_destroy(struct coda_cache *el)
-{
- ENTRY;
- if (list_empty(&el->cc_cclist) || list_empty(&el->cc_cnlist)) {
- printk("coda_cache_destroy: loose entry!");
- return;
- }
- list_del(&el->cc_cclist);
- list_del(&el->cc_cnlist);
- CODA_FREE(el, sizeof(struct coda_cache));
-}
-
-/* see if there is a match for the current
- credentials already */
-static struct coda_cache * coda_cache_find(struct inode *inode)
-{
- struct coda_inode_info *cii = ITOC(inode);
- struct list_head *le;
- struct coda_cache *cc = NULL;
-
- list_for_each(le, &cii->c_cnhead)
- {
- /* compare name and creds */
- cc = list_entry(le, struct coda_cache, cc_cnlist);
- if ( !coda_cred_ok(&cc->cc_cred) )
- continue;
- CDEBUG(D_CACHE, "HIT for ino %ld\n", inode->i_ino );
- return cc; /* cache hit */
- }
- return NULL;
-}
-
-/* create or extend an acl cache hit */
+/* replace or extend an acl cache hit */
void coda_cache_enter(struct inode *inode, int mask)
{
- struct coda_cache *cc;
-
- cc = coda_cache_find(inode);
+ struct coda_inode_info *cii = ITOC(inode);
+ ENTRY;
- if (!cc)
- cc = coda_cache_create(inode);
- if (cc)
- cc->cc_mask |= mask;
+ if ( !coda_cred_ok(&cii->c_cached_cred) ) {
+ coda_load_creds(&cii->c_cached_cred);
+ cii->c_cached_perm = mask;
+ } else
+ cii->c_cached_perm |= mask;
}
-/* remove all cached acl matches from an inode */
+/* remove cached acl from an inode */
void coda_cache_clear_inode(struct inode *inode)
{
- struct list_head *le;
- struct coda_inode_info *cii;
- struct coda_cache *cc;
+ struct coda_inode_info *cii = ITOC(inode);
ENTRY;
-
- if ( !inode ) {
- CDEBUG(D_CACHE, "coda_cache_clear_inode: NULL inode\n");
- return;
- }
- cii = ITOC(inode);
-
- le = cii->c_cnhead.next;
- while ( le != &cii->c_cnhead ) {
- cc = list_entry(le, struct coda_cache, cc_cnlist);
- le = le->next;
- coda_cache_destroy(cc);
- }
+ cii->c_cached_perm = 0;
}
-/* remove all acl caches */
-void coda_cache_clear_all(struct super_block *sb)
+/* remove all acl caches for a principal (or all principals when cred == NULL)*/
+void coda_cache_clear_all(struct super_block *sb, struct coda_cred *cred)
{
- struct list_head *le;
- struct coda_cache *cc;
- struct coda_sb_info *sbi = coda_sbp(sb);
+ struct coda_sb_info *sbi;
+ struct coda_inode_info *cii;
+ struct list_head *tmp;
- if ( !sbi ) {
- printk("coda_cache_clear_all: NULL sbi\n");
- return;
- }
-
- le = sbi->sbi_cchead.next;
- while ( le != &sbi->sbi_cchead ) {
- cc = list_entry(le, struct coda_cache, cc_cclist);
- le = le->next;
- coda_cache_destroy(cc);
- }
-}
+ ENTRY;
+ sbi = coda_sbp(sb);
+ if (!sbi) BUG();
-/* remove all acl caches for a principal */
-void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred)
-{
- struct list_head *le;
- struct coda_cache *cc;
- struct coda_sb_info *sbi = coda_sbp(sb);
+ list_for_each(tmp, &sbi->sbi_cihead)
+ {
+ cii = list_entry(tmp, struct coda_inode_info, c_cilist);
+ if ( cii->c_magic != CODA_CNODE_MAGIC ) BUG();
- if ( !sbi ) {
- printk("coda_cache_clear_all: NULL sbi\n");
- return;
- }
-
- le = sbi->sbi_cchead.next;
- while ( le != &sbi->sbi_cchead ) {
- cc = list_entry(le, struct coda_cache, cc_cclist);
- le = le->next;
- if ( coda_cred_eq(&cc->cc_cred, cred))
- coda_cache_destroy(cc);
+ if (!cred || coda_cred_eq(cred, &cii->c_cached_cred))
+ cii->c_cached_perm = 0;
}
}
-/* check if the mask has been matched against the acl
- already */
+/* check if the mask has been matched against the acl already */
int coda_cache_check(struct inode *inode, int mask)
{
struct coda_inode_info *cii = ITOC(inode);
- struct list_head *le;
- struct coda_cache *cc = NULL;
+ int hit;
- list_for_each(le, &cii->c_cnhead)
- {
- /* compare name and creds */
- cc = list_entry(le, struct coda_cache, cc_cnlist);
- if ( (cc->cc_mask & mask) != mask )
- continue;
- if ( !coda_cred_ok(&cc->cc_cred) )
- continue;
- CDEBUG(D_CACHE, "HIT for ino %ld\n", inode->i_ino );
- return 1; /* cache hit */
- }
- CDEBUG(D_CACHE, "MISS for ino %ld\n", inode->i_ino );
- return 0;
+ hit = ((mask & cii->c_cached_perm) == mask) &&
+ coda_cred_ok(&cii->c_cached_cred);
+
+ CDEBUG(D_CACHE, "%s for ino %ld\n", hit ? "HIT" : "MISS", inode->i_ino);
+ return hit;
}
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index 7c5544612..c8dc3dd8f 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -59,7 +59,6 @@ struct inode * coda_iget(struct super_block * sb, ViceFid * fid,
struct coda_vattr * attr)
{
struct inode *inode;
- struct coda_sb_info *sbi= coda_sbp(sb);
struct coda_inode_info *cii;
ino_t ino = attr->va_fileid;
@@ -71,50 +70,26 @@ struct inode * coda_iget(struct super_block * sb, ViceFid * fid,
/* check if the inode is already initialized */
cii = ITOC(inode);
- if (cii->c_magic == CODA_CNODE_MAGIC) {
+ if (cii->c_fid.Volume != 0 || cii->c_fid.Vnode != 0 || cii->c_fid.Unique != 0) {
/* see if it is the right one (might have an inode collision) */
- if ( !coda_fideq(fid, &cii->c_fid) ) {
+ if ( !coda_fideq(fid, &cii->c_fid) ) {
printk("coda_iget: initialized inode old %s new %s!\n",
coda_f2s(&cii->c_fid), coda_f2s2(fid));
iput(inode);
return ERR_PTR(-ENOENT);
}
- /* replace the attributes, type might have changed */
- coda_fill_inode(inode, attr);
+ /* we will still replace the attributes, type might have changed */
goto out;
}
/* new, empty inode found... initializing */
/* Initialize the Coda inode info structure */
- memset(cii, 0, (int) sizeof(struct coda_inode_info));
- cii->c_magic = CODA_CNODE_MAGIC;
cii->c_fid = *fid;
- cii->c_flags = 0;
cii->c_vnode = inode;
- INIT_LIST_HEAD(&(cii->c_cnhead));
- INIT_LIST_HEAD(&(cii->c_volrootlist));
- coda_fill_inode(inode, attr);
-
- /* check if it is a weird fid (hashed fid != ino), f.i mountpoints
- repair object, expanded local-global conflict trees, etc.
- */
- if ( coda_f2i(fid) == ino )
- goto out;
-
- /* check if we expected this weird fid */
- if ( !coda_fid_is_weird(fid) ) {
- printk("Coda: unknown weird fid: ino %ld, fid %s."
- "Tell Peter.\n", (long)ino, coda_f2s(&cii->c_fid));
- goto out;
- }
-
- /* add the inode to a global list so we can find it back later */
- list_add(&cii->c_volrootlist, &sbi->sbi_volroothead);
- CDEBUG(D_CNODE, "Added %ld, %s to volroothead\n",
- (long)ino, coda_f2s(&cii->c_fid));
out:
+ coda_fill_inode(inode, attr);
return inode;
}
@@ -161,22 +136,14 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
void coda_replace_fid(struct inode *inode, struct ViceFid *oldfid,
struct ViceFid *newfid)
{
- struct coda_inode_info *cnp;
- struct coda_sb_info *sbi= coda_sbp(inode->i_sb);
+ struct coda_inode_info *cii;
- cnp = ITOC(inode);
-
- if ( ! coda_fideq(&cnp->c_fid, oldfid) )
- printk("What? oldfid != cnp->c_fid. Call 911.\n");
-
- cnp->c_fid = *newfid;
+ cii = ITOC(inode);
- list_del(&cnp->c_volrootlist);
- INIT_LIST_HEAD(&cnp->c_volrootlist);
- if ( coda_fid_is_weird(newfid) )
- list_add(&cnp->c_volrootlist, &sbi->sbi_volroothead);
+ if ( ! coda_fideq(&cii->c_fid, oldfid) )
+ printk("What? oldfid != cii->c_fid. Call 911.\n");
- return;
+ cii->c_fid = *newfid;
}
@@ -197,24 +164,18 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
return NULL;
}
- if ( !fid ) {
- printk("coda_fid_to_inode: no fid!\n");
- return NULL;
- }
CDEBUG(D_INODE, "%s\n", coda_f2s(fid));
+ /* weird fids cannot be hashed, have to look for them the hard way */
if ( coda_fid_is_weird(fid) ) {
- struct list_head *lh, *le;
struct coda_sb_info *sbi = coda_sbp(sb);
- le = lh = &sbi->sbi_volroothead;
+ struct list_head *le;
- while ( (le = le->next) != lh ) {
- cii = list_entry(le, struct coda_inode_info,
- c_volrootlist);
- /* paranoia check, should never trigger */
- if ( cii->c_magic != CODA_CNODE_MAGIC )
- printk("coda_fid_to_inode: Bad magic in inode %x.\n", cii->c_magic);
+ list_for_each(le, &sbi->sbi_cihead)
+ {
+ cii = list_entry(le, struct coda_inode_info, c_cilist);
+ if ( cii->c_magic != CODA_CNODE_MAGIC ) BUG();
CDEBUG(D_DOWNCALL, "iterating, now doing %s, ino %ld\n",
coda_f2s(&cii->c_fid), cii->c_vnode->i_ino);
@@ -240,26 +201,19 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
/* check if this inode is linked to a cnode */
cii = ITOC(inode);
- if ( cii->c_magic != CODA_CNODE_MAGIC ) {
- CDEBUG(D_INODE, "uninitialized inode. Return.\n");
- goto bad_inode;
- }
- /* make sure fid is the one we want */
- if ( !coda_fideq(fid, &(cii->c_fid)) ) {
+ /* make sure this is the one we want */
+ if ( coda_fideq(fid, &cii->c_fid) ) {
+ CDEBUG(D_INODE, "found %ld\n", inode->i_ino);
+ return inode;
+ }
+
#if 0
- printk("coda_fid2inode: bad cnode (ino %ld, fid %s)", nr,
- coda_f2s(fid));
+ printk("coda_fid2inode: bad cnode (ino %ld, fid %s)", nr, coda_f2s(fid));
#endif
- goto bad_inode;
- }
-
- CDEBUG(D_INODE, "found %ld\n", inode->i_ino);
- return inode;
+ iput(inode);
+ return NULL;
-bad_inode:
- iput(inode);
- return NULL;
}
/* the CONTROL inode is made without asking attributes from Venus */
@@ -271,7 +225,7 @@ int coda_cnode_makectl(struct inode **inode, struct super_block *sb)
if ( *inode ) {
(*inode)->i_op = &coda_ioctl_inode_operations;
(*inode)->i_fop = &coda_ioctl_operations;
- (*inode)->i_mode = 00444;
+ (*inode)->i_mode = 0444;
error = 0;
} else {
error = -ENOMEM;
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index 4a7bebb62..2a3f544f3 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -23,7 +23,6 @@
#include <linux/coda_linux.h>
#include <linux/coda_psdev.h>
#include <linux/coda_fs_i.h>
-#include <linux/coda_cache.h>
/* initialize the debugging variables */
int coda_debug = 0;
@@ -71,12 +70,6 @@ int coda_isroot(struct inode *i)
}
}
-/* is this a volume root FID */
-int coda_fid_is_volroot(struct ViceFid *fid)
-{
- return ( (fid->Vnode == 1) && (fid->Unique == 1 ) );
-}
-
int coda_fid_is_weird(struct ViceFid *fid)
{
/* volume roots */
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index a51bfc647..1629be782 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -170,12 +170,13 @@ int coda_permission(struct inode *inode, int mask)
ENTRY;
coda_vfs_stat.permission++;
- coda_permission_stat.count++;
if ( mask == 0 )
return 0;
- if ( coda_access_cache == 1 ) {
+ if ( coda_access_cache ) {
+ coda_permission_stat.count++;
+
if ( coda_cache_check(inode, mask) ) {
coda_permission_stat.hit_count++;
return 0;
@@ -472,6 +473,7 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
const char *new_name = new_dentry->d_name.name;
int old_length = old_dentry->d_name.len;
int new_length = new_dentry->d_name.len;
+ int link_adjust = 0;
int error;
ENTRY;
@@ -488,16 +490,16 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
if ( !error ) {
if ( new_dentry->d_inode ) {
- if ( S_ISDIR(new_dentry->d_inode->i_mode) ) {
- old_dir->i_nlink--;
- new_dir->i_nlink++;
- }
- coda_flag_inode(new_dentry->d_inode, C_VATTR);
- }
+ if ( S_ISDIR(new_dentry->d_inode->i_mode) )
+ link_adjust = 1;
- /* coda_flag_inode(old_dir, C_VATTR); */
- /* coda_flag_inode(new_dir, C_VATTR); */
- old_dir->i_mtime = new_dir->i_mtime = CURRENT_TIME;
+ coda_dir_changed(old_dir, -link_adjust);
+ coda_dir_changed(new_dir, link_adjust);
+ coda_flag_inode(new_dentry->d_inode, C_VATTR);
+ } else {
+ coda_flag_inode(old_dir, C_VATTR);
+ coda_flag_inode(new_dir, C_VATTR);
+ }
}
CDEBUG(D_INODE, "result %d\n", error);
@@ -578,6 +580,7 @@ int coda_open(struct inode *i, struct file *f)
unsigned short flags = f->f_flags & (~O_EXCL);
unsigned short coda_flags = coda_flags_to_cflags(flags);
struct coda_cred *cred;
+ struct coda_inode_info *cii;
lock_kernel();
ENTRY;
@@ -617,8 +620,11 @@ int coda_open(struct inode *i, struct file *f)
}
i->i_mapping = cont_inode->i_mapping;
- CDEBUG(D_FILE, "result %d, coda i->i_count is %d for ino %ld\n",
- error, atomic_read(&i->i_count), i->i_ino);
+ cii = ITOC(i);
+ cii->c_contcount++;
+
+ CDEBUG(D_FILE, "result %d, coda i->i_count is %d, cii->contcount is %d for ino %ld\n",
+ error, atomic_read(&i->i_count), cii->c_contcount, i->i_ino);
CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %p\n",
cont_inode->i_ino, atomic_read(&cont_inode->i_count),
cont_inode->i_op);
@@ -634,6 +640,7 @@ int coda_release(struct inode *i, struct file *f)
unsigned short flags = (f->f_flags) & (~O_EXCL);
unsigned short cflags = coda_flags_to_cflags(flags);
struct coda_cred *cred;
+ struct coda_inode_info *cii;
lock_kernel();
ENTRY;
@@ -644,11 +651,17 @@ int coda_release(struct inode *i, struct file *f)
if (i->i_mapping != &i->i_data)
container = (struct inode *)i->i_mapping->host;
- CDEBUG(D_FILE, "RELEASE coda (ino %ld, ct %d) cache (ino %ld, ct %d)\n",
- i->i_ino, atomic_read(&i->i_count),
+ cii = ITOC(i);
+ CDEBUG(D_FILE, "RELEASE coda (ino %ld, ct %d, cc %d) cache (ino %ld, ct %d)\n",
+ i->i_ino, atomic_read(&i->i_count), cii->c_contcount,
(container ? container->i_ino : 0),
(container ? atomic_read(&container->i_count) : -99));
+ if (--cii->c_contcount == 0 && container) {
+ i->i_mapping = &i->i_data;
+ iput(container);
+ }
+
error = venus_release(i->i_sb, coda_i2f(i), cflags, cred);
f->private_data = NULL;
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 128b07d44..0344c2072 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -23,18 +23,21 @@
#include <linux/coda_linux.h>
#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
-#include <linux/coda_cache.h>
#include <linux/coda_proc.h>
static ssize_t
coda_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
+ struct inode *container = (struct inode*)inode->i_mapping->host;
ssize_t n;
+ down(&container->i_sem);
+
n = generic_file_write(file, buf, count, ppos);
+ inode->i_size = container->i_size;
- inode->i_size = ((struct inode*)inode->i_mapping->host)->i_size;
+ up(&container->i_sem);
return n;
}
@@ -63,7 +66,7 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
result = file_fsync(NULL, &cont_dentry, datasync);
up(&cont_dentry.d_inode->i_sem);
- if ( result == 0 ) {
+ if ( result == 0 && datasync == 0 ) {
lock_kernel();
result = venus_fsync(inode->i_sb, coda_i2f(inode));
unlock_kernel();
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 84191c494..94a3be389 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -18,6 +18,7 @@
#include <linux/locks.h>
#include <linux/unistd.h>
#include <linux/smp_lock.h>
+#include <linux/file.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -48,6 +49,47 @@ struct super_operations coda_super_operations =
statfs: coda_statfs,
};
+static int get_device_index(struct coda_mount_data *data)
+{
+ struct file *file;
+ struct inode *inode;
+ int idx;
+
+ if(data == NULL) {
+ printk("coda_read_super: Bad mount data\n");
+ return -1;
+ }
+
+ if(data->version != CODA_MOUNT_VERSION) {
+ printk("coda_read_super: Bad mount version\n");
+ return -1;
+ }
+
+ file = fget(data->fd);
+ inode = NULL;
+ if(file)
+ inode = file->f_dentry->d_inode;
+
+ if(!inode || !S_ISCHR(inode->i_mode) ||
+ MAJOR(inode->i_rdev) != CODA_PSDEV_MAJOR) {
+ if(file)
+ fput(file);
+
+ printk("coda_read_super: Bad file\n");
+ return -1;
+ }
+
+ idx = MINOR(inode->i_rdev);
+ fput(file);
+
+ if(idx < 0 || idx >= MAX_CODADEVS) {
+ printk("coda_read_super: Bad minor number\n");
+ return -1;
+ }
+
+ return idx;
+}
+
static struct super_block * coda_read_super(struct super_block *sb,
void *data, int silent)
{
@@ -57,23 +99,41 @@ static struct super_block * coda_read_super(struct super_block *sb,
ViceFid fid;
kdev_t dev = sb->s_dev;
int error;
-
+ int idx;
ENTRY;
- vc = &coda_upc_comm;
- sbi = &coda_super_info;
+ idx = get_device_index((struct coda_mount_data *) data);
- if ( sbi->sbi_sb ) {
- printk("Already mounted\n");
+ /* Ignore errors in data, for backward compatibility */
+ if(idx == -1)
+ idx = 0;
+
+ printk(KERN_INFO "coda_read_super: device index: %i\n", idx);
+
+ vc = &coda_comms[idx];
+ if (!vc->vc_inuse) {
+ printk("coda_read_super: No pseudo device\n");
EXIT;
return NULL;
}
+ if ( vc->vc_sb ) {
+ printk("coda_read_super: Device already mounted\n");
+ EXIT;
+ return NULL;
+ }
+
+ sbi = kmalloc(sizeof(struct coda_sb_info), GFP_KERNEL);
+ if(!sbi) {
+ EXIT;
+ return NULL;
+ }
+
+ vc->vc_sb = sb;
+
sbi->sbi_sb = sb;
- sbi->sbi_psdev = psdev;
sbi->sbi_vcomm = vc;
- INIT_LIST_HEAD(&(sbi->sbi_cchead));
- INIT_LIST_HEAD(&(sbi->sbi_volroothead));
+ INIT_LIST_HEAD(&sbi->sbi_cihead);
sb->u.generic_sbp = sbi;
sb->s_blocksize = 1024; /* XXXXX what do we put here?? */
@@ -100,7 +160,6 @@ static struct super_block * coda_read_super(struct super_block *sb,
printk("coda_read_super: rootinode is %ld dev %d\n",
root->i_ino, root->i_dev);
- sbi->sbi_root = root;
sb->s_root = d_alloc_root(root);
EXIT;
return sb;
@@ -108,9 +167,9 @@ static struct super_block * coda_read_super(struct super_block *sb,
error:
EXIT;
if (sbi) {
- sbi->sbi_vcomm = NULL;
- sbi->sbi_root = NULL;
- sbi->sbi_sb = NULL;
+ kfree(sbi);
+ if(vc)
+ vc->vc_sb = NULL;
}
if (root) {
iput(root);
@@ -120,15 +179,16 @@ static struct super_block * coda_read_super(struct super_block *sb,
static void coda_put_super(struct super_block *sb)
{
- struct coda_sb_info *sb_info;
+ struct coda_sb_info *sbi;
ENTRY;
- coda_cache_clear_all(sb);
- sb_info = coda_sbp(sb);
- coda_super_info.sbi_sb = NULL;
+ sbi = coda_sbp(sb);
+ sbi->sbi_vcomm->vc_sb = NULL;
+ list_del_init(&sbi->sbi_cihead);
+
printk("Coda: Bye bye.\n");
- memset(sb_info, 0, sizeof(* sb_info));
+ kfree(sbi);
EXIT;
}
@@ -136,11 +196,21 @@ static void coda_put_super(struct super_block *sb)
/* all filling in of inodes postponed until lookup */
static void coda_read_inode(struct inode *inode)
{
+ struct coda_sb_info *sbi = coda_sbp(inode->i_sb);
struct coda_inode_info *cii;
ENTRY;
+
+ if (!sbi) BUG();
+
cii = ITOC(inode);
- cii->c_magic = 0;
- return;
+ if (cii->c_magic == CODA_CNODE_MAGIC) {
+ printk("coda_read_inode: initialized inode");
+ return;
+ }
+
+ memset(cii, 0, sizeof(struct coda_inode_info));
+ list_add(&cii->c_cilist, &sbi->sbi_cihead);
+ cii->c_magic = CODA_CNODE_MAGIC;
}
static void coda_clear_inode(struct inode *inode)
@@ -152,15 +222,13 @@ static void coda_clear_inode(struct inode *inode)
CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n",
inode->i_ino, atomic_read(&inode->i_count));
- if ( inode->i_ino == CTL_INO || cii->c_magic != CODA_CNODE_MAGIC )
- goto out;
+ if ( cii->c_magic != CODA_CNODE_MAGIC )
+ return;
- lock_kernel();
+ list_del_init(&cii->c_cilist);
- if ( !list_empty(&cii->c_volrootlist) ) {
- list_del(&cii->c_volrootlist);
- INIT_LIST_HEAD(&cii->c_volrootlist);
- }
+ if ( inode->i_ino == CTL_INO )
+ goto out;
if ( inode->i_mapping != &inode->i_data ) {
open_inode = (struct inode *)inode->i_mapping->host;
@@ -170,12 +238,11 @@ static void coda_clear_inode(struct inode *inode)
iput(open_inode);
}
- coda_cache_clear_inode(inode);
- unlock_kernel();
-
CDEBUG(D_DOWNCALL, "clearing inode: %ld, %x\n", inode->i_ino, cii->c_flags);
+ coda_cache_clear_inode(inode);
out:
inode->u.coda_i.c_magic = 0;
+ memset(&inode->u.coda_i.c_fid, 0, sizeof(struct ViceFid));
EXIT;
}
@@ -238,8 +305,3 @@ static int coda_statfs(struct super_block *sb, struct statfs *buf)
DECLARE_FSTYPE( coda_fs_type, "coda", coda_read_super, 0);
-int init_coda_fs(void)
-{
- return register_filesystem(&coda_fs_type);
-}
-
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index 99ead4e51..6deeb927c 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -23,13 +23,12 @@
#include <linux/coda.h>
#include <linux/coda_linux.h>
#include <linux/coda_fs_i.h>
-#include <linux/coda_cache.h>
#include <linux/coda_psdev.h>
/* pioctl ops */
static int coda_ioctl_permission(struct inode *inode, int mask);
static int coda_pioctl(struct inode * inode, struct file * filp,
- unsigned int cmd, unsigned long arg);
+ unsigned int cmd, unsigned long user_data);
/* exported from this file */
struct inode_operations coda_ioctl_inode_operations =
@@ -52,7 +51,7 @@ static int coda_ioctl_permission(struct inode *inode, int mask)
}
static int coda_pioctl(struct inode * inode, struct file * filp,
- unsigned int cmd, unsigned long user_data)
+ unsigned int cmd, unsigned long user_data)
{
struct nameidata nd;
int error;
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index c475b73ac..486e42185 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -46,21 +46,19 @@
#include <linux/coda_linux.h>
#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
-#include <linux/coda_cache.h>
#include <linux/coda_proc.h>
/*
* Coda stuff
*/
extern struct file_system_type coda_fs_type;
-extern int init_coda_fs(void);
/* statistics */
int coda_hard = 0; /* allows signals during upcalls */
unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */
-struct coda_sb_info coda_super_info;
-struct venus_comm coda_upc_comm;
+
+struct venus_comm coda_comms[MAX_CODADEVS];
/*
* Device operations
@@ -68,7 +66,7 @@ struct venus_comm coda_upc_comm;
static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
{
- struct venus_comm *vcp = &coda_upc_comm;
+ struct venus_comm *vcp = (struct venus_comm *) file->private_data;
unsigned int mask = POLLOUT | POLLWRNORM;
poll_wait(file, &vcp->vc_waitq, wait);
@@ -101,7 +99,7 @@ static int coda_psdev_ioctl(struct inode * inode, struct file * filp,
static ssize_t coda_psdev_write(struct file *file, const char *buf,
size_t nbytes, loff_t *off)
{
- struct venus_comm *vcp = &coda_upc_comm;
+ struct venus_comm *vcp = (struct venus_comm *) file->private_data;
struct upc_req *req = NULL;
struct upc_req *tmp;
struct list_head *lh;
@@ -109,8 +107,6 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
ssize_t retval = 0, count = 0;
int error;
- if ( !coda_upc_comm.vc_inuse )
- return -EIO;
/* Peek at the opcode, uniquefier */
if (copy_from_user(&hdr, buf, 2 * sizeof(u_long)))
return -EFAULT;
@@ -123,7 +119,7 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
union outputArgs *dcbuf;
int size = sizeof(*dcbuf);
- sb = coda_super_info.sbi_sb;
+ sb = vcp->vc_sb;
if ( !sb ) {
CDEBUG(D_PSDEV, "coda_psdev_write: downcall, no SB!\n");
count = nbytes;
@@ -221,7 +217,7 @@ static ssize_t coda_psdev_read(struct file * file, char * buf,
size_t nbytes, loff_t *off)
{
DECLARE_WAITQUEUE(wait, current);
- struct venus_comm *vcp = &coda_upc_comm;
+ struct venus_comm *vcp = (struct venus_comm *) file->private_data;
struct upc_req *req;
ssize_t retval = 0, count = 0;
@@ -245,7 +241,7 @@ static ssize_t coda_psdev_read(struct file * file, char * buf,
schedule();
}
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&vcp->vc_waitq, &wait);
if (retval)
@@ -285,21 +281,32 @@ out:
return (count ? count : retval);
}
-
static int coda_psdev_open(struct inode * inode, struct file * file)
{
- struct venus_comm *vcp = &coda_upc_comm;
+ struct venus_comm *vcp;
+ int idx;
ENTRY;
-
- /* first opener, initialize */
+
lock_kernel();
+ idx = MINOR(inode->i_rdev);
+ if(idx >= MAX_CODADEVS)
+ return -ENODEV;
+
+ vcp = &coda_comms[idx];
+ if(vcp->vc_inuse)
+ return -EBUSY;
+
if (!vcp->vc_inuse++) {
- INIT_LIST_HEAD(&vcp->vc_pending);
- INIT_LIST_HEAD(&vcp->vc_processing);
- vcp->vc_seq = 0;
+ INIT_LIST_HEAD(&vcp->vc_pending);
+ INIT_LIST_HEAD(&vcp->vc_processing);
+ init_waitqueue_head(&vcp->vc_waitq);
+ vcp->vc_sb = 0;
+ vcp->vc_seq = 0;
}
+
+ file->private_data = vcp;
- CDEBUG(D_PSDEV, "inuse: %d\n", vcp->vc_inuse);
+ CDEBUG(D_PSDEV, "device %i - inuse: %d\n", idx, vcp->vc_inuse);
EXIT;
unlock_kernel();
@@ -309,7 +316,7 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
static int coda_psdev_release(struct inode * inode, struct file * file)
{
- struct venus_comm *vcp = &coda_upc_comm;
+ struct venus_comm *vcp = (struct venus_comm *) file->private_data;
struct upc_req *req;
struct list_head *lh, *next;
ENTRY;
@@ -369,29 +376,9 @@ static struct file_operations coda_psdev_fops = {
release: coda_psdev_release,
};
-
-
-int __init init_coda(void)
-{
- int status;
- printk(KERN_INFO "Coda Kernel/Venus communications, v4.6.0, braam@cs.cmu.edu\n");
-
- status = init_coda_psdev();
- if ( status ) {
- printk("Problem (%d) in init_coda_psdev\n", status);
- return status;
- }
-
- status = init_coda_fs();
- if (status) {
- printk("coda: failed in init_coda_fs!\n");
- }
- return status;
-}
-
static devfs_handle_t devfs_handle = NULL;
-int init_coda_psdev(void)
+static int init_coda_psdev(void)
{
if(devfs_register_chrdev(CODA_PSDEV_MAJOR,"coda_psdev",
&coda_psdev_fops)) {
@@ -404,9 +391,6 @@ int init_coda_psdev(void)
CODA_PSDEV_MAJOR, 0,
S_IFCHR | S_IRUSR | S_IWUSR,
&coda_psdev_fops, NULL);
- memset(&coda_upc_comm, 0, sizeof(coda_upc_comm));
- memset(&coda_super_info, 0, sizeof(coda_super_info));
- init_waitqueue_head(&coda_upc_comm.vc_waitq);
coda_sysctl_init();
@@ -414,36 +398,35 @@ int init_coda_psdev(void)
}
-#ifdef MODULE
-
MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
-int init_module(void)
+static int __init init_coda(void)
{
int status;
- printk(KERN_INFO "Coda Kernel/Venus communications (module), v5.0-pre1, braam@cs.cmu.edu.\n");
+ printk(KERN_INFO "Coda Kernel/Venus communications, v5.3.9, coda@cs.cmu.edu\n");
+
status = init_coda_psdev();
if ( status ) {
printk("Problem (%d) in init_coda_psdev\n", status);
return status;
}
-
- status = init_coda_fs();
+
+ status = register_filesystem(&coda_fs_type);
if (status) {
printk("coda: failed in init_coda_fs!\n");
}
return status;
}
-
-void cleanup_module(void)
+static void __exit exit_coda(void)
{
int err;
ENTRY;
- if ( (err = unregister_filesystem(&coda_fs_type)) != 0 ) {
+ err = unregister_filesystem(&coda_fs_type);
+ if ( err != 0 ) {
printk("coda: failed to unregister filesystem\n");
}
devfs_unregister (devfs_handle);
@@ -451,5 +434,5 @@ void cleanup_module(void)
coda_sysctl_clean();
}
-#endif
-
+module_init(init_coda);
+module_exit(exit_coda);
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
index 252f11664..dbdc946f4 100644
--- a/fs/coda/symlink.c
+++ b/fs/coda/symlink.c
@@ -20,7 +20,6 @@
#include <linux/coda_linux.h>
#include <linux/coda_psdev.h>
#include <linux/coda_fs_i.h>
-#include <linux/coda_cache.h>
#include <linux/coda_proc.h>
static int coda_symlink_filler(struct file *file, struct page *page)
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c
index cbfff3e5b..4215c3b41 100644
--- a/fs/coda/sysctl.c
+++ b/fs/coda/sysctl.c
@@ -76,9 +76,9 @@ int coda_upcall_timestamping = 0;
/* keep this in sync with coda.h! */
char *coda_upcall_names[] = {
"totals ", /* 0 */
- "noop ", /* 1 */
+ "- ", /* 1 */
"root ", /* 2 */
- "sync ", /* 3 */
+ "open_by_fd ", /* 3 */
"open ", /* 4 */
"close ", /* 5 */
"ioctl ", /* 6 */
@@ -96,7 +96,7 @@ char *coda_upcall_names[] = {
"symlink ", /* 18 */
"readlink ", /* 19 */
"fsync ", /* 20 */
- "inactive ", /* 21 */
+ "- ", /* 21 */
"vget ", /* 22 */
"signal ", /* 23 */
"replace ", /* 24 */
@@ -104,13 +104,12 @@ char *coda_upcall_names[] = {
"purgeuser ", /* 26 */
"zapfile ", /* 27 */
"zapdir ", /* 28 */
- "noop2 ", /* 29 */
+ "- ", /* 29 */
"purgefid ", /* 30 */
"open_by_path", /* 31 */
"resolve ", /* 32 */
"reintegrate ", /* 33 */
- "statfs ", /* 34 */
- "make_cinode " /* 35 */
+ "statfs " /* 34 */
};
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 206c9d8b0..6eb6f2e71 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -543,7 +543,8 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
goto exit;
}
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+ error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
+ &outsize, inp);
if (error) {
printk("coda_pioctl: Venus returns: %d for %s\n",
@@ -607,7 +608,8 @@ int venus_statfs(struct super_block *sb, struct statfs *sfs)
*
*/
-static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
+static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
+ struct venus_comm *vcommp)
{
DECLARE_WAITQUEUE(wait, current);
struct timeval begin = { 0, 0 }, end = { 0, 0 };
@@ -625,7 +627,7 @@ static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
set_current_state(TASK_UNINTERRUPTIBLE);
/* venus died */
- if ( !coda_upc_comm.vc_inuse )
+ if ( !vcommp->vc_inuse )
break;
/* got a reply */
@@ -634,8 +636,8 @@ static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
/* if this process really wants to die, let it go */
- if ( sigismember(&(current->signal), SIGKILL) ||
- sigismember(&(current->signal), SIGINT) )
+ if ( sigismember(&(current->pending.signal), SIGKILL) ||
+ sigismember(&(current->pending.signal), SIGINT) )
break;
/* signal is present: after timeout always return
really smart idea, probably useless ... */
@@ -645,7 +647,7 @@ static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
schedule();
}
remove_wait_queue(&vmp->uc_sleep, &wait);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
if (coda_upcall_timestamping && begin.tv_sec != 0) {
do_gettimeofday(&end);
@@ -685,9 +687,9 @@ static int coda_upcall(struct coda_sb_info *sbi,
struct upc_req *req;
int error = 0;
-ENTRY;
+ ENTRY;
- vcommp = &coda_upc_comm;
+ vcommp = sbi->sbi_vcomm;
if ( !vcommp->vc_inuse ) {
printk("No pseudo device in upcall comms at %p\n", vcommp);
return -ENXIO;
@@ -724,7 +726,7 @@ ENTRY;
* ENODEV. */
/* Go to sleep. Wake up on signals only after the timeout. */
- runtime = coda_waitfor_upcall(req);
+ runtime = coda_waitfor_upcall(req, vcommp);
coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
@@ -738,11 +740,6 @@ ENTRY;
if (req->uc_flags & REQ_WRITE) {
out = (union outputArgs *)req->uc_data;
/* here we map positive Venus errors to kernel errors */
- if ( out->oh.result < 0 ) {
- printk("Tell Peter: Venus returns negative error %ld, for oc %ld!\n",
- out->oh.result, out->oh.opcode);
- out->oh.result = EINTR;
- }
error = -out->oh.result;
CDEBUG(D_UPCALL,
"upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n",
@@ -855,7 +852,7 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
case CODA_FLUSH : {
clstats(CODA_FLUSH);
CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
- coda_cache_clear_all(sb);
+ coda_cache_clear_all(sb, NULL);
shrink_dcache_sb(sb);
coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
return(0);
@@ -869,7 +866,7 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
return 0;
}
clstats(CODA_PURGEUSER);
- coda_cache_clear_cred(sb, cred);
+ coda_cache_clear_all(sb, cred);
return(0);
}
diff --git a/fs/cramfs/uncompress.c b/fs/cramfs/uncompress.c
index d946b56e7..5cebec174 100644
--- a/fs/cramfs/uncompress.c
+++ b/fs/cramfs/uncompress.c
@@ -20,7 +20,7 @@
#include "inflate/zlib.h"
static z_stream stream;
-static int initialized = 0;
+static int initialized;
/* Returns length of decompressed data. */
int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen)
diff --git a/fs/dcache.c b/fs/dcache.c
index 214f0da2e..090bf1686 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -551,20 +551,29 @@ void shrink_dcache_parent(struct dentry * parent)
* ...
* 6 - base-level: try to shrink a bit.
*/
-int shrink_dcache_memory(int priority, unsigned int gfp_mask)
+void shrink_dcache_memory(int priority, unsigned int gfp_mask)
{
int count = 0;
+
+ /*
+ * Nasty deadlock avoidance.
+ *
+ * ext2_new_block->getblk->GFP->shrink_dcache_memory->prune_dcache->
+ * prune_one_dentry->dput->dentry_iput->iput->inode->i_sb->s_op->
+ * put_inode->ext2_discard_prealloc->ext2_free_blocks->lock_super->
+ * DEADLOCK.
+ *
+ * We should make sure we don't hold the superblock lock over
+ * block allocations, but for now:
+ */
+ if (!(gfp_mask & __GFP_IO))
+ return;
+
if (priority)
count = dentry_stat.nr_unused / priority;
+
prune_dcache(count);
- /* FIXME: kmem_cache_shrink here should tell us
- the number of pages freed, and it should
- work in a __GFP_DMA/__GFP_HIGHMEM behaviour
- to free only the interesting pages in
- function of the needs of the current allocation. */
kmem_cache_shrink(dentry_cache);
-
- return 0;
}
#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
@@ -1248,7 +1257,7 @@ void __init vfs_caches_init(unsigned long mempages)
panic("Cannot create buffer head SLAB cache");
names_cachep = kmem_cache_create("names_cache",
- PAGE_SIZE, 0,
+ PATH_MAX + 1, 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if (!names_cachep)
panic("Cannot create names SLAB cache");
diff --git a/fs/devices.c b/fs/devices.c
index 85fb7e519..bace8eccf 100644
--- a/fs/devices.c
+++ b/fs/devices.c
@@ -36,9 +36,7 @@ struct device_struct {
};
static rwlock_t chrdevs_lock = RW_LOCK_UNLOCKED;
-static struct device_struct chrdevs[MAX_CHRDEV] = {
- { NULL, NULL },
-};
+static struct device_struct chrdevs[MAX_CHRDEV];
extern int get_blkdev_list(char *);
diff --git a/fs/dnotify.c b/fs/dnotify.c
new file mode 100644
index 000000000..90fd86b06
--- /dev/null
+++ b/fs/dnotify.c
@@ -0,0 +1,140 @@
+/*
+ * Directory notifications for Linux.
+ *
+ * Copyright (C) 2000 Stephen Rothwell
+ *
+ * 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, 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.
+ */
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/dnotify.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+extern void send_sigio(struct fown_struct *fown, int fd, int band);
+
+int dir_notify_enable = 1;
+
+static rwlock_t dn_lock = RW_LOCK_UNLOCKED;
+static kmem_cache_t *dn_cache;
+
+static void redo_inode_mask(struct inode *inode)
+{
+ unsigned long new_mask;
+ struct dnotify_struct *dn;
+
+ new_mask = 0;
+ for (dn = inode->i_dnotify; dn != NULL; dn = dn->dn_next)
+ new_mask |= dn->dn_mask & ~DN_MULTISHOT;
+ inode->i_dnotify_mask = new_mask;
+}
+
+int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
+{
+ struct dnotify_struct *dn = NULL;
+ struct dnotify_struct *odn;
+ struct dnotify_struct **prev;
+ struct inode *inode;
+ int turning_off = (arg & ~DN_MULTISHOT) == 0;
+
+ if (!turning_off && !dir_notify_enable)
+ return -EINVAL;
+ inode = filp->f_dentry->d_inode;
+ if (!S_ISDIR(inode->i_mode))
+ return -ENOTDIR;
+ if (!turning_off) {
+ dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL);
+ if (dn == NULL)
+ return -ENOMEM;
+ }
+ write_lock(&dn_lock);
+ prev = &inode->i_dnotify;
+ for (odn = *prev; odn != NULL; prev = &odn->dn_next, odn = *prev)
+ if (odn->dn_filp == filp)
+ break;
+ if (odn != NULL) {
+ if (turning_off) {
+ *prev = odn->dn_next;
+ redo_inode_mask(inode);
+ dn = odn;
+ goto out_free;
+ }
+ odn->dn_fd = fd;
+ odn->dn_mask |= arg;
+ inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
+ goto out_free;
+ }
+ if (turning_off)
+ goto out;
+ filp->f_owner.pid = current->pid;
+ filp->f_owner.uid = current->uid;
+ filp->f_owner.euid = current->euid;
+ dn->dn_magic = DNOTIFY_MAGIC;
+ dn->dn_mask = arg;
+ dn->dn_fd = fd;
+ dn->dn_filp = filp;
+ inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
+ dn->dn_next = inode->i_dnotify;
+ inode->i_dnotify = dn;
+out:
+ write_unlock(&dn_lock);
+ return 0;
+out_free:
+ kmem_cache_free(dn_cache, dn);
+ goto out;
+}
+
+void __inode_dir_notify(struct inode *inode, unsigned long event)
+{
+ struct dnotify_struct * dn;
+ struct dnotify_struct **prev;
+ struct fown_struct * fown;
+ int changed = 0;
+
+ write_lock(&dn_lock);
+ prev = &inode->i_dnotify;
+ while ((dn = *prev) != NULL) {
+ if ((dn->dn_mask & event) == 0) {
+ prev = &dn->dn_next;
+ continue;
+ }
+ if (dn->dn_magic != DNOTIFY_MAGIC) {
+ printk(KERN_ERR "__inode_dir_notify: bad magic "
+ "number in dnotify_struct!\n");
+ return;
+ }
+ fown = &dn->dn_filp->f_owner;
+ if (fown->pid)
+ send_sigio(fown, dn->dn_fd, POLL_MSG);
+ if (dn->dn_mask & DN_MULTISHOT)
+ prev = &dn->dn_next;
+ else {
+ *prev = dn->dn_next;
+ changed = 1;
+ kmem_cache_free(dn_cache, dn);
+ }
+ }
+ if (changed)
+ redo_inode_mask(inode);
+ write_unlock(&dn_lock);
+}
+
+static int __init dnotify_init(void)
+{
+ dn_cache = kmem_cache_create("dnotify cache",
+ sizeof(struct dnotify_struct), 0, 0, NULL, NULL);
+ if (!dn_cache)
+ panic("cannot create dnotify slab cache");
+ return 0;
+}
+
+module_init(dnotify_init)
diff --git a/fs/dquot.c b/fs/dquot.c
index 2271f4746..ef1f15016 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -1214,14 +1214,6 @@ int dquot_transfer(struct dentry *dentry, struct iattr *iattr)
lock_kernel();
/*
- * Find out if this filesystem uses i_blocks.
- */
- if (!inode->i_sb->s_blocksize)
- blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE_BITS);
- else
- blocks = (inode->i_blocks >> 1);
-
- /*
* Build the transfer_from and transfer_to lists and check quotas to see
* if operation is permitted.
*/
@@ -1280,14 +1272,29 @@ int dquot_transfer(struct dentry *dentry, struct iattr *iattr)
* dqget() could block and so the first structure might got
* invalidated or locked...
*/
- if (!transfer_to[cnt]->dq_sb || !transfer_from[cnt]->dq_sb ||
- check_idq(transfer_to[cnt], 1) == NO_QUOTA ||
- check_bdq(transfer_to[cnt], blocks, 0) == NO_QUOTA) {
+ if (!transfer_to[cnt]->dq_sb || !transfer_from[cnt]->dq_sb) {
cnt++;
goto put_all;
}
}
+ /*
+ * Find out if this filesystem uses i_blocks.
+ */
+ if (!inode->i_sb->s_blocksize)
+ blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE_BITS);
+ else
+ blocks = (inode->i_blocks >> 1);
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+ if (!transfer_to[cnt])
+ continue;
+ if (check_idq(transfer_to[cnt], 1) == NO_QUOTA ||
+ check_bdq(transfer_to[cnt], blocks, 0) == NO_QUOTA) {
+ cnt = MAXQUOTAS;
+ goto put_all;
+ }
+ }
+
if ((error = notify_change(dentry, iattr)))
goto put_all;
/*
diff --git a/fs/exec.c b/fs/exec.c
index f0c64b43a..1cab95172 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -427,7 +427,7 @@ static int exec_mmap(void)
* This function makes sure the current process has its own signal table,
* so that flush_signal_handlers can later reset the handlers without
* disturbing other processes. (Other processes might share the signal
- * table via the CLONE_SIGHAND option to clone().)
+ * table via the CLONE_SIGNAL option to clone().)
*/
static inline int make_private_signals(void)
diff --git a/fs/ext2/Makefile b/fs/ext2/Makefile
index 456f9ba75..7321f45c8 100644
--- a/fs/ext2/Makefile
+++ b/fs/ext2/Makefile
@@ -9,7 +9,7 @@
O_TARGET := ext2.o
O_OBJS := acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
- ioctl.o namei.o super.o symlink.o truncate.o
+ ioctl.o namei.o super.o symlink.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 831aa67e9..81448e71b 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -13,6 +13,7 @@
#include <linux/config.h>
#include <linux/fs.h>
+#include <linux/ext2_fs.h>
#include <linux/locks.h>
#include <linux/quotaops.h>
@@ -325,10 +326,10 @@ do_more:
}
}
- mark_buffer_dirty(bh2, 1);
- mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ mark_buffer_dirty(bh2);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -582,7 +583,7 @@ got_block:
j = tmp;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -600,9 +601,9 @@ got_block:
"Goal hits %d of %d.\n", j, goal_hits, goal_attempts);
gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1);
- mark_buffer_dirty(bh2, 1);
+ mark_buffer_dirty(bh2);
es->s_free_blocks_count = cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - 1);
- mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
sb->s_dirt = 1;
unlock_super (sb);
*err = 0;
diff --git a/fs/ext2/bitmap.c b/fs/ext2/bitmap.c
index c0ffb68cd..c30a3b075 100644
--- a/fs/ext2/bitmap.c
+++ b/fs/ext2/bitmap.c
@@ -8,7 +8,7 @@
*/
#include <linux/fs.h>
-
+#include <linux/ext2_fs.h>
static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index cd49b5da6..5db9c4dbd 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -19,6 +19,7 @@
*/
#include <linux/fs.h>
+#include <linux/ext2_fs.h>
static unsigned char ext2_filetype_table[] = {
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 27b1fcbcb..d92e37ccc 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -19,6 +19,7 @@
*/
#include <linux/fs.h>
+#include <linux/ext2_fs.h>
#include <linux/sched.h>
static loff_t ext2_file_lseek(struct file *, loff_t, int);
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index 1e4478cc7..42ce44c65 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -23,6 +23,7 @@
*/
#include <linux/fs.h>
+#include <linux/ext2_fs.h>
#include <linux/locks.h>
#include <linux/smp_lock.h>
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index c99f7f2c8..adaab9c74 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -14,6 +14,7 @@
#include <linux/config.h>
#include <linux/fs.h>
+#include <linux/ext2_fs.h>
#include <linux/locks.h>
#include <linux/quotaops.h>
@@ -230,12 +231,12 @@ void ext2_free_inode (struct inode * inode)
gdp->bg_used_dirs_count =
cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1);
}
- mark_buffer_dirty(bh2, 1);
+ mark_buffer_dirty(bh2);
es->s_free_inodes_count =
cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1);
- mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
}
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -388,7 +389,7 @@ repeat:
"bit already set for inode %d", j);
goto repeat;
}
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -398,9 +399,13 @@ repeat:
ext2_error (sb, "ext2_new_inode",
"Free inodes count corrupted in group %d",
i);
- unlock_super (sb);
- iput (inode);
- return NULL;
+ if (sb->s_flags & MS_RDONLY) {
+ unlock_super (sb);
+ iput (inode);
+ return NULL;
+ }
+ gdp->bg_free_inodes_count = 0;
+ mark_buffer_dirty(bh2);
}
goto repeat;
}
@@ -411,6 +416,7 @@ repeat:
"block_group = %d,inode=%d", i, j);
unlock_super (sb);
iput (inode);
+ *err = -EIO;
return NULL;
}
gdp->bg_free_inodes_count =
@@ -418,10 +424,10 @@ repeat:
if (S_ISDIR(mode))
gdp->bg_used_dirs_count =
cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
- mark_buffer_dirty(bh2, 1);
+ mark_buffer_dirty(bh2);
es->s_free_inodes_count =
cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1);
- mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
sb->s_dirt = 1;
inode->i_mode = mode;
inode->i_sb = sb;
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 4f0b78da3..5852cef4c 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -23,6 +23,7 @@
*/
#include <linux/fs.h>
+#include <linux/ext2_fs.h>
#include <linux/locks.h>
#include <linux/smp_lock.h>
#include <linux/sched.h>
@@ -245,47 +246,17 @@ static inline Indirect *ext2_get_branch(struct inode *inode,
add_chain (chain, NULL, inode->u.ext2_i.i_data + *offsets);
if (!p->key)
goto no_block;
- /*
- * switch below is merely an unrolled loop - body should be
- * repeated depth-1 times. Maybe loop would be actually better,
- * but that way we get straight execution path in normal cases.
- * Easy to change, anyway - all cases in switch are literally
- * identical.
- */
- switch (depth) {
- case 4:
- bh = bread(dev, le32_to_cpu(p->key), size);
- if (!bh)
- goto failure;
- /* Reader: pointers */
- if (!verify_chain(chain, p))
- goto changed;
- add_chain(++p, bh, (u32*)bh->b_data + *++offsets);
- /* Reader: end */
- if (!p->key)
- goto no_block;
- case 3:
- bh = bread(dev, le32_to_cpu(p->key), size);
- if (!bh)
- goto failure;
- /* Reader: pointers */
- if (!verify_chain(chain, p))
- goto changed;
- add_chain(++p, bh, (u32*)bh->b_data + *++offsets);
- /* Reader: end */
- if (!p->key)
- goto no_block;
- case 2:
- bh = bread(dev, le32_to_cpu(p->key), size);
- if (!bh)
- goto failure;
- /* Reader: pointers */
- if (!verify_chain(chain, p))
- goto changed;
- add_chain(++p, bh, (u32*)bh->b_data + *++offsets);
- /* Reader: end */
- if (!p->key)
- goto no_block;
+ while (--depth) {
+ bh = bread(dev, le32_to_cpu(p->key), size);
+ if (!bh)
+ goto failure;
+ /* Reader: pointers */
+ if (!verify_chain(chain, p))
+ goto changed;
+ add_chain(++p, bh, (u32*)bh->b_data + *++offsets);
+ /* Reader: end */
+ if (!p->key)
+ goto no_block;
}
return NULL;
@@ -433,7 +404,7 @@ static int ext2_alloc_branch(struct inode *inode,
branch[n].p = (u32*) bh->b_data + offsets[n];
*branch[n].p = branch[n].key;
mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -498,7 +469,7 @@ static inline int ext2_splice_branch(struct inode *inode,
/* had we spliced it onto indirect block? */
if (where->bh) {
- mark_buffer_dirty(where->bh, 1);
+ mark_buffer_dirty(where->bh);
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
ll_rw_block (WRITE, 1, &where->bh);
wait_on_buffer(where->bh);
@@ -620,7 +591,7 @@ struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, i
wait_on_buffer(bh);
memset(bh->b_data, 0, inode->i_sb->s_blocksize);
mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
}
return bh;
}
@@ -704,6 +675,289 @@ struct address_space_operations ext2_aops = {
bmap: ext2_bmap
};
+/*
+ * Probably it should be a library function... search for first non-zero word
+ * or memcmp with zero_page, whatever is better for particular architecture.
+ * Linus?
+ */
+static inline int all_zeroes(u32 *p, u32 *q)
+{
+ while (p < q)
+ if (*p++)
+ return 0;
+ return 1;
+}
+
+/**
+ * ext2_find_shared - find the indirect blocks for partial truncation.
+ * @inode: inode in question
+ * @depth: depth of the affected branch
+ * @offsets: offsets of pointers in that branch (see ext2_block_to_path)
+ * @chain: place to store the pointers to partial indirect blocks
+ * @top: place to the (detached) top of branch
+ *
+ * This is a helper function used by ext2_truncate().
+ *
+ * When we do truncate() we may have to clean the ends of several indirect
+ * blocks but leave the blocks themselves alive. Block is partially
+ * truncated if some data below the new i_size is refered from it (and
+ * it is on the path to the first completely truncated data block, indeed).
+ * We have to free the top of that path along with everything to the right
+ * of the path. Since no allocation past the truncation point is possible
+ * until ext2_truncate() finishes, we may safely do the latter, but top
+ * of branch may require special attention - pageout below the truncation
+ * point might try to populate it.
+ *
+ * We atomically detach the top of branch from the tree, store the block
+ * number of its root in *@top, pointers to buffer_heads of partially
+ * truncated blocks - in @chain[].bh and pointers to their last elements
+ * that should not be removed - in @chain[].p. Return value is the pointer
+ * to last filled element of @chain.
+ *
+ * The work left to caller to do the actual freeing of subtrees:
+ * a) free the subtree starting from *@top
+ * b) free the subtrees whose roots are stored in
+ * (@chain[i].p+1 .. end of @chain[i].bh->b_data)
+ * c) free the subtrees growing from the inode past the @chain[0].p
+ * (no partially truncated stuff there).
+ */
+
+static Indirect *ext2_find_shared(struct inode *inode,
+ int depth,
+ int offsets[4],
+ Indirect chain[4],
+ u32 *top)
+{
+ Indirect *partial, *p;
+ int k, err;
+
+ *top = 0;
+ for (k = depth; k > 1 && !offsets[k-1]; k--)
+ ;
+ partial = ext2_get_branch(inode, k, offsets, chain, &err);
+ /* Writer: pointers */
+ if (!partial)
+ partial = chain + k-1;
+ /*
+ * If the branch acquired continuation since we've looked at it -
+ * fine, it should all survive and (new) top doesn't belong to us.
+ */
+ if (!partial->key && *partial->p)
+ /* Writer: end */
+ goto no_top;
+ for (p=partial; p>chain && all_zeroes((u32*)p->bh->b_data,p->p); p--)
+ ;
+ /*
+ * OK, we've found the last block that must survive. The rest of our
+ * branch should be detached before unlocking. However, if that rest
+ * of branch is all ours and does not grow immediately from the inode
+ * it's easier to cheat and just decrement partial->p.
+ */
+ if (p == chain + k - 1 && p > chain) {
+ p->p--;
+ } else {
+ *top = *p->p;
+ *p->p = 0;
+ }
+ /* Writer: end */
+
+ while(partial > p)
+ {
+ brelse(partial->bh);
+ partial--;
+ }
+no_top:
+ return partial;
+}
+
+/**
+ * ext2_free_data - free a list of data blocks
+ * @inode: inode we are dealing with
+ * @p: array of block numbers
+ * @q: points immediately past the end of array
+ *
+ * We are freeing all blocks refered from that array (numbers are
+ * stored as little-endian 32-bit) and updating @inode->i_blocks
+ * appropriately.
+ */
+static inline void ext2_free_data(struct inode *inode, u32 *p, u32 *q)
+{
+ int blocks = inode->i_sb->s_blocksize / 512;
+ unsigned long block_to_free = 0, count = 0;
+ unsigned long nr;
+
+ for ( ; p < q ; p++) {
+ nr = le32_to_cpu(*p);
+ if (nr) {
+ *p = 0;
+ /* accumulate blocks to free if they're contiguous */
+ if (count == 0)
+ goto free_this;
+ else if (block_to_free == nr - count)
+ count++;
+ else {
+ /* Writer: ->i_blocks */
+ inode->i_blocks -= blocks * count;
+ /* Writer: end */
+ ext2_free_blocks (inode, block_to_free, count);
+ mark_inode_dirty(inode);
+ free_this:
+ block_to_free = nr;
+ count = 1;
+ }
+ }
+ }
+ if (count > 0) {
+ /* Writer: ->i_blocks */
+ inode->i_blocks -= blocks * count;
+ /* Writer: end */
+ ext2_free_blocks (inode, block_to_free, count);
+ mark_inode_dirty(inode);
+ }
+}
+
+/**
+ * ext2_free_branches - free an array of branches
+ * @inode: inode we are dealing with
+ * @p: array of block numbers
+ * @q: pointer immediately past the end of array
+ * @depth: depth of the branches to free
+ *
+ * We are freeing all blocks refered from these branches (numbers are
+ * stored as little-endian 32-bit) and updating @inode->i_blocks
+ * appropriately.
+ */
+static void ext2_free_branches(struct inode *inode, u32 *p, u32 *q, int depth)
+{
+ struct buffer_head * bh;
+ unsigned long nr;
+
+ if (depth--) {
+ int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+ for ( ; p < q ; p++) {
+ nr = le32_to_cpu(*p);
+ if (!nr)
+ continue;
+ *p = 0;
+ bh = bread (inode->i_dev, nr, inode->i_sb->s_blocksize);
+ /*
+ * A read failure? Report error and clear slot
+ * (should be rare).
+ */
+ if (!bh) {
+ ext2_error(inode->i_sb, "ext2_free_branches",
+ "Read failure, inode=%ld, block=%ld",
+ inode->i_ino, nr);
+ continue;
+ }
+ ext2_free_branches(inode,
+ (u32*)bh->b_data,
+ (u32*)bh->b_data + addr_per_block,
+ depth);
+ bforget(bh);
+ /* Writer: ->i_blocks */
+ inode->i_blocks -= inode->i_sb->s_blocksize / 512;
+ /* Writer: end */
+ ext2_free_blocks(inode, nr, 1);
+ mark_inode_dirty(inode);
+ }
+ } else
+ ext2_free_data(inode, p, q);
+}
+
+void ext2_truncate (struct inode * inode)
+{
+ u32 *i_data = inode->u.ext2_i.i_data;
+ int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+ int offsets[4];
+ Indirect chain[4];
+ Indirect *partial;
+ int nr = 0;
+ int n;
+ long iblock;
+ unsigned blocksize;
+
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ return;
+
+ ext2_discard_prealloc(inode);
+
+ blocksize = inode->i_sb->s_blocksize;
+ iblock = (inode->i_size + blocksize-1)
+ >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
+
+ block_truncate_page(inode->i_mapping, inode->i_size, ext2_get_block);
+
+ n = ext2_block_to_path(inode, iblock, offsets);
+ if (n == 0)
+ return;
+
+ if (n == 1) {
+ ext2_free_data(inode, i_data+offsets[0],
+ i_data + EXT2_NDIR_BLOCKS);
+ goto do_indirects;
+ }
+
+ partial = ext2_find_shared(inode, n, offsets, chain, &nr);
+ /* Kill the top of shared branch (already detached) */
+ if (nr) {
+ if (partial == chain)
+ mark_inode_dirty(inode);
+ else
+ mark_buffer_dirty(partial->bh);
+ ext2_free_branches(inode, &nr, &nr+1, (chain+n-1) - partial);
+ }
+ /* Clear the ends of indirect blocks on the shared branch */
+ while (partial > chain) {
+ ext2_free_branches(inode,
+ partial->p + 1,
+ (u32*)partial->bh->b_data + addr_per_block,
+ (chain+n-1) - partial);
+ mark_buffer_dirty(partial->bh);
+ if (IS_SYNC(inode)) {
+ ll_rw_block (WRITE, 1, &partial->bh);
+ wait_on_buffer (partial->bh);
+ }
+ brelse (partial->bh);
+ partial--;
+ }
+do_indirects:
+ /* Kill the remaining (whole) subtrees */
+ switch (offsets[0]) {
+ default:
+ nr = i_data[EXT2_IND_BLOCK];
+ if (nr) {
+ i_data[EXT2_IND_BLOCK] = 0;
+ mark_inode_dirty(inode);
+ ext2_free_branches(inode, &nr, &nr+1, 1);
+ }
+ case EXT2_IND_BLOCK:
+ nr = i_data[EXT2_DIND_BLOCK];
+ if (nr) {
+ i_data[EXT2_DIND_BLOCK] = 0;
+ mark_inode_dirty(inode);
+ ext2_free_branches(inode, &nr, &nr+1, 2);
+ }
+ case EXT2_DIND_BLOCK:
+ nr = i_data[EXT2_TIND_BLOCK];
+ if (nr) {
+ i_data[EXT2_TIND_BLOCK] = 0;
+ mark_inode_dirty(inode);
+ ext2_free_branches(inode, &nr, &nr+1, 3);
+ }
+ case EXT2_TIND_BLOCK:
+ ;
+ }
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ if (IS_SYNC(inode))
+ ext2_sync_inode (inode);
+ else
+ mark_inode_dirty(inode);
+}
+
void ext2_read_inode (struct inode * inode)
{
struct buffer_head * bh;
@@ -781,30 +1035,22 @@ void ext2_read_inode (struct inode * inode)
inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
inode->i_version = ++event;
- inode->u.ext2_i.i_new_inode = 0;
inode->u.ext2_i.i_flags = le32_to_cpu(raw_inode->i_flags);
inode->u.ext2_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);
inode->u.ext2_i.i_frag_no = raw_inode->i_frag;
inode->u.ext2_i.i_frag_size = raw_inode->i_fsize;
- inode->u.ext2_i.i_osync = 0;
inode->u.ext2_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
if (S_ISDIR(inode->i_mode))
inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
else {
- inode->u.ext2_i.i_dir_acl = 0;
inode->u.ext2_i.i_high_size = le32_to_cpu(raw_inode->i_size_high);
inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
}
inode->i_generation = le32_to_cpu(raw_inode->i_generation);
inode->u.ext2_i.i_block_group = block_group;
- inode->u.ext2_i.i_next_alloc_block = 0;
- inode->u.ext2_i.i_next_alloc_goal = 0;
- if (inode->u.ext2_i.i_prealloc_count)
- ext2_error (inode->i_sb, "ext2_read_inode",
- "New inode has non-zero prealloc count!");
/*
- * NOTE! The in-memory inode i_blocks array is in little-endian order
+ * NOTE! The in-memory inode i_data array is in little-endian order
* even on big-endian machines: we do NOT byteswap the block numbers!
*/
for (block = 0; block < EXT2_N_BLOCKS; block++)
@@ -940,15 +1186,29 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl);
if (S_ISDIR(inode->i_mode))
raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl);
- else
+ else {
raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
-
+ if (raw_inode->i_size_high) {
+ struct super_block *sb = inode->i_sb;
+ struct ext2_super_block *es = sb->u.ext2_sb.s_es;
+ if (!(es->s_feature_ro_compat & cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) {
+ /* If this is the first large file
+ * created, add a flag to the superblock.
+ */
+ lock_kernel();
+ es->s_feature_ro_compat |= cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
+ unlock_kernel();
+ ext2_write_super(sb);
+ }
+ }
+ }
+
raw_inode->i_generation = cpu_to_le32(inode->i_generation);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
else for (block = 0; block < EXT2_N_BLOCKS; block++)
raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (do_sync) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -966,7 +1226,7 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
void ext2_write_inode (struct inode * inode, int wait)
{
lock_kernel();
- ext2_update_inode (inode, 0);
+ ext2_update_inode (inode, wait);
unlock_kernel();
}
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 6528f1f74..6413da21b 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -8,6 +8,7 @@
*/
#include <linux/fs.h>
+#include <linux/ext2_fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 46e273935..e4234cb45 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -19,6 +19,7 @@
*/
#include <linux/fs.h>
+#include <linux/ext2_fs.h>
#include <linux/locks.h>
#include <linux/quotaops.h>
@@ -298,7 +299,7 @@ int ext2_add_entry (struct inode * dir, const char * name, int namelen,
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -339,7 +340,7 @@ static int ext2_delete_entry (struct inode * dir,
else
de->inode = 0;
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -366,12 +367,9 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
struct inode * inode;
int err;
- /*
- * N.B. Several error exits in ext2_new_inode don't set err.
- */
inode = ext2_new_inode (dir, mode, &err);
if (!inode)
- return -EIO;
+ return err;
inode->i_op = &ext2_file_inode_operations;
inode->i_fop = &ext2_file_operations;
@@ -397,7 +395,7 @@ static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int
inode = ext2_new_inode (dir, mode, &err);
if (!inode)
- return -EIO;
+ return err;
inode->i_uid = current->fsuid;
init_special_inode(inode, mode, rdev);
@@ -428,7 +426,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode = ext2_new_inode (dir, S_IFDIR, &err);
if (!inode)
- return -EIO;
+ return err;
inode->i_op = &ext2_dir_inode_operations;
inode->i_fop = &ext2_dir_operations;
@@ -454,7 +452,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
strcpy (de->name, "..");
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
inode->i_nlink = 2;
- mark_buffer_dirty(dir_block, 1);
+ mark_buffer_dirty(dir_block);
brelse (dir_block);
inode->i_mode = S_IFDIR | mode;
if (dir->i_mode & S_ISGID)
@@ -634,7 +632,7 @@ static int ext2_symlink (struct inode * dir, struct dentry *dentry, const char *
return -ENAMETOOLONG;
if (!(inode = ext2_new_inode (dir, S_IFLNK, &err)))
- return -EIO;
+ return err;
inode->i_mode = S_IFLNK | S_IRWXUGO;
@@ -760,7 +758,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
EXT2_FEATURE_INCOMPAT_FILETYPE))
new_de->file_type = old_de->file_type;
new_dir->i_version = ++event;
- mark_buffer_dirty(new_bh, 1);
+ mark_buffer_dirty(new_bh);
if (IS_SYNC(new_dir)) {
ll_rw_block (WRITE, 1, &new_bh);
wait_on_buffer (new_bh);
@@ -791,7 +789,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
mark_inode_dirty(old_dir);
if (dir_bh) {
PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
- mark_buffer_dirty(dir_bh, 1);
+ mark_buffer_dirty(dir_bh);
old_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index bca514ee5..4d2dfedbf 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
+#include <linux/ext2_fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/locks.h>
@@ -38,7 +39,7 @@ void ext2_error (struct super_block * sb, const char * function,
sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS;
sb->u.ext2_sb.s_es->s_state =
cpu_to_le16(le16_to_cpu(sb->u.ext2_sb.s_es->s_state) | EXT2_ERROR_FS);
- mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
sb->s_dirt = 1;
}
va_start (args, fmt);
@@ -68,7 +69,7 @@ NORET_TYPE void ext2_panic (struct super_block * sb, const char * function,
sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS;
sb->u.ext2_sb.s_es->s_state =
cpu_to_le16(le16_to_cpu(sb->u.ext2_sb.s_es->s_state) | EXT2_ERROR_FS);
- mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
sb->s_dirt = 1;
}
va_start (args, fmt);
@@ -101,7 +102,7 @@ void ext2_put_super (struct super_block * sb)
if (!(sb->s_flags & MS_RDONLY)) {
sb->u.ext2_sb.s_es->s_state = le16_to_cpu(sb->u.ext2_sb.s_mount_state);
- mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
}
db_count = sb->u.ext2_sb.s_db_per_group;
for (i = 0; i < db_count; i++)
@@ -167,7 +168,7 @@ static int parse_options (char * options, unsigned long * sb_block,
else if (!strcmp (this_char, "errors")) {
if (!value || !*value) {
printk ("EXT2-fs: the errors option requires "
- "an argument");
+ "an argument\n");
return 0;
}
if (!strcmp (value, "continue")) {
@@ -286,7 +287,7 @@ static int ext2_setup_super (struct super_block * sb,
es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
es->s_mtime = cpu_to_le32(CURRENT_TIME);
- mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
sb->s_dirt = 1;
if (test_opt (sb, DEBUG))
printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, "
@@ -612,7 +613,7 @@ static void ext2_commit_super (struct super_block * sb,
struct ext2_super_block * es)
{
es->s_wtime = cpu_to_le32(CURRENT_TIME);
- mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
sb->s_dirt = 0;
}
@@ -677,7 +678,7 @@ int ext2_remount (struct super_block * sb, int * flags, char * data)
*/
es->s_state = cpu_to_le16(sb->u.ext2_sb.s_mount_state);
es->s_mtime = cpu_to_le32(CURRENT_TIME);
- mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
sb->s_dirt = 1;
ext2_commit_super (sb, es);
}
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index d992efbe7..05a4e585a 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -18,6 +18,7 @@
*/
#include <linux/fs.h>
+#include <linux/ext2_fs.h>
static int ext2_readlink(struct dentry *dentry, char *buffer, int buflen)
{
diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c
deleted file mode 100644
index ba8397196..000000000
--- a/fs/ext2/truncate.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * linux/fs/ext2/truncate.c
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- * from
- *
- * linux/fs/minix/truncate.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * Big-endian to little-endian byte-swapping/bitmaps by
- * David S. Miller (davem@caip.rutgers.edu), 1995
- *
- * General cleanup and race fixes, wsh, 1998
- */
-
-#include <linux/fs.h>
-#include <linux/locks.h>
-
-
-/*
- * Real random numbers for secure rm added 94/02/18
- * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
- */
-
-#if 0
-
-/*
- * Secure deletion currently doesn't work. It interacts very badly
- * with buffers shared with memory mappings, and for that reason
- * can't be done in the truncate() routines. It should instead be
- * done separately in "release()" before calling the truncate routines
- * that will release the actual file blocks.
- *
- * Linus
- */
-static int ext2_secrm_seed = 152; /* Random generator base */
-
-#define RANDOM_INT (ext2_secrm_seed = ext2_secrm_seed * 69069l +1)
-#endif
-
-/*
- * Macros to return the block number for the inode size and offset.
- * Currently we always hold the inode semaphore during truncate, so
- * there's no need to test for changes during the operation.
- */
-#define DIRECT_BLOCK(inode) \
- ((unsigned long) ((inode->i_size + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits))
-#define INDIRECT_BLOCK(inode,offset) ((int)DIRECT_BLOCK(inode) - offset)
-#define DINDIRECT_BLOCK(inode,offset) \
- (INDIRECT_BLOCK(inode,offset) / addr_per_block)
-#define TINDIRECT_BLOCK(inode,offset) \
- (INDIRECT_BLOCK(inode,offset) / (addr_per_block*addr_per_block))
-
-/*
- * Truncate has the most races in the whole filesystem: coding it is
- * a pain in the a**. Especially as I don't do any locking...
- *
- * The code may look a bit weird, but that's just because I've tried to
- * handle things like file-size changes in a somewhat graceful manner.
- * Anyway, truncating a file at the same time somebody else writes to it
- * is likely to result in pretty weird behaviour...
- *
- * The new code handles normal truncates (size = 0) as well as the more
- * general case (size = XXX). I hope.
- *
- *
- * Truncate operations have been rewritten to avoid various races. The
- * previous code was allowing blocking operations to precede a call to
- * bforget(), possible allowing the buffer to be used again.
- *
- * We now ensure that b_count == 1 before calling bforget() and that the
- * parent buffer (if any) is unlocked before clearing the block pointer.
- * The operations are always performed in this order:
- * (1) Make sure that the parent buffer is unlocked.
- * (2) Use find_buffer() to find the block buffer without blocking,
- * and set 'retry' if the buffer is locked or b_count > 1.
- * (3) Clear the block pointer in the parent (buffer or inode).
- * (4) Update the inode block count and mark the inode dirty.
- * (5) Forget the block buffer, if any. This call won't block, as
- * we know the buffer is unlocked from (2).
- * (6) If the block pointer is in a (parent) buffer, mark the buffer
- * dirty. (Note that this can block on a loop device.)
- * (7) Accumulate the blocks to free and/or update the block bitmap.
- * (This operation will frequently block.)
- *
- * The requirement that parent buffers be unlocked follows from the general
- * principle of not modifying a buffer that may be undergoing I/O. With the
- * the present kernels there's no problem with modifying a locked inode, as
- * the I_DIRTY bit is cleared before setting I_LOCK.
- * -- WSH, 1998
- */
-
-/*
- * Check whether any of the slots in an indirect block are
- * still in use, and if not free the block.
- */
-static int check_block_empty(struct inode *inode, struct buffer_head *bh,
- u32 *p, struct buffer_head *ind_bh)
-{
- int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- u32 * ind = (u32 *) bh->b_data;
- int i, retry;
-
- /* Make sure both buffers are unlocked */
- do {
- retry = 0;
- if (buffer_locked(bh)) {
- __wait_on_buffer(bh);
- retry = 1;
- }
- if (ind_bh && buffer_locked(ind_bh)) {
- __wait_on_buffer(ind_bh);
- retry = 1;
- }
- } while (retry);
-
- for (i = 0; i < addr_per_block; i++)
- if (*(ind++))
- goto in_use;
-
- if (atomic_read(&bh->b_count) == 1) {
- int tmp;
- tmp = le32_to_cpu(*p);
- *p = 0;
- inode->i_blocks -= (inode->i_sb->s_blocksize / 512);
- mark_inode_dirty(inode);
- /*
- * Forget the buffer, then mark the parent buffer dirty.
- */
- bforget(bh);
- if (ind_bh)
- mark_buffer_dirty(ind_bh, 1);
- ext2_free_blocks(inode, tmp, 1);
- goto out;
- }
- retry = 1;
-
-in_use:
- if (IS_SYNC(inode) && buffer_dirty(bh)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
- brelse (bh);
-
-out:
- return retry;
-}
-
-#define DATA_BUFFER_USED(bh) \
- (atomic_read(&bh->b_count) || buffer_locked(bh))
-
-static int trunc_direct (struct inode * inode)
-{
- int i, retry = 0;
- unsigned long block_to_free = 0, free_count = 0;
- int blocks = inode->i_sb->s_blocksize / 512;
- int direct_block = DIRECT_BLOCK(inode);
-
- for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) {
- u32 * p = inode->u.ext2_i.i_data + i;
- int tmp = le32_to_cpu(*p);
-
- if (!tmp)
- continue;
-
- *p = 0;
- inode->i_blocks -= blocks;
- mark_inode_dirty(inode);
-
- /* accumulate blocks to free if they're contiguous */
- if (free_count == 0)
- goto free_this;
- else if (block_to_free == tmp - free_count)
- free_count++;
- else {
- ext2_free_blocks (inode, block_to_free, free_count);
- free_this:
- block_to_free = tmp;
- free_count = 1;
- }
- }
- if (free_count > 0)
- ext2_free_blocks (inode, block_to_free, free_count);
- return retry;
-}
-
-static int trunc_indirect (struct inode * inode, int offset, u32 * p, struct buffer_head *dind_bh)
-{
- struct buffer_head * ind_bh;
- int i, tmp, retry = 0;
- unsigned long block_to_free = 0, free_count = 0;
- int indirect_block, addr_per_block, blocks;
-
- tmp = le32_to_cpu(*p);
- if (!tmp)
- return 0;
- ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
- if (tmp != le32_to_cpu(*p)) {
- brelse (ind_bh);
- return 1;
- }
- /* A read failure? Report error and clear slot (should be rare). */
- if (!ind_bh) {
- ext2_error(inode->i_sb, "trunc_indirect",
- "Read failure, inode=%ld, block=%d",
- inode->i_ino, tmp);
- *p = 0;
- if (dind_bh)
- mark_buffer_dirty(dind_bh, 1);
- else
- mark_inode_dirty(inode);
- return 0;
- }
-
- blocks = inode->i_sb->s_blocksize / 512;
- addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- indirect_block = INDIRECT_BLOCK(inode, offset);
- if (indirect_block < 0)
- indirect_block = 0;
- for (i = indirect_block ; i < addr_per_block ; i++) {
- u32 * ind = i + (u32 *) ind_bh->b_data;
-
- wait_on_buffer(ind_bh);
- tmp = le32_to_cpu(*ind);
- if (!tmp)
- continue;
-
- *ind = 0;
- inode->i_blocks -= blocks;
- mark_inode_dirty(inode);
- mark_buffer_dirty(ind_bh, 1);
-
- /* accumulate blocks to free if they're contiguous */
- if (free_count == 0)
- goto free_this;
- else if (block_to_free == tmp - free_count)
- free_count++;
- else {
- ext2_free_blocks (inode, block_to_free, free_count);
- free_this:
- block_to_free = tmp;
- free_count = 1;
- }
- }
- if (free_count > 0)
- ext2_free_blocks (inode, block_to_free, free_count);
- /*
- * Check the block and dispose of the ind_bh buffer.
- */
- retry |= check_block_empty(inode, ind_bh, p, dind_bh);
-
- return retry;
-}
-
-static int trunc_dindirect (struct inode * inode, int offset, u32 * p,
- struct buffer_head * tind_bh)
-{
- struct buffer_head * dind_bh;
- int i, tmp, retry = 0;
- int dindirect_block, addr_per_block;
-
- tmp = le32_to_cpu(*p);
- if (!tmp)
- return 0;
- dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
- if (tmp != le32_to_cpu(*p)) {
- brelse (dind_bh);
- return 1;
- }
- /* A read failure? Report error and clear slot (should be rare). */
- if (!dind_bh) {
- ext2_error(inode->i_sb, "trunc_dindirect",
- "Read failure, inode=%ld, block=%d",
- inode->i_ino, tmp);
- *p = 0;
- if (tind_bh)
- mark_buffer_dirty(tind_bh, 1);
- else
- mark_inode_dirty(inode);
- return 0;
- }
-
- addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- dindirect_block = DINDIRECT_BLOCK(inode, offset);
- if (dindirect_block < 0)
- dindirect_block = 0;
- for (i = dindirect_block ; i < addr_per_block ; i++) {
- u32 * dind = i + (u32 *) dind_bh->b_data;
-
- retry |= trunc_indirect(inode,
- offset + (i * addr_per_block),
- dind, dind_bh);
- }
- /*
- * Check the block and dispose of the dind_bh buffer.
- */
- retry |= check_block_empty(inode, dind_bh, p, tind_bh);
-
- return retry;
-}
-
-static int trunc_tindirect (struct inode * inode)
-{
- u32 * p = inode->u.ext2_i.i_data + EXT2_TIND_BLOCK;
- struct buffer_head * tind_bh;
- int i, tmp, retry = 0;
- int tindirect_block, addr_per_block, offset;
-
- tmp = le32_to_cpu(*p);
- if (!tmp)
- return 0;
- tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
- if (tmp != le32_to_cpu(*p)) {
- brelse (tind_bh);
- return 1;
- }
- /* A read failure? Report error and clear slot (should be rare). */
- if (!tind_bh) {
- ext2_error(inode->i_sb, "trunc_tindirect",
- "Read failure, inode=%ld, block=%d",
- inode->i_ino, tmp);
- *p = 0;
- mark_inode_dirty(inode);
- return 0;
- }
-
- addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- offset = EXT2_NDIR_BLOCKS + addr_per_block +
- (addr_per_block * addr_per_block);
- tindirect_block = TINDIRECT_BLOCK(inode, offset);
- if (tindirect_block < 0)
- tindirect_block = 0;
- for (i = tindirect_block ; i < addr_per_block ; i++) {
- u32 * tind = i + (u32 *) tind_bh->b_data;
-
- retry |= trunc_dindirect(inode,
- offset + (i * addr_per_block * addr_per_block),
- tind, tind_bh);
- }
- /*
- * Check the block and dispose of the tind_bh buffer.
- */
- retry |= check_block_empty(inode, tind_bh, p, NULL);
-
- return retry;
-}
-
-void ext2_truncate (struct inode * inode)
-{
- if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)))
- return;
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- return;
- ext2_discard_prealloc(inode);
- while (1) {
- int retry = trunc_direct(inode);
- retry |= trunc_indirect (inode,
- EXT2_IND_BLOCK,
- (u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK],
- NULL);
- retry |= trunc_dindirect (inode,
- EXT2_IND_BLOCK+EXT2_ADDR_PER_BLOCK(inode->i_sb),
- (u32 *)&inode->u.ext2_i.i_data[EXT2_DIND_BLOCK],
- NULL);
- retry |= trunc_tindirect (inode);
- if (!retry)
- break;
- if (IS_SYNC(inode) && (inode->i_state & I_DIRTY))
- ext2_sync_inode (inode);
- run_task_queue(&tq_disk);
- current->policy |= SCHED_YIELD;
- schedule();
- }
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(inode);
-}
diff --git a/fs/fat/buffer.c b/fs/fat/buffer.c
index 7ab13267d..6e8716b1e 100644
--- a/fs/fat/buffer.c
+++ b/fs/fat/buffer.c
@@ -32,10 +32,9 @@ void fat_brelse (struct super_block *sb, struct buffer_head *bh)
}
void fat_mark_buffer_dirty (
struct super_block *sb,
- struct buffer_head *bh,
- int dirty)
+ struct buffer_head *bh)
{
- MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty);
+ MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh);
}
void fat_set_uptodate (
struct super_block *sb,
@@ -71,10 +70,9 @@ void default_fat_brelse(struct super_block *sb, struct buffer_head *bh)
}
void default_fat_mark_buffer_dirty (
struct super_block *sb,
- struct buffer_head *bh,
- int dirty)
+ struct buffer_head *bh)
{
- mark_buffer_dirty (bh,dirty);
+ mark_buffer_dirty (bh);
}
void default_fat_set_uptodate (
struct super_block *sb,
@@ -170,10 +168,9 @@ void bigblock_fat_brelse (
void bigblock_fat_mark_buffer_dirty (
struct super_block *sb,
- struct buffer_head *bh,
- int dirty)
+ struct buffer_head *bh)
{
- mark_buffer_dirty (bh->b_next,dirty);
+ mark_buffer_dirty (bh->b_next);
}
void bigblock_fat_set_uptodate (
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index cabb08f76..fd3746920 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -106,16 +106,16 @@ int default_fat_access(struct super_block *sb,int nr,int new_value)
*p_first = new_value & 0xff;
*p_last = (*p_last & 0xf0) | (new_value >> 8);
}
- fat_mark_buffer_dirty(sb, bh2, 1);
+ fat_mark_buffer_dirty(sb, bh2);
}
- fat_mark_buffer_dirty(sb, bh, 1);
+ fat_mark_buffer_dirty(sb, bh);
for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) {
b = MSDOS_SB(sb)->fat_start + (first >> SECTOR_BITS) +
MSDOS_SB(sb)->fat_length * copy;
if (!(c_bh = fat_bread(sb, b)))
break;
memcpy(c_bh->b_data,bh->b_data,SECTOR_SIZE);
- fat_mark_buffer_dirty(sb, c_bh, 1);
+ fat_mark_buffer_dirty(sb, c_bh);
if (bh != bh2) {
if (!(c_bh2 = fat_bread(sb, b+1))) {
fat_brelse(sb, c_bh);
diff --git a/fs/fat/cvf.c b/fs/fat/cvf.c
index 24cf1164f..5bfbaeb64 100644
--- a/fs/fat/cvf.c
+++ b/fs/fat/cvf.c
@@ -27,9 +27,9 @@ struct buffer_head *bigblock_fat_bread(struct super_block *, int);
void default_fat_brelse(struct super_block *, struct buffer_head *);
void bigblock_fat_brelse(struct super_block *, struct buffer_head *);
void default_fat_mark_buffer_dirty (struct super_block *,
- struct buffer_head *, int);
+ struct buffer_head *);
void bigblock_fat_mark_buffer_dirty (struct super_block *,
- struct buffer_head *, int);
+ struct buffer_head *);
void default_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
void bigblock_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
int default_fat_is_uptodate(struct super_block *, struct buffer_head *);
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 5f7a643d7..272baa936 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -679,7 +679,7 @@ int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);
de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);
de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);
- fat_mark_buffer_dirty(sb, bh, 1);
+ fat_mark_buffer_dirty(sb, bh);
fat_brelse(sb, bh);
dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 11ac092cb..d1e8557f7 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -898,7 +898,7 @@ retry:
raw_entry->cdate = CT_LE_W(raw_entry->cdate);
}
spin_unlock(&fat_inode_lock);
- fat_mark_buffer_dirty(sb, bh, 1);
+ fat_mark_buffer_dirty(sb, bh);
fat_brelse(sb, bh);
unlock_kernel();
}
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index bca75467b..2213a41fe 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -129,7 +129,7 @@ void fat_clusters_flush(struct super_block *sb)
return;
}
fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
- fat_mark_buffer_dirty(sb, bh, 1);
+ fat_mark_buffer_dirty(sb, bh);
fat_brelse(sb, bh);
}
@@ -291,7 +291,7 @@ if (last) printk("next set to %d\n",fat_access(sb,last,-1));
else {
memset(bh->b_data,0,SECTOR_SIZE);
fat_set_uptodate(sb, bh, 1);
- fat_mark_buffer_dirty(sb, bh, 1);
+ fat_mark_buffer_dirty(sb, bh);
if (!res)
res=bh;
else
diff --git a/fs/fat/msbuffer.h b/fs/fat/msbuffer.h
index 5a052251d..563ee0df2 100644
--- a/fs/fat/msbuffer.h
+++ b/fs/fat/msbuffer.h
@@ -5,8 +5,7 @@ struct buffer_head *fat_bread (struct super_block *sb, int block);
struct buffer_head *fat_getblk (struct super_block *sb, int block);
void fat_brelse (struct super_block *sb, struct buffer_head *bh);
void fat_mark_buffer_dirty (struct super_block *sb,
- struct buffer_head *bh,
- int dirty_val);
+ struct buffer_head *bh);
void fat_set_uptodate (struct super_block *sb,
struct buffer_head *bh,
int val);
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 7a3bcefb8..d075c5c4e 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -4,8 +4,10 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#include <linux/init.h>
#include <linux/mm.h>
#include <linux/file.h>
+#include <linux/dnotify.h>
#include <linux/smp_lock.h>
#include <linux/slab.h>
@@ -14,6 +16,8 @@
#include <asm/uaccess.h>
extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
+extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
+extern int fcntl_getlease(struct file *filp);
/* Expand files. Return <0 on error; 0 nothing done; 1 files expanded,
* we may have blocked.
@@ -195,6 +199,7 @@ asmlinkage long sys_dup(unsigned int fildes)
static int setfl(int fd, struct file * filp, unsigned long arg)
{
struct inode * inode = filp->f_dentry->d_inode;
+ int error;
/*
* In the case of an append-only file, O_APPEND
@@ -205,8 +210,11 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
/* Did FASYNC state change? */
if ((arg ^ filp->f_flags) & FASYNC) {
- if (filp->f_op && filp->f_op->fasync)
- filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
+ if (filp->f_op && filp->f_op->fasync) {
+ error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
+ if (error < 0)
+ return error;
+ }
}
/* required for strict SunOS emulation */
@@ -221,11 +229,10 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
static long do_fcntl(unsigned int fd, unsigned int cmd,
unsigned long arg, struct file * filp)
{
- long err = 0;
+ long err = -EINVAL;
switch (cmd) {
case F_DUPFD:
- err = -EINVAL;
if (arg < NR_OPEN) {
get_file(filp);
err = dupfd(filp, arg);
@@ -235,20 +242,21 @@ static long do_fcntl(unsigned int fd, unsigned int cmd,
err = get_close_on_exec(fd);
break;
case F_SETFD:
+ err = 0;
set_close_on_exec(fd, arg&1);
break;
case F_GETFL:
err = filp->f_flags;
break;
case F_SETFL:
+ lock_kernel();
err = setfl(fd, filp, arg);
+ unlock_kernel();
break;
case F_GETLK:
err = fcntl_getlk(fd, (struct flock *) arg);
break;
case F_SETLK:
- err = fcntl_setlk(fd, cmd, (struct flock *) arg);
- break;
case F_SETLKW:
err = fcntl_setlk(fd, cmd, (struct flock *) arg);
break;
@@ -263,11 +271,14 @@ static long do_fcntl(unsigned int fd, unsigned int cmd,
err = filp->f_owner.pid;
break;
case F_SETOWN:
+ lock_kernel();
filp->f_owner.pid = arg;
filp->f_owner.uid = current->uid;
filp->f_owner.euid = current->euid;
+ err = 0;
if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
err = sock_fcntl (filp, F_SETOWN, arg);
+ unlock_kernel();
break;
case F_GETSIG:
err = filp->f_owner.signum;
@@ -275,12 +286,20 @@ static long do_fcntl(unsigned int fd, unsigned int cmd,
case F_SETSIG:
/* arg == 0 restores default behaviour. */
if (arg < 0 || arg > _NSIG) {
- err = -EINVAL;
break;
}
err = 0;
filp->f_owner.signum = arg;
break;
+ case F_GETLEASE:
+ err = fcntl_getlease(filp);
+ break;
+ case F_SETLEASE:
+ err = fcntl_setlease(fd, filp, arg);
+ break;
+ case F_NOTIFY:
+ err = fcntl_dirnotify(fd, filp, arg);
+ break;
default:
/* sockets need a few special fcntls. */
err = -EINVAL;
@@ -301,9 +320,7 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
if (!filp)
goto out;
- lock_kernel();
err = do_fcntl(fd, cmd, arg, filp);
- unlock_kernel();
fput(filp);
out:
@@ -356,7 +373,7 @@ static long band_table[NSIGPOLL] = {
static void send_sigio_to_task(struct task_struct *p,
struct fown_struct *fown,
- struct fasync_struct *fa,
+ int fd,
int reason)
{
if ((fown->euid != 0) &&
@@ -384,7 +401,7 @@ static void send_sigio_to_task(struct task_struct *p,
si.si_band = ~0L;
else
si.si_band = band_table[reason - POLL_IN];
- si.si_fd = fa->fa_fd;
+ si.si_fd = fd;
if (!send_sig_info(fown->signum, &si, p))
break;
/* fall-through: fall back on the old plain SIGIO signal */
@@ -393,15 +410,14 @@ static void send_sigio_to_task(struct task_struct *p,
}
}
-static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa,
- int band)
+void send_sigio(struct fown_struct *fown, int fd, int band)
{
struct task_struct * p;
int pid = fown->pid;
read_lock(&tasklist_lock);
if ( (pid > 0) && (p = find_task_by_pid(pid)) ) {
- send_sigio_to_task(p, fown, fa, band);
+ send_sigio_to_task(p, fown, fd, band);
goto out;
}
for_each_task(p) {
@@ -410,18 +426,20 @@ static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa,
match = -p->pgrp;
if (pid != match)
continue;
- send_sigio_to_task(p, fown, fa, band);
+ send_sigio_to_task(p, fown, fd, band);
}
out:
read_unlock(&tasklist_lock);
}
+static rwlock_t fasync_lock = RW_LOCK_UNLOCKED;
+static kmem_cache_t *fasync_cache;
+
/*
* fasync_helper() is used by some character device drivers (mainly mice)
* to set up the fasync queue. It returns negative on error, 0 if it did
* no changes and positive if it added/deleted the entry.
*/
-static rwlock_t fasync_lock = RW_LOCK_UNLOCKED;
int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
{
struct fasync_struct *fa, **fp;
@@ -429,7 +447,7 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap
int result = 0;
if (on) {
- new = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
+ new = kmem_cache_alloc(fasync_cache, SLAB_KERNEL);
if (!new)
return -ENOMEM;
}
@@ -438,10 +456,10 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap
if (fa->fa_file == filp) {
if(on) {
fa->fa_fd = fd;
- kfree(new);
+ kmem_cache_free(fasync_cache, new);
} else {
*fp = fa->fa_next;
- kfree(fa);
+ kmem_cache_free(fasync_cache, fa);
result = 1;
}
goto out;
@@ -466,7 +484,7 @@ void __kill_fasync(struct fasync_struct *fa, int sig, int band)
while (fa) {
struct fown_struct * fown;
if (fa->magic != FASYNC_MAGIC) {
- printk("kill_fasync: bad magic number in "
+ printk(KERN_ERR "kill_fasync: bad magic number in "
"fasync_struct!\n");
return;
}
@@ -475,7 +493,7 @@ void __kill_fasync(struct fasync_struct *fa, int sig, int band)
queued signum: SIGURG has its own default signalling
mechanism. */
if (fown->pid && !(sig == SIGURG && fown->signum == 0))
- send_sigio(fown, fa, band);
+ send_sigio(fown, fa->fa_fd, band);
fa = fa->fa_next;
}
}
@@ -486,3 +504,14 @@ void kill_fasync(struct fasync_struct **fp, int sig, int band)
__kill_fasync(*fp, sig, band);
read_unlock(&fasync_lock);
}
+
+static int __init fasync_init(void)
+{
+ fasync_cache = kmem_cache_create("fasync cache",
+ sizeof(struct fasync_struct), 0, 0, NULL, NULL);
+ if (!fasync_cache)
+ panic("cannot create fasync slab cache");
+ return 0;
+}
+
+module_init(fasync_init)
diff --git a/fs/file_table.c b/fs/file_table.c
index 54538ddf0..931314661 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -98,48 +98,35 @@ int init_private_file(struct file *filp, struct dentry *dentry, int mode)
return 0;
}
-/*
- * Called when retiring the last use of a file pointer.
- */
-static void __fput(struct file *filp)
+void fput(struct file * file)
{
- struct dentry * dentry = filp->f_dentry;
- struct vfsmount * mnt = filp->f_vfsmnt;
+ struct dentry * dentry = file->f_dentry;
+ struct vfsmount * mnt = file->f_vfsmnt;
struct inode * inode = dentry->d_inode;
- if (filp->f_op && filp->f_op->release)
- filp->f_op->release(inode, filp);
- fops_put(filp->f_op);
- filp->f_dentry = NULL;
- filp->f_vfsmnt = NULL;
- if (filp->f_mode & FMODE_WRITE)
- put_write_access(inode);
- dput(dentry);
- if (mnt)
- mntput(mnt);
-}
-
-static void _fput(struct file *file)
-{
- locks_remove_flock(file);
- __fput(file);
-
- file_list_lock();
- list_del(&file->f_list);
- list_add(&file->f_list, &free_list);
- files_stat.nr_free_files++;
- file_list_unlock();
-}
-
-void fput(struct file * file)
-{
- if (atomic_dec_and_test(&file->f_count))
- _fput(file);
+ if (atomic_dec_and_test(&file->f_count)) {
+ locks_remove_flock(file);
+ if (file->f_op && file->f_op->release)
+ file->f_op->release(inode, file);
+ fops_put(file->f_op);
+ file->f_dentry = NULL;
+ file->f_vfsmnt = NULL;
+ if (file->f_mode & FMODE_WRITE)
+ put_write_access(inode);
+ dput(dentry);
+ if (mnt)
+ mntput(mnt);
+ file_list_lock();
+ list_del(&file->f_list);
+ list_add(&file->f_list, &free_list);
+ files_stat.nr_free_files++;
+ file_list_unlock();
+ }
}
struct file * fget(unsigned int fd)
{
- struct file * file = NULL;
+ struct file * file;
struct files_struct *files = current->files;
read_lock(&files->file_lock);
diff --git a/fs/filesystems.c b/fs/filesystems.c
index e57b7b3df..00da82259 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -16,16 +16,10 @@
#include <linux/major.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
-#ifdef CONFIG_KMOD
#include <linux/kmod.h>
-#endif
-#include <linux/lockd/bind.h>
-#include <linux/lockd/xdr.h>
#include <linux/init.h>
-
-#ifdef CONFIG_CODA_FS
-extern int init_coda(void);
-#endif
+#include <linux/module.h>
+#include <linux/nfsd/interface.h>
#ifdef CONFIG_DEVPTS_FS
extern int init_devpts_fs(void);
@@ -39,41 +33,33 @@ void __init filesystem_setup(void)
init_nfs_fs();
#endif
-#ifdef CONFIG_CODA_FS
- init_coda();
-#endif
-
#ifdef CONFIG_DEVPTS_FS
init_devpts_fs();
#endif
}
-#ifndef CONFIG_NFSD
-#ifdef CONFIG_NFSD_MODULE
-long (*do_nfsservctl)(int, void *, void *);
-#endif
+#if defined(CONFIG_NFSD_MODULE)
+struct nfsd_linkage *nfsd_linkage = NULL;
+
long
asmlinkage sys_nfsservctl(int cmd, void *argp, void *resp)
{
-#ifndef CONFIG_NFSD_MODULE
- return -ENOSYS;
-#else
int ret = -ENOSYS;
lock_kernel();
- if (do_nfsservctl) {
- ret = do_nfsservctl(cmd, argp, resp);
- goto out;
- }
-#ifdef CONFIG_KMOD
- if (request_module ("nfsd") == 0) {
- if (do_nfsservctl)
- ret = do_nfsservctl(cmd, argp, resp);
- }
-#endif /* CONFIG_KMOD */
-out:
+
+ if (nfsd_linkage ||
+ (request_module ("nfsd") == 0 && nfsd_linkage))
+ ret = nfsd_linkage->do_nfsservctl(cmd, argp, resp);
+
unlock_kernel();
return ret;
-#endif /* CONFIG_NFSD_MODULE */
+}
+EXPORT_SYMBOL(nfsd_linkage);
+
+#elif ! defined (CONFIG_NFSD)
+asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp)
+{
+ return -ENOSYS;
}
#endif /* CONFIG_NFSD */
diff --git a/fs/hfs/file.c b/fs/hfs/file.c
index 4d4a3e9b8..35fbac9de 100644
--- a/fs/hfs/file.c
+++ b/fs/hfs/file.c
@@ -489,7 +489,7 @@ hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos,
written += c;
buf += c;
mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh, 0);
+ mark_buffer_dirty(bh);
brelse(bh);
}
if (written > 0) {
diff --git a/fs/hpfs/anode.c b/fs/hpfs/anode.c
index 6fb9c1633..263cce238 100644
--- a/fs/hpfs/anode.c
+++ b/fs/hpfs/anode.c
@@ -84,7 +84,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
if (btree->internal) {
a = btree->u.internal[n].down;
btree->u.internal[n].file_secno = -1;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
if (s->s_hpfs_chk)
if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_add_sector_to_btree #1")) return -1;
@@ -102,7 +102,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
}
if (hpfs_alloc_if_possible(s, se = btree->u.external[n].disk_secno + btree->u.external[n].length)) {
btree->u.external[n].length++;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
return se;
}
@@ -139,7 +139,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
btree->first_free = (char *)&(btree->u.internal[1]) - (char *)btree;
btree->u.internal[0].file_secno = -1;
btree->u.internal[0].down = na;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
} else if (!(ranode = hpfs_alloc_anode(s, /*a*/0, &ra, &bh2))) {
brelse(bh);
brelse(bh1);
@@ -156,7 +156,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
btree->u.external[n].disk_secno = se;
btree->u.external[n].file_secno = fs;
btree->u.external[n].length = 1;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
if ((a == node && fnod) || na == -1) return se;
c2 = 0;
@@ -176,14 +176,14 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
btree->u.internal[n].file_secno = -1;
btree->u.internal[n].down = na;
btree->u.internal[n-1].file_secno = fs;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
brelse(bh2);
hpfs_free_sectors(s, ra, 1);
if ((anode = hpfs_map_anode(s, na, &bh))) {
anode->up = up;
anode->btree.fnode_parent = up == node && fnod;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
}
return se;
@@ -191,7 +191,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
up = up != node ? anode->up : -1;
btree->u.internal[btree->n_used_nodes - 1].file_secno = /*fs*/-1;
if (up == -1) anode->up = ra;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
a = na;
if ((anode = hpfs_alloc_anode(s, a, &na, &bh))) {
@@ -202,11 +202,11 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
anode->btree.first_free = 16;
anode->btree.u.internal[0].down = a;
anode->btree.u.internal[0].file_secno = -1;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
if ((anode = hpfs_map_anode(s, a, &bh))) {
anode->up = na;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
}
} else na = a;
@@ -214,7 +214,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
if ((anode = hpfs_map_anode(s, na, &bh))) {
anode->up = node;
if (fnod) anode->btree.fnode_parent = 1;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
}
if (!fnod) {
@@ -239,7 +239,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
if ((unode = hpfs_map_anode(s, ranode->u.internal[n].down, &bh1))) {
unode->up = ra;
unode->btree.fnode_parent = 0;
- mark_buffer_dirty(bh1, 1);
+ mark_buffer_dirty(bh1);
brelse(bh1);
}
}
@@ -251,9 +251,9 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
btree->u.internal[0].down = ra;
btree->u.internal[1].file_secno = -1;
btree->u.internal[1].down = na;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
- mark_buffer_dirty(bh2, 1);
+ mark_buffer_dirty(bh2);
brelse(bh2);
return se;
}
@@ -367,7 +367,7 @@ int hpfs_ea_write(struct super_block *s, secno a, int ano, unsigned pos,
return -1;
l = 0x200 - (pos & 0x1ff); if (l > len) l = len;
memcpy(data + (pos & 0x1ff), buf, l);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
buf += l; pos += l; len -= l;
}
@@ -411,7 +411,7 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs)
btree->n_used_nodes = 0;
btree->first_free = 8;
btree->internal = 0;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
} else hpfs_free_sectors(s, f, 1);
brelse(bh);
return;
@@ -429,7 +429,7 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs)
btree->n_used_nodes = i + 1;
btree->n_free_nodes = nodes - btree->n_used_nodes;
btree->first_free = 8 + 8 * btree->n_used_nodes;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (btree->u.internal[i].file_secno == secs) {
brelse(bh);
return;
@@ -463,7 +463,7 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs)
btree->n_used_nodes = i + 1;
btree->n_free_nodes = nodes - btree->n_used_nodes;
btree->first_free = 8 + 12 * btree->n_used_nodes;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
}
diff --git a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c
index 7ea14e4c4..43eb2cb57 100644
--- a/fs/hpfs/buffer.c
+++ b/fs/hpfs/buffer.c
@@ -261,8 +261,8 @@ void hpfs_mark_4buffers_dirty(struct quad_buffer_head *qbh)
memcpy(qbh->bh[1]->b_data, qbh->data + 512, 512);
memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512);
memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512);
- mark_buffer_dirty(qbh->bh[0],1);
- mark_buffer_dirty(qbh->bh[1],1);
- mark_buffer_dirty(qbh->bh[2],1);
- mark_buffer_dirty(qbh->bh[3],1);
+ mark_buffer_dirty(qbh->bh[0]);
+ mark_buffer_dirty(qbh->bh[1]);
+ mark_buffer_dirty(qbh->bh[2]);
+ mark_buffer_dirty(qbh->bh[3]);
}
diff --git a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c
index d1ca8e3e6..78286ad36 100644
--- a/fs/hpfs/dnode.c
+++ b/fs/hpfs/dnode.c
@@ -337,7 +337,7 @@ int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, unsigned char *name, uns
return 1;
}
fnode->u.external[0].disk_secno = rdno;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
d->up = ad->up = i->i_hpfs_dno = rdno;
d->root_dnode = ad->root_dnode = 0;
@@ -535,7 +535,7 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno)
}
if ((fnode = hpfs_map_fnode(i->i_sb, up, &bh))) {
fnode->u.external[0].disk_secno = down;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
}
i->i_hpfs_dno = down;
diff --git a/fs/hpfs/ea.c b/fs/hpfs/ea.c
index 9632c054c..6c21acfb0 100644
--- a/fs/hpfs/ea.c
+++ b/fs/hpfs/ea.c
@@ -277,7 +277,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, char *key, char *data
fnode->ea_size_s = 0;
fnode->ea_secno = n;
fnode->ea_anode = 0;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
}
pos = fnode->ea_size_l + 5 + strlen(key) + size;
@@ -307,7 +307,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, char *key, char *data
anode->u.external[0].disk_secno = fnode->ea_secno;
anode->u.external[0].file_secno = 0;
anode->u.external[0].length = len;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
fnode->ea_anode = 1;
fnode->ea_secno = a_s;*/
@@ -329,7 +329,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, char *key, char *data
}
memcpy(b2, b1, 512);
brelse(bh1);
- mark_buffer_dirty(bh2, 1);
+ mark_buffer_dirty(bh2);
brelse(bh2);
}
hpfs_free_sectors(s, fnode->ea_secno, len);
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index a9f085863..06f5d0783 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -291,7 +291,7 @@ void hpfs_write_inode_nolock(struct inode *i)
hpfs_brelse4(&qbh);
} else hpfs_error(i->i_sb, "directory %08x doesn't have '.' entry", i->i_ino);
}
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
}
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index c912126d7..3438cdb85 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -62,7 +62,7 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
de->first = de->directory = 1;
/*de->hidden = de->system = 0;*/
de->fnode = fno;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
hpfs_mark_4buffers_dirty(&qbh0);
hpfs_brelse4(&qbh0);
@@ -128,7 +128,7 @@ int hpfs_create(struct inode *dir, struct dentry *dentry, int mode)
fnode->len = len;
memcpy(fnode->name, name, len > 15 ? 15 : len);
fnode->up = dir->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
hpfs_lock_iget(dir->i_sb, 2);
if ((result = iget(dir->i_sb, fno))) {
@@ -196,7 +196,7 @@ int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
fnode->len = len;
memcpy(fnode->name, name, len > 15 ? 15 : len);
fnode->up = dir->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
hpfs_lock_iget(dir->i_sb, 2);
if ((result = iget(dir->i_sb, fno))) {
result->i_hpfs_parent_dir = dir->i_ino;
@@ -258,7 +258,7 @@ int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
fnode->len = len;
memcpy(fnode->name, name, len > 15 ? 15 : len);
fnode->up = dir->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
hpfs_lock_iget(dir->i_sb, 2);
if ((result = iget(dir->i_sb, fno))) {
@@ -276,7 +276,7 @@ int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
result->i_data.a_ops = &hpfs_symlink_aops;
if ((fnode = hpfs_map_fnode(dir->i_sb, fno, &bh))) {
hpfs_set_ea(result, fnode, "SYMLINK", (char *)symlink, strlen(symlink));
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
}
hpfs_write_inode_nolock(result);
@@ -523,7 +523,7 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
fnode->len = new_len;
memcpy(fnode->name, new_name, new_len>15?15:new_len);
if (new_len < 15) memset(&fnode->name[new_len], 0, 15 - new_len);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
}
i->i_hpfs_conv = i->i_sb->s_hpfs_conv;
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 04cd6428d..a5db0acd3 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -21,7 +21,7 @@ static void mark_dirty(struct super_block *s)
if ((sb = hpfs_map_sector(s, 17, &bh, 0))) {
sb->dirty = 1;
sb->old_wrote = 0;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
}
}
@@ -38,7 +38,7 @@ static void unmark_dirty(struct super_block *s)
if ((sb = hpfs_map_sector(s, 17, &bh, 0))) {
sb->dirty = s->s_hpfs_chkdsk > 1 - s->s_hpfs_was_error;
sb->old_wrote = s->s_hpfs_chkdsk >= 2 && !s->s_hpfs_was_error;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
}
}
@@ -466,7 +466,7 @@ struct super_block *hpfs_read_super(struct super_block *s, void *options,
if (!(s->s_flags & MS_RDONLY)) {
spareblock->dirty = 1;
spareblock->old_wrote = 0;
- mark_buffer_dirty(bh2, 1);
+ mark_buffer_dirty(bh2);
}
if (spareblock->hotfixes_used || spareblock->n_spares_used) {
diff --git a/fs/inode.c b/fs/inode.c
index 2199d6888..ba0a3546f 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -71,7 +71,7 @@ struct {
int nr_inodes;
int nr_unused;
int dummy[5];
-} inodes_stat = {0, 0,};
+} inodes_stat;
static kmem_cache_t * inode_cachep;
@@ -454,21 +454,25 @@ void prune_icache(int goal)
dispose_list(freeable);
}
-int shrink_icache_memory(int priority, int gfp_mask)
+void shrink_icache_memory(int priority, int gfp_mask)
{
int count = 0;
-
+
+ /*
+ * Nasty deadlock avoidance..
+ *
+ * We may hold various FS locks, and we don't
+ * want to recurse into the FS that called us
+ * in clear_inode() and friends..
+ */
+ if (!(gfp_mask & __GFP_IO))
+ return;
+
if (priority)
count = inodes_stat.nr_unused / priority;
+
prune_icache(count);
- /* FIXME: kmem_cache_shrink here should tell us
- the number of pages freed, and it should
- work in a __GFP_DMA/__GFP_HIGHMEM behaviour
- to free only the interesting pages in
- function of the needs of the current allocation. */
kmem_cache_shrink(inode_cachep);
-
- return 0;
}
/*
@@ -509,9 +513,9 @@ static struct inode * find_inode(struct super_block * sb, unsigned long ino, str
*/
static void clean_inode(struct inode *inode)
{
- static struct address_space_operations empty_aops = {};
- static struct inode_operations empty_iops = {};
- static struct file_operations empty_fops = {};
+ static struct address_space_operations empty_aops;
+ static struct inode_operations empty_iops;
+ static struct file_operations empty_fops;
memset(&inode->u, 0, sizeof(inode->u));
inode->i_sock = 0;
inode->i_op = &empty_iops;
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index 266e7bf64..3ac27df92 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -10,7 +10,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * $Id: inode-v23.c,v 1.34 2000/08/10 08:58:00 dwmw2 Exp $
+ * $Id: inode-v23.c,v 1.43 2000/08/22 08:00:22 dwmw2 Exp $
*
*
* Ported to Linux 2.3.x and MTD:
@@ -151,10 +151,9 @@ jffs_put_super(struct super_block *sb)
D2(printk("jffs_put_super()\n"));
- D1(printk (KERN_NOTICE "jffs_put_super(): Telling gc thread to die.\n"));
if (c->gc_task) {
- send_sig(SIGQUIT, c->gc_task, 1);
- send_sig(SIGCONT, c->gc_task, 1);
+ D1(printk (KERN_NOTICE "jffs_put_super(): Telling gc thread to die.\n"));
+ send_sig(SIGKILL, c->gc_task, 1);
}
down (&c->gc_thread_sem);
@@ -179,54 +178,56 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr)
struct jffs_fmcontrol *fmc;
struct jffs_file *f;
struct jffs_node *new_node;
- char *name = 0;
int update_all;
int res;
+ int recoverable = 0;
+
+ if ((res = inode_change_ok(inode, iattr)))
+ return res;
+
+ c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
+ fmc = c->fmc;
+
+ D3(printk (KERN_NOTICE "notify_change(): down biglock\n"));
+ down(&fmc->biglock);
+
+ f = jffs_find_file(c, inode->i_ino);
- f = (struct jffs_file *)inode->u.generic_ip;
ASSERT(if (!f) {
printk("jffs_setattr(): Invalid inode number: %lu\n",
inode->i_ino);
- return -1;
+ D3(printk (KERN_NOTICE "notify_change(): up biglock\n"));
+ up(&fmc->biglock);
+ return -EINVAL;
});
D1(printk("***jffs_setattr(): file: \"%s\", ino: %u\n",
f->name, f->ino));
- c = f->c;
- fmc = c->fmc;
update_all = iattr->ia_valid & ATTR_FORCE;
- if (!JFFS_ENOUGH_SPACE(c)) {
- if ( (update_all || iattr->ia_valid & ATTR_SIZE)
- && (iattr->ia_size < f->size) ) {
- /* See this case where someone is trying to
- shrink the size of a file as an exception.
- Accept it. */
- /* TODO: Might just shrink it a bit?
- check f->size - ia_size */
- } else {
- D1(printk("jffs_setattr(): Free size = %u\n",
- jffs_free_size1(fmc)
- + jffs_free_size2(fmc)));
- D(printk(KERN_NOTICE "JFFS: No space left on "
- "device\n"));
- return -ENOSPC;
- }
- }
+ if ( (update_all || iattr->ia_valid & ATTR_SIZE)
+ && (iattr->ia_size + 128 < f->size) ) {
+ /* We're shrinking the file by more than 128 bytes.
+ We'll be able to GC and recover this space, so
+ allow it to go into the reserved space. */
+ recoverable = 1;
+ }
if (!(new_node = (struct jffs_node *)
kmalloc(sizeof(struct jffs_node), GFP_KERNEL))) {
D(printk("jffs_setattr(): Allocation failed!\n"));
+ D3(printk (KERN_NOTICE "notify_change(): up biglock\n"));
+ up(&fmc->biglock);
return -ENOMEM;
}
+
DJM(no_jffs_node++);
new_node->data_offset = 0;
new_node->removed_size = 0;
raw_inode.magic = JFFS_MAGIC_BITMASK;
raw_inode.ino = f->ino;
raw_inode.pino = f->pino;
- raw_inode.version = f->highest_version + 1;
raw_inode.mode = f->mode;
raw_inode.uid = f->uid;
raw_inode.gid = f->gid;
@@ -237,7 +238,7 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr)
raw_inode.offset = 0;
raw_inode.rsize = 0;
raw_inode.dsize = 0;
- raw_inode.nsize = 0;
+ raw_inode.nsize = f->nsize;
raw_inode.nlink = f->nlink;
raw_inode.spare = 0;
raw_inode.rename = 0;
@@ -278,12 +279,8 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr)
new_node->data_offset = iattr->ia_size;
new_node->removed_size = len;
inode->i_size = iattr->ia_size;
+ inode->i_blocks = (inode->i_size + 511) >> 9;
- /* If we truncate a file we want to add the name. If we
- always do that, we could perhaps free more space on
- the flash (and besides it doesn't hurt). */
- name = f->name;
- raw_inode.nsize = f->nsize;
if (len) {
invalidate_inode_pages(inode);
}
@@ -304,17 +301,20 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr)
}
/* Write this node to the flash. */
- if ((res = jffs_write_node(c, new_node, &raw_inode, name, 0)) < 0) {
+ if ((res = jffs_write_node(c, new_node, &raw_inode, f->name, 0, recoverable, f)) < 0) {
D(printk("jffs_notify_change(): The write failed!\n"));
kfree(new_node);
DJM(no_jffs_node--);
+ D3(printk (KERN_NOTICE "n_c(): up biglock\n"));
+ up(&c->fmc->biglock);
return res;
}
jffs_insert_node(c, f, &raw_inode, 0, new_node);
mark_inode_dirty(inode);
-
+ D3(printk (KERN_NOTICE "n_c(): up biglock\n"));
+ up(&c->fmc->biglock);
return 0;
} /* jffs_notify_change() */
@@ -403,7 +403,7 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
__u32 rename_data = 0;
D2(printk("***jffs_rename()\n"));
-
+
D(printk("jffs_rename(): old_dir: 0x%p, old name: 0x%p, "
"new_dir: 0x%p, new name: 0x%p\n",
old_dir, old_dentry->d_name.name,
@@ -413,17 +413,9 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
ASSERT(if (!c) {
printk(KERN_ERR "jffs_rename(): The old_dir inode "
"didn't have a reference to a jffs_file struct\n");
- return -1;
+ return -EIO;
});
- if (!JFFS_ENOUGH_SPACE(c)) {
- D1(printk("jffs_rename(): Free size = %u\n",
- jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
- D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
- return -ENOSPC;
- }
-
- /* Find the old directory. */
result = -ENOTDIR;
if (!(old_dir_f = (struct jffs_file *)old_dir->u.generic_ip)) {
D(printk("jffs_rename(): Old dir invalid.\n"));
@@ -443,7 +435,8 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
D(printk("jffs_rename(): New dir invalid.\n"));
goto jffs_rename_end;
}
-
+ D3(printk (KERN_NOTICE "rename(): down biglock\n"));
+ down(&c->fmc->biglock);
/* Create a node and initialize as much as needed. */
result = -ENOMEM;
if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
@@ -459,7 +452,7 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
raw_inode.magic = JFFS_MAGIC_BITMASK;
raw_inode.ino = f->ino;
raw_inode.pino = new_dir_f->ino;
- raw_inode.version = f->highest_version + 1;
+/* raw_inode.version = f->highest_version + 1; */
raw_inode.mode = f->mode;
raw_inode.uid = current->fsuid;
raw_inode.gid = current->fsgid;
@@ -491,7 +484,7 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
/* Write the new node to the flash memory. */
if ((result = jffs_write_node(c, node, &raw_inode,
new_dentry->d_name.name,
- (unsigned char*)&rename_data)) < 0) {
+ (unsigned char*)&rename_data, 0, f)) < 0) {
D(printk("jffs_rename(): Failed to write node to flash.\n"));
kfree(node);
DJM(no_jffs_node--);
@@ -501,14 +494,14 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (raw_inode.rename) {
/* The file with the same name must be deleted. */
- down(&c->fmc->gclock);
+ //FIXME deadlock down(&c->fmc->gclock);
if ((result = jffs_remove(new_dir, new_dentry,
del_f->mode)) < 0) {
/* This is really bad. */
printk(KERN_ERR "JFFS: An error occurred in "
"rename().\n");
}
- up(&c->fmc->gclock);
+ // up(&c->fmc->gclock);
}
if (old_dir_f != new_dir_f) {
@@ -539,6 +532,8 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
}
jffs_rename_end:
+ D3(printk (KERN_NOTICE "rename(): up biglock\n"));
+ up(&c->fmc->biglock);
return result;
} /* jffs_rename() */
@@ -551,13 +546,18 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct jffs_file *f;
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
+ struct jffs_control *c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
int j;
int ddino;
+ D3(printk (KERN_NOTICE "readdir(): down biglock\n"));
+ down(&c->fmc->biglock);
D2(printk("jffs_readdir(): inode: 0x%p, filp: 0x%p\n", inode, filp));
if (filp->f_pos == 0) {
D3(printk("jffs_readdir(): \".\" %lu\n", inode->i_ino));
if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) {
+ D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
+ up(&c->fmc->biglock);
return 0;
}
filp->f_pos = 1;
@@ -571,8 +571,11 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
inode->u.generic_ip)->pino;
}
D3(printk("jffs_readdir(): \"..\" %u\n", ddino));
- if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0)
+ if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0) {
+ D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
+ up(&c->fmc->biglock);
return 0;
+ }
filp->f_pos++;
}
f = ((struct jffs_file *)inode->u.generic_ip)->children;
@@ -583,11 +586,15 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
D3(printk("jffs_readdir(): \"%s\" ino: %u\n",
(f->name ? f->name : ""), f->ino));
if (filldir(dirent, f->name, f->nsize,
- filp->f_pos , f->ino, DT_UNKNOWN) < 0)
+ filp->f_pos , f->ino, DT_UNKNOWN) < 0) {
+ D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
+ up(&c->fmc->biglock);
return 0;
+ }
filp->f_pos++;
}
-
+ D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
+ up(&c->fmc->biglock);
return filp->f_pos;
} /* jffs_readdir() */
@@ -599,6 +606,7 @@ jffs_lookup(struct inode *dir, struct dentry *dentry)
{
struct jffs_file *d;
struct jffs_file *f;
+ struct jffs_control *c = (struct jffs_control *)dir->i_sb->u.generic_sbp;
int len;
int r = 0;
const char *name;
@@ -615,6 +623,9 @@ jffs_lookup(struct inode *dir, struct dentry *dentry)
kfree(s);
});
+ D3(printk (KERN_NOTICE "lookup(): down biglock\n"));
+ down(&c->fmc->biglock);
+
r = -ENAMETOOLONG;
if (len > JFFS_MAX_NAME_LEN) {
goto jffs_lookup_end;
@@ -628,21 +639,39 @@ jffs_lookup(struct inode *dir, struct dentry *dentry)
}
/* Get the corresponding inode to the file. */
+
+ /* iget calls jffs_read_inode, so we need to drop the biglock
+ before calling iget. Unfortunately, the GC has a tendency
+ to sneak in here, because iget sometimes calls schedule ().
+ */
+
if ((len == 1) && (name[0] == '.')) {
+ D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
+ up(&c->fmc->biglock);
if (!(inode = iget(dir->i_sb, d->ino))) {
D(printk("jffs_lookup(): . iget() ==> NULL\n"));
- goto jffs_lookup_end;
+ goto jffs_lookup_end_no_biglock;
}
+ D3(printk (KERN_NOTICE "lookup(): down biglock\n"));
+ down(&c->fmc->biglock);
} else if ((len == 2) && (name[0] == '.') && (name[1] == '.')) {
- if (!(inode = iget(dir->i_sb, d->pino))) {
+ D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
+ up(&c->fmc->biglock);
+ if (!(inode = iget(dir->i_sb, d->pino))) {
D(printk("jffs_lookup(): .. iget() ==> NULL\n"));
- goto jffs_lookup_end;
+ goto jffs_lookup_end_no_biglock;
}
+ D3(printk (KERN_NOTICE "lookup(): down biglock\n"));
+ down(&c->fmc->biglock);
} else if ((f = jffs_find_child(d, name, len))) {
+ D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
+ up(&c->fmc->biglock);
if (!(inode = iget(dir->i_sb, f->ino))) {
D(printk("jffs_lookup(): iget() ==> NULL\n"));
- goto jffs_lookup_end;
+ goto jffs_lookup_end_no_biglock;
}
+ D3(printk (KERN_NOTICE "lookup(): down biglock\n"));
+ down(&c->fmc->biglock);
} else {
D3(printk("jffs_lookup(): Couldn't find the file. "
"f = 0x%p, name = \"%s\", d = 0x%p, d->ino = %u\n",
@@ -651,9 +680,15 @@ jffs_lookup(struct inode *dir, struct dentry *dentry)
}
d_add(dentry, inode);
+ D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
+ up(&c->fmc->biglock);
return NULL;
jffs_lookup_end:
+ D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
+ up(&c->fmc->biglock);
+
+jffs_lookup_end_no_biglock:
return ERR_PTR(r);
} /* jffs_lookup() */
@@ -667,6 +702,7 @@ jffs_readpage(struct file *file, struct page *page)
int result = -EIO;
struct inode *inode = (struct inode*)page->mapping->host;
struct jffs_file *f = (struct jffs_file *)inode->u.generic_ip;
+ struct jffs_control *c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
int r;
loff_t offset;
@@ -679,6 +715,9 @@ jffs_readpage(struct file *file, struct page *page)
ClearPageUptodate(page);
ClearPageError(page);
+ D3(printk (KERN_NOTICE "readpage(): down biglock\n"));
+ down(&c->fmc->biglock);
+
offset = page->index << PAGE_CACHE_SHIFT;
if (offset < inode->i_size) {
read_len = jffs_min(inode->i_size - offset, PAGE_SIZE);
@@ -697,6 +736,10 @@ jffs_readpage(struct file *file, struct page *page)
"read %d bytes.\n", read_len, r);
});
}
+
+ D3(printk (KERN_NOTICE "readpage(): up biglock\n"));
+ up(&c->fmc->biglock);
+
if (result) {
memset(buf, 0, PAGE_SIZE);
SetPageError(page);
@@ -737,22 +780,16 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
});
dir_f = (struct jffs_file *)dir->u.generic_ip;
+
ASSERT(if (!dir_f) {
printk(KERN_ERR "jffs_mkdir(): No reference to a "
"jffs_file struct in inode.\n");
- result = -1;
- goto jffs_mkdir_end;
+ return -EIO;
});
c = dir_f->c;
-
- if (!JFFS_ENOUGH_SPACE(c)) {
- D1(printk("jffs_mkdir(): Free size = %u\n",
- jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
- D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
- result = -ENOSPC;
- goto jffs_mkdir_end;
- }
+ D3(printk (KERN_NOTICE "mkdir(): down biglock\n"));
+ down(&c->fmc->biglock);
dir_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX)
& ~current->fs->umask);
@@ -794,7 +831,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
/* Write the new node to the flash. */
if ((result = jffs_write_node(c, node, &raw_inode,
- dentry->d_name.name, 0)) < 0) {
+ dentry->d_name.name, 0, 0, NULL)) < 0) {
D(printk("jffs_mkdir(): jffs_write_node() failed.\n"));
kfree(node);
DJM(no_jffs_node--);
@@ -821,6 +858,8 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
result = 0;
jffs_mkdir_end:
+ D3(printk (KERN_NOTICE "mkdir(): up biglock\n"));
+ up(&c->fmc->biglock);
return result;
} /* jffs_mkdir() */
@@ -829,8 +868,15 @@ jffs_mkdir_end:
static int
jffs_rmdir(struct inode *dir, struct dentry *dentry)
{
+ struct jffs_control *c = (struct jffs_control *)dir->i_sb->u.generic_sbp;
+ int ret;
D3(printk("***jffs_rmdir()\n"));
- return jffs_remove(dir, dentry, S_IFDIR);
+ D3(printk (KERN_NOTICE "rmdir(): down biglock\n"));
+ down(&c->fmc->biglock);
+ ret = jffs_remove(dir, dentry, S_IFDIR);
+ D3(printk (KERN_NOTICE "rmdir(): up biglock\n"));
+ up(&c->fmc->biglock);
+ return ret;
}
@@ -838,8 +884,16 @@ jffs_rmdir(struct inode *dir, struct dentry *dentry)
static int
jffs_unlink(struct inode *dir, struct dentry *dentry)
{
+ struct jffs_control *c = (struct jffs_control *)dir->i_sb->u.generic_sbp;
+ int ret;
+
D3(printk("***jffs_unlink()\n"));
- return jffs_remove(dir, dentry, 0);
+ D3(printk (KERN_NOTICE "unlink(): down biglock\n"));
+ down(&c->fmc->biglock);
+ ret = jffs_remove(dir, dentry, 0);
+ D3(printk (KERN_NOTICE "unlink(): up biglock\n"));
+ up(&c->fmc->biglock);
+ return ret;
}
@@ -862,7 +916,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type)
char *_name = (char *) kmalloc(len + 1, GFP_KERNEL);
memcpy(_name, name, len);
_name[len] = '\0';
- printk("***jffs_remove(): file = \"%s\"\n", _name);
+ printk("***jffs_remove(): file = \"%s\", ino = %ld\n", _name, dentry->d_inode->i_ino);
kfree(_name);
});
@@ -916,7 +970,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type)
raw_inode.magic = JFFS_MAGIC_BITMASK;
raw_inode.ino = del_f->ino;
raw_inode.pino = del_f->pino;
- raw_inode.version = del_f->highest_version + 1;
+/* raw_inode.version = del_f->highest_version + 1; */
raw_inode.mode = del_f->mode;
raw_inode.uid = current->fsuid;
raw_inode.gid = current->fsgid;
@@ -933,7 +987,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type)
raw_inode.deleted = 1;
/* Write the new node to the flash memory. */
- if (jffs_write_node(c, del_node, &raw_inode, 0, 0) < 0) {
+ if (jffs_write_node(c, del_node, &raw_inode, 0, 0, 1, del_f) < 0) {
kfree(del_node);
DJM(no_jffs_node--);
result = -EIO;
@@ -979,13 +1033,8 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
dir_f = (struct jffs_file *)dir->u.generic_ip;
c = dir_f->c;
- if (!JFFS_ENOUGH_SPACE(c)) {
- D1(printk("jffs_mknod(): Free size = %u\n",
- jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
- D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
- result = -ENOSPC;
- goto jffs_mknod_end;
- }
+ D3(printk (KERN_NOTICE "mknod(): down biglock\n"));
+ down(&c->fmc->biglock);
/* Create and initialize a new node. */
if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
@@ -1021,7 +1070,7 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
/* Write the new node to the flash. */
if ((err = jffs_write_node(c, node, &raw_inode, dentry->d_name.name,
- (unsigned char *)&dev)) < 0) {
+ (unsigned char *)&dev, 0, NULL)) < 0) {
D(printk("jffs_mknod(): jffs_write_node() failed.\n"));
result = err;
goto jffs_mknod_err;
@@ -1053,6 +1102,8 @@ jffs_mknod_err:
}
jffs_mknod_end:
+ D3(printk (KERN_NOTICE "mknod(): up biglock\n"));
+ up(&c->fmc->biglock);
return result;
} /* jffs_mknod() */
@@ -1088,24 +1139,20 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
ASSERT(if (!dir_f) {
printk(KERN_ERR "jffs_symlink(): No reference to a "
"jffs_file struct in inode.\n");
- return -1;
+ return -EIO;
});
c = dir_f->c;
- if (!JFFS_ENOUGH_SPACE(c)) {
- D1(printk("jffs_symlink(): Free size = %u\n",
- jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
- D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
- return -ENOSPC;
- }
-
/* Create a node and initialize it as much as needed. */
if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
GFP_KERNEL))) {
D(printk("jffs_symlink(): Allocation failed: node = NULL\n"));
return -ENOMEM;
}
+ D3(printk (KERN_NOTICE "symlink(): down biglock\n"));
+ down(&c->fmc->biglock);
+
DJM(no_jffs_node++);
node->data_offset = 0;
node->removed_size = 0;
@@ -1132,30 +1179,32 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
/* Write the new node to the flash. */
if ((err = jffs_write_node(c, node, &raw_inode, dentry->d_name.name,
- (const unsigned char *)symname)) < 0) {
+ (const unsigned char *)symname, 0, NULL)) < 0) {
D(printk("jffs_symlink(): jffs_write_node() failed.\n"));
kfree(node);
DJM(no_jffs_node--);
- return err;
+ goto jffs_symlink_end;
}
/* Insert the new node into the file system. */
if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name,
node)) < 0) {
- return err;
+ goto jffs_symlink_end;
}
inode = jffs_new_inode(dir, &raw_inode, &err);
if (inode == NULL) {
- return err;
+ goto jffs_symlink_end;
}
-
+ err = 0;
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &jffs_address_operations;
d_instantiate(dentry, inode);
-
- return 0;
+ jffs_symlink_end:
+ D3(printk (KERN_NOTICE "symlink(): up biglock\n"));
+ up(&c->fmc->biglock);
+ return err;
} /* jffs_symlink() */
@@ -1191,24 +1240,20 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode)
ASSERT(if (!dir_f) {
printk(KERN_ERR "jffs_create(): No reference to a "
"jffs_file struct in inode.\n");
- return -1;
+ return -EIO;
});
c = dir_f->c;
- if (!JFFS_ENOUGH_SPACE(c)) {
- D1(printk("jffs_create(): Free size = %u\n",
- jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
- D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
- return -ENOSPC;
- }
-
/* Create a node and initialize as much as needed. */
if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
GFP_KERNEL))) {
D(printk("jffs_create(): Allocation failed: node == 0\n"));
return -ENOMEM;
}
+ D3(printk (KERN_NOTICE "create(): down biglock\n"));
+ down(&c->fmc->biglock);
+
DJM(no_jffs_node++);
node->data_offset = 0;
node->removed_size = 0;
@@ -1235,33 +1280,35 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode)
/* Write the new node to the flash. */
if ((err = jffs_write_node(c, node, &raw_inode,
- dentry->d_name.name, 0)) < 0) {
+ dentry->d_name.name, 0, 0, NULL)) < 0) {
D(printk("jffs_create(): jffs_write_node() failed.\n"));
kfree(node);
DJM(no_jffs_node--);
- return err;
+ goto jffs_create_end;
}
/* Insert the new node into the file system. */
if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name,
node)) < 0) {
- return err;
+ goto jffs_create_end;
}
/* Initialize an inode. */
inode = jffs_new_inode(dir, &raw_inode, &err);
if (inode == NULL) {
- return err;
+ goto jffs_create_end;
}
-
+ err = 0;
inode->i_op = &jffs_file_inode_operations;
inode->i_fop = &jffs_file_operations;
inode->i_mapping->a_ops = &jffs_address_operations;
inode->i_mapping->nrpages = 0;
d_instantiate(dentry, inode);
-
- return 0;
+ jffs_create_end:
+ D3(printk (KERN_NOTICE "create(): up biglock\n"));
+ up(&c->fmc->biglock);
+ return err;
} /* jffs_create() */
@@ -1277,7 +1324,9 @@ jffs_file_write(struct file *filp, const char *buf, size_t count,
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
unsigned char *vbuf;
- int written = 0;
+ int recoverable = 0;
+ size_t written = 0;
+ __u32 thiscount = count;
loff_t pos;
int err;
@@ -1287,147 +1336,176 @@ jffs_file_write(struct file *filp, const char *buf, size_t count,
"filp: 0x%p, buf: 0x%p, count: %d\n",
inode, inode->i_ino, filp, buf, count));
- down(&inode->i_sem);
-
- pos = *ppos;
- err = -EINVAL;
- if (pos < 0)
- goto out;
-
err = filp->f_error;
if (err) {
filp->f_error = 0;
- goto out;
+ return err;
}
+ down(&inode->i_sem);
+
if (inode->i_sb->s_flags & MS_RDONLY) {
D(printk("jffs_file_write(): MS_RDONLY\n"));
- err = -ENOSPC;
- goto out;
+ err = -EROFS;
+ goto out_isem;
}
+ err = -EINVAL;
+
if (!S_ISREG(inode->i_mode)) {
D(printk("jffs_file_write(): inode->i_mode == 0x%08x\n",
inode->i_mode));
- err = -EINVAL;
- goto out;
+ goto out_isem;
}
if (!(f = (struct jffs_file *)inode->u.generic_ip)) {
D(printk("jffs_file_write(): inode->u.generic_ip = 0x%p\n",
inode->u.generic_ip));
- err = -EINVAL;
- goto out;
+ goto out_isem;
}
c = f->c;
- if (!JFFS_ENOUGH_SPACE(c)) {
- D1(printk("jffs_file_write(): Free size = %u\n",
- jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
- D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
- err = -ENOSPC;
- goto out;
- }
-
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
+ else
+ pos = *ppos;
+
+ if (pos < 0) {
+ goto out_isem;
+ }
+
+ thiscount = jffs_min(c->fmc->max_chunk_size - sizeof(struct jffs_raw_inode), count);
-
- if (!(vbuf = kmalloc(count, GFP_KERNEL))) {
+ if (!(vbuf = kmalloc(thiscount, GFP_KERNEL))) {
D(printk("jffs_file_write(): failed to allocate bounce buffer. Fix me to use page cache\n"));
err = -ENOMEM;
- goto out;
+ goto out_isem;
}
- /* FIXME: This is entirely gratuitous use of bounce buffers.
- Get a clue and use the page cache.
- /me wanders off to get a crash course on Linux VFS
- dwmw2
- */
- if (copy_from_user(vbuf, buf, count)) {
- kfree(vbuf);
- return -EFAULT;
- }
-
-
- /* Things are going to be written so we could allocate and
- initialize the necessary data structures now. */
- if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
- GFP_KERNEL))) {
- D(printk("jffs_file_write(): node == 0\n"));
- err = -ENOMEM;
- kfree(vbuf);
- goto out;
- }
- DJM(no_jffs_node++);
- node->data_offset = pos;
- node->removed_size = 0;
+ D3(printk (KERN_NOTICE "file_write(): down biglock\n"));
+ down(&c->fmc->biglock);
- /* Initialize the raw inode. */
- raw_inode.magic = JFFS_MAGIC_BITMASK;
- raw_inode.ino = f->ino;
- raw_inode.pino = f->pino;
- raw_inode.version = f->highest_version + 1;
- raw_inode.mode = f->mode;
+ /* Urgh. POSIX says we can do short writes if we feel like it.
+ * In practice, we can't. Nothing will cope. So we loop until
+ * we're done.
+ *
+ * <_Anarchy_> posix and reality are not interconnected on this issue
+ */
+ while (count) {
+
+ /* FIXME: This is entirely gratuitous use of bounce buffers.
+ Get a clue and use the page cache.
+ /me wanders off to get a crash course on Linux VFS
+ dwmw2
+ */
+ if (copy_from_user(vbuf, buf, thiscount)) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ /* Things are going to be written so we could allocate and
+ initialize the necessary data structures now. */
+ if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
+ GFP_KERNEL))) {
+ D(printk("jffs_file_write(): node == 0\n"));
+ err = -ENOMEM;
+ goto out;
+ }
+ DJM(no_jffs_node++);
+
+ node->data_offset = pos;
+ node->removed_size = 0;
+
+ /* Initialize the raw inode. */
+ raw_inode.magic = JFFS_MAGIC_BITMASK;
+ raw_inode.ino = f->ino;
+ raw_inode.pino = f->pino;
- raw_inode.uid = f->uid;
- raw_inode.gid = f->gid;
- /*
- raw_inode.uid = current->fsuid;
- raw_inode.gid = current->fsgid;
- */
- raw_inode.atime = CURRENT_TIME;
- raw_inode.mtime = raw_inode.atime;
- raw_inode.ctime = f->ctime;
- raw_inode.offset = pos;
- raw_inode.dsize = count;
- raw_inode.rsize = 0;
- raw_inode.nsize = 0;
- raw_inode.nlink = f->nlink;
- raw_inode.spare = 0;
- raw_inode.rename = 0;
- raw_inode.deleted = 0;
+ raw_inode.mode = f->mode;
+
+ raw_inode.uid = f->uid;
+ raw_inode.gid = f->gid;
+ raw_inode.atime = CURRENT_TIME;
+ raw_inode.mtime = raw_inode.atime;
+ raw_inode.ctime = f->ctime;
+ raw_inode.offset = pos;
+ raw_inode.dsize = thiscount;
+ raw_inode.rsize = 0;
+ raw_inode.nsize = f->nsize;
+ raw_inode.nlink = f->nlink;
+ raw_inode.spare = 0;
+ raw_inode.rename = 0;
+ raw_inode.deleted = 0;
+
+ if (pos < f->size) {
+ node->removed_size = raw_inode.rsize = jffs_min(thiscount, f->size - pos);
+
+ /* If this node is going entirely over the top of old data,
+ we can allow it to go into the reserved space, because
+ we can that GC can reclaim the space later.
+ */
+ if (pos + thiscount < f->size) {
+ /* If all the data we're overwriting are _real_,
+ not just holes, then:
+ recoverable = 1;
+ */
+ }
+ }
+
+ /* Write the new node to the flash. */
+ /* NOTE: We would be quite happy if jffs_write_node() wrote a
+ smaller node than we were expecting. There's no need for it
+ to waste the space at the end of the flash just because it's
+ a little smaller than what we asked for. But that's a whole
+ new can of worms which I'm not going to open this week. dwmw2.
+ */
+ if ((err = jffs_write_node(c, node, &raw_inode, f->name,
+ (const unsigned char *)vbuf,
+ recoverable, f)) < 0) {
+ D(printk("jffs_file_write(): jffs_write_node() failed.\n"));
+ kfree(node);
+ DJM(no_jffs_node--);
+ goto out;
+ }
- if (pos < f->size) {
- node->removed_size = raw_inode.rsize = jffs_min(count, f->size - pos);
- }
+ written += err;
+ buf += err;
+ count -= err;
+ pos += err;
- /* Write the new node to the flash. */
- if ((written = jffs_write_node(c, node, &raw_inode, 0,
- (const unsigned char *)vbuf)) < 0) {
- D(printk("jffs_file_write(): jffs_write_node() failed.\n"));
- kfree(node);
- kfree(vbuf);
- DJM(no_jffs_node--);
- err = written;
- goto out;
- }
+ /* Insert the new node into the file system. */
+ if ((err = jffs_insert_node(c, f, &raw_inode, 0, node)) < 0) {
+ goto out;
+ }
- kfree(vbuf);
+ D3(printk("jffs_file_write(): new f_pos %ld.\n", (long)pos));
- /* Insert the new node into the file system. */
- if ((err = jffs_insert_node(c, f, &raw_inode, 0, node)) < 0) {
- goto out;
+ thiscount = jffs_min(c->fmc->max_chunk_size - sizeof(struct jffs_raw_inode), count);
}
-
- pos += written;
+ out:
+ D3(printk (KERN_NOTICE "file_write(): up biglock\n"));
+ up(&c->fmc->biglock);
*ppos = pos;
-
- D3(printk("jffs_file_write(): new f_pos %ld.\n", (long)pos));
+ kfree(vbuf);
/* Fix things in the real inode. */
if (pos > inode->i_size) {
inode->i_size = pos;
+ inode->i_blocks = (inode->i_size + 511) >> 9;
}
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
mark_inode_dirty(inode);
invalidate_inode_pages(inode);
- err = written;
-out:
+ out_isem:
up(&inode->i_sem);
- return err;
+
+ /* What if there was an error, _and_ we've written some data. */
+ if (written)
+ return written;
+ else
+ return err;
} /* jffs_file_write() */
@@ -1437,6 +1515,7 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
struct jffs_control *c;
+ int ret = 0;
D2(printk("***jffs_ioctl(): cmd = 0x%08x, arg = 0x%08lx\n",
cmd, arg));
@@ -1446,6 +1525,8 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
"(cmd = 0x%08x)\n", cmd);
return -EIO;
}
+ D3(printk (KERN_NOTICE "ioctl(): down biglock\n"));
+ down(&c->fmc->biglock);
switch (cmd) {
case JFFS_PRINT_HASH:
@@ -1464,7 +1545,8 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
sizeof(struct jffs_flash_status))) {
D(printk("jffs_ioctl(): Bad arg in "
"JFFS_GET_STATUS ioctl!\n"));
- return -EFAULT;
+ ret = -EFAULT;
+ break;
}
fst.size = fmc->flash_size;
fst.used = fmc->used_size;
@@ -1478,15 +1560,16 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
if (copy_to_user((struct jffs_flash_status *)arg,
&fst,
sizeof(struct jffs_flash_status))) {
- return -EFAULT;
+ ret = -EFAULT;
}
}
break;
default:
- return -ENOTTY;
+ ret = -ENOTTY;
}
-
- return 0;
+ D3(printk (KERN_NOTICE "ioctl(): up biglock\n"));
+ up(&c->fmc->biglock);
+ return ret;
} /* jffs_ioctl() */
@@ -1555,9 +1638,13 @@ jffs_read_inode(struct inode *inode)
return;
}
c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
+ D3(printk (KERN_NOTICE "read_inode(): down biglock\n"));
+ down(&c->fmc->biglock);
if (!(f = jffs_find_file(c, inode->i_ino))) {
D(printk("jffs_read_inode(): No such inode (%lu).\n",
inode->i_ino));
+ D3(printk (KERN_NOTICE "read_inode(): up biglock\n"));
+ up(&c->fmc->biglock);
return;
}
inode->u.generic_ip = (void *)f;
@@ -1592,6 +1679,8 @@ jffs_read_inode(struct inode *inode)
jffs_read_data(f, (char *)&rdev, 0, sizeof(kdev_t));
init_special_inode(inode, inode->i_mode, kdev_t_to_nr(rdev));
}
+ D3(printk (KERN_NOTICE "read_inode(): up biglock\n"));
+ up(&c->fmc->biglock);
}
@@ -1603,6 +1692,7 @@ jffs_delete_inode(struct inode *inode)
lock_kernel();
inode->i_size = 0;
+ inode->i_blocks = 0;
clear_inode(inode);
unlock_kernel();
}
diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c
index adb2e0c46..5cf82f468 100644
--- a/fs/jffs/intrep.c
+++ b/fs/jffs/intrep.c
@@ -10,7 +10,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * $Id: intrep.c,v 1.39 2000/08/09 13:23:36 dwmw2 Exp $
+ * $Id: intrep.c,v 1.69 2000/08/24 09:35:47 dwmw2 Exp $
*
* Ported to Linux 2.3.x and MTD:
* Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB
@@ -191,12 +191,13 @@ flash_safe_read(struct mtd_info *mtd, loff_t from,
u_char *buf, size_t count)
{
size_t retlen;
+ int res;
- MTD_READ(mtd, from, count, &retlen, buf);
+ res = MTD_READ(mtd, from, count, &retlen, buf);
if (retlen != count) {
- printk("Didn't read all bytes in flash_safe_read()\n");
+ printk("Didn't read all bytes in flash_safe_read(). Returned %d\n", res);
}
- return retlen;
+ return res?res:retlen;
}
@@ -205,10 +206,11 @@ flash_read_u32(struct mtd_info *mtd, loff_t from)
{
size_t retlen;
__u32 ret;
+ int res;
- MTD_READ(mtd, from, 4, &retlen, (unsigned char *)&ret);
+ res = MTD_READ(mtd, from, 4, &retlen, (unsigned char *)&ret);
if (retlen != 4) {
- printk("Didn't read all bytes in flash_read_u32()\n");
+ printk("Didn't read all bytes in flash_read_u32(). Returned %d\n", res);
return 0;
}
@@ -221,10 +223,11 @@ flash_read_u8(struct mtd_info *mtd, loff_t from)
{
size_t retlen;
__u8 ret;
+ int res;
- MTD_READ(mtd, from, 1, &retlen, &ret);
+ res = MTD_READ(mtd, from, 1, &retlen, &ret);
if (retlen != 1) {
- printk("Didn't read a byte in flash_read_u8()\n");
+ printk("Didn't read a byte in flash_read_u8(). Returned %d\n", res);
return 0;
}
@@ -237,12 +240,13 @@ flash_safe_write(struct mtd_info *mtd, loff_t to,
const u_char *buf, size_t count)
{
size_t retlen;
+ int res;
- MTD_WRITE(mtd, to, count, &retlen, buf);
+ res = MTD_WRITE(mtd, to, count, &retlen, buf);
if (retlen != count) {
- printk("Didn't write all bytes in flash_safe_write()\n");
+ printk("Didn't write all bytes in flash_safe_write(). Returned %d\n", res);
}
- return retlen;
+ return res?res:retlen;
}
@@ -306,7 +310,8 @@ flash_erase_region(struct mtd_info *mtd, loff_t start,
erase->len = size;
erase->priv = (u_long)&wait_q;
- set_current_state(TASK_INTERRUPTIBLE);
+ /* FIXME: Use TASK_INTERRUPTIBLE and deal with being interrupted */
+ set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&wait_q, &wait);
if (MTD_ERASE(mtd, erase) < 0) {
@@ -321,7 +326,6 @@ flash_erase_region(struct mtd_info *mtd, loff_t start,
}
schedule(); /* Wait for flash to finish. */
- /* FIXME: We could have been interrupted here. We don't deal with it */
remove_wait_queue(&wait_q, &wait);
kfree(erase);
@@ -369,15 +373,14 @@ jffs_checksum_flash(struct mtd_info *mtd, loff_t start, int size)
D3(printk("checksum result: 0x%08x\n", sum));
return sum;
}
-
static __inline__ void jffs_fm_write_lock(struct jffs_fmcontrol *fmc)
{
- down(&fmc->wlock);
+ // down(&fmc->wlock);
}
static __inline__ void jffs_fm_write_unlock(struct jffs_fmcontrol *fmc)
{
- up(&fmc->wlock);
+ // up(&fmc->wlock);
}
@@ -421,6 +424,7 @@ jffs_create_control(kdev_t dev)
}
DJM(no_jffs_control++);
c->root = 0;
+ c->gc_task = 0;
c->hash_len = JFFS_HASH_SIZE;
s = sizeof(struct list_head) * c->hash_len;
if (!(c->hash = (struct list_head *)kmalloc(s, GFP_KERNEL))) {
@@ -640,6 +644,16 @@ jffs_scan_flash(struct jffs_control *c)
a single kernel thread will fix the original problem.
*/
if ((__u32) pos % fmc->sector_size) {
+ /* If there was free space in previous
+ sectors, don't mark that dirty too -
+ only from the beginning of this sector
+ (or from start)
+ */
+ if (start < (pos & ~(fmc->sector_size-1))) {
+ D1(printk("Reducing start to 0x%x from 0x%x\n", pos & ~(fmc->sector_size-1), start));
+ start = pos & ~(fmc->sector_size-1);
+ }
+ D1(printk("Dirty space: 0x%x for 0x%x bytes\n", start, (pos - start)));
jffs_fmalloced(fmc, (__u32) start,
(__u32) (pos - start), 0);
}
@@ -672,6 +686,7 @@ jffs_scan_flash(struct jffs_control *c)
"hexdump(pos = 0x%lx, len = 128):\n",
(long)pos));
D1(jffs_hexdump(fmc->mtd, pos, 128));
+ cont_dirty:
for (pos += 4; pos < end; pos += 4) {
switch (flash_read_u32(fmc->mtd, pos)) {
case JFFS_MAGIC_BITMASK:
@@ -679,6 +694,46 @@ jffs_scan_flash(struct jffs_control *c)
(__u32) (pos - start),
0);
goto cont_scan;
+ case JFFS_EMPTY_BITMASK:
+ /* First, mark as dirty the region
+ which really does contain crap. */
+ jffs_fmalloced(fmc, (__u32) start,
+ (__u32) (pos - start),
+ 0);
+
+ /* Then, scan the region which looks free.
+ Depending on how large it is, we may
+ mark it dirty too.
+ */
+ start = pos;
+ for (; pos < end ; pos += 4) {
+ switch (flash_read_u32(fmc->mtd, pos)) {
+ case JFFS_MAGIC_BITMASK:
+ if (pos - start < fmc->max_chunk_size) {
+ /* Not much free space. Mark it dirty. */
+ jffs_fmalloced(fmc, (__u32)start,
+ (__u32)pos-start, 0);
+ }
+ goto cont_scan;
+
+ case JFFS_EMPTY_BITMASK:
+ /* More empty space */
+ continue;
+
+ default:
+ /* i.e. more dirt */
+ if (pos - start < fmc->max_chunk_size) {
+ /* There wasn't much before the dirt
+ started again. Just mark it all dirty
+ */
+ goto cont_dirty;
+ }
+ /* There was quite a lot of free space. Leave it
+ free.
+ */
+ goto cont_scan;
+ }
+ }
default:
break;
}
@@ -734,6 +789,8 @@ jffs_scan_flash(struct jffs_control *c)
/* Check the raw inode read so far. Start with the
maximum length of the filename. */
if (raw_inode.nsize > JFFS_MAX_NAME_LEN) {
+ printk(KERN_WARNING "jffs_scan_flash: Found a "
+ "JFFS node with name too large\n");
goto bad_inode;
}
@@ -748,6 +805,9 @@ jffs_scan_flash(struct jffs_control *c)
/* The node's data segment should not exceed a
certain length. */
if (raw_inode.dsize > fmc->max_chunk_size) {
+ printk(KERN_WARNING "jffs_scan_flash: Found a "
+ "JFFS node with dsize (0x%x) > max_chunk_size (0x%x)\n",
+ raw_inode.dsize, fmc->max_chunk_size);
goto bad_inode;
}
@@ -895,9 +955,9 @@ jffs_insert_node(struct jffs_control *c, struct jffs_file *f,
int insert_into_tree = 0;
D2(printk("jffs_insert_node(): ino = %u, version = %u, "
- "name = \"%s\"\n",
+ "name = \"%s\", deleted = %d\n",
raw_inode->ino, raw_inode->version,
- ((name && *name) ? name : "")));
+ ((name && *name) ? name : ""), raw_inode->deleted));
/* If there doesn't exist an associated jffs_file, then
create, initialize and insert one into the file system. */
@@ -908,7 +968,6 @@ jffs_insert_node(struct jffs_control *c, struct jffs_file *f,
jffs_insert_file_into_hash(f);
insert_into_tree = 1;
}
-
node->ino = raw_inode->ino;
node->version = raw_inode->version;
node->data_size = raw_inode->dsize;
@@ -1345,18 +1404,30 @@ jffs_write_dummy_node(struct jffs_control *c, struct jffs_fm *dirty_fm)
int
jffs_write_node(struct jffs_control *c, struct jffs_node *node,
struct jffs_raw_inode *raw_inode,
- const char *name, const unsigned char *data)
+ const char *name, const unsigned char *data,
+ int recoverable,
+ struct jffs_file *f)
{
struct jffs_fmcontrol *fmc = c->fmc;
struct jffs_fm *fm = NULL;
__u32 pos;
int err;
+ __u32 slack = 0;
+
__u32 total_name_size = raw_inode->nsize
+ JFFS_GET_PAD_BYTES(raw_inode->nsize);
__u32 total_data_size = raw_inode->dsize
+ JFFS_GET_PAD_BYTES(raw_inode->dsize);
__u32 total_size = sizeof(struct jffs_raw_inode)
+ total_name_size + total_data_size;
+
+ /* If this node isn't something that will eventually let
+ GC free even more space, then don't allow it unless
+ there's at least max_chunk_size space still available
+ */
+ if (!recoverable)
+ slack = fmc->max_chunk_size;
+
/* Fire the retrorockets and shoot the fruiton torpedoes, sir! */
@@ -1371,14 +1442,22 @@ jffs_write_node(struct jffs_control *c, struct jffs_node *node,
});
D1(printk("jffs_write_node(): filename = \"%s\", ino = %u, "
- "version = %u, total_size = %u\n",
+ "total_size = %u\n",
(name ? name : ""), raw_inode->ino,
- raw_inode->version, total_size));
+ total_size));
jffs_fm_write_lock(fmc);
while (!fm) {
+ /* Deadlocks suck. */
+ while(fmc->free_size < fmc->min_free_size + total_size + slack) {
+ jffs_fm_write_unlock(fmc);
+ if (!JFFS_ENOUGH_SPACE(c, total_size + slack))
+ return -ENOSPC;
+ jffs_fm_write_lock(fmc);
+ }
+
/* First try to allocate some flash memory. */
err = jffs_fmalloc(fmc, total_size, node, &fm);
@@ -1431,6 +1510,15 @@ jffs_write_node(struct jffs_control *c, struct jffs_node *node,
pos = node->fm->offset;
+ /* Increment the version number here. We can't let the caller
+ set it beforehand, because we might have had to do GC on a node
+ of this file - and we'd end up reusing version numbers.
+ */
+ if (f) {
+ raw_inode->version = f->highest_version + 1;
+ D1(printk (KERN_NOTICE "jffs_write_node(): setting version of %s to %d\n", f->name, raw_inode->version));
+ }
+
/* Compute the checksum for the data and name chunks. */
raw_inode->dchksum = jffs_checksum(data, raw_inode->dsize);
raw_inode->nchksum = jffs_checksum(name, raw_inode->nsize);
@@ -1496,8 +1584,9 @@ jffs_write_node(struct jffs_control *c, struct jffs_node *node,
shouldn't be read again. 'max_size' is how much space there is in
the buffer. */
static int
-jffs_get_node_data(struct jffs_file *f, struct jffs_node *node, char *buf,
- __u32 node_offset, __u32 max_size, kdev_t dev)
+jffs_get_node_data(struct jffs_file *f, struct jffs_node *node,
+ unsigned char *buf,__u32 node_offset, __u32 max_size,
+ kdev_t dev)
{
struct jffs_fmcontrol *fmc = f->c->fmc;
__u32 pos = node->fm->offset + node->fm_offset + node_offset;
@@ -1521,14 +1610,15 @@ jffs_get_node_data(struct jffs_file *f, struct jffs_node *node, char *buf,
/* Read data from the file's nodes. Write the data to the buffer
'buf'. 'read_offset' tells how much data we should skip. */
int
-jffs_read_data(struct jffs_file *f, char *buf, __u32 read_offset, __u32 size)
+jffs_read_data(struct jffs_file *f, unsigned char *buf, __u32 read_offset,
+ __u32 size)
{
struct jffs_node *node;
__u32 read_data = 0; /* Total amount of read data. */
__u32 node_offset = 0;
__u32 pos = 0; /* Number of bytes traversed. */
- D1(printk("jffs_read_data(): file = \"%s\", read_offset = %d, "
+ D2(printk("jffs_read_data(): file = \"%s\", read_offset = %d, "
"size = %u\n",
(f->name ? f->name : ""), read_offset, size));
@@ -1842,7 +1932,21 @@ jffs_delete_data(struct jffs_file *f, struct jffs_node *node)
n = n->range_next;
}
- f->size -= node->removed_size;
+ if (node->removed_size > (f->size - node->data_offset)) {
+ /* It's possible that the removed_size is in fact
+ * greater than the amount of data we actually thought
+ * were present in the first place - some of the nodes
+ * which this node originally obsoleted may already have
+ * been deleted from the flash by subsequent garbage
+ * collection.
+ *
+ * If this is the case, don't let f->size go negative.
+ * Bad things would happen :)
+ */
+ f->size = node->data_offset;
+ } else {
+ f->size -= node->removed_size;
+ }
D3(printk("jffs_delete_data(): f->size = %d\n", f->size));
return 0;
} /* jffs_delete_data() */
@@ -1881,7 +1985,7 @@ jffs_insert_data(struct jffs_file *f, struct jffs_node *node)
/* Find the correct place for the insertion and then insert
the node. */
for (n = f->range_head; n; n = n->range_next) {
- D1(printk("Cool stuff's happening!\n"));
+ D2(printk("Cool stuff's happening!\n"));
if (n->data_offset == node->data_offset) {
node->range_prev = n->range_prev;
@@ -2223,7 +2327,7 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size)
int err;
D1(printk("***jffs_rewrite_data(): node: %u, name: \"%s\", size: %u\n",
- f->ino, (f->name ? f->name : ""), size));
+ f->ino, (f->name ? f->name : "(null)"), size));
/* Create and initialize the new node. */
if (!(new_node = (struct jffs_node *)
@@ -2235,8 +2339,8 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size)
DJM(no_jffs_node++);
new_node->data_offset = node->data_offset;
new_node->removed_size = size;
- total_name_size = f->nsize + JFFS_GET_PAD_BYTES(f->nsize);
- total_data_size = size + JFFS_GET_PAD_BYTES(size);
+ total_name_size = JFFS_PAD(f->nsize);
+ total_data_size = JFFS_PAD(size);
total_size = sizeof(struct jffs_raw_inode)
+ total_name_size + total_data_size;
new_node->fm_offset = sizeof(struct jffs_raw_inode)
@@ -2252,31 +2356,24 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size)
return err;
}
else if (!fm->nodes) {
- /* The jffs_fm struct that we got is not good enough. */
+ /* The jffs_fm struct that we got is not big enough. */
+ /* This should never happen, because we deal with this case
+ in jffs_garbage_collect_next().*/
+ printk(KERN_WARNING "jffs_rewrite_data(): Allocated node is too small (%d bytes of %d)\n", fm->size, total_size);
if ((err = jffs_write_dummy_node(c, fm)) < 0) {
- DJM(no_jffs_fm--);
- jffs_fm_write_unlock(fmc);
D(printk("jffs_rewrite_data(): "
"jffs_write_dummy_node() Failed!\n"));
- kfree(fm);
- return err;
- }
- /* Get a new one. */
- if ((err = jffs_fmalloc(fmc, total_size, node, &fm)) < 0) {
- jffs_fm_write_unlock(fmc);
- D(printk("jffs_rewrite_data(): Second "
- "jffs_fmalloc(0x%p, %u) failed!\n",
- fmc, total_size));
- return err;
+ } else {
+ err = -ENOSPC;
}
+ DJM(no_jffs_fm--);
+ jffs_fm_write_unlock(fmc);
+ kfree(fm);
+
+ return err;
}
new_node->fm = fm;
- ASSERT(if (new_node->fm->nodes == 0) {
- printk(KERN_ERR "jffs_rewrite_data(): "
- "new_node->fm->nodes == 0\n");
- });
-
/* Initialize the raw inode. */
raw_inode.magic = JFFS_MAGIC_BITMASK;
raw_inode.ino = f->ino;
@@ -2418,10 +2515,11 @@ jffs_garbage_collect_next(struct jffs_control *c)
struct jffs_fmcontrol *fmc = c->fmc;
struct jffs_node *node;
struct jffs_file *f;
- int size;
+ int size, err = 0;
int data_size;
int total_name_size;
- int free_size = fmc->flash_size - (fmc->used_size + fmc->dirty_size);
+ __u32 extra_available;
+ __u32 space_needed;
__u32 free_chunk_size1 = jffs_free_size1(fmc);
D2(__u32 free_chunk_size2 = jffs_free_size2(fmc));
@@ -2430,47 +2528,64 @@ jffs_garbage_collect_next(struct jffs_control *c)
ASSERT(if (!node) {
printk(KERN_ERR "JFFS: jffs_garbage_collect_next: "
"No oldest node found!\n");
- return -1;
+ err = -1;
+ goto jffs_garbage_collect_next_end;
+
+
});
/* Find its corresponding file too. */
f = jffs_find_file(c, node->ino);
- ASSERT(if (!f) {
- printk(KERN_ERR "JFFS: jffs_garbage_collect_next: "
- "No file to garbage collect! "
- "(ino = 0x%08x)\n", node->ino);
- return -1;
- });
+
+ if (!f) {
+ printk (KERN_ERR "JFFS: jffs_garbage_collect_next: "
+ "No file to garbage collect! "
+ "(ino = 0x%08x)\n", node->ino);
+ /* FIXME: Free the offending node and recover. */
+ err = -1;
+ goto jffs_garbage_collect_next_end;
+ }
+
+ /* We always write out the name. Theoretically, we don't need
+ to, but for now it's easier - because otherwise we'd have
+ to keep track of how many times the current name exists on
+ the flash and make sure it never reaches zero.
+
+ The current approach means that would be possible to cause
+ the GC to end up eating its tail by writing lots of nodes
+ with no name for it to garbage-collect. Hence the change in
+ inode.c to write names with _every_ node.
+
+ It sucks, but it _should_ work.
+ */
+ total_name_size = JFFS_PAD(f->nsize);
D1(printk("jffs_garbage_collect_next(): \"%s\", "
- "ino: %u, version: %u\n",
- (f->name ? f->name : ""), node->ino, node->version));
+ "ino: %u, version: %u, location 0x%x, dsize %u\n",
+ (f->name ? f->name : ""), node->ino, node->version,
+ node->fm->offset, node->data_size));
- /* Compute how much we want to rewrite at the moment. */
+ /* Compute how many data it's possible to rewrite at the moment. */
data_size = f->size - node->data_offset;
- total_name_size = f->nsize + JFFS_GET_PAD_BYTES(f->nsize);
+
+ /* And from that, the total size of the chunk we want to write */
size = sizeof(struct jffs_raw_inode) + total_name_size
+ data_size + JFFS_GET_PAD_BYTES(data_size);
- D2(printk(" total_name_size: %u\n", total_name_size));
- D2(printk(" data_size: %u\n", data_size));
- D2(printk(" size: %u\n", size));
- D2(printk(" f->nsize: %u\n", f->nsize));
- D2(printk(" f->size: %u\n", f->size));
- D2(printk(" node->data_offset: %u\n", node->data_offset));
- D2(printk(" free_chunk_size1: %u\n", free_chunk_size1));
- D2(printk(" free_chunk_size2: %u\n", free_chunk_size2));
- D2(printk(" node->fm->offset: 0x%08x\n", node->fm->offset));
-
+ /* If that's more than max_chunk_size, reduce it accordingly */
if (size > fmc->max_chunk_size) {
size = fmc->max_chunk_size;
data_size = size - sizeof(struct jffs_raw_inode)
- total_name_size;
}
+
+ /* If we're asking to take up more space than free_chunk_size1
+ but we _could_ fit in it, shrink accordingly.
+ */
if (size > free_chunk_size1) {
if (free_chunk_size1 <
- (sizeof(struct jffs_raw_inode) + f->nsize + BLOCK_SIZE)) {
+ (sizeof(struct jffs_raw_inode) + total_name_size + BLOCK_SIZE)){
/* The space left is too small to be of any
use really. */
struct jffs_fm *dirty_fm
@@ -2482,32 +2597,81 @@ jffs_garbage_collect_next(struct jffs_control *c)
"jffs_garbage_collect_next: "
"Failed to allocate `dirty' "
"flash memory!\n");
- return -1;
+ err = -1;
+ goto jffs_garbage_collect_next_end;
}
+ D1(printk("Dirtying end of flash - too small\n"));
jffs_write_dummy_node(c, dirty_fm);
+ err = 0;
goto jffs_garbage_collect_next_end;
}
+ D1(printk("Reducing size of new node from %d to %d to avoid "
+ " exceeding free_chunk_size1\n",
+ size, free_chunk_size1));
size = free_chunk_size1;
data_size = size - sizeof(struct jffs_raw_inode)
- total_name_size;
}
- D2(printk(" size: %u (again)\n", size));
- if (free_size - size < fmc->sector_size) {
- /* Just rewrite that node (or even less). */
- jffs_rewrite_data(f, node,
- jffs_min(node->data_size, data_size));
- }
- else {
- size -= (sizeof(struct jffs_raw_inode) + f->nsize);
- jffs_rewrite_data(f, node, data_size);
- }
+ /* Calculate the amount of space needed to hold the nodes
+ which are remaining in the tail */
+ space_needed = fmc->min_free_size - (node->fm->offset % fmc->sector_size);
+
+ /* From that, calculate how much 'extra' space we can use to
+ increase the size of the node we're writing from the size
+ of the node we're obsoleting
+ */
+ if (space_needed > fmc->free_size) {
+ /* If we've gone below min_free_size for some reason,
+ don't fuck up. This is why we have
+ min_free_size > sector_size. Whinge about it though,
+ just so I can convince myself my maths is right.
+ */
+ D1(printk(KERN_WARNING "jffs_garbage_collect_next(): "
+ "space_needed %d exceeded free_size %d\n",
+ space_needed, fmc->free_size));
+ extra_available = 0;
+ } else {
+ extra_available = fmc->free_size - space_needed;
+ }
+
+ /* Check that we don't use up any more 'extra' space than
+ what's available */
+ if (size > JFFS_PAD(node->data_size) + total_name_size +
+ sizeof(struct jffs_raw_inode) + extra_available) {
+ D1(printk("Reducing size of new node from %d to %ld to avoid "
+ "catching our tail\n", size,
+ JFFS_PAD(node->data_size) + JFFS_PAD(node->name_size) +
+ sizeof(struct jffs_raw_inode) + extra_available));
+ D1(printk("space_needed = %d, extra_available = %d\n",
+ space_needed, extra_available));
+
+ size = JFFS_PAD(node->data_size) + total_name_size +
+ sizeof(struct jffs_raw_inode) + extra_available;
+ data_size = size - sizeof(struct jffs_raw_inode)
+ - total_name_size;
+ };
+ D2(printk(" total_name_size: %u\n", total_name_size));
+ D2(printk(" data_size: %u\n", data_size));
+ D2(printk(" size: %u\n", size));
+ D2(printk(" f->nsize: %u\n", f->nsize));
+ D2(printk(" f->size: %u\n", f->size));
+ D2(printk(" node->data_offset: %u\n", node->data_offset));
+ D2(printk(" free_chunk_size1: %u\n", free_chunk_size1));
+ D2(printk(" free_chunk_size2: %u\n", free_chunk_size2));
+ D2(printk(" node->fm->offset: 0x%08x\n", node->fm->offset));
+
+ if ((err = jffs_rewrite_data(f, node, data_size))) {
+ printk(KERN_WARNING "jffs_rewrite_data() failed: %d\n", err);
+ return err;
+ }
+
jffs_garbage_collect_next_end:
D3(printk("jffs_garbage_collect_next: Leaving...\n"));
- return 0;
+ return err;
} /* jffs_garbage_collect_next */
@@ -2683,75 +2847,75 @@ jffs_try_to_erase(struct jffs_control *c)
for exemple). Of course there is a limit on how intelligent this garbage
collection can be. */
+
int
jffs_garbage_collect_now(struct jffs_control *c)
{
struct jffs_fmcontrol *fmc = c->fmc;
- long erased_total = 0;
- long erased;
+ long erased = 0;
int result = 0;
D1(int i = 1);
- D2(printk("***jffs_garbage_collect_now(): fmc->dirty_size = %u\n",
- fmc->dirty_size));
+ D2(printk("***jffs_garbage_collect_now(): fmc->dirty_size = %u, fmc->free_size = 0x%x\n, fcs1=0x%x, fcs2=0x%x",
+ fmc->dirty_size, fmc->free_size, jffs_free_size1(fmc), jffs_free_size2(fmc)));
D2(jffs_print_fmcontrol(fmc));
- down(&fmc->gclock);
+ // down(&fmc->gclock);
/* If it is possible to garbage collect, do so. */
-
- if (fmc->dirty_size >= fmc->sector_size) {
-
+
+ while (erased == 0) {
D1(printk("***jffs_garbage_collect_now(): round #%u, "
- "fmc->dirty_size = %u\n", i++, fmc->dirty_size));
+ "fmc->dirty_size = %u\n", i++, fmc->dirty_size));
D2(jffs_print_fmcontrol(fmc));
- /* At least one sector should be able to free now. */
if ((erased = jffs_try_to_erase(c)) < 0) {
printk(KERN_WARNING "JFFS: Error in "
"garbage collector.\n");
result = erased;
goto gc_end;
}
- else if (erased == 0) {
- __u32 free_size = fmc->flash_size
- - (fmc->used_size
- + fmc->dirty_size);
-
- if (free_size > 0) {
- /* Let's dare to make a garbage collect. */
- if ((result = jffs_garbage_collect_next(c))
- < 0) {
- printk(KERN_ERR "JFFS: Something "
- "has gone seriously wrong "
- "with a garbage collect.\n");
- goto gc_end;
- }
- }
- else {
- /* What should we do here? */
- D(printk(" jffs_garbage_collect_now(): "
- "erased: %ld, free_size: %u\n",
- erased, free_size));
- result = -1;
- goto gc_end;
- }
+ if (erased)
+ break;
+
+ if (fmc->free_size == 0) {
+ /* Argh */
+ printk(KERN_ERR "jffs_garbage_collect_now(): free_size == 0. This is BAD.\n");
+ result = -ENOSPC;
+ break;
+ }
+
+ if (fmc->dirty_size < fmc->sector_size) {
+ /* Actually, we _may_ have been able to free some,
+ * if there are many overlapping nodes which aren't
+ * actually marked dirty because they still have
+ * some valid data in each.
+ */
+ result = -ENOSPC;
+ break;
+ }
+
+ /* Let's dare to make a garbage collect. */
+ if ((result = jffs_garbage_collect_next(c)) < 0) {
+ printk(KERN_ERR "JFFS: Something "
+ "has gone seriously wrong "
+ "with a garbage collect.\n");
+ goto gc_end;
}
D1(printk(" jffs_garbage_collect_now(): erased: %ld\n", erased));
- erased_total += erased;
DJM(jffs_print_memory_allocation_statistics());
}
-
+
gc_end:
- up(&fmc->gclock);
+ // up(&fmc->gclock);
D3(printk(" jffs_garbage_collect_now(): Leaving...\n"));
- D1(if (erased_total) {
- printk("erased_total = %ld\n", erased_total);
+ D1(if (erased) {
+ printk("jffs_g_c_now(): erased = %ld\n", erased);
jffs_print_fmcontrol(fmc);
});
- if (!erased_total && !result)
+ if (!erased && !result)
return -ENOSPC;
return result;
@@ -2766,17 +2930,15 @@ gc_end:
*/
static inline int thread_should_wake (struct jffs_control *c)
{
- __u32 nfree = c->fmc->flash_size - c->fmc->used_size - c->fmc->dirty_size;
-
D1(printk (KERN_NOTICE "thread_should_wake(): free=%d, dirty=%d, blocksize=%d.\n",
- nfree, c->fmc->dirty_size, c->fmc->sector_size));
+ c->fmc->free_size, c->fmc->dirty_size, c->fmc->sector_size));
/* If there's not enough dirty space to free a block, there's no point. */
if (c->fmc->dirty_size < c->fmc->sector_size)
return 0;
/* If there are fewer free bytes than the threshold, GC */
- if (nfree < c->gc_minfree_threshold)
+ if (c->fmc->dirty_size < c->gc_minfree_threshold)
return 1;
/* If there are more dirty bytes than the threshold, GC */
@@ -2807,7 +2969,6 @@ jffs_garbage_collect_thread(void *ptr)
{
struct jffs_control *c = (struct jffs_control *) ptr;
struct jffs_fmcontrol *fmc = c->fmc;
- long erased_total = 0;
long erased;
int result = 0;
D1(int i = 1);
@@ -2821,7 +2982,7 @@ jffs_garbage_collect_thread(void *ptr)
current->pgrp = 1;
init_MUTEX_LOCKED(&c->gc_thread_sem); /* barrier */
spin_lock_irq(&current->sigmask_lock);
- siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGQUIT) | sigmask(SIGSTOP) | sigmask(SIGCONT));
+ siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
strcpy(current->comm, "jffs_gcd");
@@ -2829,6 +2990,7 @@ jffs_garbage_collect_thread(void *ptr)
D1(printk (KERN_NOTICE "jffs_garbage_collect_thread(): Starting infinite loop.\n"));
for (;;) {
+
/* See if we need to start gc. If we don't, go to sleep.
Current implementation is a BAD THING(tm). If we try
@@ -2836,7 +2998,7 @@ jffs_garbage_collect_thread(void *ptr)
for this thread to exit. We need to arrange to send it a
sig before the umount process sleeps.
*/
-
+
if (!thread_should_wake(c))
set_current_state (TASK_INTERRUPTIBLE);
@@ -2844,7 +3006,7 @@ jffs_garbage_collect_thread(void *ptr)
on immediately - we're a low priority
background task. */
- /* Put_super will send a SIGQUIT and then wait on the sem.
+ /* Put_super will send a SIGKILL and then wait on the sem.
*/
while (signal_pending(current)) {
siginfo_t info;
@@ -2861,8 +3023,8 @@ jffs_garbage_collect_thread(void *ptr)
schedule();
break;
- case SIGQUIT:
- D1(printk("jffs_garbage_collect_thread(): SIGQUIT received.\n"));
+ case SIGKILL:
+ D1(printk("jffs_garbage_collect_thread(): SIGKILL received.\n"));
c->gc_task = NULL;
up(&c->gc_thread_sem);
unlock_kernel();
@@ -2872,69 +3034,44 @@ jffs_garbage_collect_thread(void *ptr)
D1(printk (KERN_NOTICE "jffs_garbage_collect_thread(): collecting.\n"));
-// printk (KERN_NOTICE "free=%d, dirty=%d, blocksize=%ld.\n", count_free_bytes(c), count_dirty_bytes(c), c->sb->s_blocksize);
- D2(printk("***jffs_garbage_collect_thread(): fmc->dirty_size = %u\n",
- fmc->dirty_size));
- D2(jffs_print_fmcontrol(fmc));
-
if (fmc->dirty_size < fmc->sector_size) {
- printk(KERN_WARNING "jffs_garbage_collect_thread with insufficient dirty space (0x%x)\n", fmc->dirty_size);
+ D1(printk(KERN_WARNING "jffs_garbage_collect_thread with insufficient dirty space (0x%x)\n", fmc->dirty_size));
continue;
}
- down(&c->fmc->gclock);
-
+ D3(printk (KERN_NOTICE "g_c_thread(): down biglock\n"));
+ down(&fmc->biglock);
+
D1(printk("***jffs_garbage_collect_thread(): round #%u, "
"fmc->dirty_size = %u\n", i++, fmc->dirty_size));
D2(jffs_print_fmcontrol(fmc));
-
- /* At least one sector should be able to free now. */
+
if ((erased = jffs_try_to_erase(c)) < 0) {
printk(KERN_WARNING "JFFS: Error in "
- "garbage collector.\n");
- result = erased;
+ "garbage collector: %ld.\n", erased);
+ }
+
+ if (erased)
+ goto gc_end;
+
+ if (fmc->free_size == 0) {
+ /* Argh. Might as well commit suicide. */
+ printk(KERN_ERR "jffs_garbage_collect_thread(): free_size == 0. This is BAD.\n");
+ send_sig(SIGQUIT, c->gc_task, 1);
+ // panic()
goto gc_end;
}
- else if (erased == 0) {
- __u32 free_size = fmc->flash_size
- - (fmc->used_size
- + fmc->dirty_size);
-
- if (free_size > 0) {
- /* Let's dare to make a garbage collect. */
- if ((result = jffs_garbage_collect_next(c))
- < 0) {
- printk(KERN_ERR "JFFS: Something "
- "has gone seriously wrong "
- "with a garbage collect.\n");
- goto gc_end;
- }
- }
- else {
- /* What should we do here? */
- D(printk(" jffs_garbage_collect(): "
- "erased: %ld, free_size: %u\n",
- erased, free_size));
- result = -1;
- goto gc_end;
- }
+
+ /* Let's dare to make a garbage collect. */
+ if ((result = jffs_garbage_collect_next(c)) < 0) {
+ printk(KERN_ERR "JFFS: Something "
+ "has gone seriously wrong "
+ "with a garbage collect: %d\n", result);
}
-
- D1(printk(" jffs_garbage_collect(): erased: %ld\n", erased));
- erased_total += erased;
- DJM(jffs_print_memory_allocation_statistics());
-
gc_end:
- up(&c->fmc->gclock);
-
- D3(printk(" jffs_garbage_collect(): Leaving...\n"));
- D1(if (erased_total) {
- printk("erased_total = %ld\n", erased_total);
- jffs_print_fmcontrol(fmc);
- });
-
+ D3(printk (KERN_NOTICE "g_c_thread(): up biglock\n"));
+ up(&fmc->biglock);
} /* for (;;) */
} /* jffs_garbage_collect_thread() */
-
diff --git a/fs/jffs/intrep.h b/fs/jffs/intrep.h
index d4638af20..f10a994b4 100644
--- a/fs/jffs/intrep.h
+++ b/fs/jffs/intrep.h
@@ -10,7 +10,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * $Id: intrep.h,v 1.6 2000/08/04 14:29:17 dwmw2 Exp $
+ * $Id: intrep.h,v 1.11 2000/08/17 22:46:46 bmatthews Exp $
*
*/
@@ -46,8 +46,9 @@ int jffs_file_count(struct jffs_file *f);
int jffs_write_node(struct jffs_control *c, struct jffs_node *node,
struct jffs_raw_inode *raw_inode,
- const char *name, const unsigned char *buf);
-int jffs_read_data(struct jffs_file *f, char *buf, __u32 read_offset, __u32 size);
+ const char *name, const unsigned char *buf,
+ int recoverable, struct jffs_file *f);
+int jffs_read_data(struct jffs_file *f, unsigned char *buf, __u32 read_offset, __u32 size);
/* Garbage collection stuff. */
int jffs_garbage_collect_thread(void *c);
@@ -55,19 +56,22 @@ void jffs_garbage_collect_trigger(struct jffs_control *c);
int jffs_garbage_collect_now(struct jffs_control *c);
/* Is there enough space on the flash? */
-static inline int JFFS_ENOUGH_SPACE(struct jffs_control *c)
+static inline int JFFS_ENOUGH_SPACE(struct jffs_control *c, __u32 space)
{
struct jffs_fmcontrol *fmc = c->fmc;
while (1) {
if ((fmc->flash_size - (fmc->used_size + fmc->dirty_size))
- >= fmc->min_free_size) {
+ >= fmc->min_free_size + space) {
return 1;
}
if (fmc->dirty_size < fmc->sector_size)
return 0;
- jffs_garbage_collect_now(c);
+ if (jffs_garbage_collect_now(c)) {
+ D1(printk("JFFS_ENOUGH_SPACE: jffs_garbage_collect_now() failed.\n"));
+ return 0;
+ }
}
}
diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c
index 3140b8a53..b9bbeb4a9 100644
--- a/fs/jffs/jffs_fm.c
+++ b/fs/jffs/jffs_fm.c
@@ -10,7 +10,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * $Id: jffs_fm.c,v 1.14 2000/08/09 14:26:35 dwmw2 Exp $
+ * $Id: jffs_fm.c,v 1.18 2000/08/21 10:41:45 dwmw2 Exp $
*
* Ported to Linux 2.3.x and MTD:
* Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB
@@ -57,17 +57,26 @@ jffs_build_begin(struct jffs_control *c, kdev_t dev)
fmc->used_size = 0;
fmc->dirty_size = 0;
+ fmc->free_size = mtd->size;
fmc->sector_size = mtd->erasesize;
fmc->max_chunk_size = fmc->sector_size >> 1;
- fmc->min_free_size = (fmc->sector_size << 1) - fmc->max_chunk_size;
+ /* min_free_size:
+ 1 sector, obviously.
+ + 1 x max_chunk_size, for when a nodes overlaps the end of a sector
+ + 1 x max_chunk_size again, which ought to be enough to handle
+ the case where a rename causes a name to grow, and GC has
+ to write out larger nodes than the ones it's obsoleting.
+ We should fix it so it doesn't have to write the name
+ _every_ time. Later.
+ */
+ fmc->min_free_size = fmc->sector_size << 1;
fmc->mtd = mtd;
- init_MUTEX(&fmc->gclock);
fmc->c = c;
fmc->head = 0;
fmc->tail = 0;
fmc->head_extra = 0;
fmc->tail_extra = 0;
- init_MUTEX(&fmc->wlock);
+ init_MUTEX(&fmc->biglock);
return fmc;
}
@@ -203,6 +212,11 @@ jffs_fmalloc(struct jffs_fmcontrol *fmc, __u32 size, struct jffs_node *node,
free_chunk_size1 = jffs_free_size1(fmc);
free_chunk_size2 = jffs_free_size2(fmc);
+ if (free_chunk_size1 + free_chunk_size2 != fmc->free_size) {
+ printk(KERN_WARNING "Free size accounting screwed\n");
+ printk(KERN_WARNING "free_chunk_size1 == 0x%x, free_chunk_size2 == 0x%x, fmc->free_size == 0x%x\n", free_chunk_size1, free_chunk_size2, fmc->free_size);
+ }
+
D3(printk("jffs_fmalloc(): free_chunk_size1 = %u, "
"free_chunk_size2 = %u\n",
free_chunk_size1, free_chunk_size2));
@@ -240,6 +254,7 @@ jffs_fmalloc(struct jffs_fmcontrol *fmc, __u32 size, struct jffs_node *node,
fm->offset = fmc->flash_start;
}
fm->size = size;
+ fmc->free_size -= size;
fmc->used_size += size;
}
else if (size > free_chunk_size2) {
@@ -253,6 +268,7 @@ jffs_fmalloc(struct jffs_fmcontrol *fmc, __u32 size, struct jffs_node *node,
fm->offset = fmc->tail->offset + fmc->tail->size;
fm->size = free_chunk_size1;
fm->nodes = 0;
+ fmc->free_size -= fm->size;
fmc->dirty_size += fm->size; /* Changed by simonk. This seemingly fixes a
bug that caused infinite garbage collection.
It previously set fmc->dirty_size to size (which is the
@@ -380,10 +396,12 @@ jffs_fmalloced(struct jffs_fmcontrol *fmc, __u32 offset, __u32 size,
fm->nodes->node = node;
fm->nodes->next = 0;
fmc->used_size += size;
+ fmc->free_size -= size;
}
else {
/* If there is no node, then this is just a chunk of dirt. */
fmc->dirty_size += size;
+ fmc->free_size -= size;
}
if (fmc->head_extra) {
@@ -505,6 +523,7 @@ jffs_sync_erase(struct jffs_fmcontrol *fmc, int erased_size)
});
fmc->dirty_size -= erased_size;
+ fmc->free_size += erased_size;
for (fm = fmc->head; fm && (erased_size > 0);) {
if (erased_size >= fm->size) {
@@ -701,6 +720,7 @@ jffs_print_fmcontrol(struct jffs_fmcontrol *fmc)
D(printk(" %u, /* flash_size */\n", fmc->flash_size));
D(printk(" %u, /* used_size */\n", fmc->used_size));
D(printk(" %u, /* dirty_size */\n", fmc->dirty_size));
+ D(printk(" %u, /* free_size */\n", fmc->free_size));
D(printk(" %u, /* sector_size */\n", fmc->sector_size));
D(printk(" %u, /* min_free_size */\n", fmc->min_free_size));
D(printk(" %u, /* max_chunk_size */\n", fmc->max_chunk_size));
diff --git a/fs/jffs/jffs_fm.h b/fs/jffs/jffs_fm.h
index 82077d9d1..2bac0cb01 100644
--- a/fs/jffs/jffs_fm.h
+++ b/fs/jffs/jffs_fm.h
@@ -10,7 +10,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * $Id: jffs_fm.h,v 1.7 2000/08/08 09:10:39 dwmw2 Exp $
+ * $Id: jffs_fm.h,v 1.10 2000/08/17 15:42:44 dwmw2 Exp $
*
* Ported to Linux 2.3.x and MTD:
* Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB
@@ -62,7 +62,7 @@
#define JFFS_GET_PAD_BYTES(size) ((JFFS_ALIGN_SIZE \
- ((__u32)(size) % JFFS_ALIGN_SIZE)) \
% JFFS_ALIGN_SIZE)
-
+#define JFFS_PAD(size) ( (size + (JFFS_ALIGN_SIZE-1)) & ~(JFFS_ALIGN_SIZE-1) )
struct jffs_node_ref
{
struct jffs_node *node;
@@ -86,18 +86,18 @@ struct jffs_fmcontrol
__u32 flash_size;
__u32 used_size;
__u32 dirty_size;
+ __u32 free_size;
__u32 sector_size;
__u32 min_free_size; /* The minimum free space needed to be able
to perform garbage collections. */
__u32 max_chunk_size; /* The maximum size of a chunk of data. */
struct mtd_info *mtd;
- struct semaphore gclock;
struct jffs_control *c;
struct jffs_fm *head;
struct jffs_fm *tail;
struct jffs_fm *head_extra;
struct jffs_fm *tail_extra;
- struct semaphore wlock;
+ struct semaphore biglock;
};
/* Notice the two members head_extra and tail_extra in the jffs_control
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index a3a4f072f..820bc4c7b 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -168,6 +168,7 @@ reclaimer(void *ptr)
* reclaim is in progress */
lock_kernel();
lockd_up();
+ down(&file_lock_sem);
/* First, reclaim all locks that have been granted previously. */
restart:
@@ -185,6 +186,7 @@ restart:
}
tmp = tmp->next;
}
+ up(&file_lock_sem);
host->h_reclaiming = 0;
wake_up(&host->h_gracewait);
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index a5ec6c774..c60f48da1 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -47,7 +47,6 @@ nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
struct nlm_args *argp = &req->a_args;
struct nlm_lock *lock = &argp->lock;
- memset(argp, 0, sizeof(*argp));
nlmclnt_next_cookie(&argp->cookie);
argp->state = nsm_local_state;
memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry), sizeof(struct nfs_fh));
@@ -55,7 +54,7 @@ nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
lock->oh.data = req->a_owner;
lock->oh.len = sprintf(req->a_owner, "%d@%s",
current->pid, system_utsname.nodename);
- lock->fl = *fl;
+ locks_copy_lock(&lock->fl, fl);
}
/*
@@ -157,7 +156,9 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
call->a_flags = RPC_TASK_ASYNC;
} else {
spin_unlock_irqrestore(&current->sigmask_lock, flags);
- call->a_flags = 0;
+ memset(call, 0, sizeof(*call));
+ locks_init_lock(&call->a_args.lock.fl);
+ locks_init_lock(&call->a_res.lock.fl);
}
call->a_host = host;
@@ -214,8 +215,12 @@ nlmclnt_alloc_call(void)
while (!signalled()) {
call = (struct nlm_rqst *) kmalloc(sizeof(struct nlm_rqst), GFP_KERNEL);
- if (call)
+ if (call) {
+ memset(call, 0, sizeof(*call));
+ locks_init_lock(&call->a_args.lock.fl);
+ locks_init_lock(&call->a_res.lock.fl);
return call;
+ }
printk("nlmclnt_alloc_call: failed, waiting for memory\n");
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(5*HZ);
@@ -389,7 +394,7 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
* Report the conflicting lock back to the application.
* FIXME: Is it OK to report the pid back as well?
*/
- memcpy(fl, &req->a_res.lock.fl, sizeof(*fl));
+ locks_copy_lock(fl, &req->a_res.lock.fl);
/* fl->fl_pid = 0; */
} else {
return nlm_stat_to_errno(req->a_res.status);
@@ -476,6 +481,9 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
int status;
req = &reqst;
+ memset(req, 0, sizeof(*req));
+ locks_init_lock(&req->a_args.lock.fl);
+ locks_init_lock(&req->a_res.lock.fl);
req->a_host = host;
req->a_flags = 0;
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index a18c2d109..f14c9fcdf 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -29,8 +29,8 @@
#define NLM_HOST_ADDR(sv) (&(sv)->s_nlmclnt->cl_xprt->addr)
static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH];
-static unsigned long next_gc = 0;
-static int nrhosts = 0;
+static unsigned long next_gc;
+static int nrhosts;
static DECLARE_MUTEX(nlm_host_sema);
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index c9e4b4b17..951ecbeaa 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -39,12 +39,12 @@
#define ALLOWED_SIGS (sigmask(SIGKILL))
extern struct svc_program nlmsvc_program;
-struct nlmsvc_binding * nlmsvc_ops = NULL;
+struct nlmsvc_binding * nlmsvc_ops;
static DECLARE_MUTEX(nlmsvc_sema);
-static unsigned int nlmsvc_users = 0;
-static pid_t nlmsvc_pid = 0;
-unsigned long nlmsvc_grace_period = 0;
-unsigned long nlmsvc_timeout = 0;
+static unsigned int nlmsvc_users;
+static pid_t nlmsvc_pid;
+unsigned long nlmsvc_grace_period;
+unsigned long nlmsvc_timeout;
static DECLARE_MUTEX_LOCKED(lockd_start);
static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
@@ -53,7 +53,7 @@ static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
* Currently the following can be set only at insmod time.
* Ideally, they would be accessible through the sysctl interface.
*/
-unsigned long nlm_grace_period = 0;
+unsigned long nlm_grace_period;
unsigned long nlm_timeout = LOCKD_DFLT_TIMEO;
/*
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 56c8d8173..a175d39eb 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -170,6 +170,8 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
if (!(block = (struct nlm_block *) kmalloc(sizeof(*block), GFP_KERNEL)))
goto failed;
memset(block, 0, sizeof(*block));
+ locks_init_lock(&block->b_call.a_args.lock.fl);
+ locks_init_lock(&block->b_call.a_res.lock.fl);
/* Set notifier function for VFS, and init args */
lock->fl.fl_notify = nlmsvc_notify_blocked;
@@ -347,7 +349,7 @@ again:
/* Append to list of blocked */
nlmsvc_insert_block(block, NLM_NEVER);
- if (!list_empty(&block->b_call.a_args.lock.fl.fl_block)) {
+ if (list_empty(&block->b_call.a_args.lock.fl.fl_list)) {
/* Now add block to block list of the conflicting lock
if we haven't done so. */
dprintk("lockd: blocking on this lock.\n");
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
index 4b34b9786..ab06a5d31 100644
--- a/fs/lockd/svcshare.c
+++ b/fs/lockd/svcshare.c
@@ -54,7 +54,6 @@ nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
share->s_owner.len = oh->len;
share->s_next = file->f_shares;
file->f_shares = share;
- file->f_count += 1;
update:
share->s_access = argp->fsm_access;
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index d93ed2ac5..062191b9a 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -129,7 +129,7 @@ nlm_decode_lock(u32 *p, struct nlm_lock *lock)
|| !(p = nlm_decode_oh(p, &lock->oh)))
return NULL;
- memset(fl, 0, sizeof(*fl));
+ locks_init_lock(fl);
fl->fl_owner = current->files;
fl->fl_pid = ntohl(*p++);
fl->fl_flags = FL_POSIX;
@@ -314,6 +314,7 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
int len;
memset(lock, 0, sizeof(*lock));
+ locks_init_lock(&lock->fl);
lock->fl.fl_pid = ~(u32) 0;
if (!(p = nlm_decode_cookie(p, &argp->cookie))
@@ -430,6 +431,7 @@ nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
s32 start, len, end;
memset(&resp->lock, 0, sizeof(resp->lock));
+ locks_init_lock(fl);
excl = ntohl(*p++);
fl->fl_pid = ntohl(*p++);
if (!(p = nlm_decode_oh(p, &resp->lock.oh)))
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index 7ffa0a433..739387ab9 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -131,7 +131,7 @@ nlm4_decode_lock(u32 *p, struct nlm_lock *lock)
|| !(p = nlm4_decode_oh(p, &lock->oh)))
return NULL;
- memset(fl, 0, sizeof(*fl));
+ locks_init_lock(fl);
fl->fl_owner = current->files;
fl->fl_pid = ntohl(*p++);
fl->fl_flags = FL_POSIX;
@@ -322,6 +322,7 @@ nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
int len;
memset(lock, 0, sizeof(*lock));
+ locks_init_lock(&lock->fl);
lock->fl.fl_pid = ~(u32) 0;
if (!(p = nlm4_decode_cookie(p, &argp->cookie))
@@ -438,6 +439,7 @@ nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
s64 start, end, len;
memset(&resp->lock, 0, sizeof(resp->lock));
+ locks_init_lock(fl);
excl = ntohl(*p++);
fl->fl_pid = ntohl(*p++);
if (!(p = nlm4_decode_oh(p, &resp->lock.oh)))
diff --git a/fs/locks.c b/fs/locks.c
index ae4cc8069..95310133d 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1,3 +1,4 @@
+#define MSNFS /* HACK HACK */
/*
* linux/fs/locks.c
*
@@ -108,25 +109,44 @@
* Use generic list implementation from <linux/list.h>.
* Sped up posix_locks_deadlock by only considering blocked locks.
* Matthew Wilcox <willy@thepuffingroup.com>, March, 2000.
+ *
+ * Leases and LOCK_MAND
+ * Matthew Wilcox <willy@linuxcare.com>, June, 2000.
+ * Stephen Rothwell <sfr@linuxcare.com>, June, 2000.
*/
#include <linux/malloc.h>
#include <linux/file.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <asm/semaphore.h>
#include <asm/uaccess.h>
+DECLARE_MUTEX(file_lock_sem);
+
+#define acquire_fl_sem() down(&file_lock_sem)
+#define release_fl_sem() up(&file_lock_sem)
+
+int leases_enable = 1;
+int lease_break_time = 45;
+
LIST_HEAD(file_lock_list);
static LIST_HEAD(blocked_list);
static kmem_cache_t *filelock_cache;
/* Allocate an empty lock structure. */
-static struct file_lock *locks_alloc_lock(void)
+static struct file_lock *locks_alloc_lock(int account)
{
struct file_lock *fl;
+ if (account && current->locks >= current->rlim[RLIMIT_LOCKS].rlim_cur)
+ return NULL;
fl = kmem_cache_alloc(filelock_cache, SLAB_KERNEL);
+ if (fl)
+ current->locks++;
return fl;
}
@@ -137,19 +157,38 @@ static inline void locks_free_lock(struct file_lock *fl)
BUG();
return;
}
-
+ current->locks--;
if (waitqueue_active(&fl->fl_wait))
panic("Attempting to free lock with active wait queue");
if (!list_empty(&fl->fl_block))
panic("Attempting to free lock with active block list");
- if (!list_empty(&fl->fl_link))
+ if (!list_empty(&fl->fl_link) || !list_empty(&fl->fl_list))
panic("Attempting to free lock on active lock list");
kmem_cache_free(filelock_cache, fl);
}
+void locks_init_lock(struct file_lock *fl)
+{
+ INIT_LIST_HEAD(&fl->fl_link);
+ INIT_LIST_HEAD(&fl->fl_block);
+ INIT_LIST_HEAD(&fl->fl_list);
+ init_waitqueue_head(&fl->fl_wait);
+ fl->fl_next = NULL;
+ fl->fl_fasync = NULL;
+ fl->fl_owner = 0;
+ fl->fl_pid = 0;
+ fl->fl_file = NULL;
+ fl->fl_flags = 0;
+ fl->fl_type = 0;
+ fl->fl_start = fl->fl_end = 0;
+ fl->fl_notify = NULL;
+ fl->fl_insert = NULL;
+ fl->fl_remove = NULL;
+}
+
/*
* Initialises the fields of the file lock which are invariant for
* free file_locks.
@@ -162,16 +201,13 @@ static void init_once(void *foo, kmem_cache_t *cache, unsigned long flags)
SLAB_CTOR_CONSTRUCTOR)
return;
- lock->fl_next = NULL;
- INIT_LIST_HEAD(&lock->fl_link);
- INIT_LIST_HEAD(&lock->fl_block);
- init_waitqueue_head(&lock->fl_wait);
+ locks_init_lock(lock);
}
/*
* Initialize a new lock from an existing file_lock structure.
*/
-static void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
+void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
{
new->fl_owner = fl->fl_owner;
new->fl_pid = fl->fl_pid;
@@ -189,7 +225,7 @@ static void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
/* Fill in a file_lock structure with an appropriate FLOCK lock. */
static struct file_lock *flock_make_lock(struct file *filp, unsigned int type)
{
- struct file_lock *fl = locks_alloc_lock();
+ struct file_lock *fl = locks_alloc_lock(1);
if (fl == NULL)
return NULL;
@@ -207,6 +243,20 @@ static struct file_lock *flock_make_lock(struct file *filp, unsigned int type)
return fl;
}
+static int assign_type(struct file_lock *fl, int type)
+{
+ switch (type) {
+ case F_RDLCK:
+ case F_WRLCK:
+ case F_UNLCK:
+ fl->fl_type = type;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
* style lock.
*/
@@ -234,6 +284,8 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
fl->fl_end = start + l->l_len - 1;
if (l->l_len > 0 && fl->fl_end < 0)
return (0);
+ if (fl->fl_end > OFFT_OFFSET_MAX)
+ return 0;
fl->fl_start = start; /* we record the absolute position */
if (l->l_len == 0)
fl->fl_end = OFFSET_MAX;
@@ -246,17 +298,7 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
fl->fl_insert = NULL;
fl->fl_remove = NULL;
- switch (l->l_type) {
- case F_RDLCK:
- case F_WRLCK:
- case F_UNLCK:
- fl->fl_type = l->l_type;
- break;
- default:
- return (0);
- }
-
- return (1);
+ return (assign_type(fl, l->l_type) == 0);
}
#if BITS_PER_LONG == 32
@@ -310,6 +352,32 @@ static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl,
}
#endif
+/* Allocate a file_lock initialised to this type of lease */
+static int lease_alloc(struct file *filp, int type, struct file_lock **flp)
+{
+ struct file_lock *fl = locks_alloc_lock(1);
+ if (fl == NULL)
+ return -ENOMEM;
+
+ fl->fl_owner = current->files;
+ fl->fl_pid = current->pid;
+
+ fl->fl_file = filp;
+ fl->fl_flags = FL_LEASE;
+ if (assign_type(fl, type) != 0) {
+ locks_free_lock(fl);
+ return -EINVAL;
+ }
+ fl->fl_start = 0;
+ fl->fl_end = OFFSET_MAX;
+ fl->fl_notify = NULL;
+ fl->fl_insert = NULL;
+ fl->fl_remove = NULL;
+
+ *flp = fl;
+ return 0;
+}
+
/* Check if two locks overlap each other.
*/
static inline int locks_overlap(struct file_lock *fl1, struct file_lock *fl2)
@@ -335,10 +403,11 @@ locks_same_owner(struct file_lock *fl1, struct file_lock *fl2)
*/
static void locks_delete_block(struct file_lock *waiter)
{
- list_del(&waiter->fl_block);
- INIT_LIST_HEAD(&waiter->fl_block);
+ list_del(&waiter->fl_list);
+ INIT_LIST_HEAD(&waiter->fl_list);
list_del(&waiter->fl_link);
INIT_LIST_HEAD(&waiter->fl_link);
+ waiter->fl_next = NULL;
}
/* Insert waiter into blocker's block list.
@@ -349,15 +418,15 @@ static void locks_delete_block(struct file_lock *waiter)
static void locks_insert_block(struct file_lock *blocker,
struct file_lock *waiter)
{
- if (!list_empty(&waiter->fl_block)) {
+ if (!list_empty(&waiter->fl_list)) {
printk(KERN_ERR "locks_insert_block: removing duplicated lock "
"(pid=%d %Ld-%Ld type=%d)\n", waiter->fl_pid,
waiter->fl_start, waiter->fl_end, waiter->fl_type);
locks_delete_block(waiter);
}
- list_add_tail(&waiter->fl_block, &blocker->fl_block);
- list_add(&waiter->fl_link, &blocked_list);
+ list_add_tail(&waiter->fl_list, &blocker->fl_block);
waiter->fl_next = blocker;
+ list_add(&waiter->fl_link, &blocked_list);
}
/* Wake up processes blocked waiting for blocker.
@@ -367,7 +436,7 @@ static void locks_insert_block(struct file_lock *blocker,
static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait)
{
while (!list_empty(&blocker->fl_block)) {
- struct file_lock *waiter = list_entry(blocker->fl_block.next, struct file_lock, fl_block);
+ struct file_lock *waiter = list_entry(blocker->fl_block.next, struct file_lock, fl_list);
/* N.B. Is it possible for the notify function to block?? */
if (waiter->fl_notify)
waiter->fl_notify(waiter);
@@ -402,10 +471,10 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
fl->fl_insert(fl);
}
-/* Delete a lock and free it.
- * First remove our lock from the active lock lists. Then call
- * locks_wake_up_blocks() to wake up processes that are blocked
- * waiting for this lock. Finally free the lock structure.
+/* Delete a lock and then free it.
+ * Remove our lock from the lock lists, wake up processes that are blocked
+ * waiting for this lock, notify the FS that the lock has been cleared and
+ * finally free the lock.
*/
static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
{
@@ -418,6 +487,12 @@ static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
list_del(&fl->fl_link);
INIT_LIST_HEAD(&fl->fl_link);
+ fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
+ if (fl->fl_fasync != NULL){
+ printk("locks_delete_lock: fasync == %p\n", fl->fl_fasync);
+ fl->fl_fasync = NULL;
+ }
+
if (fl->fl_remove)
fl->fl_remove(fl);
@@ -431,17 +506,14 @@ static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
}
/* Determine if lock sys_fl blocks lock caller_fl. Common functionality
- * checks for overlapping locks and shared/exclusive status.
+ * checks for shared/exclusive status of overlapping locks.
*/
static int locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
{
- if (!locks_overlap(caller_fl, sys_fl))
- return (0);
-
switch (caller_fl->fl_type) {
case F_RDLCK:
return (sys_fl->fl_type == F_WRLCK);
-
+
case F_WRLCK:
return (1);
@@ -465,6 +537,10 @@ static int posix_locks_conflict(struct file_lock *caller_fl, struct file_lock *s
locks_same_owner(caller_fl, sys_fl))
return (0);
+ /* Check whether they overlap */
+ if (!locks_overlap(caller_fl, sys_fl))
+ return 0;
+
return (locks_conflict(caller_fl, sys_fl));
}
@@ -479,21 +555,66 @@ static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *s
if (!(sys_fl->fl_flags & FL_FLOCK) ||
(caller_fl->fl_file == sys_fl->fl_file))
return (0);
+#ifdef MSNFS
+ if ((caller_fl->fl_type & LOCK_MAND) || (sys_fl->fl_type & LOCK_MAND))
+ return 0;
+#endif
return (locks_conflict(caller_fl, sys_fl));
}
+int interruptible_sleep_on_locked(wait_queue_head_t *fl_wait, struct semaphore *sem, int timeout)
+{
+ int result = 0;
+ wait_queue_t wait;
+ init_waitqueue_entry(&wait, current);
+
+ __add_wait_queue(fl_wait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+ up(sem);
+ if (timeout == 0)
+ schedule();
+ else
+ result = schedule_timeout(timeout);
+ if (signal_pending(current))
+ result = -ERESTARTSYS;
+ down(sem);
+ remove_wait_queue(fl_wait, &wait);
+ current->state = TASK_RUNNING;
+ return result;
+}
+
+static int locks_block_on(struct file_lock *blocker, struct file_lock *waiter)
+{
+ int result;
+ locks_insert_block(blocker, waiter);
+ result = interruptible_sleep_on_locked(&waiter->fl_wait, &file_lock_sem, 0);
+ locks_delete_block(waiter);
+ return result;
+}
+
+static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *waiter, int time)
+{
+ int result;
+ locks_insert_block(blocker, waiter);
+ result = interruptible_sleep_on_locked(&waiter->fl_wait, &file_lock_sem, time);
+ locks_delete_block(waiter);
+ return result;
+}
+
struct file_lock *
posix_test_lock(struct file *filp, struct file_lock *fl)
{
struct file_lock *cfl;
+ acquire_fl_sem();
for (cfl = filp->f_dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
if (!(cfl->fl_flags & FL_POSIX))
continue;
if (posix_locks_conflict(cfl, fl))
break;
}
+ release_fl_sem();
return (cfl);
}
@@ -528,9 +649,8 @@ static int posix_locks_deadlock(struct file_lock *caller_fl,
next_task:
if (caller_owner == blocked_owner && caller_pid == blocked_pid)
return 1;
- while (tmp != &blocked_list) {
+ list_for_each(tmp, &blocked_list) {
struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
- tmp = tmp->next;
if ((fl->fl_owner == blocked_owner)
&& (fl->fl_pid == blocked_pid)) {
fl = fl->fl_next;
@@ -550,14 +670,14 @@ int locks_mandatory_locked(struct inode *inode)
/*
* Search the lock list for this inode for any POSIX locks.
*/
- lock_kernel();
+ acquire_fl_sem();
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & FL_POSIX))
continue;
if (fl->fl_owner != owner)
break;
}
- unlock_kernel();
+ release_fl_sem();
return fl ? -EAGAIN : 0;
}
@@ -566,7 +686,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
size_t count)
{
struct file_lock *fl;
- struct file_lock *new_fl = locks_alloc_lock();
+ struct file_lock *new_fl = locks_alloc_lock(0);
int error;
new_fl->fl_owner = current->files;
@@ -578,36 +698,29 @@ int locks_mandatory_area(int read_write, struct inode *inode,
new_fl->fl_end = offset + count - 1;
error = 0;
- lock_kernel();
+ acquire_fl_sem();
repeat:
/* Search the lock list for this inode for locks that conflict with
* the proposed read/write.
*/
- for (fl = inode->i_flock; ; fl = fl->fl_next) {
- error = 0;
- if (!fl)
- break;
+ for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & FL_POSIX))
continue;
- /* Block for writes against a "read" lock,
- * and both reads and writes against a "write" lock.
- */
+ if (fl->fl_start > new_fl->fl_end)
+ break;
if (posix_locks_conflict(new_fl, fl)) {
error = -EAGAIN;
if (filp && (filp->f_flags & O_NONBLOCK))
break;
- error = -ERESTARTSYS;
- if (signal_pending(current))
- break;
error = -EDEADLK;
if (posix_locks_deadlock(new_fl, fl))
break;
-
- locks_insert_block(fl, new_fl);
- interruptible_sleep_on(&new_fl->fl_wait);
- locks_delete_block(new_fl);
-
+
+ error = locks_block_on(fl, new_fl);
+ if (error != 0)
+ break;
+
/*
* If we've been sleeping someone might have
* changed the permissions behind our back.
@@ -617,14 +730,14 @@ repeat:
goto repeat;
}
}
- unlock_kernel();
locks_free_lock(new_fl);
+ release_fl_sem();
return error;
}
-/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks at
- * the head of the list, but that's secret knowledge known only to the next
- * two functions.
+/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
+ * at the head of the list, but that's secret knowledge known only to
+ * flock_lock_file and posix_lock_file.
*/
static int flock_lock_file(struct file *filp, unsigned int lock_type,
unsigned int wait)
@@ -643,7 +756,7 @@ static int flock_lock_file(struct file *filp, unsigned int lock_type,
error = -ENOLCK;
new_fl = flock_make_lock(filp, lock_type);
if (!new_fl)
- goto out;
+ return error;
}
error = 0;
@@ -659,7 +772,7 @@ search:
}
before = &fl->fl_next;
}
- /* change means that we are changing the type of an existing lock, or
+ /* change means that we are changing the type of an existing lock,
* or else unlocking it.
*/
if (change) {
@@ -675,10 +788,6 @@ search:
goto out;
repeat:
- /* Check signals each time we start */
- error = -ERESTARTSYS;
- if (signal_pending(current))
- goto out;
for (fl = inode->i_flock; (fl != NULL) && (fl->fl_flags & FL_FLOCK);
fl = fl->fl_next) {
if (!flock_locks_conflict(new_fl, fl))
@@ -686,9 +795,9 @@ repeat:
error = -EAGAIN;
if (!wait)
goto out;
- locks_insert_block(fl, new_fl);
- interruptible_sleep_on(&new_fl->fl_wait);
- locks_delete_block(new_fl);
+ error = locks_block_on(fl, new_fl);
+ if (error != 0)
+ goto out;
goto repeat;
}
locks_insert_lock(&inode->i_flock, new_fl);
@@ -701,7 +810,13 @@ out:
return error;
}
-/* Add a POSIX style lock to a file.
+/**
+ * posix_lock_file:
+ * @filp: The file to apply the lock to
+ * @caller: The lock to be applied
+ * @wait: 1 to retry automatically, 0 to return -EAGAIN
+ *
+ * Add a POSIX style lock to a file.
* We merge adjacent locks whenever possible. POSIX locks are sorted by owner
* task, then by starting address
*
@@ -728,12 +843,13 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
* We may need two file_lock structures for this operation,
* so we get them in advance to avoid races.
*/
- new_fl = locks_alloc_lock();
- new_fl2 = locks_alloc_lock();
+ new_fl = locks_alloc_lock(0);
+ new_fl2 = locks_alloc_lock(0);
error = -ENOLCK; /* "no luck" */
if (!(new_fl && new_fl2))
goto out;
+ acquire_fl_sem();
if (caller->fl_type != F_UNLCK) {
repeat:
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
@@ -747,12 +863,10 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
error = -EDEADLK;
if (posix_locks_deadlock(caller, fl))
goto out;
- error = -ERESTARTSYS;
- if (signal_pending(current))
+
+ error = locks_block_on(fl, caller);
+ if (error != 0)
goto out;
- locks_insert_block(fl, caller);
- interruptible_sleep_on(&caller->fl_wait);
- locks_delete_block(caller);
goto repeat;
}
}
@@ -880,6 +994,7 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
locks_wake_up_blocks(left, 0);
}
out:
+ release_fl_sem();
/*
* Free any unused locks.
*/
@@ -891,6 +1006,10 @@ out:
}
static inline int flock_translate_cmd(int cmd) {
+#ifdef MSNFS
+ if (cmd & LOCK_MAND)
+ return cmd & (LOCK_MAND | LOCK_RW);
+#endif
switch (cmd &~ LOCK_NB) {
case LOCK_SH:
return F_RDLCK;
@@ -902,8 +1021,270 @@ static inline int flock_translate_cmd(int cmd) {
return -EINVAL;
}
-/* flock() system call entry point. Apply a FL_FLOCK style lock to
- * an open file descriptor.
+/**
+ * __get_lease - revoke all outstanding leases on file
+ * @inode: the inode of the file to return
+ * @mode: the open mode (read or write)
+ *
+ * get_lease (inlined for speed) has checked there already
+ * is a lease on this file. Leases are broken on a call to open()
+ * or truncate(). This function can sleep unless you
+ * specified %O_NONBLOCK to your open().
+ */
+int __get_lease(struct inode *inode, unsigned int mode)
+{
+ int error = 0, future;
+ struct file_lock *new_fl, *flock;
+ struct file_lock *fl;
+ int alloc_err;
+
+ alloc_err = lease_alloc(NULL, 0, &new_fl);
+
+ acquire_fl_sem();
+ flock = inode->i_flock;
+ if (flock->fl_type & F_INPROGRESS) {
+ if ((mode & O_NONBLOCK)
+ || (flock->fl_owner == current->files)) {
+ error = -EWOULDBLOCK;
+ goto out;
+ }
+ if (alloc_err != 0) {
+ error = alloc_err;
+ goto out;
+ }
+ do {
+ error = locks_block_on(flock, new_fl);
+ if (error != 0)
+ goto out;
+ flock = inode->i_flock;
+ if (!(flock && (flock->fl_flags & FL_LEASE)))
+ goto out;
+ } while (flock->fl_type & F_INPROGRESS);
+ }
+
+ if (mode & FMODE_WRITE) {
+ /* If we want write access, we have to revoke any lease. */
+ future = F_UNLCK | F_INPROGRESS;
+ } else if (flock->fl_type & F_WRLCK) {
+ /* Downgrade the exclusive lease to a read-only lease. */
+ future = F_RDLCK | F_INPROGRESS;
+ } else {
+ /* the existing lease was read-only, so we can read too. */
+ goto out;
+ }
+
+ if (alloc_err && (flock->fl_owner != current->files)) {
+ error = alloc_err;
+ goto out;
+ }
+
+ fl = flock;
+ do {
+ fl->fl_type = future;
+ fl = fl->fl_next;
+ } while (fl != NULL && (fl->fl_flags & FL_LEASE));
+
+ kill_fasync(&flock->fl_fasync, SIGIO, POLL_MSG);
+
+ if ((mode & O_NONBLOCK) || (flock->fl_owner == current->files)) {
+ error = -EWOULDBLOCK;
+ goto out;
+ }
+
+ if (lease_break_time > 0)
+ error = lease_break_time * HZ;
+ else
+ error = 0;
+restart:
+ error = locks_block_on_timeout(flock, new_fl, error);
+ if (error == 0) {
+ /* We timed out. Unilaterally break the lease. */
+ locks_delete_lock(&inode->i_flock, 0);
+ printk(KERN_WARNING "lease timed out\n");
+ } else if (error > 0) {
+ flock = inode->i_flock;
+ if (flock && (flock->fl_flags & FL_LEASE))
+ goto restart;
+ error = 0;
+ }
+
+out:
+ release_fl_sem();
+ if (!alloc_err)
+ locks_free_lock(new_fl);
+ return error;
+}
+
+/**
+ * lease_get_mtime
+ * @inode: the inode
+ *
+ * This is to force NFS clients to flush their caches for files with
+ * exclusive leases. The justification is that if someone has an
+ * exclusive lease, then they could be modifiying it.
+ */
+time_t lease_get_mtime(struct inode *inode)
+{
+ struct file_lock *flock = inode->i_flock;
+ if (flock && (flock->fl_flags & FL_LEASE) && (flock->fl_type & F_WRLCK))
+ return CURRENT_TIME;
+ return inode->i_mtime;
+}
+
+/**
+ * fcntl_getlease - Enquire what lease is currently active
+ * @filp: the file
+ *
+ * The value returned by this function will be one of
+ *
+ * %F_RDLCK to indicate a read-only (type II) lease is held.
+ *
+ * %F_WRLCK to indicate an exclusive lease is held.
+ *
+ * XXX: sfr & i disagree over whether F_INPROGRESS
+ * should be returned to userspace.
+ */
+int fcntl_getlease(struct file *filp)
+{
+ struct file_lock *fl;
+
+ fl = filp->f_dentry->d_inode->i_flock;
+ if ((fl == NULL) || ((fl->fl_flags & FL_LEASE) == 0))
+ return F_UNLCK;
+ return fl->fl_type & ~F_INPROGRESS;
+}
+
+/* We already had a lease on this file; just change its type */
+static int lease_modify(struct file_lock **before, int arg, int fd, struct file *filp)
+{
+ struct file_lock *fl = *before;
+ int error = assign_type(fl, arg);
+ if (error < 0)
+ goto out;
+
+ locks_wake_up_blocks(fl, 0);
+
+ if (arg == F_UNLCK) {
+ filp->f_owner.pid = 0;
+ filp->f_owner.uid = 0;
+ filp->f_owner.euid = 0;
+ filp->f_owner.signum = 0;
+ locks_delete_lock(before, 0);
+ fasync_helper(fd, filp, 0, &fl->fl_fasync);
+ }
+
+out:
+ return error;
+}
+
+/**
+ * fcntl_setlease - sets a lease on an open file
+ * @fd: open file descriptor
+ * @filp: file pointer
+ * @arg: type of lease to obtain
+ *
+ * Call this fcntl to establish a lease on the file.
+ * Note that you also need to call %F_SETSIG to
+ * receive a signal when the lease is broken.
+ */
+int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
+{
+ struct file_lock *fl, **before, **my_before = NULL;
+ struct dentry *dentry;
+ struct inode *inode;
+ int error, rdlease_count = 0, wrlease_count = 0;
+
+ dentry = filp->f_dentry;
+ inode = dentry->d_inode;
+
+ if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
+ return -EACCES;
+ if (!S_ISREG(inode->i_mode))
+ return -EINVAL;
+
+ /*
+ * FIXME: What about F_RDLCK and files open for writing?
+ */
+ if ((arg == F_WRLCK)
+ && ((atomic_read(&dentry->d_count) > 1)
+ || (atomic_read(&inode->i_count) > 1)))
+ return -EAGAIN;
+
+ before = &inode->i_flock;
+
+ acquire_fl_sem();
+
+ while ((fl = *before) != NULL) {
+ if (fl->fl_flags != FL_LEASE)
+ break;
+ if (fl->fl_file == filp)
+ my_before = before;
+ else if (fl->fl_type & F_WRLCK)
+ wrlease_count++;
+ else
+ rdlease_count++;
+ before = &fl->fl_next;
+ }
+
+ if ((arg == F_RDLCK && (wrlease_count > 0)) ||
+ (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0))) {
+ error = -EAGAIN;
+ goto out_unlock;
+ }
+
+ if (my_before != NULL) {
+ error = lease_modify(my_before, arg, fd, filp);
+ goto out_unlock;
+ }
+
+ if (arg == F_UNLCK) {
+ error = 0;
+ goto out_unlock;
+ }
+
+ if (!leases_enable) {
+ error = -EINVAL;
+ goto out_unlock;
+ }
+
+ error = lease_alloc(filp, arg, &fl);
+ if (error)
+ goto out_unlock;
+
+ error = fasync_helper(fd, filp, 1, &fl->fl_fasync);
+ if (error < 0) {
+ locks_free_lock(fl);
+ goto out_unlock;
+ }
+ fl->fl_next = *before;
+ *before = fl;
+ list_add(&fl->fl_link, &file_lock_list);
+ filp->f_owner.pid = current->pid;
+ filp->f_owner.uid = current->uid;
+ filp->f_owner.euid = current->euid;
+out_unlock:
+ release_fl_sem();
+ return error;
+}
+
+/**
+ * sys_flock: - flock() system call.
+ * @fd: the file descriptor to lock.
+ * @cmd: the type of lock to apply.
+ *
+ * Apply a %FL_FLOCK style lock to an open file descriptor.
+ * The @cmd can be one of
+ *
+ * %LOCK_SH -- a shared lock.
+ *
+ * %LOCK_EX -- an exclusive lock.
+ *
+ * %LOCK_UN -- remove an existing lock.
+ *
+ * %LOCK_MAND -- a `mandatory' flock. This exists to emulate Windows Share Modes.
+ *
+ * %LOCK_MAND can be combined with %LOCK_READ or %LOCK_WRITE to allow other
+ * processes read and write access respectively.
*/
asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
{
@@ -921,13 +1302,17 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
type = error;
error = -EBADF;
- if ((type != F_UNLCK) && !(filp->f_mode & 3))
+ if ((type != F_UNLCK)
+#ifdef MSNFS
+ && !(type & LOCK_MAND)
+#endif
+ && !(filp->f_mode & 3))
goto out_putf;
- lock_kernel();
+ acquire_fl_sem();
error = flock_lock_file(filp, type,
(cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
- unlock_kernel();
+ release_fl_sem();
out_putf:
fput(filp);
@@ -941,7 +1326,7 @@ out:
int fcntl_getlk(unsigned int fd, struct flock *l)
{
struct file *filp;
- struct file_lock *fl, *file_lock = locks_alloc_lock();
+ struct file_lock *fl, file_lock;
struct flock flock;
int error;
@@ -958,20 +1343,20 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
goto out;
error = -EINVAL;
- if (!flock_to_posix_lock(filp, file_lock, &flock))
+ if (!flock_to_posix_lock(filp, &file_lock, &flock))
goto out_putf;
if (filp->f_op->lock) {
- error = filp->f_op->lock(filp, F_GETLK, file_lock);
+ error = filp->f_op->lock(filp, F_GETLK, &file_lock);
if (error < 0)
goto out_putf;
else if (error == LOCK_USE_CLNT)
/* Bypass for NFS with no locking - 2.0.36 compat */
- fl = posix_test_lock(filp, file_lock);
+ fl = posix_test_lock(filp, &file_lock);
else
- fl = (file_lock->fl_type == F_UNLCK ? NULL : file_lock);
+ fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
} else {
- fl = posix_test_lock(filp, file_lock);
+ fl = posix_test_lock(filp, &file_lock);
}
flock.l_type = F_UNLCK;
@@ -1002,7 +1387,6 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
out_putf:
fput(filp);
out:
- locks_free_lock(file_lock);
return error;
}
@@ -1012,7 +1396,7 @@ out:
int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
{
struct file *filp;
- struct file_lock *file_lock = locks_alloc_lock();
+ struct file_lock *file_lock = locks_alloc_lock(0);
struct flock flock;
struct inode *inode;
int error;
@@ -1040,17 +1424,12 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
*/
if (IS_MANDLOCK(inode) &&
(inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
- struct vm_area_struct *vma;
struct address_space *mapping = inode->i_mapping;
- spin_lock(&mapping->i_shared_lock);
- for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) {
- if (!(vma->vm_flags & VM_MAYSHARE))
- continue;
- spin_unlock(&mapping->i_shared_lock);
+
+ if (mapping->i_mmap_shared != NULL) {
error = -EAGAIN;
goto out_putf;
}
- spin_unlock(&mapping->i_shared_lock);
}
error = -EINVAL;
@@ -1112,7 +1491,7 @@ out:
int fcntl_getlk64(unsigned int fd, struct flock64 *l)
{
struct file *filp;
- struct file_lock *fl, *file_lock = locks_alloc_lock();
+ struct file_lock *fl, file_lock;
struct flock64 flock;
int error;
@@ -1129,20 +1508,20 @@ int fcntl_getlk64(unsigned int fd, struct flock64 *l)
goto out;
error = -EINVAL;
- if (!flock64_to_posix_lock(filp, file_lock, &flock))
+ if (!flock64_to_posix_lock(filp, &file_lock, &flock))
goto out_putf;
if (filp->f_op->lock) {
- error = filp->f_op->lock(filp, F_GETLK, file_lock);
+ error = filp->f_op->lock(filp, F_GETLK, &file_lock);
if (error < 0)
goto out_putf;
else if (error == LOCK_USE_CLNT)
/* Bypass for NFS with no locking - 2.0.36 compat */
- fl = posix_test_lock(filp, file_lock);
+ fl = posix_test_lock(filp, &file_lock);
else
- fl = (file_lock->fl_type == F_UNLCK ? NULL : file_lock);
+ fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
} else {
- fl = posix_test_lock(filp, file_lock);
+ fl = posix_test_lock(filp, &file_lock);
}
flock.l_type = F_UNLCK;
@@ -1161,7 +1540,6 @@ int fcntl_getlk64(unsigned int fd, struct flock64 *l)
out_putf:
fput(filp);
out:
- locks_free_lock(file_lock);
return error;
}
@@ -1171,7 +1549,7 @@ out:
int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l)
{
struct file *filp;
- struct file_lock *file_lock = locks_alloc_lock();
+ struct file_lock *file_lock = locks_alloc_lock(0);
struct flock64 flock;
struct inode *inode;
int error;
@@ -1199,17 +1577,12 @@ int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l)
*/
if (IS_MANDLOCK(inode) &&
(inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
- struct vm_area_struct *vma;
struct address_space *mapping = inode->i_mapping;
- spin_lock(&mapping->i_shared_lock);
- for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) {
- if (!(vma->vm_flags & VM_MAYSHARE))
- continue;
- spin_unlock(&mapping->i_shared_lock);
+
+ if (mapping->i_mmap_shared != NULL) {
error = -EAGAIN;
goto out_putf;
}
- spin_unlock(&mapping->i_shared_lock);
}
error = -EINVAL;
@@ -1272,17 +1645,16 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
*/
return;
}
- lock_kernel();
-repeat:
+ acquire_fl_sem();
before = &inode->i_flock;
while ((fl = *before) != NULL) {
if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == owner) {
locks_delete_lock(before, 0);
- goto repeat;
+ continue;
}
before = &fl->fl_next;
}
- unlock_kernel();
+ release_fl_sem();
}
/*
@@ -1291,76 +1663,104 @@ repeat:
void locks_remove_flock(struct file *filp)
{
struct inode * inode = filp->f_dentry->d_inode;
- struct file_lock file_lock, *fl;
+ struct file_lock *fl;
struct file_lock **before;
+
if (!inode->i_flock)
return;
- lock_kernel();
-repeat:
+ acquire_fl_sem();
before = &inode->i_flock;
+
while ((fl = *before) != NULL) {
- if ((fl->fl_flags & FL_FLOCK) && fl->fl_file == filp) {
- int (*lock)(struct file *, int, struct file_lock *);
- lock = NULL;
- if (filp->f_op)
- lock = filp->f_op->lock;
- if (lock) {
- file_lock = *fl;
- file_lock.fl_type = F_UNLCK;
- }
+ if ((fl->fl_flags & (FL_FLOCK|FL_LEASE))
+ && (fl->fl_file == filp)) {
locks_delete_lock(before, 0);
- if (lock) {
- lock(filp, F_SETLK, &file_lock);
- /* List may have changed: */
- goto repeat;
- }
continue;
- }
+ }
before = &fl->fl_next;
}
- unlock_kernel();
+ release_fl_sem();
}
-/* The following two are for the benefit of lockd.
+/**
+ * posix_block_lock - blocks waiting for a file lock
+ * @blocker: the lock which is blocking
+ * @waiter: the lock which conflicts and has to wait
+ *
+ * lockd needs to block waiting for locks.
*/
void
posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
{
- lock_kernel();
+ acquire_fl_sem();
locks_insert_block(blocker, waiter);
- unlock_kernel();
+ release_fl_sem();
}
+/**
+ * posix_unblock_lock - stop waiting for a file lock
+ * @waiter: the lock which was waiting
+ *
+ * lockd needs to block waiting for locks.
+ */
void
posix_unblock_lock(struct file_lock *waiter)
{
- locks_delete_block(waiter);
- return;
+ acquire_fl_sem();
+ if (!list_empty(&waiter->fl_list)) {
+ locks_delete_block(waiter);
+ wake_up(&waiter->fl_wait);
+ }
+ release_fl_sem();
}
static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
{
- struct inode *inode;
+ struct inode *inode = NULL;
- inode = fl->fl_file->f_dentry->d_inode;
+ if (fl->fl_file != NULL)
+ inode = fl->fl_file->f_dentry->d_inode;
out += sprintf(out, "%d:%s ", id, pfx);
if (fl->fl_flags & FL_POSIX) {
out += sprintf(out, "%6s %s ",
(fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
+ (inode == NULL) ? "*NOINODE*" :
(IS_MANDLOCK(inode) &&
(inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?
"MANDATORY" : "ADVISORY ");
+ } else if (fl->fl_flags & FL_FLOCK) {
+#ifdef MSNFS
+ if (fl->fl_type & LOCK_MAND) {
+ out += sprintf(out, "FLOCK MSNFS ");
+ } else
+#endif
+ out += sprintf(out, "FLOCK ADVISORY ");
+ } else if (fl->fl_flags & FL_LEASE) {
+ out += sprintf(out, "LEASE MANDATORY ");
+ } else {
+ out += sprintf(out, "UNKNOWN UNKNOWN ");
}
- else {
- out += sprintf(out, "FLOCK ADVISORY ");
- }
- out += sprintf(out, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE");
- out += sprintf(out, "%d %s:%ld %Ld %Ld ",
+#ifdef MSNFS
+ if (fl->fl_type & LOCK_MAND) {
+ out += sprintf(out, "%s ",
+ (fl->fl_type & LOCK_READ)
+ ? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ "
+ : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
+ } else
+#endif
+ out += sprintf(out, "%s ",
+ (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
+ out += sprintf(out, "%d %s:%ld ",
fl->fl_pid,
- kdevname(inode->i_dev), inode->i_ino,
- (long long)fl->fl_start, (long long)fl->fl_end);
+ inode ? kdevname(inode->i_dev) : "<none>",
+ inode ? inode->i_ino : 0);
+ out += sprintf(out, "%Ld ", fl->fl_start);
+ if (fl->fl_end == OFFSET_MAX)
+ out += sprintf(out, "EOF ");
+ else
+ out += sprintf(out, "%Ld ", fl->fl_end);
sprintf(out, "%08lx %08lx %08lx %08lx %08lx\n",
(long)fl, (long)fl->fl_link.prev, (long)fl->fl_link.next,
(long)fl->fl_next, (long)fl->fl_block.next);
@@ -1388,6 +1788,14 @@ static void move_lock_status(char **p, off_t* pos, off_t offset)
*pos += len;
}
+/**
+ * get_locks_status - reports lock usage in /proc/locks
+ * @buffer: address in userspace to write into
+ * @start: ?
+ * @offset: how far we are through the buffer
+ * @length: how much to read
+ */
+
int get_locks_status(char *buffer, char **start, off_t offset, int length)
{
struct list_head *tmp;
@@ -1395,7 +1803,7 @@ int get_locks_status(char *buffer, char **start, off_t offset, int length)
off_t pos = 0;
int i = 0;
- lock_kernel();
+ acquire_fl_sem();
list_for_each(tmp, &file_lock_list) {
struct list_head *btmp;
struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
@@ -1407,7 +1815,7 @@ int get_locks_status(char *buffer, char **start, off_t offset, int length)
list_for_each(btmp, &fl->fl_block) {
struct file_lock *bfl = list_entry(btmp,
- struct file_lock, fl_block);
+ struct file_lock, fl_list);
lock_get_status(q, bfl, i, " ->");
move_lock_status(&q, &pos, offset);
@@ -1416,13 +1824,89 @@ int get_locks_status(char *buffer, char **start, off_t offset, int length)
}
}
done:
- unlock_kernel();
+ release_fl_sem();
*start = buffer;
if(q-buffer < length)
return (q-buffer);
return length;
}
+#ifdef MSNFS
+/**
+ * lock_may_read - checks that the region is free of locks
+ * @inode: the inode that is being read
+ * @start: the first byte to read
+ * @len: the number of bytes to read
+ *
+ * Emulates Windows locking requirements. Whole-file
+ * mandatory locks (share modes) can prohibit a read and
+ * byte-range POSIX locks can prohibit a read if they overlap.
+ *
+ * N.B. this function is only ever called
+ * from knfsd and ownership of locks is never checked.
+ */
+int lock_may_read(struct inode *inode, loff_t start, unsigned long len)
+{
+ struct file_lock *fl;
+ int result = 1;
+ acquire_fl_sem();
+ for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
+ if (fl->fl_flags == FL_POSIX) {
+ if (fl->fl_type == F_RDLCK)
+ continue;
+ if ((fl->fl_end < start) || (fl->fl_start > (start + len)))
+ continue;
+ } else if (fl->fl_flags == FL_FLOCK) {
+ if (!(fl->fl_type & LOCK_MAND))
+ continue;
+ if (fl->fl_type & LOCK_READ)
+ continue;
+ } else
+ continue;
+ result = 0;
+ break;
+ }
+ release_fl_sem();
+ return result;
+}
+
+/**
+ * lock_may_write - checks that the region is free of locks
+ * @inode: the inode that is being written
+ * @start: the first byte to write
+ * @len: the number of bytes to write
+ *
+ * Emulates Windows locking requirements. Whole-file
+ * mandatory locks (share modes) can prohibit a write and
+ * byte-range POSIX locks can prohibit a write if they overlap.
+ *
+ * N.B. this function is only ever called
+ * from knfsd and ownership of locks is never checked.
+ */
+int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
+{
+ struct file_lock *fl;
+ int result = 1;
+ acquire_fl_sem();
+ for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
+ if (fl->fl_flags == FL_POSIX) {
+ if ((fl->fl_end < start) || (fl->fl_start > (start + len)))
+ continue;
+ } else if (fl->fl_flags == FL_FLOCK) {
+ if (!(fl->fl_type & LOCK_MAND))
+ continue;
+ if (fl->fl_type & LOCK_WRITE)
+ continue;
+ } else
+ continue;
+ result = 0;
+ break;
+ }
+ release_fl_sem();
+ return result;
+}
+#endif
+
static int __init filelock_init(void)
{
filelock_cache = kmem_cache_create("file lock cache",
diff --git a/fs/minix/Makefile b/fs/minix/Makefile
index c3aee4fe3..13841d16a 100644
--- a/fs/minix/Makefile
+++ b/fs/minix/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := minix.o
-O_OBJS := bitmap.o truncate.o namei.o inode.o file.o dir.o fsync.o
+O_OBJS := bitmap.o itree_v1.o itree_v2.o namei.o inode.o file.o dir.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index fa2bd5f03..a268be2f1 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -83,9 +83,7 @@ void minix_free_block(struct inode * inode, int block)
if (!minix_test_and_clear_bit(bit,bh->b_data))
printk("free_block (%s:%d): bit already cleared\n",
kdevname(sb->s_dev), block);
- else
- DQUOT_FREE_BLOCK(sb, inode, 1);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
return;
}
@@ -100,9 +98,6 @@ int minix_new_block(struct inode * inode)
return 0;
}
repeat:
- if(DQUOT_ALLOC_BLOCK(sb, inode, 1))
- return -EDQUOT;
-
j = 8192;
bh = NULL;
for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++) {
@@ -114,10 +109,9 @@ repeat:
return 0;
if (minix_test_and_set_bit(j,bh->b_data)) {
printk("new_block: bit already set");
- DQUOT_FREE_BLOCK(sb, inode, 1);
goto repeat;
}
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
j += i*8192 + sb->u.minix_sb.s_firstdatazone-1;
if (j < sb->u.minix_sb.s_firstdatazone ||
j >= sb->u.minix_sb.s_nzones)
@@ -156,7 +150,7 @@ static struct buffer_head *V1_minix_clear_inode(struct inode *inode)
(ino - 1) % MINIX_INODES_PER_BLOCK);
raw_inode->i_nlinks = 0;
raw_inode->i_mode = 0;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
return bh;
}
@@ -184,7 +178,7 @@ static struct buffer_head *V2_minix_clear_inode(struct inode *inode)
(ino - 1) % MINIX2_INODES_PER_BLOCK);
raw_inode->i_nlinks = 0;
raw_inode->i_mode = 0;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
return bh;
}
@@ -215,15 +209,12 @@ void minix_free_inode(struct inode * inode)
return;
}
- DQUOT_FREE_INODE(inode->i_sb, inode);
- DQUOT_DROP(inode);
-
bh = inode->i_sb->u.minix_sb.s_imap[ino >> 13];
minix_clear_inode(inode);
clear_inode(inode);
if (!minix_test_and_clear_bit(ino & 8191, bh->b_data))
printk("free_inode: bit %lu already cleared.\n",ino);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
}
struct inode * minix_new_inode(const struct inode * dir, int * error)
@@ -258,7 +249,7 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
unlock_super(sb);
return NULL;
}
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
j += i*8192;
if (!j || j > inode->i_sb->u.minix_sb.s_ninodes) {
iput(inode);
@@ -276,14 +267,6 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
mark_inode_dirty(inode);
unlock_super(sb);
- if(DQUOT_ALLOC_INODE(sb, inode)) {
- sb->dq_op->drop(inode);
- inode->i_nlink = 0;
- iput(inode);
- *error = -EDQUOT;
- return NULL;
- }
-
*error = 0;
return inode;
}
diff --git a/fs/minix/file.c b/fs/minix/file.c
index c0b5ad89f..63534d4bc 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -13,6 +13,8 @@
* We have mostly NULLs here: the current defaults are OK for
* the minix filesystem.
*/
+static int minix_sync_file(struct file *, struct dentry *, int);
+
struct file_operations minix_file_operations = {
read: generic_file_read,
write: generic_file_write,
@@ -23,3 +25,15 @@ struct file_operations minix_file_operations = {
struct inode_operations minix_file_inode_operations = {
truncate: minix_truncate,
};
+
+static int minix_sync_file(struct file * file,
+ struct dentry *dentry,
+ int datasync)
+{
+ struct inode *inode = dentry->d_inode;
+
+ if (INODE_VERSION(inode) == MINIX_V1)
+ return V1_minix_sync_file(inode);
+ else
+ return V2_minix_sync_file(inode);
+}
diff --git a/fs/minix/fsync.c b/fs/minix/fsync.c
deleted file mode 100644
index 96e1ffa86..000000000
--- a/fs/minix/fsync.c
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * linux/fs/minix/fsync.c
- *
- * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk)
- * from
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl)
- * Minix V2 fs support
- *
- * minix fsync primitive
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include <linux/locks.h>
-#include <linux/smp_lock.h>
-
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#define blocksize BLOCK_SIZE
-
-/*
- * The functions for minix V1 fs file synchronization.
- */
-static int V1_sync_block (struct inode * inode, unsigned short * block, int wait)
-{
- struct buffer_head * bh;
- unsigned short tmp;
-
- if (!*block)
- return 0;
- tmp = *block;
- bh = get_hash_table(inode->i_dev, *block, blocksize);
- if (!bh)
- return 0;
- if (*block != tmp) {
- brelse (bh);
- return 1;
- }
- 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 V1_sync_iblock (struct inode * inode, unsigned short * iblock,
- struct buffer_head **bh, int wait)
-{
- int rc;
- unsigned short tmp;
-
- *bh = NULL;
- tmp = *iblock;
- if (!tmp)
- return 0;
- rc = V1_sync_block (inode, iblock, wait);
- if (rc)
- return rc;
- *bh = bread(inode->i_dev, tmp, blocksize);
- if (tmp != *iblock) {
- brelse(*bh);
- *bh = NULL;
- return 1;
- }
- if (!*bh)
- return -1;
- return 0;
-}
-
-static int V1_sync_direct(struct inode *inode, int wait)
-{
- int i;
- int rc, err = 0;
-
- for (i = 0; i < 7; i++) {
- rc = V1_sync_block (inode,
- (unsigned short *) inode->u.minix_i.u.i1_data + i, wait);
- if (rc > 0)
- break;
- if (rc)
- err = rc;
- }
- return err;
-}
-
-static int V1_sync_indirect(struct inode *inode, unsigned short *iblock, int wait)
-{
- int i;
- struct buffer_head * ind_bh;
- int rc, err = 0;
-
- rc = V1_sync_iblock (inode, iblock, &ind_bh, wait);
- if (rc || !ind_bh)
- return rc;
-
- for (i = 0; i < 512; i++) {
- rc = V1_sync_block (inode,
- ((unsigned short *) ind_bh->b_data) + i,
- wait);
- if (rc > 0)
- break;
- if (rc)
- err = rc;
- }
- brelse(ind_bh);
- return err;
-}
-
-static int V1_sync_dindirect(struct inode *inode, unsigned short *diblock,
- int wait)
-{
- int i;
- struct buffer_head * dind_bh;
- int rc, err = 0;
-
- rc = V1_sync_iblock (inode, diblock, &dind_bh, wait);
- if (rc || !dind_bh)
- return rc;
-
- for (i = 0; i < 512; i++) {
- rc = V1_sync_indirect (inode,
- ((unsigned short *) dind_bh->b_data) + i,
- wait);
- if (rc > 0)
- break;
- if (rc)
- err = rc;
- }
- brelse(dind_bh);
- return err;
-}
-
-static int V1_minix_sync_file(struct inode * inode, struct file * file)
-{
- int wait, err = 0;
-
- lock_kernel();
- for (wait=0; wait<=1; wait++)
- {
- err |= V1_sync_direct(inode, wait);
- err |= V1_sync_indirect(inode, inode->u.minix_i.u.i1_data + 7, wait);
- err |= V1_sync_dindirect(inode, inode->u.minix_i.u.i1_data + 8, wait);
- }
- err |= minix_sync_inode (inode);
- unlock_kernel();
- return (err < 0) ? -EIO : 0;
-}
-
-/*
- * The functions for minix V2 fs file synchronization.
- */
-static int V2_sync_block (struct inode * inode, unsigned long * block, int wait)
-{
- struct buffer_head * bh;
- unsigned long tmp;
-
- if (!*block)
- return 0;
- tmp = *block;
- bh = get_hash_table(inode->i_dev, *block, blocksize);
- if (!bh)
- return 0;
- if (*block != tmp) {
- brelse (bh);
- return 1;
- }
- 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 V2_sync_iblock (struct inode * inode, unsigned long * iblock,
- struct buffer_head **bh, int wait)
-{
- int rc;
- unsigned long tmp;
-
- *bh = NULL;
- tmp = *iblock;
- if (!tmp)
- return 0;
- rc = V2_sync_block (inode, iblock, wait);
- if (rc)
- return rc;
- *bh = bread(inode->i_dev, tmp, blocksize);
- if (tmp != *iblock) {
- brelse(*bh);
- *bh = NULL;
- return 1;
- }
- if (!*bh)
- return -1;
- return 0;
-}
-
-static int V2_sync_direct(struct inode *inode, int wait)
-{
- int i;
- int rc, err = 0;
-
- for (i = 0; i < 7; i++) {
- rc = V2_sync_block (inode,
- (unsigned long *)inode->u.minix_i.u.i2_data + i, wait);
- if (rc > 0)
- break;
- if (rc)
- err = rc;
- }
- return err;
-}
-
-static int V2_sync_indirect(struct inode *inode, unsigned long *iblock, int wait)
-{
- int i;
- struct buffer_head * ind_bh;
- int rc, err = 0;
-
- rc = V2_sync_iblock (inode, iblock, &ind_bh, wait);
- if (rc || !ind_bh)
- return rc;
-
- for (i = 0; i < 256; i++) {
- rc = V2_sync_block (inode,
- ((unsigned long *) ind_bh->b_data) + i,
- wait);
- if (rc > 0)
- break;
- if (rc)
- err = rc;
- }
- brelse(ind_bh);
- return err;
-}
-
-static int V2_sync_dindirect(struct inode *inode, unsigned long *diblock,
- int wait)
-{
- int i;
- struct buffer_head * dind_bh;
- int rc, err = 0;
-
- rc = V2_sync_iblock (inode, diblock, &dind_bh, wait);
- if (rc || !dind_bh)
- return rc;
-
- for (i = 0; i < 256; i++) {
- rc = V2_sync_indirect (inode,
- ((unsigned long *) dind_bh->b_data) + i,
- wait);
- if (rc > 0)
- break;
- if (rc)
- err = rc;
- }
- brelse(dind_bh);
- return err;
-}
-
-static int V2_sync_tindirect(struct inode *inode, unsigned long *tiblock,
- int wait)
-{
- int i;
- struct buffer_head * tind_bh;
- int rc, err = 0;
-
- rc = V2_sync_iblock (inode, tiblock, &tind_bh, wait);
- if (rc || !tind_bh)
- return rc;
-
- for (i = 0; i < 256; i++) {
- rc = V2_sync_dindirect (inode,
- ((unsigned long *) tind_bh->b_data) + i,
- wait);
- if (rc > 0)
- break;
- if (rc)
- err = rc;
- }
- brelse(tind_bh);
- return err;
-}
-
-static int V2_minix_sync_file(struct inode * inode, struct file * file)
-{
- int wait, err = 0;
-
- lock_kernel();
- for (wait=0; wait<=1; wait++)
- {
- err |= V2_sync_direct(inode, wait);
- err |= V2_sync_indirect(inode,
- (unsigned long *) inode->u.minix_i.u.i2_data + 7, wait);
- err |= V2_sync_dindirect(inode,
- (unsigned long *) inode->u.minix_i.u.i2_data + 8, wait);
- err |= V2_sync_tindirect(inode,
- (unsigned long *) inode->u.minix_i.u.i2_data + 9, wait);
- }
- err |= minix_sync_inode (inode);
- unlock_kernel();
- return (err < 0) ? -EIO : 0;
-}
-
-/*
- * The function which is called for file synchronization. File may be
- * NULL
- */
-
-int minix_sync_file(struct file * file, struct dentry *dentry, int datasync)
-{
- struct inode *inode = dentry->d_inode;
-
- if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)))
- return -EINVAL;
-
- if (INODE_VERSION(inode) == MINIX_V1)
- return V1_minix_sync_file(inode, file);
- else
- return V2_minix_sync_file(inode, file);
-}
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index b49626923..38bb52cfd 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -45,7 +45,7 @@ static void minix_delete_inode(struct inode *inode)
static void minix_commit_super(struct super_block * sb)
{
- mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.minix_sb.s_sbh);
sb->s_dirt = 0;
}
@@ -70,7 +70,7 @@ static void minix_put_super(struct super_block *sb)
if (!(sb->s_flags & MS_RDONLY)) {
sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state;
- mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.minix_sb.s_sbh);
}
for (i = 0; i < sb->u.minix_sb.s_imap_blocks; i++)
brelse(sb->u.minix_sb.s_imap[i]);
@@ -105,7 +105,7 @@ static int minix_remount (struct super_block * sb, int * flags, char * data)
return 0;
/* Mounting a rw partition read-only. */
ms->s_state = sb->u.minix_sb.s_mount_state;
- mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.minix_sb.s_sbh);
sb->s_dirt = 1;
minix_commit_super(sb);
}
@@ -113,7 +113,7 @@ static int minix_remount (struct super_block * sb, int * flags, char * data)
/* Mount a partition which is read-only, read-write. */
sb->u.minix_sb.s_mount_state = ms->s_state;
ms->s_state &= ~MINIX_VALID_FS;
- mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
+ mark_buffer_dirty(sb->u.minix_sb.s_sbh);
sb->s_dirt = 1;
if (!(sb->u.minix_sb.s_mount_state & MINIX_VALID_FS))
@@ -279,7 +279,7 @@ static struct super_block *minix_read_super(struct super_block *s, void *data,
if (!(s->s_flags & MS_RDONLY)) {
ms->s_state &= ~MINIX_VALID_FS;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
s->s_dirt = 1;
}
if (!(s->u.minix_sb.s_mount_state & MINIX_VALID_FS))
@@ -348,573 +348,13 @@ static int minix_statfs(struct super_block *sb, struct statfs *buf)
return 0;
}
-/*
- * The minix V1 fs bmap functions.
- */
-#define V1_inode_bmap(inode,nr) (((unsigned short *)(inode)->u.minix_i.u.i1_data)[(nr)])
-
-static int V1_block_bmap(struct buffer_head * bh, int nr)
-{
- int tmp;
-
- if (!bh)
- return 0;
- tmp = ((unsigned short *) bh->b_data)[nr];
- brelse(bh);
- return tmp;
-}
-
-static int V1_minix_block_map(struct inode * inode, long block)
-{
- int i, ret;
-
- ret = 0;
- lock_kernel();
- if (block < 0) {
- printk("minix_bmap: block<0");
- goto out;
- }
- if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) {
- printk("minix_bmap: block>big");
- goto out;
- }
- if (block < 7) {
- ret = V1_inode_bmap(inode,block);
- goto out;
- }
- block -= 7;
- if (block < 512) {
- i = V1_inode_bmap(inode,7);
- if (!i)
- goto out;
- ret = V1_block_bmap(bread(inode->i_dev, i,
- BLOCK_SIZE), block);
- goto out;
- }
- block -= 512;
- i = V1_inode_bmap(inode,8);
- if (!i)
- goto out;
- i = V1_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block>>9);
- if (!i)
- goto out;
- ret = V1_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
- block & 511);
-out:
- unlock_kernel();
- return ret;
-}
-
-/*
- * The minix V2 fs bmap functions.
- */
-#define V2_inode_bmap(inode,nr) (((unsigned int *)(inode)->u.minix_i.u.i2_data)[(nr)])
-static int V2_block_bmap(struct buffer_head * bh, int nr)
-{
- int tmp;
-
- if (!bh)
- return 0;
- tmp = ((unsigned int *) bh->b_data)[nr];
- brelse(bh);
- return tmp;
-}
-
-static int V2_minix_block_map(struct inode * inode, int block)
-{
- int i, ret;
-
- ret = 0;
- lock_kernel();
- if (block < 0) {
- printk("minix_bmap: block<0");
- goto out;
- }
- if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) {
- printk("minix_bmap: block>big");
- goto out;
- }
- if (block < 7) {
- ret = V2_inode_bmap(inode,block);
- goto out;
- }
- block -= 7;
- if (block < 256) {
- i = V2_inode_bmap(inode, 7);
- if (!i)
- goto out;
- ret = V2_block_bmap(bread(inode->i_dev, i,
- BLOCK_SIZE), block);
- goto out;
- }
- block -= 256;
- if (block < (256 * 256)) {
- i = V2_inode_bmap(inode, 8);
- if (!i)
- goto out;
- i = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
- block >> 8);
- if (!i)
- goto out;
- ret = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
- block & 255);
- goto out;
- }
- block -= (256 * 256);
- i = V2_inode_bmap(inode, 9);
- if (!i)
- goto out;
- i = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
- block >> 16);
- if (!i)
- goto out;
- i = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
- (block >> 8) & 255);
- if (!i)
- goto out;
- ret = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
- block & 255);
-out:
- unlock_kernel();
- return ret;
-}
-
-/*
- * The minix V1 fs getblk functions.
- */
-static struct buffer_head * V1_inode_getblk(struct inode * inode, int nr,
- int new_block, int *err,
- int metadata, int *phys, int *new)
-{
- int tmp;
- unsigned short *p;
- struct buffer_head * result;
-
- p = inode->u.minix_i.u.i1_data + nr;
-repeat:
- tmp = *p;
- if (tmp) {
- if (metadata) {
- result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
- if (tmp == *p)
- return result;
- brelse(result);
- goto repeat;
- } else {
- *phys = tmp;
- return NULL;
- }
- }
-
- tmp = minix_new_block(inode);
- if (!tmp) {
- *err = -ENOSPC;
- return NULL;
- }
- if (metadata) {
- result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
- if (*p) {
- minix_free_block(inode, tmp);
- brelse(result);
- goto repeat;
- }
- memset(result->b_data, 0, BLOCK_SIZE);
- mark_buffer_uptodate(result, 1);
- mark_buffer_dirty(result, 1);
- } else {
- if (*p) {
- /*
- * Nobody is allowed to change block allocation
- * state from under us:
- */
- BUG();
- minix_free_block(inode, tmp);
- goto repeat;
- }
- *phys = tmp;
- result = NULL;
- *err = 0;
- *new = 1;
- }
- *p = tmp;
-
- inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(inode);
- return result;
-}
-
-static struct buffer_head * V1_block_getblk(struct inode * inode,
- struct buffer_head * bh, int nr, int new_block, int *err,
- int metadata, int *phys, int *new)
-{
- int tmp;
- unsigned short *p;
- struct buffer_head * result;
-
- result = NULL;
- if (!bh)
- goto out;
- if (!buffer_uptodate(bh)) {
- ll_rw_block(READ, 1, &bh);
- wait_on_buffer(bh);
- if (!buffer_uptodate(bh))
- goto out;
- }
- p = nr + (unsigned short *) bh->b_data;
-repeat:
- tmp = *p;
- if (tmp) {
- if (metadata) {
- result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
- if (tmp == *p)
- goto out;
- brelse(result);
- goto repeat;
- } else {
- *phys = tmp;
- goto out;
- }
- }
-
- tmp = minix_new_block(inode);
- if (!tmp)
- goto out;
- if (metadata) {
- result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
- if (*p) {
- minix_free_block(inode, tmp);
- brelse(result);
- goto repeat;
- }
- memset(result->b_data, 0, BLOCK_SIZE);
- mark_buffer_uptodate(result, 1);
- mark_buffer_dirty(result, 1);
- } else {
- *phys = tmp;
- *new = 1;
- }
- if (*p) {
- minix_free_block(inode, tmp);
- brelse(result);
- goto repeat;
- }
-
- *p = tmp;
- mark_buffer_dirty(bh, 1);
- *err = 0;
-out:
- brelse(bh);
- return result;
-}
-
-static int V1_get_block(struct inode * inode, long block,
- struct buffer_head *bh_result, int create)
-{
- int ret, err, new, phys, ptr;
- struct buffer_head *bh;
-
- if (!create) {
- phys = V1_minix_block_map(inode, block);
- if (phys) {
- bh_result->b_dev = inode->i_dev;
- bh_result->b_blocknr = phys;
- bh_result->b_state |= (1UL << BH_Mapped);
- }
- return 0;
- }
-
- err = -EIO;
- new = 0;
- ret = 0;
- bh = NULL;
-
- lock_kernel();
- if (block < 0)
- goto abort_negative;
- if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)
- goto abort_too_big;
-
- err = 0;
- ptr = block;
- /*
- * ok, these macros clean the logic up a bit and make
- * it much more readable:
- */
-#define GET_INODE_DATABLOCK(x) \
- V1_inode_getblk(inode, x, block, &err, 0, &phys, &new)
-#define GET_INODE_PTR(x) \
- V1_inode_getblk(inode, x, block, &err, 1, NULL, NULL)
-#define GET_INDIRECT_DATABLOCK(x) \
- V1_block_getblk(inode, bh, x, block, &err, 0, &phys, &new)
-#define GET_INDIRECT_PTR(x) \
- V1_block_getblk(inode, bh, x, block, &err, 1, NULL, NULL)
-
- if (ptr < 7) {
- bh = GET_INODE_DATABLOCK(ptr);
- goto out;
- }
- ptr -= 7;
- if (ptr < 512) {
- bh = GET_INODE_PTR(7);
- goto get_indirect;
- }
- ptr -= 512;
- bh = GET_INODE_PTR(8);
- bh = GET_INDIRECT_PTR((ptr >> 9) & 511);
-get_indirect:
- bh = GET_INDIRECT_DATABLOCK(ptr & 511);
-
-#undef GET_INODE_DATABLOCK
-#undef GET_INODE_PTR
-#undef GET_INDIRECT_DATABLOCK
-#undef GET_INDIRECT_PTR
-
-out:
- if (err)
- goto abort;
- bh_result->b_dev = inode->i_dev;
- bh_result->b_blocknr = phys;
- bh_result->b_state |= (1UL << BH_Mapped);
- if (new)
- bh_result->b_state |= (1UL << BH_New);
-abort:
- unlock_kernel();
- return err;
-
-abort_negative:
- printk("minix_getblk: block<0");
- goto abort;
-
-abort_too_big:
- printk("minix_getblk: block>big");
- goto abort;
-}
-
-/*
- * The minix V2 fs getblk functions.
- */
-static struct buffer_head * V2_inode_getblk(struct inode * inode, int nr,
- int new_block, int *err,
- int metadata, int *phys, int *new)
-{
- int tmp;
- unsigned int *p;
- struct buffer_head * result;
-
- p = (unsigned int *) inode->u.minix_i.u.i2_data + nr;
-repeat:
- tmp = *p;
- if (tmp) {
- if (metadata) {
- result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
- if (tmp == *p)
- return result;
- brelse(result);
- goto repeat;
- } else {
- *phys = tmp;
- return NULL;
- }
- }
-
- tmp = minix_new_block(inode);
- if (!tmp) {
- *err = -ENOSPC;
- return NULL;
- }
- if (metadata) {
- result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
- if (*p) {
- minix_free_block(inode, tmp);
- brelse(result);
- goto repeat;
- }
- memset(result->b_data, 0, BLOCK_SIZE);
- mark_buffer_uptodate(result, 1);
- mark_buffer_dirty(result, 1);
- } else {
- if (*p) {
- /*
- * Nobody is allowed to change block allocation
- * state from under us:
- */
- BUG();
- minix_free_block(inode, tmp);
- goto repeat;
- }
- *phys = tmp;
- result = NULL;
- *err = 0;
- *new = 1;
- }
- *p = tmp;
-
- inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(inode);
- return result;
-}
-
-static struct buffer_head * V2_block_getblk(struct inode * inode,
- struct buffer_head * bh, int nr, int new_block, int *err,
- int metadata, int *phys, int *new)
-{
- int tmp;
- unsigned int *p;
- struct buffer_head * result;
-
- result = NULL;
- if (!bh)
- goto out;
- if (!buffer_uptodate(bh)) {
- ll_rw_block(READ, 1, &bh);
- wait_on_buffer(bh);
- if (!buffer_uptodate(bh))
- goto out;
- }
- p = nr + (unsigned int *) bh->b_data;
-repeat:
- tmp = *p;
- if (tmp) {
- if (metadata) {
- result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
- if (tmp == *p)
- goto out;
- brelse(result);
- goto repeat;
- } else {
- *phys = tmp;
- goto out;
- }
- }
-
- tmp = minix_new_block(inode);
- if (!tmp)
- goto out;
- if (metadata) {
- result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
- if (*p) {
- minix_free_block(inode, tmp);
- brelse(result);
- goto repeat;
- }
- memset(result->b_data, 0, BLOCK_SIZE);
- mark_buffer_uptodate(result, 1);
- mark_buffer_dirty(result, 1);
- } else {
- *phys = tmp;
- *new = 1;
- }
- if (*p) {
- minix_free_block(inode, tmp);
- brelse(result);
- goto repeat;
- }
-
- *p = tmp;
- mark_buffer_dirty(bh, 1);
- *err = 0;
-out:
- brelse(bh);
- return result;
-}
-
-static int V2_get_block(struct inode * inode, long block,
- struct buffer_head *bh_result, int create)
-{
- int ret, err, new, phys, ptr;
- struct buffer_head * bh;
-
- if (!create) {
- phys = V2_minix_block_map(inode, block);
- if (phys) {
- bh_result->b_dev = inode->i_dev;
- bh_result->b_blocknr = phys;
- bh_result->b_state |= (1UL << BH_Mapped);
- }
- return 0;
- }
-
- err = -EIO;
- new = 0;
- ret = 0;
- bh = NULL;
-
- lock_kernel();
- if (block < 0)
- goto abort_negative;
- if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)
- goto abort_too_big;
-
- err = 0;
- ptr = block;
- /*
- * ok, these macros clean the logic up a bit and make
- * it much more readable:
- */
-#define GET_INODE_DATABLOCK(x) \
- V2_inode_getblk(inode, x, block, &err, 0, &phys, &new)
-#define GET_INODE_PTR(x) \
- V2_inode_getblk(inode, x, block, &err, 1, NULL, NULL)
-#define GET_INDIRECT_DATABLOCK(x) \
- V2_block_getblk(inode, bh, x, block, &err, 0, &phys, &new)
-#define GET_INDIRECT_PTR(x) \
- V2_block_getblk(inode, bh, x, block, &err, 1, NULL, NULL)
-
- if (ptr < 7) {
- bh = GET_INODE_DATABLOCK(ptr);
- goto out;
- }
- ptr -= 7;
- if (ptr < 256) {
- bh = GET_INODE_PTR(7);
- goto get_indirect;
- }
- ptr -= 256;
- if (ptr < 256*256) {
- bh = GET_INODE_PTR(8);
- goto get_double;
- }
- ptr -= 256*256;
- bh = GET_INODE_PTR(9);
- bh = GET_INDIRECT_PTR((ptr >> 16) & 255);
-get_double:
- bh = GET_INDIRECT_PTR((ptr >> 8) & 255);
-get_indirect:
- bh = GET_INDIRECT_DATABLOCK(ptr & 255);
-
-#undef GET_INODE_DATABLOCK
-#undef GET_INODE_PTR
-#undef GET_INDIRECT_DATABLOCK
-#undef GET_INDIRECT_PTR
-
-out:
- if (err)
- goto abort;
- bh_result->b_dev = inode->i_dev;
- bh_result->b_blocknr = phys;
- bh_result->b_state |= (1UL << BH_Mapped);
- if (new)
- bh_result->b_state |= (1UL << BH_New);
-abort:
- unlock_kernel();
- return err;
-
-abort_negative:
- printk("minix_getblk: block<0");
- goto abort;
-
-abort_too_big:
- printk("minix_getblk: block>big");
- goto abort;
-}
-
static int minix_get_block(struct inode *inode, long block,
struct buffer_head *bh_result, int create)
{
if (INODE_VERSION(inode) == MINIX_V1)
- return V1_get_block(inode, block, bh_result, create);
+ return V1_minix_get_block(inode, block, bh_result, create);
else
- return V2_get_block(inode, block, bh_result, create);
+ return V2_minix_get_block(inode, block, bh_result, create);
}
/*
@@ -934,7 +374,7 @@ struct buffer_head *minix_getblk(struct inode *inode, int block, int create)
if (buffer_new(&dummy)) {
memset(bh->b_data, 0, BLOCK_SIZE);
mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
}
return bh;
}
@@ -1130,7 +570,7 @@ static struct buffer_head * V1_minix_update_inode(struct inode * inode)
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];
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
return bh;
}
@@ -1170,7 +610,7 @@ static struct buffer_head * V2_minix_update_inode(struct inode * inode)
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];
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
return bh;
}
@@ -1216,6 +656,17 @@ int minix_sync_inode(struct inode * inode)
return err;
}
+/*
+ * The function that is called for file truncation.
+ */
+void minix_truncate(struct inode * inode)
+{
+ if (INODE_VERSION(inode) == MINIX_V1)
+ V1_minix_truncate(inode);
+ else
+ V2_minix_truncate(inode);
+}
+
static DECLARE_FSTYPE_DEV(minix_fs_type,"minix",minix_read_super);
static int __init init_minix_fs(void)
diff --git a/fs/minix/itree_common.c b/fs/minix/itree_common.c
new file mode 100644
index 000000000..0ad6b18c1
--- /dev/null
+++ b/fs/minix/itree_common.c
@@ -0,0 +1,417 @@
+/* Generic part */
+
+typedef struct {
+ block_t *p;
+ block_t key;
+ struct buffer_head *bh;
+} Indirect;
+
+static inline void add_chain(Indirect *p, struct buffer_head *bh, block_t *v)
+{
+ p->key = *(p->p = v);
+ p->bh = bh;
+}
+
+static inline int verify_chain(Indirect *from, Indirect *to)
+{
+ while (from <= to && from->key == *from->p)
+ from++;
+ return (from > to);
+}
+
+static inline block_t *block_end(struct buffer_head *bh)
+{
+ return (block_t *)((char*)bh->b_data + BLOCK_SIZE);
+}
+
+static inline Indirect *get_branch(struct inode *inode,
+ int depth,
+ int *offsets,
+ Indirect chain[DEPTH],
+ int *err)
+{
+ kdev_t dev = inode->i_dev;
+ Indirect *p = chain;
+ struct buffer_head *bh;
+
+ *err = 0;
+ /* i_data is not going away, no lock needed */
+ add_chain (chain, NULL, i_data(inode) + *offsets);
+ if (!p->key)
+ goto no_block;
+ while (--depth) {
+ bh = bread(dev, block_to_cpu(p->key), BLOCK_SIZE);
+ if (!bh)
+ goto failure;
+ /* Reader: pointers */
+ if (!verify_chain(chain, p))
+ goto changed;
+ add_chain(++p, bh, (block_t *)bh->b_data + *++offsets);
+ /* Reader: end */
+ if (!p->key)
+ goto no_block;
+ }
+ return NULL;
+
+changed:
+ *err = -EAGAIN;
+ goto no_block;
+failure:
+ *err = -EIO;
+no_block:
+ return p;
+}
+
+static int alloc_branch(struct inode *inode,
+ int num,
+ int *offsets,
+ Indirect *branch)
+{
+ int n = 0;
+ int i;
+ int parent = minix_new_block(inode);
+
+ branch[0].key = cpu_to_block(parent);
+ if (parent) for (n = 1; n < num; n++) {
+ struct buffer_head *bh;
+ /* Allocate the next block */
+ int nr = minix_new_block(inode);
+ if (!nr)
+ break;
+ branch[n].key = cpu_to_block(nr);
+ bh = getblk(inode->i_dev, parent, BLOCK_SIZE);
+ if (!buffer_uptodate(bh))
+ wait_on_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);
+ parent = nr;
+ }
+ if (n == num)
+ return 0;
+
+ /* Allocation failed, free what we already allocated */
+ for (i = 1; i < n; i++)
+ bforget(branch[i].bh);
+ for (i = 0; i < n; i++)
+ minix_free_block(inode, block_to_cpu(branch[i].key));
+ return -ENOSPC;
+}
+
+static inline int splice_branch(struct inode *inode,
+ Indirect chain[DEPTH],
+ Indirect *where,
+ int num)
+{
+ int i;
+
+ /* Verify that place we are splicing to is still there and vacant */
+
+ /* Writer: pointers */
+ if (!verify_chain(chain, where-1) || *where->p)
+ /* Writer: end */
+ goto changed;
+
+ /* That's it */
+
+ *where->p = where->key;
+
+ /* Writer: end */
+
+ /* We are done with atomic stuff, now do the rest of housekeeping */
+
+ inode->i_ctime = CURRENT_TIME;
+
+ /* had we spliced it onto indirect block? */
+ if (where->bh)
+ mark_buffer_dirty(where->bh);
+
+ mark_inode_dirty(inode);
+ return 0;
+
+changed:
+ for (i = 1; i < num; i++)
+ bforget(where[i].bh);
+ for (i = 0; i < num; i++)
+ minix_free_block(inode, block_to_cpu(where[i].key));
+ return -EAGAIN;
+}
+
+static inline int get_block(struct inode * inode, long block,
+ struct buffer_head *bh_result, int create)
+{
+ int err = -EIO;
+ int offsets[DEPTH];
+ Indirect chain[DEPTH];
+ Indirect *partial;
+ int left;
+ int depth = block_to_path(inode, block, offsets);
+
+ if (depth == 0)
+ goto out;
+
+ lock_kernel();
+reread:
+ partial = get_branch(inode, depth, offsets, chain, &err);
+
+ /* Simplest case - block found, no allocation needed */
+ if (!partial) {
+got_it:
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = block_to_cpu(chain[depth-1].key);
+ bh_result->b_state |= (1UL << BH_Mapped);
+ /* Clean up and exit */
+ partial = chain+depth-1; /* the whole chain */
+ goto cleanup;
+ }
+
+ /* Next simple case - plain lookup or failed read of indirect block */
+ if (!create || err == -EIO) {
+cleanup:
+ while (partial > chain) {
+ brelse(partial->bh);
+ partial--;
+ }
+ unlock_kernel();
+out:
+ return err;
+ }
+
+ /*
+ * Indirect block might be removed by truncate while we were
+ * reading it. Handling of that case (forget what we've got and
+ * reread) is taken out of the main path.
+ */
+ if (err == -EAGAIN)
+ goto changed;
+
+ left = (chain + depth) - partial;
+ err = alloc_branch(inode, left, offsets+(partial-chain), partial);
+ if (err)
+ goto cleanup;
+
+ if (splice_branch(inode, chain, partial, left) < 0)
+ goto changed;
+
+ bh_result->b_state |= (1UL << BH_New);
+ goto got_it;
+
+changed:
+ while (partial > chain) {
+ bforget(partial->bh);
+ partial--;
+ }
+ goto reread;
+}
+
+static inline int all_zeroes(block_t *p, block_t *q)
+{
+ while (p < q)
+ if (*p++)
+ return 0;
+ return 1;
+}
+
+static Indirect *find_shared(struct inode *inode,
+ int depth,
+ int offsets[DEPTH],
+ Indirect chain[DEPTH],
+ block_t *top)
+{
+ Indirect *partial, *p;
+ int k, err;
+
+ *top = 0;
+ for (k = depth; k > 1 && !offsets[k-1]; k--)
+ ;
+ partial = get_branch(inode, k, offsets, chain, &err);
+ /* Writer: pointers */
+ if (!partial)
+ partial = chain + k-1;
+ if (!partial->key && *partial->p)
+ /* Writer: end */
+ goto no_top;
+ for (p=partial;p>chain && all_zeroes((block_t*)p->bh->b_data,p->p);p--)
+ ;
+ if (p == chain + k - 1 && p > chain) {
+ p->p--;
+ } else {
+ *top = *p->p;
+ *p->p = 0;
+ }
+ /* Writer: end */
+
+ while(partial > p)
+ {
+ brelse(partial->bh);
+ partial--;
+ }
+no_top:
+ return partial;
+}
+
+static inline void free_data(struct inode *inode, block_t *p, block_t *q)
+{
+ unsigned long nr;
+
+ for ( ; p < q ; p++) {
+ nr = block_to_cpu(*p);
+ if (nr) {
+ *p = 0;
+ minix_free_block(inode, nr);
+ }
+ }
+}
+
+static void free_branches(struct inode *inode, block_t *p, block_t *q, int depth)
+{
+ struct buffer_head * bh;
+ unsigned long nr;
+
+ if (depth--) {
+ for ( ; p < q ; p++) {
+ nr = block_to_cpu(*p);
+ if (!nr)
+ continue;
+ *p = 0;
+ bh = bread (inode->i_dev, nr, BLOCK_SIZE);
+ if (!bh)
+ continue;
+ free_branches(inode, (block_t*)bh->b_data,
+ block_end(bh), depth);
+ bforget(bh);
+ minix_free_block(inode, nr);
+ mark_inode_dirty(inode);
+ }
+ } else
+ free_data(inode, p, q);
+}
+
+static inline void truncate (struct inode * inode)
+{
+ block_t *idata = i_data(inode);
+ int offsets[DEPTH];
+ Indirect chain[DEPTH];
+ Indirect *partial;
+ block_t nr = 0;
+ int n;
+ int first_whole;
+ long iblock;
+
+ iblock = (inode->i_size + BLOCK_SIZE-1) >> 10;
+ block_truncate_page(inode->i_mapping, inode->i_size, get_block);
+
+ n = block_to_path(inode, iblock, offsets);
+ if (!n)
+ return;
+
+ if (n == 1) {
+ free_data(inode, idata+offsets[0], idata + DIRECT);
+ first_whole = 0;
+ goto do_indirects;
+ }
+
+ first_whole = offsets[0] + 1 - DIRECT;
+ partial = find_shared(inode, n, offsets, chain, &nr);
+ if (nr) {
+ if (partial == chain)
+ mark_inode_dirty(inode);
+ else
+ mark_buffer_dirty(partial->bh);
+ 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);
+ brelse (partial->bh);
+ partial--;
+ }
+do_indirects:
+ /* Kill the remaining (whole) subtrees */
+ while (first_whole < DEPTH-1) {
+ nr = idata[DIRECT+first_whole];
+ if (nr) {
+ idata[DIRECT+first_whole] = 0;
+ mark_inode_dirty(inode);
+ free_branches(inode, &nr, &nr+1, first_whole+1);
+ }
+ first_whole++;
+ }
+ 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;
+}
diff --git a/fs/minix/itree_v1.c b/fs/minix/itree_v1.c
new file mode 100644
index 000000000..47aee63e1
--- /dev/null
+++ b/fs/minix/itree_v1.c
@@ -0,0 +1,63 @@
+#include <linux/sched.h>
+#include <linux/locks.h>
+#include <linux/minix_fs.h>
+#include <linux/smp_lock.h>
+
+enum {DEPTH = 3, DIRECT = 7}; /* Only double indirect */
+
+typedef u16 block_t; /* 16 bit, host order */
+
+static inline unsigned long block_to_cpu(block_t n)
+{
+ return n;
+}
+
+static inline block_t cpu_to_block(unsigned long n)
+{
+ return n;
+}
+
+static inline block_t *i_data(struct inode *inode)
+{
+ return (block_t *)inode->u.minix_i.u.i1_data;
+}
+
+static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
+{
+ int n = 0;
+
+ if (block < 0) {
+ printk("minix_bmap: block<0");
+ } else if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) {
+ printk("minix_bmap: block>big");
+ } else if (block < 7) {
+ offsets[n++] = block;
+ } else if ((block -= 7) < 512) {
+ offsets[n++] = 7;
+ offsets[n++] = block;
+ } else {
+ block -= 512;
+ offsets[n++] = 8;
+ offsets[n++] = block>>9;
+ offsets[n++] = block & 511;
+ }
+ return n;
+}
+
+#include "itree_common.c"
+
+int V1_minix_get_block(struct inode * inode, long block,
+ struct buffer_head *bh_result, int create)
+{
+ return get_block(inode, block, bh_result, create);
+}
+
+void V1_minix_truncate(struct inode * inode)
+{
+ truncate(inode);
+}
+
+int V1_minix_sync_file(struct inode * inode)
+{
+ return sync_file(inode);
+}
diff --git a/fs/minix/itree_v2.c b/fs/minix/itree_v2.c
new file mode 100644
index 000000000..333d5f785
--- /dev/null
+++ b/fs/minix/itree_v2.c
@@ -0,0 +1,68 @@
+#include <linux/sched.h>
+#include <linux/locks.h>
+#include <linux/minix_fs.h>
+#include <linux/smp_lock.h>
+
+enum {DIRECT = 7, DEPTH = 4}; /* Have triple indirect */
+
+typedef u32 block_t; /* 32 bit, host order */
+
+static inline unsigned long block_to_cpu(block_t n)
+{
+ return n;
+}
+
+static inline block_t cpu_to_block(unsigned long n)
+{
+ return n;
+}
+
+static inline block_t *i_data(struct inode *inode)
+{
+ return (block_t *)inode->u.minix_i.u.i2_data;
+}
+
+static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
+{
+ int n = 0;
+
+ if (block < 0) {
+ printk("minix_bmap: block<0");
+ } else if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) {
+ printk("minix_bmap: block>big");
+ } else if (block < 7) {
+ offsets[n++] = block;
+ } else if ((block -= 7) < 256) {
+ offsets[n++] = 7;
+ offsets[n++] = block;
+ } else if ((block -= 256) < 256*256) {
+ offsets[n++] = 8;
+ offsets[n++] = block>>8;
+ offsets[n++] = block & 255;
+ } else {
+ block -= 256*256;
+ offsets[n++] = 9;
+ offsets[n++] = block>>16;
+ offsets[n++] = (block>>8) & 255;
+ offsets[n++] = block & 255;
+ }
+ return n;
+}
+
+#include "itree_common.c"
+
+int V2_minix_get_block(struct inode * inode, long block,
+ struct buffer_head *bh_result, int create)
+{
+ return get_block(inode, block, bh_result, create);
+}
+
+void V2_minix_truncate(struct inode * inode)
+{
+ truncate(inode);
+}
+
+int V2_minix_sync_file(struct inode * inode)
+{
+ return sync_file(inode);
+}
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 0de210186..870656cb7 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -187,7 +187,7 @@ static int minix_add_entry(struct inode * 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, 1);
+ mark_buffer_dirty(bh);
*res_dir = de;
break;
}
@@ -228,7 +228,7 @@ static int minix_create(struct inode * dir, struct dentry *dentry, int mode)
return error;
}
de->inode = inode->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
d_instantiate(dentry, inode);
return 0;
@@ -257,7 +257,7 @@ static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int
return error;
}
de->inode = inode->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
d_instantiate(dentry, inode);
return 0;
@@ -296,7 +296,7 @@ static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
de->inode = dir->i_ino;
strcpy(de->name,"..");
inode->i_nlink = 2;
- mark_buffer_dirty(dir_block, 1);
+ mark_buffer_dirty(dir_block);
brelse(dir_block);
inode->i_mode = S_IFDIR | mode;
if (dir->i_mode & S_ISGID)
@@ -310,7 +310,7 @@ static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
return error;
}
de->inode = inode->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
dir->i_nlink++;
mark_inode_dirty(dir);
brelse(bh);
@@ -389,7 +389,6 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry)
if (!bh)
goto end_rmdir;
inode = dentry->d_inode;
- DQUOT_INIT(inode);
if (!empty_dir(inode)) {
retval = -ENOTEMPTY;
@@ -403,7 +402,7 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry)
printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
de->inode = 0;
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
inode->i_nlink=0;
mark_inode_dirty(inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -424,7 +423,6 @@ static int minix_unlink(struct inode * dir, struct dentry *dentry)
retval = -ENOENT;
inode = dentry->d_inode;
- DQUOT_INIT(inode);
bh = minix_find_entry(dir, dentry->d_name.name,
dentry->d_name.len, &de);
if (!bh || de->inode != inode->i_ino)
@@ -437,7 +435,7 @@ static int minix_unlink(struct inode * dir, struct dentry *dentry)
}
de->inode = 0;
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
inode->i_nlink--;
@@ -482,7 +480,7 @@ static int minix_symlink(struct inode * dir, struct dentry *dentry,
goto fail;
de->inode = inode->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
d_instantiate(dentry, inode);
out:
@@ -515,7 +513,7 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir,
return error;
}
de->inode = inode->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
inode->i_nlink++;
inode->i_ctime = CURRENT_TIME;
@@ -557,8 +555,6 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
if (!new_inode) {
brelse(new_bh);
new_bh = NULL;
- } else {
- DQUOT_INIT(new_inode);
}
}
if (S_ISDIR(old_inode->i_mode)) {
@@ -600,11 +596,11 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
new_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(new_inode);
}
- mark_buffer_dirty(old_bh, 1);
- mark_buffer_dirty(new_bh, 1);
+ 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, 1);
+ mark_buffer_dirty(dir_bh);
old_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
diff --git a/fs/minix/truncate.c b/fs/minix/truncate.c
deleted file mode 100644
index 70b01dc20..000000000
--- a/fs/minix/truncate.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * linux/fs/truncate.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl)
- * Minix V2 fs support.
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/minix_fs.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-
-#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
-#define INDIRECT_BLOCK(offset) (DIRECT_BLOCK-offset)
-#define V1_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>9)
-#define V2_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>8)
-#define TINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-(offset))>>8)
-
-/*
- * Truncate has the most races in the whole filesystem: coding it is
- * a pain in the a**, especially as I don't do any locking.
- *
- * The code may look a bit weird, but that's just because I've tried to
- * handle things like file-size changes in a somewhat graceful manner.
- * Anyway, truncating a file at the same time somebody else writes to it
- * is likely to result in pretty weird behaviour...
- *
- * The new code handles normal truncates (size = 0) as well as the more
- * general case (size = XXX). I hope.
- */
-
-#define DATA_BUFFER_USED(bh) \
- (atomic_read(&bh->b_count) > 1 || buffer_locked(bh))
-
-/*
- * The functions for minix V1 fs truncation.
- */
-static int V1_trunc_direct(struct inode * inode)
-{
- unsigned short * p;
- struct buffer_head * bh;
- int i, tmp;
- int retry = 0;
-
-repeat:
- for (i = DIRECT_BLOCK ; i < 7 ; i++) {
- p = i + inode->u.minix_i.u.i1_data;
- if (!(tmp = *p))
- continue;
- bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
- if (i < DIRECT_BLOCK) {
- brelse(bh);
- goto repeat;
- }
- if ((bh && DATA_BUFFER_USED(bh)) || tmp != *p) {
- retry = 1;
- brelse(bh);
- continue;
- }
- *p = 0;
- mark_inode_dirty(inode);
- bforget(bh);
- minix_free_block(inode,tmp);
- }
- return retry;
-}
-
-static int V1_trunc_indirect(struct inode * inode, int offset, unsigned short * p)
-{
- struct buffer_head * bh;
- int i, tmp;
- struct buffer_head * ind_bh;
- unsigned short * ind;
- int retry = 0;
-
- tmp = *p;
- if (!tmp)
- return 0;
- ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
- if (tmp != *p) {
- brelse(ind_bh);
- return 1;
- }
- if (!ind_bh) {
- *p = 0;
- return 0;
- }
-repeat:
- for (i = INDIRECT_BLOCK(offset) ; i < 512 ; i++) {
- if (i < 0)
- i = 0;
- if (i < INDIRECT_BLOCK(offset))
- goto repeat;
- ind = i+(unsigned short *) ind_bh->b_data;
- tmp = *ind;
- if (!tmp)
- continue;
- bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
- if (i < INDIRECT_BLOCK(offset)) {
- brelse(bh);
- goto repeat;
- }
- if ((bh && DATA_BUFFER_USED(bh)) || tmp != *ind) {
- retry = 1;
- brelse(bh);
- continue;
- }
- *ind = 0;
- mark_buffer_dirty(ind_bh, 1);
- bforget(bh);
- minix_free_block(inode,tmp);
- }
- ind = (unsigned short *) ind_bh->b_data;
- for (i = 0; i < 512; i++)
- if (*(ind++))
- break;
- if (i >= 512) {
- if (atomic_read(&ind_bh->b_count) != 1)
- retry = 1;
- else {
- tmp = *p;
- *p = 0;
- minix_free_block(inode,tmp);
- }
- }
- brelse(ind_bh);
- return retry;
-}
-
-static int V1_trunc_dindirect(struct inode * inode, int offset, unsigned short *p)
-{
- int i, tmp;
- struct buffer_head * dind_bh;
- unsigned short * dind;
- int retry = 0;
-
- if (!(tmp = *p))
- return 0;
- dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
- if (tmp != *p) {
- brelse(dind_bh);
- return 1;
- }
- if (!dind_bh) {
- *p = 0;
- return 0;
- }
-repeat:
- for (i = V1_DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) {
- if (i < 0)
- i = 0;
- if (i < V1_DINDIRECT_BLOCK(offset))
- goto repeat;
- dind = i+(unsigned short *) dind_bh->b_data;
- retry |= V1_trunc_indirect(inode,offset+(i<<9),dind);
- mark_buffer_dirty(dind_bh, 1);
- }
- dind = (unsigned short *) dind_bh->b_data;
- for (i = 0; i < 512; i++)
- if (*(dind++))
- break;
- if (i >= 512) {
- if (atomic_read(&dind_bh->b_count) != 1)
- retry = 1;
- else {
- tmp = *p;
- *p = 0;
- mark_inode_dirty(inode);
- minix_free_block(inode,tmp);
- }
- }
- brelse(dind_bh);
- return retry;
-}
-
-static void V1_minix_truncate(struct inode * inode)
-{
- int retry;
-
- if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)))
- return;
- while (1) {
- retry = V1_trunc_direct(inode);
- retry |= V1_trunc_indirect(inode, 7, inode->u.minix_i.u.i1_data + 7);
- retry |= V1_trunc_dindirect(inode, 7+512, inode->u.minix_i.u.i1_data + 8);
- if (!retry)
- break;
- current->counter = 0;
- schedule();
- }
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(inode);
-}
-
-/*
- * The functions for minix V2 fs truncation.
- */
-static int V2_trunc_direct(struct inode * inode)
-{
- unsigned long * p;
- struct buffer_head * bh;
- int i, tmp;
- int retry = 0;
-
-repeat:
- for (i = DIRECT_BLOCK ; i < 7 ; i++) {
- p = (unsigned long *) inode->u.minix_i.u.i2_data + i;
- if (!(tmp = *p))
- continue;
- bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
- if (i < DIRECT_BLOCK) {
- brelse(bh);
- goto repeat;
- }
- if ((bh && DATA_BUFFER_USED(bh)) || tmp != *p) {
- retry = 1;
- brelse(bh);
- continue;
- }
- *p = 0;
- mark_inode_dirty(inode);
- bforget(bh);
- minix_free_block(inode,tmp);
- }
- return retry;
-}
-
-static int V2_trunc_indirect(struct inode * inode, int offset, unsigned long * p)
-{
- struct buffer_head * bh;
- int i, tmp;
- struct buffer_head * ind_bh;
- unsigned long * ind;
- int retry = 0;
-
- tmp = *p;
- if (!tmp)
- return 0;
- ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
- if (tmp != *p) {
- brelse(ind_bh);
- return 1;
- }
- if (!ind_bh) {
- *p = 0;
- return 0;
- }
-repeat:
- for (i = INDIRECT_BLOCK(offset) ; i < 256 ; i++) {
- if (i < 0)
- i = 0;
- if (i < INDIRECT_BLOCK(offset))
- goto repeat;
- ind = i+(unsigned long *) ind_bh->b_data;
- tmp = *ind;
- if (!tmp)
- continue;
- bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
- if (i < INDIRECT_BLOCK(offset)) {
- brelse(bh);
- goto repeat;
- }
- if ((bh && DATA_BUFFER_USED(bh)) || tmp != *ind) {
- retry = 1;
- brelse(bh);
- continue;
- }
- *ind = 0;
- mark_buffer_dirty(ind_bh, 1);
- bforget(bh);
- minix_free_block(inode,tmp);
- }
- ind = (unsigned long *) ind_bh->b_data;
- for (i = 0; i < 256; i++)
- if (*(ind++))
- break;
- if (i >= 256) {
- if (atomic_read(&ind_bh->b_count) != 1)
- retry = 1;
- else {
- tmp = *p;
- *p = 0;
- minix_free_block(inode,tmp);
- }
- }
- brelse(ind_bh);
- return retry;
-}
-
-static int V2_trunc_dindirect(struct inode * inode, int offset, unsigned long *p)
-{
- int i, tmp;
- struct buffer_head * dind_bh;
- unsigned long * dind;
- int retry = 0;
-
- if (!(tmp = *p))
- return 0;
- dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
- if (tmp != *p) {
- brelse(dind_bh);
- return 1;
- }
- if (!dind_bh) {
- *p = 0;
- return 0;
- }
-repeat:
- for (i = V2_DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
- if (i < 0)
- i = 0;
- if (i < V2_DINDIRECT_BLOCK(offset))
- goto repeat;
- dind = i+(unsigned long *) dind_bh->b_data;
- retry |= V2_trunc_indirect(inode,offset+(i<<8),dind);
- mark_buffer_dirty(dind_bh, 1);
- }
- dind = (unsigned long *) dind_bh->b_data;
- for (i = 0; i < 256; i++)
- if (*(dind++))
- break;
- if (i >= 256) {
- if (atomic_read(&dind_bh->b_count) != 1)
- retry = 1;
- else {
- tmp = *p;
- *p = 0;
- mark_inode_dirty(inode);
- minix_free_block(inode,tmp);
- }
- }
- brelse(dind_bh);
- return retry;
-}
-
-static int V2_trunc_tindirect(struct inode * inode, int offset, unsigned long * p)
-{
- int i, tmp;
- struct buffer_head * tind_bh;
- unsigned long * tind;
- int retry = 0;
-
- if (!(tmp = *p))
- return 0;
- tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
- if (tmp != *p) {
- brelse(tind_bh);
- return 1;
- }
- if (!tind_bh) {
- *p = 0;
- return 0;
- }
-repeat:
- for (i = TINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
- if (i < 0)
- i = 0;
- if (i < TINDIRECT_BLOCK(offset))
- goto repeat;
- tind = i+(unsigned long *) tind_bh->b_data;
- retry |= V2_trunc_dindirect(inode,offset+(i<<8),tind);
- mark_buffer_dirty(tind_bh, 1);
- }
- tind = (unsigned long *) tind_bh->b_data;
- for (i = 0; i < 256; i++)
- if (*(tind++))
- break;
- if (i >= 256) {
- if (atomic_read(&tind_bh->b_count) != 1)
- retry = 1;
- else {
- tmp = *p;
- *p = 0;
- mark_inode_dirty(inode);
- minix_free_block(inode,tmp);
- }
- }
- brelse(tind_bh);
- return retry;
-}
-
-static void V2_minix_truncate(struct inode * inode)
-{
- int retry;
-
- if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)))
- return;
- while (1) {
- retry = V2_trunc_direct(inode);
- retry |= V2_trunc_indirect(inode,7,
- (unsigned long *) inode->u.minix_i.u.i2_data + 7);
- retry |= V2_trunc_dindirect(inode, 7+256,
- (unsigned long *) inode->u.minix_i.u.i2_data + 8);
- retry |= V2_trunc_tindirect(inode, 7+256+256*256,
- (unsigned long *) inode->u.minix_i.u.i2_data + 9);
- if (!retry)
- break;
- run_task_queue(&tq_disk);
- current->policy |= SCHED_YIELD;
- schedule();
- }
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(inode);
-}
-
-/*
- * The function that is called for file truncation.
- */
-void minix_truncate(struct inode * inode)
-{
- if (INODE_VERSION(inode) == MINIX_V1)
- V1_minix_truncate(inode);
- else
- V2_minix_truncate(inode);
-}
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 79f700650..d7e77a316 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -265,7 +265,7 @@ static int msdos_add_entry(struct inode *dir, const char *name,
(*de)->starthi = 0;
fat_date_unix2dos(dir->i_mtime,&(*de)->time,&(*de)->date);
(*de)->size = 0;
- fat_mark_buffer_dirty(sb, *bh, 1);
+ fat_mark_buffer_dirty(sb, *bh);
return 0;
}
@@ -330,7 +330,7 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry)
goto rmdir_done;
de->name[0] = DELETED_FLAG;
- fat_mark_buffer_dirty(sb, bh, 1);
+ fat_mark_buffer_dirty(sb, bh);
fat_detach(inode);
inode->i_nlink = 0;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -396,7 +396,7 @@ mkdir_error:
mark_inode_dirty(inode);
mark_inode_dirty(dir);
de->name[0] = DELETED_FLAG;
- fat_mark_buffer_dirty(sb, bh, 1);
+ fat_mark_buffer_dirty(sb, bh);
fat_brelse(sb, bh);
fat_detach(inode);
iput(inode);
@@ -424,7 +424,7 @@ int msdos_unlink( struct inode *dir, struct dentry *dentry)
goto unlink_done;
de->name[0] = DELETED_FLAG;
- fat_mark_buffer_dirty(sb, bh, 1);
+ fat_mark_buffer_dirty(sb, bh);
fat_detach(inode);
fat_brelse(sb, bh);
inode->i_nlink = 0;
@@ -485,7 +485,7 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name,
if (new_inode)
fat_detach(new_inode);
old_de->name[0] = DELETED_FLAG;
- fat_mark_buffer_dirty(sb, old_bh, 1);
+ fat_mark_buffer_dirty(sb, old_bh);
fat_detach(old_inode);
fat_attach(old_inode, new_ino);
if (is_hid)
@@ -504,7 +504,7 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name,
if (dotdot_bh) {
dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
- fat_mark_buffer_dirty(sb, dotdot_bh, 1);
+ fat_mark_buffer_dirty(sb, dotdot_bh);
old_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
diff --git a/fs/namei.c b/fs/namei.c
index 75ffc6ef0..c22fc2ec3 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -21,6 +21,7 @@
#include <linux/quotaops.h>
#include <linux/pagemap.h>
#include <linux/dcache.h>
+#include <linux/dnotify.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
@@ -107,7 +108,7 @@
static inline int do_getname(const char *filename, char *page)
{
int retval;
- unsigned long len = PAGE_SIZE;
+ unsigned long len = PATH_MAX + 1;
if ((unsigned long) filename >= TASK_SIZE) {
if (!segment_eq(get_fs(), KERNEL_DS))
@@ -180,7 +181,7 @@ int permission(struct inode * inode,int mask)
/* read and search access */
if ((mask == S_IROTH) ||
- (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH))))
+ (S_ISDIR(inode->i_mode) && !(mask & ~(S_IROTH | S_IXOTH))))
if (capable(CAP_DAC_READ_SEARCH))
return 0;
@@ -683,7 +684,7 @@ walk_init_root(const char *name, struct nameidata *nd)
}
/* SMP-safe */
-int path_init(const char *name,unsigned int flags,struct nameidata *nd)
+int path_init(const char *name, unsigned int flags, struct nameidata *nd)
{
nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags;
@@ -912,6 +913,8 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
unlock_kernel();
exit_lock:
up(&dir->i_zombie);
+ if (!error)
+ inode_dir_notify(dir, DN_CREATE);
return error;
}
@@ -1066,6 +1069,13 @@ ok:
goto exit;
}
+ /*
+ * Ensure there are no outstanding leases on the file.
+ */
+ error = get_lease(inode, flag);
+ if (error)
+ goto exit;
+
if (flag & O_TRUNC) {
error = get_write_access(inode);
if (error)
@@ -1183,6 +1193,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
unlock_kernel();
exit_lock:
up(&dir->i_zombie);
+ if (!error)
+ inode_dir_notify(dir, DN_CREATE);
return error;
}
@@ -1250,6 +1262,8 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
exit_lock:
up(&dir->i_zombie);
+ if (!error)
+ inode_dir_notify(dir, DN_CREATE);
return error;
}
@@ -1338,8 +1352,10 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
dentry->d_inode->i_flags |= S_DEAD;
}
double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
- if (!error)
+ if (!error) {
+ inode_dir_notify(dir, DN_DELETE);
d_delete(dentry);
+ }
dput(dentry);
return error;
@@ -1406,6 +1422,8 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
}
}
up(&dir->i_zombie);
+ if (!error)
+ inode_dir_notify(dir, DN_DELETE);
return error;
}
@@ -1472,6 +1490,8 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
exit_lock:
up(&dir->i_zombie);
+ if (!error)
+ inode_dir_notify(dir, DN_CREATE);
return error;
}
@@ -1544,6 +1564,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
exit_lock:
up(&dir->i_zombie);
+ if (!error)
+ inode_dir_notify(dir, DN_CREATE);
return error;
}
@@ -1749,10 +1771,20 @@ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
+ int error;
if (S_ISDIR(old_dentry->d_inode->i_mode))
- return vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
+ error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
else
- return vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
+ error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
+ if (!error) {
+ if (old_dir == new_dir)
+ inode_dir_notify(old_dir, DN_RENAME);
+ else {
+ inode_dir_notify(old_dir, DN_DELETE);
+ inode_dir_notify(new_dir, DN_CREATE);
+ }
+ }
+ return error;
}
static inline int do_rename(const char * oldname, const char * newname)
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 1c0f13e3b..eda3fe6af 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -342,7 +342,8 @@ ncp_d_validate(struct dentry *dentry)
goto bad_addr;
if ((dent_addr & ~align_mask) != dent_addr)
goto bad_align;
- if (!kern_addr_valid(dent_addr))
+ if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 +
+ sizeof(struct dentry))))
goto bad_addr;
/*
* Looks safe enough to dereference ...
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index a5c68e18c..139c9262d 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -256,7 +256,7 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
}
if (ncp_write_kernel(NCP_SERVER(inode),
NCP_FINFO(inode)->file_handle,
- pos, to_write, buf, &written_this_time) != 0) {
+ pos, to_write, bouncebuffer, &written_this_time) != 0) {
errno = -EIO;
break;
}
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index f1c9099bc..4df91abe3 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -290,7 +290,8 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
return -EACCES;
}
/* get only low 8 bits... */
- get_user_ret(newstate, (unsigned char*)arg, -EFAULT);
+ if (get_user(newstate, (unsigned char *) arg))
+ return -EFAULT;
if (server->sign_active) {
/* cannot turn signatures OFF when active */
if (!newstate) return -EINVAL;
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 64ef9274b..52283d234 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -9,7 +9,7 @@
O_TARGET := nfs.o
O_OBJS := inode.o file.o read.o write.o dir.o symlink.o proc.o \
- nfs2xdr.o flushd.o
+ nfs2xdr.o flushd.o unlink.o
ifdef CONFIG_ROOT_NFS
O_OBJS += nfsroot.o mount_clnt.o
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 11b8e5d79..ec4540f12 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -606,16 +606,8 @@ static void nfs_dentry_release(struct dentry *dentry)
static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
{
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
- struct dentry *dir = dentry->d_parent;
- struct inode *dir_i = dir->d_inode;
- int error;
-
lock_kernel();
- dir = dentry->d_parent;
- dir_i = dir->d_inode;
- nfs_zap_caches(dir_i);
- NFS_CACHEINV(inode);
- error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name);
+ nfs_complete_unlink(dentry);
unlock_kernel();
}
iput(inode);
@@ -817,14 +809,9 @@ static int nfs_sillyrename(struct inode *dir_i, struct dentry *dentry)
dentry->d_parent->d_name.name, dentry->d_name.name,
atomic_read(&dentry->d_count));
- /*
- * Note that a silly-renamed file can be deleted once it's
- * no longer in use -- it's just an ordinary file now.
- */
- if (atomic_read(&dentry->d_count) == 1) {
- dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+ if (atomic_read(&dentry->d_count) == 1)
goto out; /* No need to silly rename. */
- }
+
#ifdef NFS_PARANOIA
if (!dentry->d_inode)
@@ -868,7 +855,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
if (!error) {
nfs_renew_times(dentry);
d_move(dentry, sdentry);
- dentry->d_flags |= DCACHE_NFSFS_RENAMED;
+ error = nfs_async_unlink(dentry);
/* If we return 0 we don't unlink */
}
dput(sdentry);
@@ -908,12 +895,21 @@ static int nfs_safe_remove(struct dentry *dentry)
#endif
goto out;
}
+
+ /* If the dentry was sillyrenamed, we simply call d_delete() */
+ if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+ error = 0;
+ goto out_delete;
+ }
+
nfs_zap_caches(dir_i);
if (inode)
NFS_CACHEINV(inode);
error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name);
if (error < 0)
goto out;
+
+ out_delete:
/*
* Free the inode
*/
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 06f067eea..21ae090a3 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -291,10 +291,13 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
status = 0;
/*
- * Make sure we re-validate anything we've got cached.
+ * Make sure we clear the cache whenever we try to get the lock.
* This makes locking act as a cache coherency point.
*/
out_ok:
- NFS_CACHEINV(inode);
+ if ((cmd == F_SETLK || cmd == F_SETLKW) && fl->fl_type != F_UNLCK) {
+ nfs_wb_all(inode); /* we may have slept */
+ nfs_zap_caches(inode);
+ }
return status;
}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 5e7ced09e..b21592528 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -353,6 +353,7 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
clnt->cl_intr = (data->flags & NFS_MOUNT_INTR)? 1 : 0;
clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0;
+ clnt->cl_droppriv = (data->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0;
clnt->cl_chatty = 1;
server->client = clnt;
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 42191418f..d75e9eda0 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -267,6 +267,38 @@ nfs3_proc_remove(struct dentry *dir, struct qstr *name)
}
static int
+nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
+{
+ struct nfs3_diropargs *arg;
+ struct nfs_fattr *res;
+
+ arg = (struct nfs3_diropargs *)kmalloc(sizeof(*arg)+sizeof(*res), GFP_KERNEL);
+ if (!arg)
+ return -ENOMEM;
+ res = (struct nfs_fattr*)(arg + 1);
+ arg->fh = NFS_FH(dir);
+ arg->name = name->name;
+ arg->len = name->len;
+ res->valid = 0;
+ msg->rpc_proc = NFS3PROC_REMOVE;
+ msg->rpc_argp = arg;
+ msg->rpc_resp = res;
+ return 0;
+}
+
+static void
+nfs3_proc_unlink_done(struct dentry *dir, struct rpc_message *msg)
+{
+ struct nfs_fattr *dir_attr;
+
+ if (msg->rpc_argp) {
+ dir_attr = (struct nfs_fattr*)msg->rpc_resp;
+ nfs_refresh_inode(dir->d_inode, dir_attr);
+ kfree(msg->rpc_argp);
+ }
+}
+
+static int
nfs3_proc_rename(struct dentry *old_dir, struct qstr *old_name,
struct dentry *new_dir, struct qstr *new_name)
{
@@ -469,6 +501,8 @@ struct nfs_rpc_ops nfs_v3_clientops = {
NULL, /* commit */
nfs3_proc_create,
nfs3_proc_remove,
+ nfs3_proc_unlink_setup,
+ nfs3_proc_unlink_done,
nfs3_proc_rename,
nfs3_proc_link,
nfs3_proc_symlink,
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 7c3a7a0cc..ce05e1843 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -157,6 +157,7 @@ static struct nfs_bool_opts {
#endif
{ "udp", ~NFS_MOUNT_TCP, 0 },
{ "tcp", ~NFS_MOUNT_TCP, NFS_MOUNT_TCP },
+ { "broken_suid",~NFS_MOUNT_BROKEN_SUID, NFS_MOUNT_BROKEN_SUID },
{ NULL, 0, 0 }
};
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 574c26a15..be935c083 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -233,6 +233,31 @@ nfs_proc_remove(struct dentry *dir, struct qstr *name)
}
static int
+nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
+{
+ struct nfs_diropargs *arg;
+
+ arg = (struct nfs_diropargs *)kmalloc(sizeof(*arg), GFP_KERNEL);
+ if (!arg)
+ return -ENOMEM;
+ arg->fh = NFS_FH(dir);
+ arg->name = name->name;
+ arg->len = name->len;
+ msg->rpc_proc = NFSPROC_REMOVE;
+ msg->rpc_argp = arg;
+ return 0;
+}
+
+static void
+nfs_proc_unlink_done(struct dentry *dir, struct rpc_message *msg)
+{
+ if (msg->rpc_argp) {
+ NFS_CACHEINV(dir->d_inode);
+ kfree(msg->rpc_argp);
+ }
+}
+
+static int
nfs_proc_rename(struct dentry *old_dir, struct qstr *old_name,
struct dentry *new_dir, struct qstr *new_name)
{
@@ -365,6 +390,8 @@ struct nfs_rpc_ops nfs_v2_clientops = {
NULL, /* commit */
nfs_proc_create,
nfs_proc_remove,
+ nfs_proc_unlink_setup,
+ nfs_proc_unlink_done,
nfs_proc_rename,
nfs_proc_link,
nfs_proc_symlink,
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
new file mode 100644
index 000000000..f4abfe7b3
--- /dev/null
+++ b/fs/nfs/unlink.c
@@ -0,0 +1,216 @@
+/*
+ * linux/fs/nfs/unlink.c
+ *
+ * nfs sillydelete handling
+ *
+ * NOTE: we rely on holding the BKL for list manipulation protection.
+ */
+
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/dcache.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfs_fs.h>
+
+
+struct nfs_unlinkdata {
+ struct nfs_unlinkdata *next;
+ struct dentry *dir, *dentry;
+ struct qstr name;
+ struct rpc_task task;
+ struct rpc_cred *cred;
+ unsigned int count;
+};
+
+static struct nfs_unlinkdata *nfs_deletes;
+static struct rpc_wait_queue nfs_delete_queue = RPC_INIT_WAITQ("nfs_delete_queue");
+
+/**
+ * nfs_detach_unlinkdata - Remove asynchronous unlink from global list
+ * @data: pointer to descriptor
+ */
+static inline void
+nfs_detach_unlinkdata(struct nfs_unlinkdata *data)
+{
+ struct nfs_unlinkdata **q;
+
+ for (q = &nfs_deletes; *q != NULL; q = &((*q)->next)) {
+ if (*q == data) {
+ *q = data->next;
+ break;
+ }
+ }
+}
+
+/**
+ * nfs_put_unlinkdata - release data from a sillydelete operation.
+ * @data: pointer to unlink structure.
+ */
+static void
+nfs_put_unlinkdata(struct nfs_unlinkdata *data)
+{
+ if (--data->count == 0) {
+ nfs_detach_unlinkdata(data);
+ if (data->name.name != NULL)
+ kfree(data->name.name);
+ kfree(data);
+ }
+}
+
+#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
+/**
+ * nfs_copy_dname - copy dentry name to data structure
+ * @dentry: pointer to dentry
+ * @data: nfs_unlinkdata
+ */
+static inline void
+nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
+{
+ char *str;
+ int len = dentry->d_name.len;
+
+ str = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL);
+ if (!str)
+ return;
+ memcpy(str, dentry->d_name.name, len);
+ if (!data->name.len) {
+ data->name.len = len;
+ data->name.name = str;
+ } else
+ kfree(str);
+}
+
+/**
+ * nfs_async_unlink_init - Initialize the RPC info
+ * @task: rpc_task of the sillydelete
+ *
+ * We delay initializing RPC info until after the call to dentry_iput()
+ * in order to minimize races against rename().
+ */
+static void
+nfs_async_unlink_init(struct rpc_task *task)
+{
+ struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata;
+ struct dentry *dir = data->dir;
+ struct rpc_message msg;
+ int status = -ENOENT;
+
+ if (!data->name.len)
+ goto out_err;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.rpc_cred = data->cred;
+ status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name);
+ if (status < 0)
+ goto out_err;
+ rpc_call_setup(task, &msg, 0);
+ return;
+ out_err:
+ rpc_exit(task, status);
+}
+
+/**
+ * nfs_async_unlink_done - Sillydelete post-processing
+ * @task: rpc_task of the sillydelete
+ *
+ * Do the directory attribute update.
+ */
+static void
+nfs_async_unlink_done(struct rpc_task *task)
+{
+ struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata;
+ struct dentry *dir = data->dir;
+ struct inode *dir_i;
+
+ if (!dir)
+ return;
+ dir_i = dir->d_inode;
+ nfs_zap_caches(dir_i);
+ NFS_PROTO(dir_i)->unlink_done(dir, &task->tk_msg);
+ rpcauth_releasecred(task->tk_auth, data->cred);
+ data->cred = NULL;
+ dput(dir);
+}
+
+/**
+ * nfs_async_unlink_release - Release the sillydelete data.
+ * @task: rpc_task of the sillydelete
+ *
+ * We need to call nfs_put_unlinkdata as a 'tk_release' task since the
+ * rpc_task would be freed too.
+ */
+static void
+nfs_async_unlink_release(struct rpc_task *task)
+{
+ struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata;
+ nfs_put_unlinkdata(data);
+}
+
+/**
+ * nfs_async_unlink - asynchronous unlinking of a file
+ * @dir: directory in which the file resides.
+ * @name: name of the file to unlink.
+ */
+int
+nfs_async_unlink(struct dentry *dentry)
+{
+ struct dentry *dir = dentry->d_parent;
+ struct nfs_unlinkdata *data;
+ struct rpc_task *task;
+ struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode);
+ int status = -ENOMEM;
+
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto out;
+ memset(data, 0, sizeof(*data));
+
+ data->dir = dget(dir);
+ data->dentry = dentry;
+
+ data->next = nfs_deletes;
+ nfs_deletes = data;
+ data->count = 1;
+
+ task = &data->task;
+ rpc_init_task(task, clnt, nfs_async_unlink_done , RPC_TASK_ASYNC);
+ task->tk_calldata = data;
+ task->tk_action = nfs_async_unlink_init;
+ task->tk_release = nfs_async_unlink_release;
+
+ dentry->d_flags |= DCACHE_NFSFS_RENAMED;
+ data->cred = rpcauth_lookupcred(clnt->cl_auth, 0);
+
+ rpc_sleep_on(&nfs_delete_queue, task, NULL, NULL);
+ status = 0;
+ out:
+ return status;
+}
+
+/**
+ * nfs_complete_remove - Initialize completion of the sillydelete
+ * @dentry: dentry to delete
+ *
+ * Since we're most likely to be called by dentry_iput(), we
+ * only use the dentry to find the sillydelete. We then copy the name
+ * into the qstr.
+ */
+void
+nfs_complete_unlink(struct dentry *dentry)
+{
+ struct nfs_unlinkdata *data;
+
+ for(data = nfs_deletes; data != NULL; data = data->next) {
+ if (dentry == data->dentry)
+ break;
+ }
+ if (!data)
+ return;
+ data->count++;
+ nfs_copy_dname(dentry, data);
+ dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+ if (data->task.tk_rpcwait == &nfs_delete_queue)
+ rpc_wake_up_task(&data->task);
+ nfs_put_unlinkdata(data);
+}
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index df2532048..2beed5cf9 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1,3 +1,4 @@
+#define MSNFS /* HACK HACK */
/*
* linux/fs/nfsd/export.c
*
@@ -56,12 +57,12 @@ struct svc_clnthash {
struct svc_client * h_client;
};
static struct svc_clnthash * clnt_hash[CLIENT_HASHMAX];
-static svc_client * clients = NULL;
-static int initialized = 0;
+static svc_client * clients;
+static int initialized;
-static int hash_lock = 0;
-static int want_lock = 0;
-static int hash_count = 0;
+static int hash_lock;
+static int want_lock;
+static int hash_count;
static DECLARE_WAIT_QUEUE_HEAD( hash_wait );
@@ -556,6 +557,9 @@ struct flags {
{ NFSEXP_CROSSMNT, {"nohide", ""}},
{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
{ NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
+#ifdef NSMFS
+ { NFSEXP_MSNFS, {"msnfs", ""}},
+#endif
{ 0, {"", ""}}
};
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index e6118a967..a513bfbe0 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/locks.h>
#include <linux/fs.h>
+#include <linux/ext2_fs.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/net.h>
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 308db4cd5..d97e1717d 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -193,7 +193,7 @@ encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
p = xdr_encode_hyper(p, (u64) inode->i_dev);
p = xdr_encode_hyper(p, (u64) inode->i_ino);
p = encode_time3(p, inode->i_atime);
- p = encode_time3(p, inode->i_mtime);
+ p = encode_time3(p, lease_get_mtime(inode));
p = encode_time3(p, inode->i_ctime);
return p;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 20e82fa7a..7a80fe990 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -46,7 +46,7 @@ static int nfsctl_getfs(struct nfsctl_fsparm *, struct knfsd_fh *);
static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data);
#endif
-static int initialized = 0;
+static int initialized;
int exp_procfs_exports(char *buffer, char **start, off_t offset,
int length, int *eof, void *data);
@@ -312,7 +312,9 @@ done:
EXPORT_NO_SYMBOLS;
MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
-extern long (*do_nfsservctl)(int, void *, void *);
+struct nfsd_linkage nfsd_linkage_s = {
+ do_nfsservctl: handle_sys_nfsservctl,
+};
/*
* Initialize the module
@@ -321,7 +323,7 @@ int
init_module(void)
{
printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
- do_nfsservctl = handle_sys_nfsservctl;
+ nfsd_linkage = &nfsd_linkage_s;
return 0;
}
@@ -331,7 +333,7 @@ init_module(void)
void
cleanup_module(void)
{
- do_nfsservctl = NULL;
+ nfsd_linkage = NULL;
nfsd_export_shutdown();
nfsd_cache_shutdown();
remove_proc_entry("fs/nfs/exports", NULL);
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index d1b6306db..672d66bf8 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -405,7 +405,7 @@ find_fh_dentry(struct super_block *sb, ino_t ino, int generation, ino_t dirino,
|| !S_ISDIR(dentry->d_inode->i_mode)) {
goto err_dentry;
}
- if ((!dentry->d_flags & DCACHE_NFSD_DISCONNECTED))
+ if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED))
found = 1;
tmp = splice(result, dentry);
err = PTR_ERR(tmp);
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 11297fef5..a4a642c44 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -41,9 +41,9 @@
extern struct svc_program nfsd_program;
static void nfsd(struct svc_rqst *rqstp);
-struct timeval nfssvc_boot = { 0, 0 };
-static struct svc_serv *nfsd_serv = NULL;
-static int nfsd_busy = 0;
+struct timeval nfssvc_boot;
+static struct svc_serv *nfsd_serv;
+static int nfsd_busy;
static unsigned long nfsd_last_call;
struct nfsd_list {
@@ -155,6 +155,8 @@ nfsd(struct svc_rqst *rqstp)
sprintf(current->comm, "nfsd");
current->fs->umask = 0;
+ current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
+
nfsdstats.th_cnt++;
/* Let svc_process check client's authentication. */
rqstp->rq_auth = 1;
@@ -213,7 +215,7 @@ nfsd(struct svc_rqst *rqstp)
unsigned int signo;
for (signo = 1; signo <= _NSIG; signo++)
- if (sigismember(&current->signal, signo) &&
+ if (sigismember(&current->pending.signal, signo) &&
!sigismember(&current->blocked, signo))
break;
printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo);
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 9127e0869..fcbddc5ed 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -155,7 +155,7 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct inode *inode)
*p++ = htonl((u32) inode->i_ino);
*p++ = htonl((u32) inode->i_atime);
*p++ = 0;
- *p++ = htonl((u32) inode->i_mtime);
+ *p++ = htonl((u32) lease_get_mtime(inode));
*p++ = 0;
*p++ = htonl((u32) inode->i_ctime);
*p++ = 0;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 20fa7fafe..a796885e3 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1,3 +1,4 @@
+#define MSNFS /* HACK HACK */
/*
* linux/fs/nfsd/vfs.c
*
@@ -142,6 +143,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
} else
dentry = dget(dparent->d_parent);
} else {
+ fh_lock(fhp);
dentry = lookup_one(name, dparent);
err = PTR_ERR(dentry);
if (IS_ERR(dentry))
@@ -248,6 +250,15 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
if (err)
goto out;
}
+
+ /*
+ * If we are changing the size of the file, then
+ * we need to break all leases.
+ */
+ err = get_lease(inode, FMODE_WRITE);
+ if (err)
+ goto out_nfserr;
+
err = get_write_access(inode);
if (err)
goto out_nfserr;
@@ -442,6 +453,14 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if (!inode->i_fop)
goto out;
+ /*
+ * Check to see if there are any leases on this file.
+ * This may block while leases are broken.
+ */
+ err = get_lease(inode, (access & MAY_WRITE) ? FMODE_WRITE : 0);
+ if (err)
+ goto out_nfserr;
+
if ((access & MAY_WRITE) && (err = get_write_access(inode)) != 0)
goto out_nfserr;
@@ -450,11 +469,11 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
atomic_set(&filp->f_count, 1);
filp->f_dentry = dentry;
if (access & MAY_WRITE) {
- filp->f_flags = O_WRONLY;
+ filp->f_flags = O_WRONLY|O_LARGEFILE;
filp->f_mode = FMODE_WRITE;
DQUOT_INIT(inode);
} else {
- filp->f_flags = O_RDONLY;
+ filp->f_flags = O_RDONLY|O_LARGEFILE;
filp->f_mode = FMODE_READ;
}
@@ -576,6 +595,11 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
err = nfserr_perm;
if (!file.f_op->read)
goto out_close;
+#ifdef MSNFS
+ if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
+ (!lock_may_read(file.f_dentry->d_inode, offset, *count)))
+ goto out_close;
+#endif
/* Get readahead parameters */
ra = nfsd_get_raparms(fhp->fh_export->ex_dev, fhp->fh_dentry->d_inode->i_ino);
@@ -642,6 +666,11 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
err = nfserr_perm;
if (!file.f_op->write)
goto out_close;
+#ifdef MSNFS
+ if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
+ (!lock_may_write(file.f_dentry->d_inode, offset, cnt)))
+ goto out_close;
+#endif
dentry = file.f_dentry;
inode = dentry->d_inode;
@@ -1249,6 +1278,13 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
goto out_dput_old;
+#ifdef MSNFS
+ if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
+ ((atomic_read(&odentry->d_count) > 1)
+ || (atomic_read(&ndentry->d_count) > 1))) {
+ err = nfserr_perm;
+ } else
+#endif
err = vfs_rename(fdir, odentry, tdir, ndentry);
if (!err && EX_ISSYNC(tfhp->fh_export)) {
nfsd_sync_dir(tdentry);
@@ -1310,6 +1346,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
}
if (type != S_IFDIR) { /* It's UNLINK */
+#ifdef MSNFS
+ if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
+ (atomic_read(&rdentry->d_count) > 1)) {
+ err = nfserr_perm;
+ } else
+#endif
err = vfs_unlink(dirp, rdentry);
} else { /* It's RMDIR */
err = vfs_rmdir(dirp, rdentry);
diff --git a/fs/ntfs/support.c b/fs/ntfs/support.c
index 274465573..7e96f21ee 100644
--- a/fs/ntfs/support.c
+++ b/fs/ntfs/support.c
@@ -177,7 +177,7 @@ int ntfs_getput_clusters(ntfs_volume *vol, int cluster, ntfs_size_t start_offs,
else
{
buf->fn_get(bh->b_data+start_offs,buf,to_copy);
- mark_buffer_dirty(bh,1);
+ mark_buffer_dirty(bh);
}
unlock_buffer(bh);
length-=to_copy;
diff --git a/fs/open.c b/fs/open.c
index 0f1787025..ac2077f1f 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -10,11 +10,14 @@
#include <linux/file.h>
#include <linux/smp_lock.h>
#include <linux/quotaops.h>
+#include <linux/dnotify.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
+#define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
+
int vfs_statfs(struct super_block *sb, struct statfs *buf)
{
int retval = -ENODEV;
@@ -115,6 +118,13 @@ static inline long do_sys_truncate(const char * path, loff_t length)
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
goto dput_and_out;
+ /*
+ * Make sure that there are no leases.
+ */
+ error = get_lease(inode, FMODE_WRITE);
+ if (error)
+ goto dput_and_out;
+
error = get_write_access(inode);
if (error)
goto dput_and_out;
@@ -314,7 +324,8 @@ asmlinkage long sys_access(const char * filename, int mode)
if (!res) {
res = permission(nd.dentry->d_inode, mode);
/* SuS v2 requires we report a read only fs too */
- if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode))
+ if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
+ && !special_file(nd.dentry->d_inode->i_mode))
res = -EROFS;
path_release(&nd);
}
@@ -790,6 +801,7 @@ int filp_close(struct file *filp, fl_owner_t id)
retval = filp->f_op->flush(filp);
unlock_kernel();
}
+ fcntl_dirnotify(0, filp, 0);
locks_remove_posix(filp, id);
fput(filp);
return retval;
diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c
index fc13e8698..d0afb47ee 100644
--- a/fs/partitions/acorn.c
+++ b/fs/partitions/acorn.c
@@ -1,12 +1,17 @@
/*
- * linux/arch/arm/drivers/block/adfspart.c
+ * linux/fs/partitions/acorn.c
*
- * Copyright (c) 1996-2000 Russell King.
+ * Copyright (c) 1996-2000 Russell King.
*
- * Scan ADFS partitions on hard disk drives.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Scan ADFS partitions on hard disk drives.
*/
#include <linux/config.h>
#include <linux/kernel.h>
+#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/major.h>
#include <linux/string.h>
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 29b93e5a5..1dfc4ad3e 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -146,6 +146,16 @@ char *disk_name (struct gendisk *hd, int minor, char *buf)
sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part);
return buf;
}
+ if (hd->major >= COMPAQ_CISS_MAJOR && hd->major <= COMPAQ_CISS_MAJOR+7) {
+ int ctlr = hd->major - COMPAQ_CISS_MAJOR;
+ int disk = minor >> hd->minor_shift;
+ int part = minor & (( 1 << hd->minor_shift) - 1);
+ if (part == 0)
+ sprintf(buf, "%s/c%dd%d", maj, ctlr, disk);
+ else
+ sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part);
+ return buf;
+ }
if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) {
int ctlr = hd->major - DAC960_MAJOR;
int disk = minor >> hd->minor_shift;
@@ -177,7 +187,8 @@ void add_gd_partition(struct gendisk *hd, int minor, int start, int size)
#ifdef CONFIG_DEVFS_FS
printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
#else
- if (hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7)
+ if ((hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7) ||
+ (hd->major >= COMPAQ_CISS_MAJOR+0 && hd->major <= COMPAQ_CISS_MAJOR+7))
printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
else
printk(" %s", disk_name(hd, minor, buf));
@@ -228,24 +239,35 @@ unsigned int get_ptable_blocksize(kdev_t dev)
}
#ifdef CONFIG_PROC_FS
-int get_partition_list(char * page)
+int get_partition_list(char *page, char **start, off_t offset, int count)
{
- struct gendisk *p;
- char buf[64];
- int n, len;
+ struct gendisk *dsk;
+ int len;
len = sprintf(page, "major minor #blocks name\n\n");
- for (p = gendisk_head; p; p = p->next) {
- for (n=0; n < (p->nr_real << p->minor_shift); n++) {
- if (p->part[n].nr_sects && len < PAGE_SIZE - 80) {
- len += sprintf(page+len,
+ for (dsk = gendisk_head; dsk; dsk = dsk->next) {
+ int n;
+
+ for (n = 0; n < (dsk->nr_real << dsk->minor_shift); n++)
+ if (dsk->part[n].nr_sects) {
+ char buf[64];
+
+ len += sprintf(page + len,
"%4d %4d %10d %s\n",
- p->major, n, p->sizes[n],
- disk_name(p, n, buf));
+ dsk->major, n, dsk->sizes[n],
+ disk_name(dsk, n, buf));
+ if (len < offset)
+ offset -= len, len = 0;
+ else if (len >= offset + count)
+ goto leave_loops;
}
- }
}
- return len;
+leave_loops:
+ *start = page + offset;
+ len -= offset;
+ if (len < 0)
+ len = 0;
+ return len > count ? count : len;
}
#endif
@@ -428,9 +450,6 @@ int __init partition_setup(void)
#endif
rd_load();
#endif
-#ifdef CONFIG_BLK_DEV_MD
- md_run_setup();
-#endif
return 0;
}
diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c
index 119de17ba..5c46935c7 100644
--- a/fs/partitions/mac.c
+++ b/fs/partitions/mac.c
@@ -21,7 +21,7 @@
#include "mac.h"
#ifdef CONFIG_PPC
-extern void note_bootable_part(kdev_t dev, int part);
+extern void note_bootable_part(kdev_t dev, int part, int goodness);
#endif
/*
@@ -67,7 +67,7 @@ int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_
brelse(bh);
dev_pos = secsize;
if ((bh = bread(dev, secsize/dev_bsize, dev_bsize)) == 0) {
- printk("%s: error reading partition table\n",
+ printk("%s: error reading Mac partition table\n",
kdevname(dev));
return -1;
}
@@ -77,6 +77,7 @@ int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_
brelse(bh);
return 0; /* not a MacOS disk */
}
+ printk(" [mac]");
blocks_in_map = be32_to_cpu(part->map_count);
for (blk = 1; blk <= blocks_in_map; ++blk) {
pos = blk * secsize;
@@ -114,7 +115,8 @@ int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_
goodness++;
if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
- || strcasecmp(part->type, "Linux_PPC") == 0) {
+ || (strnicmp(part->type, "Linux", 5) == 0
+ && strcasecmp(part->type, "Linux_swap") != 0)) {
int i, l;
goodness++;
@@ -143,7 +145,7 @@ int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_
}
#ifdef CONFIG_PPC
if (found_root_goodness)
- note_bootable_part(dev, found_root);
+ note_bootable_part(dev, found_root, found_root_goodness);
#endif
brelse(bh);
printk("\n");
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 4bcb92d31..81884a281 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -241,7 +241,7 @@ static inline char * task_sig(struct task_struct *p, char *buffer)
sigset_t ign, catch;
buffer += sprintf(buffer, "SigPnd:\t");
- buffer = render_sigset_t(&p->signal, buffer);
+ buffer = render_sigset_t(&p->pending.signal, buffer);
*buffer++ = '\n';
buffer += sprintf(buffer, "SigBlk:\t");
buffer = render_sigset_t(&p->blocked, buffer);
@@ -382,7 +382,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
* It must be decimal for Linux 2.0 compatibility.
* Use /proc/#/status for real-time signals.
*/
- task->signal .sig[0] & 0x7fffffffUL,
+ task->pending.signal.sig[0] & 0x7fffffffUL,
task->blocked.sig[0] & 0x7fffffffUL,
sigign .sig[0] & 0x7fffffffUL,
sigcatch .sig[0] & 0x7fffffffUL,
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index ba2f88e9f..0dd6e6063 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -190,7 +190,7 @@ static int xlate_proc_name(const char *name,
return 0;
}
-static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
+static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8];
static int make_inode_number(void)
{
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index fe944bab6..00c16769e 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -4,8 +4,9 @@
* Modelled on fs/exec.c:aout_core_dump()
* Jeremy Fitzhardinge <jeremy@sw.oz.au>
* ELF version written by David Howells <David.Howells@nexor.co.uk>
- * Modified and incorporated into 2.3.x by Tigran Aivazian <tigran@sco.com>
- * Support to dump vmalloc'd areas (ELF only), Tigran Aivazian <tigran@sco.com>
+ * Modified and incorporated into 2.3.x by Tigran Aivazian <tigran@veritas.com>
+ * Support to dump vmalloc'd areas (ELF only), Tigran Aivazian <tigran@veritas.com>
+ * Safe accesses to vmalloc/direct-mapped discontiguous areas, Kanoj Sarcar <kanoj@sgi.com>
*/
#include <linux/config.h>
@@ -112,18 +113,17 @@ extern char saved_command_line[];
static size_t get_kcore_size(int *num_vma, size_t *elf_buflen)
{
- size_t try, size = 0;
+ size_t try, size;
struct vm_struct *m;
*num_vma = 0;
+ size = ((size_t)high_memory - PAGE_OFFSET + PAGE_SIZE);
if (!vmlist) {
*elf_buflen = PAGE_SIZE;
- return ((size_t)high_memory - PAGE_OFFSET + PAGE_SIZE);
+ return (size);
}
for (m=vmlist; m; m=m->next) {
- if (m->flags & VM_IOREMAP) /* don't dump ioremap'd stuff! (TA) */
- continue;
try = (size_t)m->addr + m->size;
if (try > size)
size = try;
@@ -315,6 +315,7 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
size_t size, tsz;
size_t elf_buflen;
int num_vma;
+ unsigned long start;
read_lock(&vmlist_lock);
proc_root_kcore->size = size = get_kcore_size(&num_vma, &elf_buflen);
@@ -380,11 +381,77 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
}
#endif
/* fill the remainder of the buffer from kernel VM space */
- if (copy_to_user(buffer, __va(*fpos - elf_buflen), buflen))
- return -EFAULT;
+ start = (unsigned long)__va(*fpos - elf_buflen);
+ if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
+ tsz = buflen;
+
+ while (buflen) {
+ if ((start >= VMALLOC_START) && (start < VMALLOC_END)) {
+ char * elf_buf;
+ struct vm_struct *m;
+ unsigned long curstart = start;
+ unsigned long cursize = tsz;
+
+ elf_buf = kmalloc(tsz, GFP_KERNEL);
+ if (!elf_buf)
+ return -ENOMEM;
+ memset(elf_buf, 0, tsz);
+
+ read_lock(&vmlist_lock);
+ for (m=vmlist; m && cursize; m=m->next) {
+ unsigned long vmstart;
+ unsigned long vmsize;
+ unsigned long msize = m->size - PAGE_SIZE;
+
+ if (((unsigned long)m->addr + msize) <
+ curstart)
+ continue;
+ if ((unsigned long)m->addr > (curstart +
+ cursize))
+ break;
+ vmstart = (curstart < (unsigned long)m->addr ?
+ (unsigned long)m->addr : curstart);
+ if (((unsigned long)m->addr + msize) >
+ (curstart + cursize))
+ vmsize = curstart + cursize - vmstart;
+ else
+ vmsize = (unsigned long)m->addr +
+ msize - vmstart;
+ curstart = vmstart + vmsize;
+ cursize -= vmsize;
+ /* don't dump ioremap'd stuff! (TA) */
+ if (m->flags & VM_IOREMAP)
+ continue;
+ memcpy(elf_buf + (vmstart - start),
+ (char *)vmstart, vmsize);
+ }
+ read_unlock(&vmlist_lock);
+ if (copy_to_user(buffer, elf_buf, tsz)) {
+ kfree(elf_buf);
+ return -EFAULT;
+ }
+ kfree(elf_buf);
+ } else if ((start > PAGE_OFFSET) && (start <
+ (unsigned long)high_memory)) {
+ if (kern_addr_valid(start)) {
+ if (copy_to_user(buffer, (char *)start, tsz))
+ return -EFAULT;
+ } else {
+ if (clear_user(buffer, tsz))
+ return -EFAULT;
+ }
+ } else {
+ if (clear_user(buffer, tsz))
+ return -EFAULT;
+ }
+ buflen -= tsz;
+ *fpos += tsz;
+ buffer += tsz;
+ acc += tsz;
+ start += tsz;
+ tsz = (buflen > PAGE_SIZE ? PAGE_SIZE : buflen);
+ }
- acc += buflen;
- *fpos += buflen;
return acc;
}
#endif /* CONFIG_KCORE_AOUT */
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index d7aabc334..8ff300269 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -56,7 +56,7 @@ extern int get_module_list(char *);
extern int get_ksyms_list(char *, char **, off_t, int);
#endif
extern int get_device_list(char *);
-extern int get_partition_list(char *);
+extern int get_partition_list(char *, char **, off_t, int);
extern int get_filesystem_list(char *);
extern int get_filesystem_info(char *);
extern int get_exec_domain_list(char *);
@@ -156,22 +156,30 @@ static int meminfo_read_proc(char *page, char **start, off_t off,
* have been updated.
*/
len += sprintf(page+len,
- "MemTotal: %8lu kB\n"
- "MemFree: %8lu kB\n"
- "MemShared: %8lu kB\n"
- "Buffers: %8lu kB\n"
- "Cached: %8u kB\n"
- "HighTotal: %8lu kB\n"
- "HighFree: %8lu kB\n"
- "LowTotal: %8lu kB\n"
- "LowFree: %8lu kB\n"
- "SwapTotal: %8lu kB\n"
- "SwapFree: %8lu kB\n",
+ "MemTotal: %8lu kB\n"
+ "MemFree: %8lu kB\n"
+ "MemShared: %8lu kB\n"
+ "Buffers: %8lu kB\n"
+ "Cached: %8u kB\n"
+ "Active: %8u kB\n"
+ "Inact_dirty: %8u kB\n"
+ "Inact_clean: %8u kB\n"
+ "Inact_target: %8lu kB\n"
+ "HighTotal: %8lu kB\n"
+ "HighFree: %8lu kB\n"
+ "LowTotal: %8lu kB\n"
+ "LowFree: %8lu kB\n"
+ "SwapTotal: %8lu kB\n"
+ "SwapFree: %8lu kB\n",
K(i.totalram),
K(i.freeram),
K(i.sharedram),
K(i.bufferram),
K(atomic_read(&page_cache_size)),
+ K(nr_active_pages),
+ K(nr_inactive_dirty_pages),
+ K(nr_inactive_clean_pages()),
+ K(inactive_target),
K(i.totalhigh),
K(i.freehigh),
K(i.totalram-i.totalhigh),
@@ -328,14 +336,14 @@ static int kstat_read_proc(char *page, char **start, off_t off,
for (major = 0; major < DK_MAX_MAJOR; major++) {
for (disk = 0; disk < DK_MAX_DISK; disk++) {
- int active = kstat.dk_drive_rio[major][disk] +
+ int active = kstat.dk_drive[major][disk] +
kstat.dk_drive_rblk[major][disk] +
- kstat.dk_drive_wio[major][disk] +
kstat.dk_drive_wblk[major][disk];
if (active)
len += sprintf(page + len,
- "(%u,%u):(%u,%u,%u,%u) ",
+ "(%u,%u):(%u,%u,%u,%u,%u) ",
major, disk,
+ kstat.dk_drive[major][disk],
kstat.dk_drive_rio[major][disk],
kstat.dk_drive_rblk[major][disk],
kstat.dk_drive_wio[major][disk],
@@ -375,12 +383,8 @@ static int devices_read_proc(char *page, char **start, off_t off,
static int partitions_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
- int len = get_partition_list(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
+ int len = get_partition_list(page, start, off, count);
+ if (len < count) *eof = 1;
return len;
}
diff --git a/fs/proc/procfs_syms.c b/fs/proc/procfs_syms.c
index e6d1cf74c..8f79730fe 100644
--- a/fs/proc/procfs_syms.c
+++ b/fs/proc/procfs_syms.c
@@ -28,7 +28,9 @@ static int __init init_proc_fs(void)
if (!err) {
proc_mnt = kern_mount(&proc_fs_type);
err = PTR_ERR(proc_mnt);
- if (!IS_ERR(proc_mnt))
+ if (IS_ERR(proc_mnt))
+ unregister_filesystem(&proc_fs_type);
+ else
err = 0;
}
return err;
diff --git a/fs/qnx4/bitmap.c b/fs/qnx4/bitmap.c
index 03e89e64d..09b94399a 100644
--- a/fs/qnx4/bitmap.c
+++ b/fs/qnx4/bitmap.c
@@ -134,7 +134,7 @@ int qnx4_set_bitmap(struct super_block *sb, long block, int busy)
} else {
(*g) |= (1 << (block % 8));
}
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
return 0;
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 34bfbaa6c..78dbc34f0 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -112,7 +112,7 @@ static void qnx4_write_inode(struct inode *inode, int unused)
raw_inode->di_atime = cpu_to_le32(inode->i_atime);
raw_inode->di_ctime = cpu_to_le32(inode->i_ctime);
raw_inode->di_first_xtnt.xtnt_size = cpu_to_le32(inode->i_blocks);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
unlock_kernel();
}
@@ -149,7 +149,7 @@ static int qnx4_remount(struct super_block *sb, int *flags, char *data)
if (*flags & MS_RDONLY) {
return 0;
}
- mark_buffer_dirty(qs->sb_buf, 1);
+ mark_buffer_dirty(qs->sb_buf);
return 0;
}
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
index 3ef38467c..7366b757f 100644
--- a/fs/qnx4/namei.c
+++ b/fs/qnx4/namei.c
@@ -178,7 +178,7 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry)
de->di_status = 0;
memset(de->di_fname, 0, sizeof de->di_fname);
de->di_mode = 0;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
inode->i_nlink = 0;
mark_inode_dirty(inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -221,7 +221,7 @@ int qnx4_unlink(struct inode *dir, struct dentry *dentry)
de->di_status = 0;
memset(de->di_fname, 0, sizeof de->di_fname);
de->di_mode = 0;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
inode->i_nlink--;
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index dc424b72e..f13ba4f3d 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -121,7 +121,7 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, int dev)
inode->i_size = 0;
inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
- inode->i_rdev = dev;
+ inode->i_rdev = to_kdev_t(dev);
inode->i_nlink = 1;
inode->i_op = NULL;
inode->i_fop = NULL;
diff --git a/fs/read_write.c b/fs/read_write.c
index 3d3519146..00b0daf7e 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -10,6 +10,7 @@
#include <linux/file.h>
#include <linux/uio.h>
#include <linux/smp_lock.h>
+#include <linux/dnotify.h>
#include <asm/uaccess.h>
@@ -132,6 +133,9 @@ asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
ret = read(file, buf, count, &file->f_pos);
}
}
+ if (ret > 0)
+ inode_dir_notify(file->f_dentry->d_parent->d_inode,
+ DN_ACCESS);
fput(file);
}
return ret;
@@ -156,6 +160,9 @@ asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
ret = write(file, buf, count, &file->f_pos);
}
}
+ if (ret > 0)
+ inode_dir_notify(file->f_dentry->d_parent->d_inode,
+ DN_MODIFY);
fput(file);
}
return ret;
@@ -257,6 +264,10 @@ out:
if (iov != iovstack)
kfree(iov);
out_nofree:
+ /* VERIFY_WRITE actually means a read, as we write to user space */
+ if ((ret + (type == VERIFY_WRITE)) > 0)
+ inode_dir_notify(file->f_dentry->d_parent->d_inode,
+ (type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS);
return ret;
}
@@ -327,6 +338,8 @@ asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
if (pos < 0)
goto out;
ret = read(file, buf, count, &pos);
+ if (ret > 0)
+ inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_ACCESS);
out:
fput(file);
bad_file:
@@ -357,6 +370,8 @@ asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
goto out;
ret = write(file, buf, count, &pos);
+ if (ret > 0)
+ inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_MODIFY);
out:
fput(file);
bad_file:
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index b063860ee..0406f72cb 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -33,6 +33,13 @@
#include "smb_debug.h"
#include "getopt.h"
+/* Always pick a default string */
+#ifdef CONFIG_SMB_NLS_REMOTE
+#define SMB_NLS_REMOTE CONFIG_SMB_NLS_REMOTE
+#else
+#define SMB_NLS_REMOTE ""
+#endif
+
static void smb_delete_inode(struct inode *);
static void smb_put_super(struct super_block *);
static int smb_statfs(struct super_block *, struct statfs *);
@@ -445,7 +452,7 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
SMB_NLS_MAXNAMELEN);
- strncpy(mnt->codepage.remote_name, CONFIG_SMB_NLS_REMOTE,
+ strncpy(mnt->codepage.remote_name, SMB_NLS_REMOTE,
SMB_NLS_MAXNAMELEN);
if (ver == SMB_MOUNT_OLDVERSION) {
diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c
index 01ae6ec87..66dbd9efb 100644
--- a/fs/smbfs/sock.c
+++ b/fs/smbfs/sock.c
@@ -641,7 +641,7 @@ smb_request(struct smb_sb_info *server)
DEBUG1("len = %d cmd = 0x%X\n", len, buffer[8]);
spin_lock_irqsave(&current->sigmask_lock, flags);
- sigpipe = sigismember(&current->signal, SIGPIPE);
+ sigpipe = sigismember(&current->pending.signal, SIGPIPE);
old_set = current->blocked;
siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));
recalc_sigpending(current);
@@ -659,7 +659,7 @@ smb_request(struct smb_sb_info *server)
/* read/write errors are handled by errno */
spin_lock_irqsave(&current->sigmask_lock, flags);
if (result == -EPIPE && !sigpipe)
- sigdelset(&current->signal, SIGPIPE);
+ sigdelset(&current->pending.signal, SIGPIPE);
current->blocked = old_set;
recalc_sigpending(current);
spin_unlock_irqrestore(&current->sigmask_lock, flags);
@@ -821,7 +821,7 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
goto bad_conn;
spin_lock_irqsave(&current->sigmask_lock, flags);
- sigpipe = sigismember(&current->signal, SIGPIPE);
+ sigpipe = sigismember(&current->pending.signal, SIGPIPE);
old_set = current->blocked;
siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));
recalc_sigpending(current);
@@ -841,7 +841,7 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
/* read/write errors are handled by errno */
spin_lock_irqsave(&current->sigmask_lock, flags);
if (result == -EPIPE && !sigpipe)
- sigdelset(&current->signal, SIGPIPE);
+ sigdelset(&current->pending.signal, SIGPIPE);
current->blocked = old_set;
recalc_sigpending(current);
spin_unlock_irqrestore(&current->sigmask_lock, flags);
diff --git a/fs/super.c b/fs/super.c
index 81a3fafc2..fb5c5895c 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -483,6 +483,7 @@ static struct proc_nfs_info {
{ NFS_MOUNT_NOCTO, ",nocto", "" },
{ NFS_MOUNT_NOAC, ",noac", "" },
{ NFS_MOUNT_NONLM, ",nolock", ",lock" },
+ { NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
{ 0, NULL, NULL }
};
@@ -1303,20 +1304,21 @@ static int copy_mount_options (const void *data, unsigned long *where)
* information (or be NULL).
*
* NOTE! As pre-0.97 versions of mount() didn't use this setup, the
- * flags have to have a special 16-bit magic number in the high word:
- * 0xC0ED. If this magic word isn't present, the flags and data info
- * aren't used, as the syscall assumes we are talking to an older
- * version that didn't understand them.
+ * flags used to have a special 16-bit magic number in the high word:
+ * 0xC0ED. If this magic number is present, the high word is discarded.
*/
long do_mount(char * dev_name, char * dir_name, char *type_page,
- unsigned long new_flags, void *data_page)
+ unsigned long flags, void *data_page)
{
struct file_system_type * fstype;
struct nameidata nd;
struct vfsmount *mnt = NULL;
struct super_block *sb;
int retval = 0;
- unsigned long flags = 0;
+
+ /* Discard magic */
+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+ flags &= ~MS_MGC_MSK;
/* Basic sanity checks */
@@ -1328,21 +1330,25 @@ long do_mount(char * dev_name, char * dir_name, char *type_page,
/* OK, looks good, now let's see what do they want */
/* just change the flags? - capabilities are checked in do_remount() */
- if ((new_flags & (MS_MGC_MSK|MS_REMOUNT)) == (MS_MGC_VAL|MS_REMOUNT))
- return do_remount(dir_name, new_flags&~(MS_MGC_MSK|MS_REMOUNT),
- (char *) data_page);
+ if (flags & MS_REMOUNT)
+ return do_remount(dir_name, flags & ~MS_REMOUNT,
+ (char *) data_page);
- if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL)
- flags = new_flags & ~MS_MGC_MSK;
+ /* "mount --bind"? Equivalent to older "mount -t bind" */
+ /* No capabilities? What if users do thousands of these? */
+ if (flags & MS_BIND)
+ return do_loopback(dev_name, dir_name);
/* For the rest we need the type */
if (!type_page || !memchr(type_page, 0, PAGE_SIZE))
return -EINVAL;
+#if 0 /* Can be deleted again. Introduced in patch-2.3.99-pre6 */
/* loopback mount? This is special - requires fewer capabilities */
if (strcmp(type_page, "bind")==0)
return do_loopback(dev_name, dir_name);
+#endif
/* for the rest we _really_ need capabilities... */
if (!capable(CAP_SYS_ADMIN))
@@ -1354,7 +1360,8 @@ long do_mount(char * dev_name, char * dir_name, char *type_page,
return -ENODEV;
/* ... and mountpoint. Do the lookup first to force automounting. */
- if (path_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))
+ if (path_init(dir_name,
+ LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))
retval = path_walk(dir_name, &nd);
if (retval)
goto fs_out;
@@ -1363,7 +1370,7 @@ long do_mount(char * dev_name, char * dir_name, char *type_page,
if (fstype->fs_flags & FS_NOMOUNT)
sb = ERR_PTR(-EINVAL);
else if (fstype->fs_flags & FS_REQUIRES_DEV)
- sb = get_sb_bdev(fstype, dev_name,flags, data_page);
+ sb = get_sb_bdev(fstype, dev_name, flags, data_page);
else if (fstype->fs_flags & FS_SINGLE)
sb = get_sb_single(fstype, flags, data_page);
else
@@ -1376,6 +1383,13 @@ long do_mount(char * dev_name, char * dir_name, char *type_page,
/* Something was mounted here while we slept */
while(d_mountpoint(nd.dentry) && follow_down(&nd.mnt, &nd.dentry))
;
+
+ /* Refuse the same filesystem on the same mount point */
+ retval = -EBUSY;
+ if (nd.mnt && nd.mnt->mnt_sb == sb
+ && nd.mnt->mnt_root == nd.dentry)
+ goto fail;
+
retval = -ENOENT;
if (!nd.dentry->d_inode)
goto fail;
@@ -1403,7 +1417,7 @@ fail:
}
asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
- unsigned long new_flags, void * data)
+ unsigned long flags, void * data)
{
int retval;
unsigned long data_page;
@@ -1423,14 +1437,18 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
retval = copy_mount_options (dev_name, &dev_page);
if (retval < 0)
goto out2;
+
retval = copy_mount_options (data, &data_page);
- if (retval >= 0) {
- lock_kernel();
- retval = do_mount((char*)dev_page,dir_page,(char*)type_page,
- new_flags, (void*)data_page);
- unlock_kernel();
- free_page(data_page);
- }
+ if (retval < 0)
+ goto out3;
+
+ lock_kernel();
+ retval = do_mount((char*)dev_page, dir_page, (char*)type_page,
+ flags, (void*)data_page);
+ unlock_kernel();
+ free_page(data_page);
+
+out3:
free_page(dev_page);
out2:
putname(dir_page);
diff --git a/fs/sysv/balloc.c b/fs/sysv/balloc.c
index f5240a75c..978bc2a91 100644
--- a/fs/sysv/balloc.c
+++ b/fs/sysv/balloc.c
@@ -83,7 +83,7 @@ void sysv_free_block(struct super_block * sb, unsigned int block)
}
*flc_count = *sb->sv_sb_flc_count; /* = sb->sv_flc_size */
memcpy(flc_blocks, sb->sv_sb_flc_blocks, *flc_count * sizeof(sysv_zone_t));
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
mark_buffer_uptodate(bh, 1);
brelse(bh);
*sb->sv_sb_flc_count = 0;
@@ -100,7 +100,7 @@ void sysv_free_block(struct super_block * sb, unsigned int block)
}
memset(bh->b_data, 0, sb->sv_block_size);
/* this implies ((struct ..._freelist_chunk *) bh->b_data)->flc_count = 0; */
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
mark_buffer_uptodate(bh, 1);
brelse(bh);
/* still *sb->sv_sb_flc_count = 0 */
@@ -119,8 +119,8 @@ void sysv_free_block(struct super_block * sb, unsigned int block)
to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) + 1);
else
*sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks + 1;
- mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */
- if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
+ mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */
+ if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2);
sb->s_dirt = 1; /* and needs time stamp */
unlock_super(sb);
}
@@ -207,7 +207,7 @@ int sysv_new_block(struct super_block * sb)
return 0;
}
memset(bh->b_data, 0, sb->sv_block_size);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
mark_buffer_uptodate(bh, 1);
brelse(bh);
if (sb->sv_convert)
@@ -215,8 +215,8 @@ int sysv_new_block(struct super_block * sb)
to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) - 1);
else
*sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks - 1;
- mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */
- if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
+ mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */
+ if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2);
sb->s_dirt = 1; /* and needs time stamp */
unlock_super(sb);
return block;
@@ -311,7 +311,7 @@ unsigned long sysv_count_free_blocks(struct super_block * sb)
printk("sysv_count_free_blocks: free block count was %d, correcting to %d\n",old_count,count);
if (!(sb->s_flags & MS_RDONLY)) {
*sb->sv_sb_total_free_blocks = (sb->sv_convert ? to_coh_ulong(count) : count);
- mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified */
+ mark_buffer_dirty(sb->sv_bh2); /* super-block has been modified */
sb->s_dirt = 1; /* and needs time stamp */
}
}
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index bbd88336c..8469366cf 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -74,11 +74,11 @@ void sysv_free_inode(struct inode * inode)
if (*sb->sv_sb_fic_count < sb->sv_fic_size)
*sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)++) = ino;
(*sb->sv_sb_total_free_inodes)++;
- mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */
- if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
+ mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */
+ if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2);
sb->s_dirt = 1; /* and needs time stamp */
memset(raw_inode, 0, sizeof(struct sysv_inode));
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
unlock_super(sb);
brelse(bh);
}
@@ -128,8 +128,8 @@ struct inode * sysv_new_inode(const struct inode * dir)
}
/* Now *sb->sv_sb_fic_count > 0. */
ino = *sv_sb_fic_inode(sb,--(*sb->sv_sb_fic_count));
- mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */
- if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
+ mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */
+ if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2);
sb->s_dirt = 1; /* and needs time stamp */
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
@@ -147,7 +147,7 @@ struct inode * sysv_new_inode(const struct inode * dir)
mark_inode_dirty(inode); /* cleared by sysv_write_inode() */
/* That's it. */
(*sb->sv_sb_total_free_inodes)--;
- mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified again */
+ mark_buffer_dirty(sb->sv_bh2); /* super-block has been modified again */
sb->s_dirt = 1; /* and needs time stamp again */
unlock_super(sb);
return inode;
@@ -185,7 +185,7 @@ unsigned long sysv_count_free_inodes(struct super_block * sb)
printk("sysv_count_free_inodes: free inode count was %d, correcting to %d\n",(short)(*sb->sv_sb_total_free_inodes),count);
if (!(sb->s_flags & MS_RDONLY)) {
*sb->sv_sb_total_free_inodes = count;
- mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified */
+ mark_buffer_dirty(sb->sv_bh2); /* super-block has been modified */
sb->s_dirt = 1; /* and needs time stamp */
}
}
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index b7a1068ce..7e5f6c54a 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -532,7 +532,7 @@ static void sysv_write_super(struct super_block *sb)
if (sb->sv_convert)
time = to_coh_ulong(time);
*sb->sv_sb_time = time;
- mark_buffer_dirty(sb->sv_bh2, 1);
+ mark_buffer_dirty(sb->sv_bh2);
}
sb->s_dirt = 0;
}
@@ -769,7 +769,7 @@ repeat:
}
memset(result->b_data, 0, sb->sv_block_size);
mark_buffer_uptodate(result, 1);
- mark_buffer_dirty(result, 1);
+ mark_buffer_dirty(result);
} else {
*phys = tmp;
*new = 1;
@@ -780,7 +780,7 @@ repeat:
goto repeat;
}
*p = (sb->sv_convert ? to_coh_ulong(block) : block);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
*err = 0;
out:
brelse(bh);
@@ -894,7 +894,7 @@ static struct buffer_head *sysv_getblk(struct inode *inode, unsigned int block,
if (buffer_new(&dummy)) {
memset(bh->b_data, 0, inode->i_sb->sv_block_size);
mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
}
return bh;
}
@@ -1126,7 +1126,7 @@ static struct buffer_head * sysv_update_inode(struct inode * inode)
else
for (block = 0; block < 10+1+1+1; block++)
write3byte(&raw_inode->i_a.i_addb[3*block],inode->u.sysv_i.i_data[block]);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
return bh;
}
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index 517371319..aba233768 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -179,7 +179,7 @@ static int sysv_add_entry(struct inode * dir,
mark_inode_dirty(dir);
for (i = 0; i < SYSV_NAMELEN ; i++)
de->name[i] = (i < namelen) ? name[i] : 0;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
*res_dir = de;
break;
}
@@ -217,7 +217,7 @@ static int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
return error;
}
de->inode = inode->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
d_instantiate(dentry, inode);
return 0;
@@ -251,7 +251,7 @@ static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int
return error;
}
de->inode = inode->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
d_instantiate(dentry, inode);
return 0;
@@ -292,7 +292,7 @@ static int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
de->inode = dir->i_ino;
strcpy(de->name,".."); /* rest of de->name is zero, see sysv_new_block */
inode->i_nlink = 2;
- mark_buffer_dirty(dir_block, 1);
+ mark_buffer_dirty(dir_block);
brelse(dir_block);
inode->i_mode = S_IFDIR | mode;
if (dir->i_mode & S_ISGID)
@@ -306,7 +306,7 @@ static int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
return error;
}
de->inode = inode->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
dir->i_nlink++;
mark_inode_dirty(dir);
brelse(bh);
@@ -392,7 +392,7 @@ static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
if (inode->i_nlink != 2)
printk("empty directory has nlink!=2 (%d)\n", inode->i_nlink);
de->inode = 0;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
inode->i_nlink=0;
dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -422,7 +422,7 @@ static int sysv_unlink(struct inode * dir, struct dentry * dentry)
inode->i_nlink=1;
}
de->inode = 0;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
inode->i_nlink--;
@@ -463,7 +463,7 @@ static int sysv_symlink(struct inode * dir, struct dentry * dentry,
if (err)
goto out_no_entry;
de->inode = inode->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
d_instantiate(dentry, inode);
out:
@@ -502,7 +502,7 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir,
return error;
}
de->inode = oldinode->i_ino;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
brelse(bh);
oldinode->i_nlink++;
oldinode->i_ctime = CURRENT_TIME;
@@ -578,11 +578,11 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
new_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(new_inode);
}
- mark_buffer_dirty(old_bh, 1);
- mark_buffer_dirty(new_bh, 1);
+ 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, 1);
+ mark_buffer_dirty(dir_bh);
old_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
diff --git a/fs/sysv/truncate.c b/fs/sysv/truncate.c
index 32bfccf6d..559af828d 100644
--- a/fs/sysv/truncate.c
+++ b/fs/sysv/truncate.c
@@ -124,7 +124,7 @@ repeat:
continue;
}
*ind = 0;
- mark_buffer_dirty(indbh, 1);
+ mark_buffer_dirty(indbh);
brelse(bh);
sysv_free_block(sb,block);
}
@@ -183,7 +183,7 @@ static int trunc_dindirect(struct inode * inode, unsigned long offset, sysv_zone
continue;
retry |= trunc_indirect(inode,offset+(i<<sb->sv_ind_per_block_bits),ind,sb->sv_convert,&dirty);
if (dirty)
- mark_buffer_dirty(indbh, 1);
+ mark_buffer_dirty(indbh);
}
for (i = 0; i < sb->sv_ind_per_block; i++)
if (((sysv_zone_t *) indbh->b_data)[i])
@@ -240,7 +240,7 @@ static int trunc_tindirect(struct inode * inode, unsigned long offset, sysv_zone
continue;
retry |= trunc_dindirect(inode,offset+(i<<sb->sv_ind_per_block_2_bits),ind,sb->sv_convert,&dirty);
if (dirty)
- mark_buffer_dirty(indbh, 1);
+ mark_buffer_dirty(indbh);
}
for (i = 0; i < sb->sv_ind_per_block; i++)
if (((sysv_zone_t *) indbh->b_data)[i])
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index 2be4e8562..8d7fdfdee 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -268,7 +268,7 @@ do_more:
}
}
}
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (overflow)
{
block += count;
@@ -278,7 +278,7 @@ do_more:
error_return:
sb->s_dirt = 1;
if (UDF_SB_LVIDBH(sb))
- mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb));
unlock_super(sb);
return;
}
@@ -334,7 +334,7 @@ repeat:
bit ++;
block ++;
}
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (block_count > 0)
goto repeat;
out:
@@ -342,7 +342,7 @@ out:
{
UDF_SB_LVID(sb)->freeSpaceTable[partition] =
cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
- mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb));
}
sb->s_dirt = 1;
unlock_super(sb);
@@ -478,13 +478,13 @@ got_block:
goto repeat;
}
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (UDF_SB_LVIDBH(sb))
{
UDF_SB_LVID(sb)->freeSpaceTable[partition] =
cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1);
- mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb));
}
sb->s_dirt = 1;
unlock_super(sb);
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 0b3dce0d1..9ba4a6641 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -82,7 +82,7 @@ static int udf_adinicb_writepage(struct file *file, struct page *page)
block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize);
memcpy(bh->b_data + udf_ext0_offset(inode), kaddr, inode->i_size);
- mark_buffer_dirty(bh, 0);
+ mark_buffer_dirty(bh);
brelse(bh);
SetPageUptodate(page);
kunmap(page);
@@ -107,7 +107,7 @@ static int udf_adinicb_commit_write(struct file *file, struct page *page, unsign
bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize);
memcpy(bh->b_data + udf_file_entry_alloc_offset(inode) + offset,
kaddr + offset, to-offset);
- mark_buffer_dirty(bh, 0);
+ mark_buffer_dirty(bh);
brelse(bh);
SetPageUptodate(page);
kunmap(page);
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index 11e5711f5..5377773ce 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -62,7 +62,7 @@ void udf_free_inode(struct inode * inode)
UDF_SB_LVIDIU(sb)->numFiles =
cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) - 1);
- mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb));
}
unlock_super(sb);
@@ -112,17 +112,14 @@ struct inode * udf_new_inode (const struct inode *dir, int mode, int * err)
if (!(++uniqueID & 0x00000000FFFFFFFFUL))
uniqueID += 16;
lvhd->uniqueID = cpu_to_le64(uniqueID);
- mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb));
}
inode->i_mode = mode;
inode->i_sb = sb;
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
- if (test_opt (sb, GRPID))
- inode->i_gid = dir->i_gid;
- else if (dir->i_mode & S_ISGID)
- {
+ if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
mode |= S_ISGID;
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index e7e6c53e8..4219c505f 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -200,7 +200,7 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
else
UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
inode->i_blocks = inode->i_sb->s_blocksize / 512;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
udf_release_data(bh);
inode->i_data.a_ops->writepage(NULL, page);
@@ -276,7 +276,7 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
return NULL;
}
}
- mark_buffer_dirty(dbh, 1);
+ mark_buffer_dirty(dbh);
memset(sbh->b_data + udf_file_entry_alloc_offset(inode),
0, UDF_I_LENALLOC(inode));
@@ -295,7 +295,7 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
/* UniqueID stuff */
inode->i_blocks = inode->i_sb->s_blocksize / 512;
- mark_buffer_dirty(sbh, 1);
+ mark_buffer_dirty(sbh);
udf_release_data(sbh);
mark_inode_dirty(inode);
inode->i_version ++;
@@ -379,7 +379,7 @@ struct buffer_head * udf_getblk(struct inode * inode, long block,
wait_on_buffer(bh);
memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
}
return bh;
}
@@ -1294,7 +1294,7 @@ udf_update_inode(struct inode *inode, int do_sync)
eid->identSuffix[1] = UDF_OS_ID_LINUX;
dsea->majorDeviceIdent = kdev_t_to_nr(inode->i_rdev) >> 8;
dsea->minorDeviceIdent = kdev_t_to_nr(inode->i_rdev) & 0xFF;
- mark_buffer_dirty(tbh, 1);
+ mark_buffer_dirty(tbh);
udf_release_data(tbh);
}
@@ -1387,7 +1387,7 @@ udf_update_inode(struct inode *inode, int do_sync)
fe->descTag.tagChecksum += ((Uint8 *)&(fe->descTag))[i];
/* write the data blocks */
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (do_sync)
{
ll_rw_block(WRITE, 1, &bh);
@@ -1557,7 +1557,7 @@ int udf_add_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
}
}
udf_update_tag((*bh)->b_data, loffset);
- mark_buffer_dirty(*bh, 1);
+ mark_buffer_dirty(*bh);
udf_release_data(*bh);
*bh = nbh;
}
@@ -1575,7 +1575,7 @@ int udf_add_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize));
- mark_buffer_dirty(*bh, 1);
+ mark_buffer_dirty(*bh);
}
return ret;
@@ -1634,7 +1634,7 @@ int udf_write_aext(struct inode *inode, lb_addr bloc, int *extoffset,
else
mark_inode_dirty(inode);
- mark_buffer_dirty(*bh, 1);
+ mark_buffer_dirty(*bh);
if (inc)
*extoffset += adsize;
@@ -1932,7 +1932,7 @@ int udf_delete_aext(struct inode *inode, lb_addr nbloc, int nextoffset,
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize));
udf_update_tag((obh)->b_data, oextoffset - (2*adsize));
- mark_buffer_dirty(obh, 1);
+ mark_buffer_dirty(obh);
}
}
else
@@ -1949,7 +1949,7 @@ int udf_delete_aext(struct inode *inode, lb_addr nbloc, int nextoffset,
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize);
udf_update_tag((obh)->b_data, oextoffset - adsize);
- mark_buffer_dirty(obh, 1);
+ mark_buffer_dirty(obh);
}
}
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 16821704e..9cc2f3d29 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -133,8 +133,8 @@ int udf_write_fi(struct FileIdentDesc *cfi, struct FileIdentDesc *sfi,
}
if (fibh->sbh != fibh->ebh)
- mark_buffer_dirty(fibh->ebh, 1);
- mark_buffer_dirty(fibh->sbh, 1);
+ mark_buffer_dirty(fibh->ebh);
+ mark_buffer_dirty(fibh->sbh);
return 0;
}
@@ -1040,7 +1040,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
if (!(++uniqueID & 0x00000000FFFFFFFFUL))
uniqueID += 16;
lvhd->uniqueID = cpu_to_le64(uniqueID);
- mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb), 1);
+ mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
}
udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
@@ -1093,7 +1093,7 @@ static int udf_link(struct dentry * old_dentry, struct inode * dir,
if (!(++uniqueID & 0x00000000FFFFFFFFUL))
uniqueID += 16;
lvhd->uniqueID = cpu_to_le64(uniqueID);
- mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb), 1);
+ mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
}
udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
@@ -1224,7 +1224,7 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
old_inode->i_version = ++event;
}
else
- mark_buffer_dirty(dir_bh, 1);
+ mark_buffer_dirty(dir_bh);
old_dir->i_nlink --;
mark_inode_dirty(old_dir);
if (new_inode)
diff --git a/fs/udf/super.c b/fs/udf/super.c
index e89a86e72..f5e9b0b44 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1219,7 +1219,7 @@ static void udf_open_lvid(struct super_block *sb)
UDF_SB_LVID(sb)->descTag.tagChecksum +=
((Uint8 *)&(UDF_SB_LVID(sb)->descTag))[i];
- mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb));
sb->s_dirt = 0;
}
}
@@ -1254,7 +1254,7 @@ static void udf_close_lvid(struct super_block *sb)
UDF_SB_LVID(sb)->descTag.tagChecksum +=
((Uint8 *)&(UDF_SB_LVID(sb)->descTag))[i];
- mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb));
}
}
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index 262a411d6..29e059484 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -124,7 +124,7 @@ void udf_trunc(struct inode * inode)
aed->lengthAllocDescs = cpu_to_le32(lenalloc);
udf_update_tag(bh->b_data, lenalloc +
sizeof(struct AllocExtDesc));
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
}
}
@@ -166,7 +166,7 @@ void udf_trunc(struct inode * inode)
aed->lengthAllocDescs = cpu_to_le32(lenalloc);
udf_update_tag(bh->b_data, lenalloc +
sizeof(struct AllocExtDesc));
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
}
}
}
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index 2f156b42a..fa83ba5be 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -110,8 +110,8 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
INC_SWAB32(ubh_cg_blktot (ucpi, cylno));
}
- ubh_mark_buffer_dirty (USPI_UBH, 1);
- ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ ubh_mark_buffer_dirty (USPI_UBH);
+ ubh_mark_buffer_dirty (UCPI_UBH);
if (sb->s_flags & MS_SYNCHRONOUS) {
ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
ubh_wait_on_buffer (UCPI_UBH);
@@ -196,8 +196,8 @@ do_more:
INC_SWAB32(ubh_cg_blktot(ucpi, cylno));
}
- ubh_mark_buffer_dirty (USPI_UBH, 1);
- ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ ubh_mark_buffer_dirty (USPI_UBH);
+ ubh_mark_buffer_dirty (UCPI_UBH);
if (sb->s_flags & MS_SYNCHRONOUS) {
ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
ubh_wait_on_buffer (UCPI_UBH);
@@ -227,7 +227,7 @@ failed:
bh = getblk (sb->s_dev, result + i, sb->s_blocksize); \
memset (bh->b_data, 0, sb->s_blocksize); \
mark_buffer_uptodate(bh, 1); \
- mark_buffer_dirty (bh, 1); \
+ mark_buffer_dirty (bh); \
if (IS_SYNC(inode)) { \
ll_rw_block (WRITE, 1, &bh); \
wait_on_buffer (bh); \
@@ -364,7 +364,7 @@ unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment,
{
mark_buffer_clean (bh);
bh->b_blocknr = result + i;
- mark_buffer_dirty (bh, 0);
+ mark_buffer_dirty (bh);
if (IS_SYNC(inode)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -458,8 +458,8 @@ unsigned ufs_add_fragments (struct inode * inode, unsigned fragment,
SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, count);
SUB_SWAB32(usb1->fs_cstotal.cs_nffree, count);
- ubh_mark_buffer_dirty (USPI_UBH, 1);
- ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ ubh_mark_buffer_dirty (USPI_UBH);
+ ubh_mark_buffer_dirty (UCPI_UBH);
if (sb->s_flags & MS_SYNCHRONOUS) {
ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
ubh_wait_on_buffer (UCPI_UBH);
@@ -582,8 +582,8 @@ cg_found:
INC_SWAB32(ucg->cg_frsum[allocsize - count]);
succed:
- ubh_mark_buffer_dirty (USPI_UBH, 1);
- ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ ubh_mark_buffer_dirty (USPI_UBH);
+ ubh_mark_buffer_dirty (UCPI_UBH);
if (sb->s_flags & MS_SYNCHRONOUS) {
ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
ubh_wait_on_buffer (UCPI_UBH);
diff --git a/fs/ufs/cylinder.c b/fs/ufs/cylinder.c
index ed261321d..4afc9d9d6 100644
--- a/fs/ufs/cylinder.c
+++ b/fs/ufs/cylinder.c
@@ -119,7 +119,7 @@ void ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr)
ucg->cg_rotor = SWAB32(ucpi->c_rotor);
ucg->cg_frotor = SWAB32(ucpi->c_frotor);
ucg->cg_irotor = SWAB32(ucpi->c_irotor);
- ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ ubh_mark_buffer_dirty (UCPI_UBH);
for (i = 1; i < UCPI_UBH->count; i++) {
brelse (UCPI_UBH->bh[i]);
}
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index f93a55c4e..1a97daf7c 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -121,8 +121,8 @@ void ufs_free_inode (struct inode * inode)
DEC_SWAB32(sb->fs_cs(cg).cs_ndir);
}
}
- ubh_mark_buffer_dirty (USPI_UBH, 1);
- ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ ubh_mark_buffer_dirty (USPI_UBH);
+ ubh_mark_buffer_dirty (UCPI_UBH);
if (sb->s_flags & MS_SYNCHRONOUS) {
ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi);
ubh_wait_on_buffer (UCPI_UBH);
@@ -252,8 +252,8 @@ cg_found:
INC_SWAB32(sb->fs_cs(cg).cs_ndir);
}
- ubh_mark_buffer_dirty (USPI_UBH, 1);
- ubh_mark_buffer_dirty (UCPI_UBH, 1);
+ ubh_mark_buffer_dirty (USPI_UBH);
+ ubh_mark_buffer_dirty (UCPI_UBH);
if (sb->s_flags & MS_SYNCHRONOUS) {
ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi);
ubh_wait_on_buffer (UCPI_UBH);
@@ -265,9 +265,7 @@ cg_found:
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
- if (test_opt (sb, GRPID))
- inode->i_gid = dir->i_gid;
- else if (dir->i_mode & S_ISGID) {
+ if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
mode |= S_ISGID;
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 771069834..10a9d9be4 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -360,7 +360,7 @@ repeat:
*new = 1;
}
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (IS_SYNC(inode)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -493,7 +493,7 @@ struct buffer_head *ufs_getfrag(struct inode *inode, unsigned int fragment,
if (buffer_new(&dummy)) {
memset(bh->b_data, 0, inode->i_sb->s_blocksize);
mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
}
return bh;
}
@@ -711,7 +711,7 @@ static int ufs_update_inode(struct inode * inode, int do_sync)
if (!inode->i_nlink)
memset (ufs_inode, 0, sizeof(struct ufs_inode));
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (do_sync) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index 7966998d9..70a29b393 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -321,7 +321,7 @@ static struct buffer_head * ufs_add_entry (struct inode * dir,
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
mark_inode_dirty(dir);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
*res_dir = de;
*err = 0;
@@ -428,7 +428,7 @@ static int ufs_create (struct inode * dir, struct dentry * dentry, int mode)
de->d_ino = SWAB32(inode->i_ino);
ufs_set_de_type (de, inode->i_mode);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -467,7 +467,7 @@ static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int r
de->d_ino = SWAB32(inode->i_ino);
ufs_set_de_type (de, inode->i_mode);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -530,7 +530,7 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
ufs_set_de_namlen(de,2);
strcpy (de->d_name, "..");
inode->i_nlink = 2;
- mark_buffer_dirty(dir_block, 1);
+ mark_buffer_dirty(dir_block);
brelse (dir_block);
inode->i_mode = S_IFDIR | mode;
if (dir->i_mode & S_ISGID)
@@ -542,7 +542,7 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
de->d_ino = SWAB32(inode->i_ino);
ufs_set_de_type (de, inode->i_mode);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -657,7 +657,7 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
dir->i_version = ++event;
if (retval)
goto end_rmdir;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -718,7 +718,7 @@ static int ufs_unlink(struct inode * dir, struct dentry *dentry)
if (retval)
goto end_unlink;
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -785,7 +785,7 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry,
goto out_no_entry;
de->d_ino = SWAB32(inode->i_ino);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -825,7 +825,7 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir,
de->d_ino = SWAB32(inode->i_ino);
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -930,7 +930,7 @@ static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
mark_inode_dirty(old_dir);
if (dir_bh) {
PARENT_INO(dir_bh->b_data) = SWAB32(new_dir->i_ino);
- mark_buffer_dirty(dir_bh, 1);
+ mark_buffer_dirty(dir_bh);
old_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
@@ -941,13 +941,13 @@ static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
mark_inode_dirty(new_dir);
}
}
- mark_buffer_dirty(old_bh, 1);
+ mark_buffer_dirty(old_bh);
if (IS_SYNC(old_dir)) {
ll_rw_block (WRITE, 1, &old_bh);
wait_on_buffer (old_bh);
}
- mark_buffer_dirty(new_bh, 1);
+ mark_buffer_dirty(new_bh);
if (IS_SYNC(new_dir)) {
ll_rw_block (WRITE, 1, &new_bh);
wait_on_buffer (new_bh);
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index c41228adf..6d83d7c51 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -192,7 +192,7 @@ void ufs_error (struct super_block * sb, const char * function,
if (!(sb->s_flags & MS_RDONLY)) {
usb1->fs_clean = UFS_FSBAD;
- ubh_mark_buffer_dirty(USPI_UBH, 1);
+ ubh_mark_buffer_dirty(USPI_UBH);
sb->s_dirt = 1;
sb->s_flags |= MS_RDONLY;
}
@@ -224,7 +224,7 @@ void ufs_panic (struct super_block * sb, const char * function,
if (!(sb->s_flags & MS_RDONLY)) {
usb1->fs_clean = UFS_FSBAD;
- ubh_mark_buffer_dirty(USPI_UBH, 1);
+ ubh_mark_buffer_dirty(USPI_UBH);
sb->s_dirt = 1;
}
va_start (args, fmt);
@@ -422,7 +422,7 @@ void ufs_put_cylinder_structures (struct super_block * sb) {
ubh_memcpyubh (ubh, space, size);
space += size;
ubh_mark_buffer_uptodate (ubh, 1);
- ubh_mark_buffer_dirty (ubh, 0);
+ ubh_mark_buffer_dirty (ubh);
ubh_brelse (ubh);
}
for (i = 0; i < sb->u.ufs_sb.s_cg_loaded; i++) {
@@ -845,7 +845,7 @@ void ufs_write_super (struct super_block * sb) {
if ((flags & UFS_ST_MASK) == UFS_ST_SUN
|| (flags & UFS_ST_MASK) == UFS_ST_SUNx86)
ufs_set_fs_state(usb1, usb3, UFS_FSOK - SWAB32(usb1->fs_time));
- ubh_mark_buffer_dirty (USPI_UBH, 1);
+ ubh_mark_buffer_dirty (USPI_UBH);
}
sb->s_dirt = 0;
UFSD(("EXIT\n"))
@@ -915,7 +915,7 @@ int ufs_remount (struct super_block * sb, int * mount_flags, char * data)
if ((flags & UFS_ST_MASK) == UFS_ST_SUN
|| (flags & UFS_ST_MASK) == UFS_ST_SUNx86)
ufs_set_fs_state(usb1, usb3, UFS_FSOK - SWAB32(usb1->fs_time));
- ubh_mark_buffer_dirty (USPI_UBH, 1);
+ ubh_mark_buffer_dirty (USPI_UBH);
sb->s_dirt = 0;
sb->s_flags |= MS_RDONLY;
}
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
index 57de81eb8..183ccfb13 100644
--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -248,7 +248,7 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, u32 * p)
bforget (bh);
}
*ind = SWAB32(0);
- ubh_mark_buffer_dirty(ind_ubh, 1);
+ ubh_mark_buffer_dirty(ind_ubh);
if (free_count == 0) {
frag_to_free = tmp;
free_count = uspi->s_fpb;
@@ -334,7 +334,7 @@ static int ufs_trunc_dindirect (struct inode * inode, unsigned offset, u32 * p)
if (!tmp)
continue;
retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind);
- ubh_mark_buffer_dirty(dind_bh, 1);
+ ubh_mark_buffer_dirty(dind_bh);
}
for (i = 0; i < uspi->s_apb; i++)
@@ -400,7 +400,7 @@ static int ufs_trunc_tindirect (struct inode * inode)
tind = ubh_get_addr32 (tind_bh, i);
retry |= ufs_trunc_dindirect(inode, UFS_NDADDR +
uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind);
- ubh_mark_buffer_dirty(tind_bh, 1);
+ ubh_mark_buffer_dirty(tind_bh);
}
for (i = 0; i < uspi->s_apb; i++)
if (SWAB32(*ubh_get_addr32 (tind_bh, i)))
@@ -466,7 +466,7 @@ void ufs_truncate (struct inode * inode)
bh = ufs_bread (inode, inode->i_size >> uspi->s_fshift, 0, &err);
if (bh) {
memset (bh->b_data + offset, 0, uspi->s_fsize - offset);
- mark_buffer_dirty (bh, 0);
+ mark_buffer_dirty (bh);
brelse (bh);
}
}
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index e6d5f3a5b..334e0efdb 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -94,13 +94,13 @@ void ubh_brelse_uspi (struct ufs_sb_private_info * uspi)
}
}
-void ubh_mark_buffer_dirty (struct ufs_buffer_head * ubh, int flag)
+void ubh_mark_buffer_dirty (struct ufs_buffer_head * ubh)
{
unsigned i;
if (!ubh)
return;
for ( i = 0; i < ubh->count; i++ )
- mark_buffer_dirty (ubh->bh[i], flag);
+ mark_buffer_dirty (ubh->bh[i]);
}
void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag)
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index 049b194ee..0def49d95 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -212,7 +212,7 @@ extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, kdev_t
extern struct ufs_buffer_head * ubh_bread_uspi(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned);
extern void ubh_brelse (struct ufs_buffer_head *);
extern void ubh_brelse_uspi (struct ufs_sb_private_info *);
-extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *, int);
+extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *);
extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int);
extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **);
extern void ubh_wait_on_buffer (struct ufs_buffer_head *);
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index b5c14c221..63ee81b16 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -68,7 +68,8 @@ static int umsdos_dir_once ( void *buf,
const char *name,
int len,
off_t offset,
- ino_t ino)
+ ino_t ino,
+ unsigned type)
{
int ret = -EINVAL;
struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c
index 48515aa5f..551c9662f 100644
--- a/fs/umsdos/emd.c
+++ b/fs/umsdos/emd.c
@@ -505,7 +505,7 @@ int umsdos_newentry (struct dentry *parent, struct umsdos_info *info)
struct dentry *demd = umsdos_get_emd_dentry(parent);
ret = PTR_ERR(demd);
- if (IS_ERR(ret))
+ if (IS_ERR(demd))
goto out;
err = umsdos_find (demd, info);
if (err && err == -ENOENT) {
@@ -532,7 +532,7 @@ int umsdos_newhidden (struct dentry *parent, struct umsdos_info *info)
int ret;
struct dentry *demd = umsdos_get_emd_dentry(parent);
ret = PTR_ERR(demd);
- if (IS_ERR(ret))
+ if (IS_ERR(demd))
goto out;
umsdos_parse ("..LINK", 6, info);
@@ -561,7 +561,7 @@ int umsdos_delentry (struct dentry *parent, struct umsdos_info *info, int isdir)
struct dentry *demd = umsdos_get_emd_dentry(parent);
ret = PTR_ERR(demd);
- if (IS_ERR(ret))
+ if (IS_ERR(demd))
goto out;
ret = umsdos_find (demd, info);
if (ret)
@@ -642,7 +642,7 @@ int umsdos_findentry (struct dentry *parent, struct umsdos_info *info,
struct dentry *demd = umsdos_get_emd_dentry(parent);
ret = PTR_ERR(demd);
- if (IS_ERR(ret))
+ if (IS_ERR(demd))
goto out;
ret = umsdos_find (demd, info);
if (ret)
diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c
index 8731f8ecd..0b09ce60a 100644
--- a/fs/umsdos/ioctl.c
+++ b/fs/umsdos/ioctl.c
@@ -29,7 +29,8 @@ static int umsdos_ioctl_fill (
const char *name,
int name_len,
off_t offset,
- ino_t ino)
+ ino_t ino,
+ unsigned type)
{
int ret = -EINVAL;
struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index b3fcf2088..0ac6d5314 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -973,7 +973,7 @@ static int vfat_add_entry(struct inode *dir,struct qstr* qname,
goto cleanup;
}
memcpy(*de, ps, sizeof(struct msdos_dir_slot));
- fat_mark_buffer_dirty(sb, *bh, 1);
+ fat_mark_buffer_dirty(sb, *bh);
}
dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
@@ -990,7 +990,7 @@ static int vfat_add_entry(struct inode *dir,struct qstr* qname,
(*de)->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT;
- fat_mark_buffer_dirty(sb, *bh, 1);
+ fat_mark_buffer_dirty(sb, *bh);
/* slots can't be less than 1 */
sinfo_out->long_slots = slots - 1;
@@ -1106,7 +1106,7 @@ static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
dir->i_version = ++event;
mark_inode_dirty(dir);
de->name[0] = DELETED_FLAG;
- fat_mark_buffer_dirty(sb, bh, 1);
+ fat_mark_buffer_dirty(sb, bh);
/* remove the longname */
offset = sinfo->longname_offset; de = NULL;
for (i = sinfo->long_slots; i > 0; --i) {
@@ -1114,7 +1114,7 @@ static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
continue;
de->name[0] = DELETED_FLAG;
de->attr = 0;
- fat_mark_buffer_dirty(sb, bh, 1);
+ fat_mark_buffer_dirty(sb, bh);
}
if (bh) fat_brelse(sb, bh);
}
@@ -1276,7 +1276,7 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
int start = MSDOS_I(new_dir)->i_logstart;
dotdot_de->start = CT_LE_W(start);
dotdot_de->starthi = CT_LE_W(start>>16);
- fat_mark_buffer_dirty(sb, dotdot_bh, 1);
+ fat_mark_buffer_dirty(sb, dotdot_bh);
old_dir->i_nlink--;
if (new_inode) {
new_inode->i_nlink--;