summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-12-16 05:34:03 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-12-16 05:34:03 +0000
commit967c65a99059fd459b956c1588ce0ba227912c4e (patch)
tree8224d013ff5d255420713d05610c7efebd204d2a /fs
parente20c1cc1656a66a2773bca4591a895cbc12696ff (diff)
Merge with Linux 2.1.72, part 1.
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in3
-rw-r--r--fs/Makefile10
-rw-r--r--fs/affs/Changes88
-rw-r--r--fs/affs/Makefile2
-rw-r--r--fs/affs/amigaffs.c320
-rw-r--r--fs/affs/bitmap.c19
-rw-r--r--fs/affs/dir.c53
-rw-r--r--fs/affs/file.c203
-rw-r--r--fs/affs/inode.c824
-rw-r--r--fs/affs/namei.c520
-rw-r--r--fs/affs/symlink.c82
-rw-r--r--fs/autofs/waitq.c31
-rw-r--r--fs/binfmt_aout.c2
-rw-r--r--fs/binfmt_elf.c4
-rw-r--r--fs/buffer.c110
-rw-r--r--fs/dcache.c10
-rw-r--r--fs/dquot.c4
-rw-r--r--fs/exec.c38
-rw-r--r--fs/fat/file.c13
-rw-r--r--fs/fat/mmap.c2
-rw-r--r--fs/fcntl.c2
-rw-r--r--fs/isofs/inode.c9
-rw-r--r--fs/isofs/namei.c35
-rw-r--r--fs/lockd/clntproc.c34
-rw-r--r--fs/lockd/svc.c24
-rw-r--r--fs/lockd/svcsubs.c64
-rw-r--r--fs/locks.c4
-rw-r--r--fs/namei.c22
-rw-r--r--fs/nametrans.c2
-rw-r--r--fs/ncpfs/mmap.c2
-rw-r--r--fs/ncpfs/sock.c42
-rw-r--r--fs/nfs/dir.c132
-rw-r--r--fs/nfs/file.c5
-rw-r--r--fs/nfs/nfsroot.c6
-rw-r--r--fs/nfsd/lockd.c6
-rw-r--r--fs/nfsd/nfssvc.c27
-rw-r--r--fs/nfsd/vfs.c102
-rw-r--r--fs/pipe.c2
-rw-r--r--fs/proc/array.c121
-rw-r--r--fs/proc/proc_tty.c4
-rw-r--r--fs/select.c268
-rw-r--r--fs/smbfs/sock.c54
-rw-r--r--fs/super.c2
-rw-r--r--fs/sysv/namei.c188
-rw-r--r--fs/ufs/Makefile2
-rw-r--r--fs/ufs/ufs_dir.c47
-rw-r--r--fs/ufs/ufs_file.c2
-rw-r--r--fs/ufs/ufs_inode.c62
-rw-r--r--fs/ufs/ufs_namei.c115
-rw-r--r--fs/ufs/ufs_super.c120
-rw-r--r--fs/ufs/ufs_symlink.c61
-rw-r--r--fs/umsdos/emd.c4
-rw-r--r--fs/vfat/namei.c164
53 files changed, 1904 insertions, 2168 deletions
diff --git a/fs/Config.in b/fs/Config.in
index d7826af19..b8c293955 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -23,7 +23,7 @@ dep_tristate 'VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
bool '/proc filesystem support' CONFIG_PROC_FS
if [ "$CONFIG_INET" = "y" ]; then
tristate 'NFS filesystem support' CONFIG_NFS_FS
- if [ "$CONFIG_NFS_FS" = "y" ]; then
+ if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_IP_PNP" = "y" ]; then
bool ' Root file system on NFS' CONFIG_ROOT_NFS
if [ "$CONFIG_ROOT_NFS" = "y" ]; then
bool ' BOOTP support' CONFIG_RNFS_BOOTP
@@ -43,6 +43,7 @@ if [ "$CONFIG_INET" = "y" ]; then
define_bool CONFIG_LOCKD n
fi
fi
+ tristate 'Coda filesystem support (advanced network fs)' CONFIG_CODA_FS
tristate 'SMB filesystem support (to mount WfW shares etc..)' CONFIG_SMB_FS
if [ "$CONFIG_SMB_FS" != "n" ]; then
bool 'SMB Win95 bug work-around' CONFIG_SMB_WIN95
diff --git a/fs/Makefile b/fs/Makefile
index 0b0f5f5ee..9e212be70 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -16,7 +16,7 @@ O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \
inode.o dcache.o attr.o bad_inode.o $(BINFMTS)
MOD_LIST_NAME := FS_MODULES
-ALL_SUB_DIRS = minix ext2 fat msdos vfat proc isofs nfs umsdos \
+ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos \
hpfs sysv smbfs ncpfs ufs affs romfs autofs lockd nfsd nls
ifeq ($(CONFIG_QUOTA),y)
@@ -29,6 +29,14 @@ ifeq ($(CONFIG_TRANS_NAMES),y)
O_OBJS += nametrans.o
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
diff --git a/fs/affs/Changes b/fs/affs/Changes
index b19c24ae6..06736aa3a 100644
--- a/fs/affs/Changes
+++ b/fs/affs/Changes
@@ -12,16 +12,96 @@ Known bugs:
apparently not causing the failure, as directory
reads basically work (but all files are of size 0).
Alas, I've got no alpha to debug. :-(
-- If an affs mounted filesystem is exported via
- nfs, it cannot be written to.
- As soon as I have my network up and running, I'll
- try to fix this.
+
- The partition checker (drivers/block/genhd.c)
doesn't work with devices which have 256 byte
blocks (some very old SCSI drives).
+- The feature to automatically make the fs clean
+ might leave a trashed file system with the
+ bitmap flag set valid.
+
+- The blocks from deleted directories are
+ sometimes reclaimed only at umount time.
+
Please direct bug reports to: hjw@zvw.de
+Version 3.6
+-----------
+
+- dentry changes. (Thanks to Jes Sorensen for his help.)
+
+- Fixed bug in balloc(): Superblock was not set dirty after
+ the bitmap was changed, so the bitmap wasn't sync'd.
+
+- Fixed nasty bug in find_new_zone(): If the current
+ zone number was zero, the loop didn't terminate,
+ causing a solid lock-up.
+
+- Removed support for old-style directory reads.
+
+- Fixed bug in add_entry(): When doing a sorted insert,
+ the pointer to the next entry in the hash chain wasn't
+ correctly byte-swapped. Since most of the users of the
+ affs use it on a 68k, they didn't notice. But why did
+ I not find this during my tests?
+
+- Fixed some oversights (version wasn't updated on some
+ directory changes).
+
+- Handling of hard links rewritten. To the VFS
+ they appear now as normal unix links. They are
+ now resolved only once in lookup(). The backside
+ is that unlink(), rename() and rmdir() have to
+ be smart about them, but the result is worth the
+ effort. This also led to some code cleanup.
+
+- Changed name type to unsigned char; the test for
+ invalid filenames didn't work correctly.
+ (Thanks to Michael Krause for pointing at this.)
+
+- Changed mapping of executable flag.
+
+- Changed all network byte-order macros to the
+ recommended ones.
+
+- Added a remount function, so attempts to remount
+ a dircache filesystem or one with errors read/write
+ can be trapped. Previously, ro remounts didn't
+ flush the super block, and rw remounts didn't
+ create allocation zones ...
+
+- Call shrink_dcache_parent() in rmdir().
+ (Thanks to Bill Hawes.)
+
+- Permission checks in unlink().
+
+- Allow mounting of volumes with superfluous
+ bitmap pointers read only, also allows them
+ to be remounted read/write.
+
+- Owner/Group defaults now to the fs user (i.e.
+ the one that mounted it) instead of root. This
+ obsoletes the mount options uid and gid.
+
+- Argument to volume option could overflow the
+ name buffer. It is now silently truncated to
+ 30 characters. (Damnit! This kind of bug
+ is too embarrassing.)
+
+- Split inode.c into 2 files, the superblock
+ routines desperately wanted their own file.
+
+- truncate() didn't allocate an extension block
+ cache. If a file was extended by means of
+ truncate(), this led to an Oops.
+
+- fsuser is now checked last.
+
+- rename() will not ignore changes in filename
+ casing any more (though mv(1) still won't allow
+ you to do "mv oldname OldName").
+
Version 3.5
-----------
diff --git a/fs/affs/Makefile b/fs/affs/Makefile
index 77cb4225f..1dba61b41 100644
--- a/fs/affs/Makefile
+++ b/fs/affs/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := affs.o
-O_OBJS := namei.o inode.o file.o dir.o amigaffs.o bitmap.o symlink.o
+O_OBJS := super.o namei.o inode.o file.o dir.o amigaffs.o bitmap.o symlink.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index 7ddb54a62..68c61753b 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -8,6 +8,7 @@
* Please send bug reports to: hjw@zvw.de
*/
+#define DEBUG 0
#include <stdarg.h>
#include <linux/stat.h>
#include <linux/sched.h>
@@ -30,7 +31,7 @@ static char ErrorBuffer[256];
pointed to by FH_DATA. The length of the name is returned. */
int
-affs_get_file_name(int bsize, void *fh_data, char **name)
+affs_get_file_name(int bsize, void *fh_data, unsigned char **name)
{
struct file_end *file_end;
@@ -42,100 +43,142 @@ affs_get_file_name(int bsize, void *fh_data, char **name)
*name = "***BAD_FILE***";
return 14;
}
- *name = (char *)&file_end->file_name[1];
+ *name = (unsigned char *)&file_end->file_name[1];
return file_end->file_name[0];
}
-/* Find the predecessor in the hash chain */
+/* Insert a header block (file) into the directory (next).
+ * This routine assumes that the caller has the superblock locked.
+ */
int
-affs_fix_hash_pred(struct inode *startino, int startoffset, s32 key, s32 newkey)
+affs_insert_hash(unsigned long next, struct buffer_head *file, struct inode *inode)
{
- struct buffer_head *bh = NULL;
- s32 nextkey;
- s32 ptype, stype;
- int retval;
+ struct buffer_head *bh;
+ s32 ino;
+ int offset;
+
+ offset = affs_hash_name(FILE_END(file->b_data,inode)->file_name+1,
+ FILE_END(file->b_data,inode)->file_name[0],
+ AFFS_I2FSTYPE(inode),AFFS_I2HSIZE(inode)) + 6;
+ ino = be32_to_cpu(((struct dir_front *)file->b_data)->own_key);
+
+ pr_debug("AFFS: insert_hash(dir_ino=%lu,ino=%d)\n",next,ino);
+
+ FILE_END(file->b_data,inode)->parent = cpu_to_be32(next);
- nextkey = startino->i_ino;
- retval = -ENOENT;
- lock_super(startino->i_sb);
while (1) {
- pr_debug("AFFS: fix_hash_pred(): next key=%d, offset=%d\n",nextkey,startoffset);
- if (nextkey == 0)
+ if (!(bh = affs_bread(inode->i_dev,next,AFFS_I2BSIZE(inode))))
+ return -EIO;
+ next = be32_to_cpu(((s32 *)bh->b_data)[offset]);
+ if (!next || next > ino)
break;
- if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino))))
+ offset = AFFS_I2BSIZE(inode) / 4 - 4;
+ affs_brelse(bh);
+ }
+
+ 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);
+ affs_brelse(bh);
+
+ return 0;
+}
+/* Remove a header block from it's hash table (directory).
+ * 'inode' may be any inode on the partition, it's only
+ * used for calculating the block size and superblock
+ * reference.
+ */
+
+int
+affs_remove_hash(struct buffer_head *dbh, struct inode *inode)
+{
+ s32 ownkey;
+ s32 key;
+ s32 ptype;
+ s32 stype;
+ int offset;
+ int retval;
+ struct buffer_head *bh;
+
+ ownkey = be32_to_cpu(((struct dir_front *)dbh->b_data)->own_key);
+ key = be32_to_cpu(FILE_END(dbh->b_data,inode)->parent);
+ offset = affs_hash_name(FILE_END(dbh->b_data,inode)->file_name+1,
+ FILE_END(dbh->b_data,inode)->file_name[0],
+ AFFS_I2FSTYPE(inode),AFFS_I2HSIZE(inode)) + 6;
+ pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n",key,ownkey,offset-6);
+ retval = -ENOENT;
+
+ lock_super(inode->i_sb);
+ while (key) {
+ if (!(bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
+ retval = -EIO;
break;
- if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype)
+ }
+ if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype)
|| ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR &&
stype != ST_LINKFILE && stype != ST_LINKDIR &&
stype != ST_ROOT && stype != ST_SOFTLINK)) {
- affs_error(startino->i_sb,"affs_fix_hash_pred",
- "Bad block in link chain (ptype=%d, stype=%d)",ptype,stype);
+ affs_error(inode->i_sb,"affs_remove_hash",
+ "Bad block in hash chain (key=%d, ptype=%d, stype=%d, ownkey=%d)",
+ key,ptype,stype,ownkey);
affs_brelse(bh);
+ retval = -EINVAL;
break;
}
- nextkey = htonl(((s32 *)bh->b_data)[startoffset]);
- if (nextkey == key) {
- ((s32 *)bh->b_data)[startoffset] = newkey;
- affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
+ key = be32_to_cpu(((s32 *)bh->b_data)[offset]);
+ 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);
affs_brelse(bh);
retval = 0;
break;
}
affs_brelse(bh);
- startoffset = AFFS_I2BSIZE(startino) / 4 - 4;
+ offset = AFFS_I2BSIZE(inode) / 4 - 4;
}
- unlock_super(startino->i_sb);
+ unlock_super(inode->i_sb);
return retval;
}
-/* Remove inode from link chain */
+/* Remove header from link chain */
int
-affs_fix_link_pred(struct inode *startino, s32 key, s32 newkey)
+affs_remove_link(struct buffer_head *dbh, struct inode *inode)
{
- struct buffer_head *bh = NULL;
- s32 nextkey;
- int offset;
- s32 etype = 0;
- s32 ptype, stype;
int retval;
-
- offset = AFFS_I2BSIZE(startino) / 4 - 10;
- nextkey = startino->i_ino;
- retval = -ENOENT;
- lock_super(startino->i_sb);
- while (1) {
- if (nextkey == 0)
- break;
- pr_debug("AFFS: find_link_pred(): next key=%d\n",nextkey);
- if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino))))
- break;
- if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype)
- || ptype != T_SHORT) {
- affs_brelse(bh);
+ s32 key;
+ s32 ownkey;
+ s32 ptype;
+ s32 stype;
+ struct buffer_head *bh;
+
+ ownkey = be32_to_cpu((DIR_FRONT(dbh)->own_key));
+ key = be32_to_cpu(FILE_END(dbh->b_data,inode)->original);
+ retval = -ENOENT;
+
+ pr_debug("AFFS: remove_link(link=%d, original=%d)\n",ownkey,key);
+
+ lock_super(inode->i_sb);
+ while (key) {
+ if (!(bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
+ retval = -EIO;
break;
}
- if (!etype) {
- if (stype != ST_FILE && stype != ST_USERDIR) {
- affs_brelse(bh);
- break;
- }
- if (stype == ST_FILE)
- etype = ST_LINKFILE;
- else
- etype = ST_LINKDIR;
- } else if (stype != etype) {
+ if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype)) {
+ affs_error(inode->i_sb,"affs_remove_link","Checksum error (block %d)",key);
affs_brelse(bh);
- retval = -EPERM;
+ retval = -EINVAL;
break;
}
- nextkey = htonl(((s32 *)bh->b_data)[offset]);
- if (nextkey == key) {
- FILE_END(bh->b_data,startino)->link_chain = newkey;
- affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
+ key = be32_to_cpu(FILE_END(bh->b_data,inode)->link_chain);
+ if (ownkey == key) {
+ 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);
affs_brelse(bh);
retval = 0;
@@ -143,10 +186,102 @@ affs_fix_link_pred(struct inode *startino, s32 key, s32 newkey)
}
affs_brelse(bh);
}
- unlock_super(startino->i_sb);
+ unlock_super(inode->i_sb);
+
return retval;
}
+/* Remove a filesystem object. If the object to be removed has
+ * links to it, one of the links must be changed to inherit
+ * the file or directory. As above, any inode will do.
+ * The buffer will not be freed. If the header is a link, the
+ * block will be marked as free.
+ * This function returns a negative error number in case of
+ * an error, else 0 if the inode is to be deleted or 1 if not.
+ */
+
+int
+affs_remove_header(struct buffer_head *bh, struct inode *inode)
+{
+ struct buffer_head *link_bh;
+ struct inode *dir;
+ unsigned long link_ino;
+ unsigned long orig_ino;
+ unsigned int dir_ino;
+ int error;
+
+ pr_debug("AFFS: remove_header(key=%ld)\n",be32_to_cpu(DIR_FRONT(bh)->own_key));
+
+ /* Mark directory as changed. We do this before anything else,
+ * as it must be done anyway and doesn't hurt even if an
+ * error occures later.
+ */
+ dir = iget(inode->i_sb,be32_to_cpu(FILE_END(bh->b_data,inode)->parent));
+ if (!dir)
+ return -EIO;
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_version++;
+ mark_inode_dirty(dir);
+ iput(dir);
+
+ orig_ino = be32_to_cpu(FILE_END(bh->b_data,inode)->original);
+ if (orig_ino) { /* This is just a link. Nothing much to do. */
+ pr_debug(" Removing link.\n");
+ if ((error = affs_remove_link(bh,inode)))
+ return error;
+ if ((error = affs_remove_hash(bh,inode)))
+ return error;
+ affs_free_block(inode->i_sb,be32_to_cpu(DIR_FRONT(bh)->own_key));
+ return 1;
+ }
+
+ link_ino = be32_to_cpu(FILE_END(bh->b_data,inode)->link_chain);
+ if (link_ino) { /* This is the complicated case. Yuck. */
+ pr_debug(" Removing original with links to it.\n");
+ /* Unlink the object and its first link from their directories. */
+ if ((error = affs_remove_hash(bh,inode)))
+ return error;
+ if (!(link_bh = affs_bread(inode->i_dev,link_ino,AFFS_I2BSIZE(inode))))
+ return -EIO;
+ if ((error = affs_remove_hash(link_bh,inode))) {
+ affs_brelse(link_bh);
+ return error;
+ }
+ /* Fix link chain. */
+ if ((error = affs_remove_link(link_bh,inode))) {
+ affs_brelse(link_bh);
+ return error;
+ }
+ /* Rename link to object. */
+ memcpy(FILE_END(bh->b_data,inode)->file_name,
+ FILE_END(link_bh->b_data,inode)->file_name,32);
+ /* Insert object into dir the link was in. */
+ dir_ino = be32_to_cpu(FILE_END(link_bh->b_data,inode)->parent);
+ if ((error = affs_insert_hash(dir_ino,bh,inode))) {
+ affs_brelse(link_bh);
+ return error;
+ }
+ affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+ mark_buffer_dirty(bh,1);
+ affs_brelse(link_bh);
+ affs_free_block(inode->i_sb,link_ino);
+ /* Mark the link's parent dir as changed, too. */
+ if (!(dir = iget(inode->i_sb,dir_ino)))
+ return -EIO;
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_version++;
+ mark_inode_dirty(dir);
+ iput(dir);
+ return 1;
+ }
+ /* Plain file/dir. This is the simplest case. */
+ pr_debug(" Removing plain file/dir.\n");
+ if ((error = affs_remove_hash(bh,inode)))
+ return error;
+ return 0;
+}
+
+
/* Checksum a block, do various consistency checks and optionally return
the blocks type number. DATA points to the block. If their pointers
are non-null, *PTYPE and *STYPE are set to the primary and secondary
@@ -162,14 +297,14 @@ affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype)
bsize /= 4;
if (ptype)
- *ptype = htonl(((s32 *)data)[0]);
+ *ptype = be32_to_cpu(((s32 *)data)[0]);
if (stype)
- *stype = htonl(((s32 *)data)[bsize - 1]);
+ *stype = be32_to_cpu(((s32 *)data)[bsize - 1]);
sum = 0;
p = data;
while (bsize--)
- sum += htonl(*p++);
+ sum += be32_to_cpu(*p++);
return sum;
}
@@ -180,9 +315,9 @@ affs_fix_checksum(int bsize, void *data, int cspos)
u32 cs;
cs = affs_checksum_block(bsize,data,NULL,NULL);
- ocs = htonl (((u32 *)data)[cspos]);
+ ocs = be32_to_cpu(((u32 *)data)[cspos]);
ocs -= cs;
- ((u32 *)data)[cspos] = htonl(ocs);
+ ((u32 *)data)[cspos] = be32_to_cpu(ocs);
}
void
@@ -191,7 +326,7 @@ secs_to_datestamp(time_t secs, struct DateStamp *ds)
u32 days;
u32 minute;
- secs -= sys_tz.tz_minuteswest * 60 +((8 * 365 + 2) * 24 * 60 * 60);
+ secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60);
if (secs < 0)
secs = 0;
days = secs / 86400;
@@ -199,9 +334,9 @@ secs_to_datestamp(time_t secs, struct DateStamp *ds)
minute = secs / 60;
secs -= minute * 60;
- ds->ds_Days = htonl(days);
- ds->ds_Minute = htonl(minute);
- ds->ds_Tick = htonl(secs * 50);
+ ds->ds_Days = be32_to_cpu(days);
+ ds->ds_Minute = be32_to_cpu(minute);
+ ds->ds_Tick = be32_to_cpu(secs * 50);
}
int
@@ -268,6 +403,7 @@ affs_error(struct super_block *sb, const char *function, const char *fmt, ...)
if (!(sb->s_flags & MS_RDONLY))
printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n");
sb->s_flags |= MS_RDONLY;
+ sb->u.affs_sb.s_flags |= SF_READONLY; /* Don't allow to remount rw */
}
void
@@ -279,6 +415,50 @@ affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
vsprintf(ErrorBuffer,fmt,args);
va_end(args);
- printk(KERN_WARNING "AFFS error (device %s): %s(): %s\n",kdevname(sb->s_dev),
+ printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n",kdevname(sb->s_dev),
function,ErrorBuffer);
}
+
+/* Check if the name is valid for a affs object. */
+
+int
+affs_check_name(const unsigned char *name, int len)
+{
+ int i;
+
+ if (len > 30)
+#ifdef AFFS_NO_TRUNCATE
+ return -ENAMETOOLONG;
+#else
+ len = 30;
+#endif
+
+ for (i = 0; i < len; i++) {
+ if (name[i] < ' ' || name[i] == ':'
+ || (name[i] > 0x7e && name[i] < 0xa0))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* This function copies name to bstr, with at most 30
+ * characters length. The bstr will be prepended by
+ * a length byte.
+ * NOTE: The name will must be already checked by
+ * affs_check_name()!
+ */
+
+int
+affs_copy_name(unsigned char *bstr, const unsigned char *name)
+{
+ int len;
+
+ for (len = 0; len < 30; len++) {
+ bstr[len + 1] = name[len];
+ if (name[len] == '\0')
+ break;
+ }
+ bstr[0] = len;
+ return len;
+}
diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c
index a7382db4c..832214e79 100644
--- a/fs/affs/bitmap.c
+++ b/fs/affs/bitmap.c
@@ -91,7 +91,7 @@ affs_free_block(struct super_block *sb, s32 block)
block);
else {
sb->u.affs_sb.s_alloc[zone_no].az_free++;
- ((u32 *)bm->bm_bh->b_data)[0] = ntohl(htonl(((u32 *)bm->bm_bh->b_data)[0]) - blk);
+ ((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);
sb->s_dirt = 1;
}
@@ -136,7 +136,7 @@ found:
fwb = zone->z_bm->bm_firstblk + (i - 1) * 32;
lock_super(sb);
zone->z_start = i;
- w = ~htonl(bm[i]);
+ w = ~be32_to_cpu(bm[i]);
fb = find_first_zero_bit(&w,32);
if (fb > 31 || !test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) {
unlock_super(sb);
@@ -163,10 +163,11 @@ found:
az->az_free--;
}
}
- w = ~w - htonl(bm[i]);
- bm[0] = ntohl(htonl(bm[0]) + w);
+ 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);
+ sb->s_dirt = 1;
zone->z_lru_time = jiffies;
return block;
@@ -208,8 +209,6 @@ affs_find_new_zone(struct super_block *sb, int zone_no)
}
while (1) {
- if (i >= sb->u.affs_sb.s_num_az)
- i = 0;
az = &sb->u.affs_sb.s_alloc[i];
if (!az->az_count) {
if (az->az_free > min) {
@@ -223,7 +222,9 @@ affs_find_new_zone(struct super_block *sb, int zone_no)
lusers = az->az_count;
bestused = i;
}
- if (++i == zone->z_az_no) { /* Seen all */
+ if (++i >= sb->u.affs_sb.s_num_az)
+ i = 0;
+ if (i == zone->z_az_no) { /* Seen all */
if (bestno >= 0) {
i = bestno;
} else {
@@ -279,7 +280,7 @@ affs_new_header(struct inode *inode)
}
init_block:
if (!(bh = getblk(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
- affs_error(inode->i_sb,"new_header","Cannot read block %d",block);
+ affs_error(inode->i_sb,"new_header","Cannot get block %d",block);
return 0;
}
memset(bh->b_data,0,AFFS_I2BSIZE(inode));
@@ -357,7 +358,7 @@ found:
init_block:
if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) {
- affs_error(inode->i_sb,"new_data","Cannot read block %d",block);
+ affs_error(inode->i_sb,"new_data","Cannot get block %d",block);
return 0;
}
memset(bh->b_data,0,sb->s_blocksize);
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
index 95bf3080c..d98ab280d 100644
--- a/fs/affs/dir.c
+++ b/fs/affs/dir.c
@@ -13,6 +13,7 @@
*
*/
+#define DEBUG 0
#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -24,8 +25,7 @@
#include <linux/amigaffs.h>
static int affs_readdir(struct file *, void *, filldir_t);
-static ssize_t affs_dir_read(struct file * filp, char * buf,
- size_t count, loff_t *ppos);
+static ssize_t affs_dir_read(struct file *, char *, size_t, loff_t *);
static struct file_operations affs_dir_operations = {
NULL, /* lseek - default */
@@ -55,11 +55,15 @@ struct inode_operations affs_dir_inode_operations = {
NULL, /* mknod */
affs_rename, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permissions */
+ NULL, /* permissions */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL /* revalidate */
};
static ssize_t
@@ -76,15 +80,14 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
int hash_pos;
int chain_pos;
unsigned long ino;
- unsigned long old;
int stored;
- char *name;
- struct buffer_head *dir_bh;
- struct buffer_head *fh_bh;
- struct inode *dir;
- struct inode *inode = filp->f_dentry->d_inode;
+ unsigned char *name;
+ struct buffer_head *dir_bh;
+ struct buffer_head *fh_bh;
+ struct inode *dir;
+ struct inode *inode = filp->f_dentry->d_inode;
- pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos);
+ pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos);
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
@@ -93,8 +96,7 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
dir_bh = NULL;
fh_bh = NULL;
dir = NULL;
- old = filp->f_pos & 0x80000000;
- filp->f_pos &= 0x7FFFFFFF;
+ ino = inode->i_ino;
if (filp->f_pos == 0) {
filp->private_data = (void *)0;
@@ -106,18 +108,11 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
if (filp->f_pos == 1) {
if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
- filp->f_pos |= 0x80000000;
return stored;
}
filp->f_pos = 2;
stored++;
}
-
- /* Read original if this is a link */
- ino = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
- if (!(dir = iget(inode->i_sb,ino)))
- return stored;
-
chain_pos = (filp->f_pos - 2) & 0xffff;
hash_pos = (filp->f_pos - 2) >> 16;
if (chain_pos == 0xffff) {
@@ -126,27 +121,29 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
hash_pos++;
filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
}
- if (!(dir_bh = affs_bread(inode->i_dev,ino,AFFS_I2BSIZE(inode))))
+ if (!(dir_bh = affs_bread(inode->i_dev,inode->i_ino,
+ AFFS_I2BSIZE(inode))))
goto readdir_done;
- while (!stored || !old) {
+ while (1) {
while (hash_pos < AFFS_I2HSIZE(inode) &&
!((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
hash_pos++;
if (hash_pos >= AFFS_I2HSIZE(inode))
- goto readdir_done;
+ break;
- i = htonl(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
+ i = be32_to_cpu(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
j = chain_pos;
+
/* If the directory hasn't changed since the last call to readdir(),
* we can jump directly to where we left off.
*/
- if (filp->private_data && filp->f_version == dir->i_version) {
+ if (filp->private_data && filp->f_version == inode->i_version) {
i = (s32)filp->private_data;
j = 0;
pr_debug("AFFS: readdir() left off=%d\n",i);
}
- filp->f_version = dir->i_version;
+ filp->f_version = inode->i_version;
pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos);
while (i) {
if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
@@ -154,7 +151,7 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto readdir_done;
}
ino = i;
- i = htonl(FILE_END(fh_bh->b_data,inode)->hash_chain);
+ i = be32_to_cpu(FILE_END(fh_bh->b_data,inode)->hash_chain);
if (j == 0)
break;
affs_brelse(fh_bh);
@@ -163,7 +160,7 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
if (fh_bh) {
namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
- pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%d\n",
+ pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n",
namelen,name,ino,i);
filp->private_data = (void *)ino;
if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
@@ -182,10 +179,8 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
readdir_done:
- filp->f_pos |= old;
affs_brelse(dir_bh);
affs_brelse(fh_bh);
- iput(dir);
pr_debug("AFFS: readdir()=%d\n",stored);
return stored;
}
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 273de8ebe..df130db03 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -36,13 +36,10 @@
#endif
static int affs_bmap(struct inode *inode, int block);
-static struct buffer_head * affs_getblock(struct inode *inode, s32 block);
-static ssize_t affs_file_read_ofs(struct file *filp, char *buf,
- size_t count, loff_t *ppos);
-static ssize_t affs_file_write(struct file *filp, const char *buf,
- size_t count, loff_t *ppos);
-static ssize_t affs_file_write_ofs(struct file *filp, const char *buf,
- size_t count, loff_t *ppos);
+static struct buffer_head *affs_getblock(struct inode *inode, s32 block);
+static ssize_t affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos);
+static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos);
+static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, size_t cnt, loff_t *ppos);
static int affs_release_file(struct inode *inode, struct file *filp);
static int alloc_ext_cache(struct inode *inode);
@@ -56,7 +53,11 @@ static struct file_operations affs_file_operations = {
generic_file_mmap, /* mmap */
NULL, /* no special open */
affs_release_file, /* release */
- file_fsync /* brute force, but works */
+ file_fsync, /* brute force, but works */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
};
struct inode_operations affs_file_inode_operations = {
@@ -71,12 +72,15 @@ struct inode_operations affs_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
affs_bmap, /* bmap */
affs_truncate, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL /* revalidate */
};
static struct file_operations affs_file_operations_ofs = {
@@ -89,7 +93,11 @@ static struct file_operations affs_file_operations_ofs = {
NULL, /* mmap */
NULL, /* no special open */
affs_release_file, /* release */
- file_fsync /* brute force, but works */
+ file_fsync, /* brute force, but works */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
};
struct inode_operations affs_file_inode_operations_ofs = {
@@ -104,12 +112,15 @@ struct inode_operations affs_file_inode_operations_ofs = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
affs_truncate, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL /* revalidate */
};
#define AFFS_ISINDEX(x) ((x < 129) || \
@@ -255,7 +266,7 @@ affs_bmap(struct inode *inode, int block)
/* Try to find the requested key in the cache.
* In order to speed this up as much as possible,
- * the cache line lookup is done in a seperate
+ * the cache line lookup is done in a separate
* step.
*/
@@ -306,7 +317,7 @@ affs_bmap(struct inode *inode, int block)
affs_brelse(bh);
return 0;
}
- nkey = htonl(FILE_END(bh->b_data,inode)->extension);
+ nkey = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
if (block < AFFS_I2HSIZE(inode)) {
/* Fill cache as much as possible */
if (keycount) {
@@ -314,7 +325,7 @@ affs_bmap(struct inode *inode, int block)
keycount = keycount < AFFS_I2HSIZE(inode) - block ? keycount :
AFFS_I2HSIZE(inode) - block;
for (i = 0; i < keycount; i++)
- kc->kc_keys[i] = htonl(AFFS_BLOCK(bh->b_data,inode,block + i));
+ kc->kc_keys[i] = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block + i));
kc->kc_last = kc->kc_first + i - 1;
}
break;
@@ -331,11 +342,20 @@ affs_bmap(struct inode *inode, int block)
kc->kc_this_key = key;
kc->kc_this_seq = ext;
kc->kc_next_key = nkey;
- key = htonl(AFFS_BLOCK(bh->b_data,inode,block));
+ key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block));
affs_brelse(bh);
return key;
}
+/* With the affs, getting a random block from a file is not
+ * a simple business. Since this fs does not allow holes,
+ * it may be neccessary to allocate all the missing blocks
+ * inbetween, as well as some new extension blocks. The OFS
+ * is even worse: All data blocks contain pointers to the
+ * next ones, so you have to fix [n-1] after allocating [n].
+ * What a mess.
+ */
+
static struct buffer_head *
affs_getblock(struct inode *inode, s32 block)
{
@@ -368,7 +388,7 @@ affs_getblock(struct inode *inode, s32 block)
pt = ext ? T_LIST : T_SHORT;
pbh = NULL;
- for (;;) {
+ for (;;) { /* Loop over header block and extension blocks */
bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
if (!bh)
return NULL;
@@ -379,12 +399,12 @@ affs_getblock(struct inode *inode, s32 block)
affs_brelse(bh);
return NULL;
}
- j = htonl(((struct file_front *)bh->b_data)->block_count);
+ j = be32_to_cpu(((struct file_front *)bh->b_data)->block_count);
cf = 0;
while (j < AFFS_I2HSIZE(inode) && j <= block) {
if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) {
if (j > 0)
- pbh = affs_bread(inode->i_dev,ntohl(AFFS_BLOCK(bh->b_data,inode,j - 1)),
+ pbh = affs_bread(inode->i_dev,cpu_to_be32(AFFS_BLOCK(bh->b_data,inode,j - 1)),
AFFS_I2BSIZE(inode));
else
pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock);
@@ -406,7 +426,7 @@ affs_getblock(struct inode *inode, s32 block)
continue;
}
unlock_super(inode->i_sb);
- AFFS_BLOCK(bh->b_data,inode,j) = ntohl(nkey);
+ AFFS_BLOCK(bh->b_data,inode,j) = cpu_to_be32(nkey);
if (ofs) {
ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode));
if (!ebh) {
@@ -417,12 +437,12 @@ affs_getblock(struct inode *inode, s32 block)
break;
}
inode->u.affs_i.i_lastblock++;
- DATA_FRONT(ebh)->primary_type = ntohl(T_DATA);
- DATA_FRONT(ebh)->header_key = ntohl(inode->i_ino);
- DATA_FRONT(ebh)->sequence_number = ntohl(inode->u.affs_i.i_lastblock + 1);
+ DATA_FRONT(ebh)->primary_type = cpu_to_be32(T_DATA);
+ 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);
if (pbh) {
- DATA_FRONT(pbh)->data_size = ntohl(AFFS_I2BSIZE(inode) - 24);
- DATA_FRONT(pbh)->next_data = ntohl(nkey);
+ 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(ebh,0);
@@ -437,7 +457,7 @@ affs_getblock(struct inode *inode, s32 block)
if (pt == T_SHORT)
((struct file_front *)bh->b_data)->first_data =
AFFS_BLOCK(bh->b_data,inode,0);
- ((struct file_front *)bh->b_data)->block_count = ntohl(j);
+ ((struct file_front *)bh->b_data)->block_count = cpu_to_be32(j);
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
mark_buffer_dirty(bh,1);
}
@@ -453,7 +473,7 @@ affs_getblock(struct inode *inode, s32 block)
}
block -= AFFS_I2HSIZE(inode);
- key = htonl(FILE_END(bh->b_data,inode)->extension);
+ key = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
if (!key) {
key = affs_new_header(inode);
if (!key) {
@@ -465,12 +485,12 @@ affs_getblock(struct inode *inode, s32 block)
affs_free_block(inode->i_sb,key);
return NULL;
}
- ((struct file_front *)ebh->b_data)->primary_type = ntohl(T_LIST);
- ((struct file_front *)ebh->b_data)->own_key = ntohl(key);
- FILE_END(ebh->b_data,inode)->secondary_type = ntohl(ST_FILE);
- FILE_END(ebh->b_data,inode)->parent = ntohl(inode->i_ino);
+ ((struct file_front *)ebh->b_data)->primary_type = cpu_to_be32(T_LIST);
+ ((struct file_front *)ebh->b_data)->own_key = cpu_to_be32(key);
+ 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);
- FILE_END(bh->b_data,inode)->extension = ntohl(key);
+ 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);
affs_brelse(bh);
@@ -487,8 +507,8 @@ affs_getblock(struct inode *inode, s32 block)
}
kc->kc_this_key = key;
kc->kc_this_seq = ext;
- kc->kc_next_key = htonl(FILE_END(bh->b_data,inode)->extension);
- key = htonl(AFFS_BLOCK(bh->b_data,inode,block));
+ kc->kc_next_key = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
+ key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block));
affs_brelse(bh);
if (!key)
return NULL;
@@ -499,14 +519,15 @@ affs_getblock(struct inode *inode, s32 block)
static ssize_t
affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos)
{
- struct inode *inode = filp->f_dentry->d_inode;
- char *start;
- ssize_t left, offset, size, sector;
- ssize_t blocksize;
- struct buffer_head *bh;
- void *data;
+ struct inode *inode = filp->f_dentry->d_inode;
+ char *start;
+ ssize_t left, offset, size, sector;
+ ssize_t blocksize;
+ struct buffer_head *bh;
+ void *data;
- pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,(long)*ppos,count);
+ pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,
+ (unsigned long)*ppos,count);
if (!inode) {
affs_error(inode->i_sb,"file_read_ofs","Inode = NULL");
@@ -553,40 +574,25 @@ affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
ssize_t c;
ssize_t blocksize;
struct buffer_head *bh;
- struct inode *ino;
char *p;
- /* Not that I wanted to be POSIX compliant ... */
if (!count)
return 0;
pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
- (unsigned long)*ppos,count);
+ (unsigned long)*ppos,count);
- ino = NULL;
if (!inode) {
affs_error(inode->i_sb,"file_write","Inode = NULL");
return -EINVAL;
}
- if (inode->u.affs_i.i_original) {
- ino = iget(inode->i_sb,inode->u.affs_i.i_original);
- if (!ino) {
- affs_error(inode->i_sb,"file_write",
- "Could not follow link from inode %lu to %d",
- inode->i_ino,inode->u.affs_i.i_original);
- return -EINVAL;
- }
- inode = ino;
- }
if (!S_ISREG(inode->i_mode)) {
affs_error(inode->i_sb,"file_write",
"Trying to write to non-regular file (mode=%07o)",
inode->i_mode);
- iput(inode);
return -EINVAL;
}
if (!inode->u.affs_i.i_ec) {
if (alloc_ext_cache(inode)) {
- iput(inode);
return -ENOMEM;
}
}
@@ -617,8 +623,14 @@ affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
break;
}
}
- p = (pos % blocksize) + bh->b_data;
- copy_from_user(p,buf,c);
+ p = (pos % blocksize) + bh->b_data;
+ c -= copy_from_user(p,buf,c);
+ if (!c) {
+ affs_brelse(bh);
+ if (!written)
+ written = -EFAULT;
+ break;
+ }
update_vm_cache(inode,pos,p,c);
mark_buffer_uptodate(bh,1);
mark_buffer_dirty(bh,0);
@@ -630,22 +642,20 @@ affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
if (pos > inode->i_size)
inode->i_size = pos;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- *ppos = pos;
+ *ppos = pos;
mark_inode_dirty(inode);
- iput(ino);
return written;
}
static ssize_t
affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *ppos)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_dentry->d_inode;
off_t pos;
ssize_t written;
ssize_t c;
ssize_t blocksize;
struct buffer_head *bh;
- struct inode *ino;
char *p;
pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
@@ -657,24 +667,17 @@ affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *pp
affs_error(inode->i_sb,"file_write_ofs","Inode = NULL");
return -EINVAL;
}
- ino = NULL;
- if (inode->u.affs_i.i_original) {
- ino = iget(inode->i_sb,inode->u.affs_i.i_original);
- if (!ino) {
- affs_error(inode->i_sb,"file_write_ofs",
- "Could not follow link from inode %lu to %d",
- inode->i_ino,inode->u.affs_i.i_original);
- return -EINVAL;
- }
- inode = ino;
- }
if (!S_ISREG(inode->i_mode)) {
affs_error(inode->i_sb,"file_write_ofs",
"Trying to write to non-regular file (mode=%07o)",
inode->i_mode);
- iput(inode);
return -EINVAL;
}
+ if (!inode->u.affs_i.i_ec) {
+ if (alloc_ext_cache(inode)) {
+ return -ENOMEM;
+ }
+ }
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else
@@ -703,14 +706,20 @@ affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *pp
break;
}
}
- p = (pos % blocksize) + bh->b_data + 24;
- copy_from_user(p,buf,c);
+ p = (pos % blocksize) + bh->b_data + 24;
+ c -= copy_from_user(p,buf,c);
+ if (!c) {
+ affs_brelse(bh);
+ if (!written)
+ written = -EFAULT;
+ break;
+ }
update_vm_cache(inode,pos,p,c);
pos += c;
buf += c;
written += c;
- DATA_FRONT(bh)->data_size = ntohl(htonl(DATA_FRONT(bh)->data_size) + c);
+ DATA_FRONT(bh)->data_size = cpu_to_be32(be32_to_cpu(DATA_FRONT(bh)->data_size) + c);
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
mark_buffer_uptodate(bh,1);
mark_buffer_dirty(bh,0);
@@ -721,7 +730,6 @@ affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *pp
*ppos = pos;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
- iput(ino);
return written;
}
@@ -730,7 +738,6 @@ affs_truncate(struct inode *inode)
{
struct buffer_head *bh;
struct buffer_head *ebh;
- struct inode *ino;
struct affs_zone *zone;
int first;
int block;
@@ -745,20 +752,16 @@ affs_truncate(struct inode *inode)
pr_debug("AFFS: file_truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
- ino = NULL;
- if (inode->u.affs_i.i_original) {
- ino = iget(inode->i_sb,inode->u.affs_i.i_original);
- if (!ino) {
- affs_error(inode->i_sb,"truncate","Cannot follow link from %lu to %d",
- inode->i_ino,inode->u.affs_i.i_original);
- return;
- }
- inode = ino;
- }
blocksize = AFFS_I2BSIZE(inode) - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0);
first = (inode->i_size + blocksize - 1) / blocksize;
if (inode->u.affs_i.i_lastblock < first - 1) {
- bh = affs_getblock(inode,first - 1);
+ if (!inode->u.affs_i.i_ec) {
+ if (alloc_ext_cache(inode)) {
+ /* Fine! No way to indicate an error. What can we do? */
+ return;
+ }
+ }
+ bh = affs_getblock(inode,first - 1);
while (inode->u.affs_i.i_pa_cnt) { /* Free any preallocated blocks */
affs_free_block(inode->i_sb,
@@ -778,12 +781,11 @@ affs_truncate(struct inode *inode)
inode->i_size = blocksize * (inode->u.affs_i.i_lastblock + 1);
} else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
rem = inode->i_size % blocksize;
- DATA_FRONT(bh)->data_size = ntohl(rem ? rem : blocksize);
+ DATA_FRONT(bh)->data_size = cpu_to_be32(rem ? rem : blocksize);
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
mark_buffer_dirty(bh,0);
}
affs_brelse(bh);
- iput(ino);
return;
}
ekey = inode->i_ino;
@@ -794,8 +796,8 @@ affs_truncate(struct inode *inode)
affs_error(inode->i_sb,"truncate","Cannot read block %d",ekey);
break;
}
- ptype = htonl(((struct file_front *)bh->b_data)->primary_type);
- stype = htonl(FILE_END(bh->b_data,inode)->secondary_type);
+ ptype = be32_to_cpu(((struct file_front *)bh->b_data)->primary_type);
+ stype = be32_to_cpu(FILE_END(bh->b_data,inode)->secondary_type);
if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE &&
LINK_END(bh->b_data,inode)->original == 0) {
pr_debug("AFFS: truncate(): dumping link\n");
@@ -812,7 +814,7 @@ affs_truncate(struct inode *inode)
freethis = first == 0 && ekey != inode->i_ino;
for (block = first; block < AFFS_I2HSIZE(inode); block++) {
keyp = &AFFS_BLOCK(bh->b_data,inode,block);
- key = htonl(*keyp);
+ key = be32_to_cpu(*keyp);
if (key) {
*keyp = 0;
affs_free_block(inode->i_sb,key);
@@ -822,18 +824,18 @@ affs_truncate(struct inode *inode)
}
}
keyp = &GET_END_PTR(struct file_end,bh->b_data,AFFS_I2BSIZE(inode))->extension;
- key = htonl(*keyp);
+ key = be32_to_cpu(*keyp);
if (first <= AFFS_I2HSIZE(inode)) {
- ((struct file_front *)bh->b_data)->block_count = htonl(first);
+ ((struct file_front *)bh->b_data)->block_count = be32_to_cpu(first);
first = 0;
*keyp = 0;
if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) && first > 0) {
- block = htonl(AFFS_BLOCK(bh->b_data,inode,first - 1));
+ block = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,first - 1));
if ((ebh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
if(!(affs_checksum_block(AFFS_I2BSIZE(inode),ebh->b_data,
&ptype,NULL))) {
rem = inode->i_size % blocksize;
- rem = ntohl(rem ? blocksize : rem);
+ rem = cpu_to_be32(rem ? blocksize : rem);
((struct data_front *)ebh->b_data)->data_size = rem;
((struct data_front *)ebh->b_data)->next_data = 0;
affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
@@ -866,7 +868,6 @@ affs_truncate(struct inode *inode)
}
}
- iput(ino);
}
static int
@@ -900,6 +901,8 @@ alloc_ext_cache(struct inode *inode)
s32 key;
int i;
+ pr_debug("AFFS: alloc_ext_cache(ino=%lu)\n",inode->i_ino);
+
lock_super(inode->i_sb);
if (!inode->u.affs_i.i_ec) {
inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL);
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 1999902eb..676e43470 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -10,7 +10,7 @@
* (C) 1991 Linus Torvalds - minix filesystem
*/
-#include <linux/module.h>
+#define DEBUG 0
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/malloc.h>
@@ -30,106 +30,17 @@
#include <asm/system.h>
#include <asm/uaccess.h>
-/* AmigaOS allows file names with up to 30 characters length.
- * Names longer than that will be silently truncated. If you
- * want to disallow this, comment out the following #define.
- * Creating filesystem objects with longer names will then
- * result in an error (ENAMETOOLONG).
- */
-/*#define NO_TRUNCATE */
-
extern int *blk_size[];
extern struct timezone sys_tz;
#define MIN(a,b) (((a)<(b))?(a):(b))
-static int affs_notify_change(struct inode *inode, struct iattr *attr);
-static void affs_put_inode(struct inode *inode);
-static void affs_read_inode(struct inode *inode);
-static void affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
-static void affs_write_inode(struct inode *inode);
-
-static void
-affs_put_super(struct super_block *sb)
-{
- int i;
-
- pr_debug("affs_put_super()\n");
-
- lock_super(sb);
- for (i = 0; i < sb->u.affs_sb.s_bm_count; i++)
- affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh);
- if (!(sb->s_flags & MS_RDONLY)) {
- ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(1);
- 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);
- }
-
- if (sb->u.affs_sb.s_flags & SF_PREFIX)
- kfree(sb->u.affs_sb.s_prefix);
- kfree(sb->u.affs_sb.s_bitmap);
- affs_brelse(sb->u.affs_sb.s_root_bh);
-
- /* I'm not happy with this. It would be better to save the previous
- * value of this devices blksize_size[][] in the super block and
- * restore it here, but with the affs superblock being quite large
- * already ...
- */
- set_blocksize(sb->s_dev,BLOCK_SIZE);
-
- sb->s_dev = 0;
- unlock_super(sb);
- MOD_DEC_USE_COUNT;
- return;
-}
-
-static void
-affs_write_super(struct super_block *sb)
-{
- int i, clean = 2;
-
- if (!(sb->s_flags & MS_RDONLY)) {
- lock_super(sb);
- for (i = 0, clean = 1; i < sb->u.affs_sb.s_bm_count; i++) {
- if (sb->u.affs_sb.s_bitmap[i].bm_bh) {
- if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) {
- clean = 0;
- break;
- }
- }
- }
- unlock_super(sb);
- ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(clean);
- 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);
- sb->s_dirt = !clean; /* redo until bitmap synced */
- } else
- sb->s_dirt = 0;
-
- pr_debug("AFFS: write_super() at %d, clean=%d\n",CURRENT_TIME,clean);
-}
-
-static struct super_operations affs_sops = {
- affs_read_inode,
- affs_notify_change,
- affs_write_inode,
- affs_put_inode,
- affs_put_super,
- affs_write_super,
- affs_statfs,
- NULL /* remount */
-};
-
unsigned long
affs_parent_ino(struct inode *dir)
{
int root_ino = (dir->i_sb->u.affs_sb.s_root_block);
- if (!S_ISDIR (dir->i_mode)) {
+ if (!S_ISDIR(dir->i_mode)) {
affs_error(dir->i_sb,"parent_ino","Trying to get parent of non-directory");
return root_ino;
}
@@ -138,524 +49,10 @@ affs_parent_ino(struct inode *dir)
return dir->u.affs_i.i_parent;
}
-static int
-parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *root,
- int *blocksize, char **prefix, char *volume, unsigned long *mount_opts)
-{
- char *this_char, *value;
- int f;
-
- /* Fill in defaults */
-
- *uid = 0;
- *gid = 0;
- *reserved = 2;
- *root = -1;
- *blocksize = -1;
- *prefix = "/";
- volume[0] = ':';
- volume[1] = 0;
- *mount_opts = 0;
- if (!options)
- return 1;
- for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
- f = 0;
- if ((value = strchr(this_char,'=')) != NULL)
- *value++ = 0;
- if (!strcmp(this_char,"protect")) {
- if (value) {
- printk("AFFS: Option protect does not take an argument\n");
- return 0;
- }
- *mount_opts |= SF_IMMUTABLE;
- }
- else if (!strcmp(this_char,"verbose")) {
- if (value) {
- printk("AFFS: Option verbose does not take an argument\n");
- return 0;
- }
- *mount_opts |= SF_VERBOSE;
- }
- else if ((f = !strcmp(this_char,"uid")) || !strcmp(this_char,"setuid")) {
- if (!value)
- *uid = current->uid;
- else if (!*value) {
- printk("AFFS: Argument for uid option missing\n");
- return 0;
- } else {
- *uid = simple_strtoul(value,&value,0);
- if (*value)
- return 0;
- if (!f)
- *mount_opts |= SF_SETUID;
- }
- }
- else if ((f = !strcmp(this_char,"gid")) || !strcmp(this_char,"setgid")) {
- if (!value)
- *gid = current->gid;
- else if (!*value) {
- printk("AFFS: Argument for gid option missing\n");
- return 0;
- } else {
- *gid = simple_strtoul(value,&value,0);
- if (*value)
- return 0;
- if (!f)
- *mount_opts |= SF_SETGID;
- }
- }
- else if (!strcmp(this_char,"prefix")) {
- if (!value) {
- printk("AFFS: The prefix option requires an argument\n");
- return 0;
- }
- *prefix = kmalloc(strlen(value) + 1,GFP_KERNEL);
- if (!*prefix)
- return 0;
- strcpy(*prefix,value);
- *mount_opts |= SF_PREFIX;
- }
- else if (!strcmp(this_char,"volume")) {
- if (!value) {
- printk("AFFS: The volume option requires an argument\n");
- return 0;
- }
- if (strlen(value) > 30)
- value[30] = 0;
- strcpy(volume,value);
- }
- else if (!strcmp(this_char,"mode")) {
- if (!value || !*value) {
- printk("AFFS: The mode option requires an argument\n");
- return 0;
- }
- *mode = simple_strtoul(value,&value,8) & 0777;
- if (*value)
- return 0;
- *mount_opts |= SF_SETMODE;
- }
- else if (!strcmp(this_char,"reserved")) {
- if (!value || !*value) {
- printk("AFFS: The reserved option requires an argument\n");
- return 0;
- }
- *reserved = simple_strtoul(value,&value,0);
- if (*value)
- return 0;
- }
- else if (!strcmp(this_char,"root")) {
- if (!value || !*value) {
- printk("AFFS: The root option requires an argument\n");
- return 0;
- }
- *root = simple_strtoul(value,&value,0);
- if (*value)
- return 0;
- }
- else if (!strcmp(this_char,"bs")) {
- if (!value || !*value) {
- printk("AFFS: The bs option requires an argument\n");
- return 0;
- }
- *blocksize = simple_strtoul(value,&value,0);
- if (*value)
- return 0;
- if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048
- && *blocksize != 4096) {
- printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n");
- return 0;
- }
- }
- /* Silently ignore the quota options */
- else if (!strcmp (this_char, "grpquota")
- || !strcmp (this_char, "noquota")
- || !strcmp (this_char, "quota")
- || !strcmp (this_char, "usrquota"))
- ;
- else {
- printk("AFFS: Unrecognized mount option %s\n", this_char);
- return 0;
- }
- }
- return 1;
-}
-
-/* This function definitely needs to be split up. Some fine day I'll
- * hopefully have the guts to do so. Until then: sorry for the mess.
- */
-
-static struct super_block *
-affs_read_super(struct super_block *s,void *data, int silent)
-{
- struct buffer_head *bh = NULL;
- struct buffer_head *bb;
- kdev_t dev = s->s_dev;
- s32 root_block;
- int size;
- u32 chksum;
- u32 *bm;
- s32 ptype, stype;
- int mapidx;
- int num_bm;
- int i, j;
- s32 key;
- int blocksize;
- uid_t uid;
- gid_t gid;
- int reserved;
- int az_no;
- unsigned long mount_flags;
- unsigned long offset;
-
- pr_debug("affs_read_super(%s)\n",data ? (const char *)data : "no options");
-
- MOD_INC_USE_COUNT;
-
- if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
- &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) {
- s->s_dev = 0;
- printk(KERN_ERR "AFFS: Error parsing options\n");
- MOD_DEC_USE_COUNT;
- return NULL;
- }
- lock_super(s);
-
- /* Get the size of the device in 512-byte blocks.
- * If we later see that the partition uses bigger
- * blocks, we will have to change it.
- */
-
- size = blksize_size[MAJOR(dev)][MINOR(dev)];
- size = (size ? size : BLOCK_SIZE) / 512 * blk_size[MAJOR(dev)][MINOR(dev)];
-
- s->u.affs_sb.s_bitmap = NULL;
- s->u.affs_sb.s_root_bh = NULL;
- s->u.affs_sb.s_flags = mount_flags;
- s->u.affs_sb.s_mode = i;
- s->u.affs_sb.s_uid = uid;
- s->u.affs_sb.s_gid = gid;
-
- if (size == 0) {
- s->s_dev = 0;
- unlock_super(s);
- printk(KERN_ERR "AFFS: Could not determine device size\n");
- goto out;
- }
- s->u.affs_sb.s_partition_size = size;
- s->u.affs_sb.s_reserved = reserved;
-
- /* Try to find root block. Its location depends on the block size. */
-
- s->u.affs_sb.s_hashsize = 0;
- if (blocksize > 0) {
- i = blocksize;
- j = blocksize;
- } else {
- i = 512;
- j = 4096;
- }
- for (blocksize = i, key = 0; blocksize <= j; blocksize <<= 1, size >>= 1) {
- if (root_block < 0)
- s->u.affs_sb.s_root_block = (reserved + size - 1) / 2;
- else
- s->u.affs_sb.s_root_block = root_block;
- set_blocksize(dev,blocksize);
-
- /* The root block location that was calculated above is not
- * correct if the partition size is an odd number of 512-
- * byte blocks, which will be rounded down to a number of
- * 1024-byte blocks, and if there were an even number of
- * reserved blocks. Ideally, all partition checkers should
- * report the real number of blocks of the real blocksize,
- * but since this just cannot be done, we have to try to
- * find the root block anyways. In the above case, it is one
- * block behind the calculated one. So we check this one, too.
- */
- for (num_bm = 0; num_bm < 2; num_bm++) {
- pr_debug("AFFS: Dev %s - trying bs=%d bytes, root at %u, "
- "size=%d blocks, %d reserved\n",kdevname(dev),blocksize,
- s->u.affs_sb.s_root_block + num_bm,size,reserved);
- bh = affs_bread(dev,s->u.affs_sb.s_root_block + num_bm,blocksize);
- if (!bh) {
- printk(KERN_ERR "AFFS: Cannot read root block\n");
- goto out;
- }
- if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) &&
- ptype == T_SHORT && stype == ST_ROOT) {
- s->s_blocksize = blocksize;
- s->u.affs_sb.s_hashsize = blocksize / 4 - 56;
- s->u.affs_sb.s_root_block += num_bm;
- key = 1;
- break;
- }
- }
- if (key)
- break;
- affs_brelse(bh);
- bh = NULL;
- }
- if (!key) {
- affs_brelse(bh);
- if (!silent)
- printk(KERN_ERR "AFFS: Cannot find a valid root block on device %s\n",
- kdevname(dev));
- goto out;
- }
- root_block = s->u.affs_sb.s_root_block;
-
- s->u.affs_sb.s_partition_size = size;
- s->s_blocksize_bits = blocksize == 512 ? 9 :
- blocksize == 1024 ? 10 :
- blocksize == 2048 ? 11 : 12;
-
- /* Find out which kind of FS we have */
- bb = affs_bread(dev,0,s->s_blocksize);
- if (bb) {
- chksum = htonl(*(u32 *)bb->b_data);
-
- /* Dircache filesystems are compatible with non-dircache ones
- * when reading. As long as they aren't supported, writing is
- * not recommended.
- */
- if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS
- || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) {
- printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n",
- kdevname(dev));
- s->s_flags |= MS_RDONLY;
- }
- switch (chksum) {
- case MUFS_FS:
- case MUFS_INTLFFS:
- s->u.affs_sb.s_flags |= SF_MUFS;
- /* fall thru */
- case FS_INTLFFS:
- s->u.affs_sb.s_flags |= SF_INTL;
- break;
- case MUFS_DCFFS:
- case MUFS_FFS:
- s->u.affs_sb.s_flags |= SF_MUFS;
- break;
- case FS_DCFFS:
- case FS_FFS:
- break;
- case MUFS_OFS:
- s->u.affs_sb.s_flags |= SF_MUFS;
- /* fall thru */
- case FS_OFS:
- s->u.affs_sb.s_flags |= SF_OFS;
- break;
- case MUFS_DCOFS:
- case MUFS_INTLOFS:
- s->u.affs_sb.s_flags |= SF_MUFS;
- case FS_DCOFS:
- case FS_INTLOFS:
- s->u.affs_sb.s_flags |= SF_INTL | SF_OFS;
- break;
- default:
- printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n",
- kdevname(dev),chksum);
- affs_brelse(bb);
- goto out;
- }
- affs_brelse(bb);
- } else {
- printk(KERN_ERR "AFFS: Cannot read boot block\n");
- goto out;
- }
- if (mount_flags & SF_VERBOSE) {
- chksum = ntohl(chksum);
- printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
- GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0],
- &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1],
- (char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
- }
-
- s->s_magic = AFFS_SUPER_MAGIC;
- s->s_flags |= MS_NODEV | MS_NOSUID;
-
- /* Keep super block in cache */
- if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) {
- printk(KERN_ERR "AFFS: Cannot read root block\n");
- goto out;
- }
-
- /* Allocate space for bitmaps, zones and others */
-
- size = s->u.affs_sb.s_partition_size - reserved;
- num_bm = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32);
- az_no = (size + AFFS_ZONE_SIZE - 1) / (AFFS_ZONE_SIZE - 32);
- ptype = num_bm * sizeof(struct affs_bm_info) +
- az_no * sizeof(struct affs_alloc_zone) +
- MAX_ZONES * sizeof(struct affs_zone);
- pr_debug("num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype);
- if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) {
- printk(KERN_ERR "AFFS: Not enough memory\n");
- goto out;
- }
- memset(s->u.affs_sb.s_bitmap,0,ptype);
-
- s->u.affs_sb.s_zones = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm];
- s->u.affs_sb.s_alloc = (struct affs_alloc_zone *)&s->u.affs_sb.s_zones[MAX_ZONES];
- s->u.affs_sb.s_num_az = az_no;
-
- mapidx = 0;
-
- if (ROOT_END_S(bh->b_data,s)->bm_flag == 0) {
- if (!(s->s_flags & MS_RDONLY)) {
- printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n",
- kdevname(dev));
- s->s_flags |= MS_RDONLY;
- }
- affs_brelse(bh);
- bh = NULL;
- goto nobitmap;
- }
-
- /* The following section is ugly, I know. Especially because of the
- * reuse of some variables that are not named properly.
- */
-
- key = root_block;
- ptype = s->s_blocksize / 4 - 49;
- stype = ptype + 25;
- offset = s->u.affs_sb.s_reserved;
- az_no = 0;
- while (bh) {
- bm = (u32 *)bh->b_data;
- for (i = ptype; i < stype && bm[i]; i++, mapidx++) {
- if (mapidx >= num_bm) {
- printk(KERN_ERR "AFFS: Not enough bitmap space!?\n");
- goto out;
- }
- bb = affs_bread(s->s_dev,htonl(bm[i]),s->s_blocksize);
- if (bb) {
- if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) &&
- !(s->s_flags & MS_RDONLY)) {
- printk(KERN_WARNING "AFFS: Bitmap (%d,key=%lu) invalid - "
- "mounting %s read only.\n",mapidx,htonl(bm[i]),
- kdevname(dev));
- s->s_flags |= MS_RDONLY;
- }
- /* Mark unused bits in the last word as allocated */
- if (size <= s->s_blocksize * 8 - 32) { /* last bitmap */
- ptype = size / 32 + 1; /* word number */
- key = size & 0x1F; /* used bits */
- if (key) {
- chksum = ntohl(0x7FFFFFFF >> (31 - key));
- ((u32 *)bb->b_data)[ptype] &= chksum;
- affs_fix_checksum(s->s_blocksize,bb->b_data,0);
- mark_buffer_dirty(bb,1);
- }
- ptype = (size + 31) & ~0x1F;
- size = 0;
- s->u.affs_sb.s_flags |= SF_BM_VALID;
- } else {
- ptype = s->s_blocksize * 8 - 32;
- size -= ptype;
- }
- s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset;
- s->u.affs_sb.s_bitmap[mapidx].bm_bh = NULL;
- s->u.affs_sb.s_bitmap[mapidx].bm_key = htonl(bm[i]);
- s->u.affs_sb.s_bitmap[mapidx].bm_count = 0;
- offset += ptype;
-
- for (j = 0; ptype > 0; j++, az_no++, ptype -= key) {
- key = MIN(ptype,AFFS_ZONE_SIZE); /* size in bits */
- s->u.affs_sb.s_alloc[az_no].az_size = key / 32;
- s->u.affs_sb.s_alloc[az_no].az_free =
- affs_count_free_bits(key / 8,bb->b_data +
- j * (AFFS_ZONE_SIZE / 8) + 4);
- }
- affs_brelse(bb);
- } else {
- printk(KERN_ERR "AFFS: Cannot read bitmap\n");
- goto out;
- }
- }
- key = htonl(bm[stype]); /* Next block of bitmap pointers */
- ptype = 0;
- stype = s->s_blocksize / 4 - 1;
- affs_brelse(bh);
- if (key) {
- if (!(bh = affs_bread(s->s_dev,key,s->s_blocksize))) {
- printk(KERN_ERR "AFFS: Cannot read bitmap extension\n");
- goto out;
- }
- } else
- bh = NULL;
- }
- if (mapidx != num_bm) {
- printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm);
- goto out;
- }
-nobitmap:
- s->u.affs_sb.s_bm_count = mapidx;
-
- /* set up enough so that it can read an inode */
-
- s->s_dev = dev;
- s->s_op = &affs_sops;
- s->s_root = d_alloc_root(iget(s,root_block),NULL);
- s->s_dirt = 1;
- unlock_super(s);
-
- if (!(s->s_root)) {
- s->s_dev = 0;
- printk(KERN_ERR "AFFS: get root inode failed\n");
- MOD_DEC_USE_COUNT;
- return NULL;
- }
-
- /* create data zones if the fs is mounted r/w */
-
- if (!(s->s_flags & MS_RDONLY)) {
- ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_root->d_inode)->bm_flag = 0;
- secs_to_datestamp(CURRENT_TIME,&ROOT_END(s->u.affs_sb.s_root_bh->b_data,
- s->s_root->d_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);
- affs_make_zones(s);
- }
-
- pr_debug("AFFS: s_flags=%lX\n",s->s_flags);
- return s;
-
- out: /* Kick out for various error conditions */
- affs_brelse (bh);
- affs_brelse(s->u.affs_sb.s_root_bh);
- if (s->u.affs_sb.s_bitmap)
- kfree(s->u.affs_sb.s_bitmap);
- set_blocksize(dev,BLOCK_SIZE);
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
- return NULL;
-}
-
-static void
-affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
-{
- int free;
- struct statfs tmp;
-
- pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",sb->u.affs_sb.s_partition_size,
- sb->u.affs_sb.s_reserved);
-
- free = affs_count_free_blocks(sb);
- tmp.f_type = AFFS_SUPER_MAGIC;
- tmp.f_bsize = sb->s_blocksize;
- tmp.f_blocks = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved;
- tmp.f_bfree = free;
- tmp.f_bavail = free;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- copy_to_user(buf,&tmp,bufsiz);
-}
-
-static void
+void
affs_read_inode(struct inode *inode)
{
- struct buffer_head *bh, *lbh;
+ struct buffer_head *bh;
struct file_front *file_front;
struct file_end *file_end;
s32 block;
@@ -665,7 +62,6 @@ affs_read_inode(struct inode *inode)
pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
- lbh = NULL;
block = inode->i_ino;
if (!(bh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
affs_error(inode->i_sb,"read_inode","Cannot read block %d",block);
@@ -680,10 +76,10 @@ affs_read_inode(struct inode *inode)
file_front = (struct file_front *)bh->b_data;
file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
- prot = (htonl(file_end->protect) & ~0x10) ^ FIBF_OWNER;
+ prot = (be32_to_cpu(file_end->protect) & ~0x10) ^ FIBF_OWNER;
inode->u.affs_i.i_protect = prot;
- inode->u.affs_i.i_parent = htonl(file_end->parent);
+ inode->u.affs_i.i_parent = be32_to_cpu(file_end->parent);
inode->u.affs_i.i_original = 0;
inode->u.affs_i.i_zone = 0;
inode->u.affs_i.i_hlink = 0;
@@ -702,31 +98,28 @@ affs_read_inode(struct inode *inode)
if (inode->i_sb->u.affs_sb.s_flags & SF_SETUID)
inode->i_uid = inode->i_sb->u.affs_sb.s_uid;
- else {
- id = htons(file_end->owner_uid);
- if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) {
- if (id == 0 || id == 0xFFFF)
- id ^= ~0;
- }
+ id = be16_to_cpu(file_end->owner_uid);
+ if (id == 0 || inode->i_sb->u.affs_sb.s_flags & SF_SETUID)
+ inode->i_uid = inode->i_sb->u.affs_sb.s_uid;
+ else if (id == 0xFFFF && inode->i_sb->u.affs_sb.s_flags & SF_MUFS)
+ inode->i_uid = 0;
+ else
inode->i_uid = id;
- }
- if (inode->i_sb->u.affs_sb.s_flags & SF_SETGID)
+
+ id = be16_to_cpu(file_end->owner_gid);
+ if (id == 0 || inode->i_sb->u.affs_sb.s_flags & SF_SETGID)
inode->i_gid = inode->i_sb->u.affs_sb.s_gid;
- else {
- id = htons(file_end->owner_gid);
- if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) {
- if (id == 0 || id == 0xFFFF)
- id ^= ~0;
- }
+ else if (id == 0xFFFF && inode->i_sb->u.affs_sb.s_flags & SF_MUFS)
+ inode->i_gid = 0;
+ else
inode->i_gid = id;
- }
- switch (htonl(file_end->secondary_type)) {
+ switch (be32_to_cpu(file_end->secondary_type)) {
case ST_ROOT:
inode->i_uid = inode->i_sb->u.affs_sb.s_uid;
inode->i_gid = inode->i_sb->u.affs_sb.s_gid;
case ST_USERDIR:
- if (htonl(file_end->secondary_type) == ST_USERDIR ||
+ if (be32_to_cpu(file_end->secondary_type) == ST_USERDIR ||
inode->i_sb->u.affs_sb.s_flags & SF_SETMODE) {
if (inode->i_mode & S_IRUSR)
inode->i_mode |= S_IXUSR;
@@ -740,25 +133,16 @@ affs_read_inode(struct inode *inode)
inode->i_size = 0;
break;
case ST_LINKDIR:
- inode->u.affs_i.i_original = htonl(file_end->original);
- inode->u.affs_i.i_hlink = 1;
- inode->i_mode |= S_IFDIR;
- inode->i_size = 0;
- break;
+ affs_error(inode->i_sb,"read_inode","inode is LINKDIR");
+ affs_brelse(bh);
+ return;
case ST_LINKFILE:
- inode->u.affs_i.i_original = htonl(file_end->original);
- inode->u.affs_i.i_hlink = 1;
- if (!(lbh = affs_bread(inode->i_dev,inode->u.affs_i.i_original,
- AFFS_I2BSIZE(inode)))) {
- affs_brelse(bh);
- affs_error(inode->i_sb,"read_inode","Cannot read block %lu",
- inode->i_ino);
- return;
- }
- file_end = GET_END_PTR(struct file_end,lbh->b_data,AFFS_I2BSIZE(inode));
+ affs_error(inode->i_sb,"read_inode","inode is LINKFILE");
+ affs_brelse(bh);
+ return;
case ST_FILE:
inode->i_mode |= S_IFREG;
- inode->i_size = htonl(file_end->byte_size);
+ inode->i_size = be32_to_cpu(file_end->byte_size);
if (inode->i_sb->u.affs_sb.s_flags & SF_OFS)
block = AFFS_I2BSIZE(inode) - 24;
else
@@ -772,13 +156,12 @@ affs_read_inode(struct inode *inode)
}
inode->i_mtime = inode->i_atime = inode->i_ctime
- = (htonl(file_end->created.ds_Days) * (24 * 60 * 60) +
- htonl(file_end->created.ds_Minute) * 60 +
- htonl(file_end->created.ds_Tick) / 50 +
+ = (be32_to_cpu(file_end->created.ds_Days) * (24 * 60 * 60) +
+ be32_to_cpu(file_end->created.ds_Minute) * 60 +
+ be32_to_cpu(file_end->created.ds_Tick) / 50 +
((8 * 365 + 2) * 24 * 60 * 60)) +
sys_tz.tz_minuteswest * 60;
affs_brelse(bh);
- affs_brelse(lbh);
inode->i_op = NULL;
if (S_ISREG(inode->i_mode)) {
@@ -793,7 +176,7 @@ affs_read_inode(struct inode *inode)
inode->i_op = &affs_symlink_inode_operations;
}
-static void
+void
affs_write_inode(struct inode *inode)
{
struct buffer_head *bh;
@@ -810,11 +193,11 @@ affs_write_inode(struct inode *inode)
return;
}
file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
- if (file_end->secondary_type == htonl(ST_ROOT)) {
+ if (file_end->secondary_type == be32_to_cpu(ST_ROOT)) {
secs_to_datestamp(inode->i_mtime,&ROOT_END(bh->b_data,inode)->disk_altered);
} else {
- file_end->protect = ntohl(inode->u.affs_i.i_protect ^ FIBF_OWNER);
- file_end->byte_size = ntohl(inode->i_size);
+ file_end->protect = cpu_to_be32(inode->u.affs_i.i_protect ^ FIBF_OWNER);
+ file_end->byte_size = cpu_to_be32(inode->i_size);
secs_to_datestamp(inode->i_mtime,&file_end->created);
if (!(inode->i_ino == inode->i_sb->u.affs_sb.s_root_block)) {
uid = inode->i_uid;
@@ -826,9 +209,9 @@ affs_write_inode(struct inode *inode)
gid = inode->i_gid ^ ~0;
}
if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETUID))
- file_end->owner_uid = ntohs(uid);
+ file_end->owner_uid = cpu_to_be16(uid);
if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETGID))
- file_end->owner_gid = ntohs(gid);
+ file_end->owner_gid = cpu_to_be16(gid);
}
}
affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
@@ -836,7 +219,7 @@ affs_write_inode(struct inode *inode)
brelse(bh);
}
-static int
+int
affs_notify_change(struct inode *inode, struct iattr *attr)
{
int error;
@@ -864,19 +247,23 @@ affs_notify_change(struct inode *inode, struct iattr *attr)
return 0;
}
-static void
+void
affs_put_inode(struct inode *inode)
{
pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink);
lock_super(inode->i_sb);
if (inode->u.affs_i.i_ec) {
+ pr_debug("AFFS: freeing ext cache\n");
free_page((unsigned long)inode->u.affs_i.i_ec);
inode->u.affs_i.i_ec = NULL;
}
unlock_super(inode->i_sb);
- if (inode->i_nlink) {
- return;
- }
+}
+
+void
+affs_delete_inode(struct inode *inode)
+{
+ pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink);
inode->i_size = 0;
if (S_ISREG(inode->i_mode) && !inode->u.affs_i.i_hlink)
affs_truncate(inode);
@@ -916,15 +303,15 @@ affs_new_inode(const struct inode *dir)
inode->i_blksize = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->u.affs_i.i_original = 0;
- inode->u.affs_i.i_parent = dir->i_ino;
- inode->u.affs_i.i_zone = 0;
- inode->u.affs_i.i_hlink = 0;
- inode->u.affs_i.i_pa_cnt = 0;
- inode->u.affs_i.i_pa_next = 0;
- inode->u.affs_i.i_pa_last = 0;
- inode->u.affs_i.i_ec = NULL;
- inode->u.affs_i.i_lastblock = -1;
+ inode->u.affs_i.i_original = 0;
+ inode->u.affs_i.i_parent = dir->i_ino;
+ inode->u.affs_i.i_zone = 0;
+ inode->u.affs_i.i_hlink = 0;
+ inode->u.affs_i.i_pa_cnt = 0;
+ inode->u.affs_i.i_pa_next = 0;
+ inode->u.affs_i.i_pa_last = 0;
+ inode->u.affs_i.i_ec = NULL;
+ inode->u.affs_i.i_lastblock = -1;
insert_inode_hash(inode);
mark_inode_dirty(inode);
@@ -934,23 +321,27 @@ affs_new_inode(const struct inode *dir)
int
affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
- const char *name, int len, int type)
+ struct dentry *dentry, int type)
{
struct buffer_head *dir_bh;
struct buffer_head *inode_bh;
struct buffer_head *link_bh;
- struct buffer_head *ibh;
int retval;
- int i;
- s32 next;
+ const unsigned char *name = dentry->d_name.name;
+ int len = dentry->d_name.len;
- pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d\n",dir->i_ino,inode->i_ino,
+ pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d)\n",dir->i_ino,inode->i_ino,
len,name,type);
- dir_bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
- inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
- link_bh = NULL;
- retval = -EIO;
+ if ((retval = affs_check_name(name,len)))
+ return retval;
+ if (len > 30)
+ len = 30;
+
+ dir_bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
+ inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+ link_bh = NULL;
+ retval = -EIO;
if (!dir_bh || !inode_bh)
goto addentry_done;
if (link) {
@@ -958,57 +349,21 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
if (!link_bh)
goto addentry_done;
}
- ((struct dir_front *)inode_bh->b_data)->primary_type = ntohl(T_SHORT);
- ((struct dir_front *)inode_bh->b_data)->own_key = ntohl(inode->i_ino);
-
- retval = -ENAMETOOLONG;
- if (len > 30)
-#ifdef NO_TRUNCATE
- goto addentry_done;
-#else
- len = 30;
-#endif
-
- /* Check if name is valid */
- retval = -EINVAL;
- for (i = 0; i < len; i++) {
- if (name[i] < ' ' || name[i] == ':'
- || ((unsigned char)name[i] > 0x7e && (unsigned char)name[i] < 0xa0))
- goto addentry_done;
- }
- retval = 0;
- DIR_END(inode_bh->b_data,inode)->dir_name[0] = len;
+ ((struct dir_front *)inode_bh->b_data)->primary_type = cpu_to_be32(T_SHORT);
+ ((struct dir_front *)inode_bh->b_data)->own_key = cpu_to_be32(inode->i_ino);
+ DIR_END(inode_bh->b_data,inode)->dir_name[0] = len;
strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len);
- DIR_END(inode_bh->b_data,inode)->secondary_type = ntohl(type);
- DIR_END(inode_bh->b_data,inode)->parent = ntohl(dir->i_ino);
-
- i = affs_hash_name(name,len,AFFS_I2FSTYPE(dir),AFFS_I2HSIZE(dir)) + 6;
- next = dir->i_ino;
-
- /* Alas, we have to search the insertion point with a locked sb */
+ DIR_END(inode_bh->b_data,inode)->secondary_type = cpu_to_be32(type);
+ DIR_END(inode_bh->b_data,inode)->parent = cpu_to_be32(dir->i_ino);
lock_super(inode->i_sb);
- while (1) {
- if (!(ibh = affs_bread(dir->i_dev,next,AFFS_I2BSIZE(dir))))
- goto addentry_done;
- next = htonl(((s32 *)ibh->b_data)[i]);
- if (!next || next > inode->i_ino)
- break;
- i = AFFS_I2BSIZE(dir) / 4 - 4;
- affs_brelse(ibh);
- }
-
- DIR_END(inode_bh->b_data,inode)->hash_chain = next;
- ((s32 *)ibh->b_data)[i] = ntohl(inode->i_ino);
- affs_fix_checksum(AFFS_I2BSIZE(dir),ibh->b_data,5);
- mark_buffer_dirty(ibh,1);
- affs_brelse(ibh);
+ retval = affs_insert_hash(dir->i_ino,inode_bh,dir);
if (link_bh) {
- LINK_END(inode_bh->b_data,inode)->original = ntohl(link->i_ino);
+ LINK_END(inode_bh->b_data,inode)->original = cpu_to_be32(link->i_ino);
LINK_END(inode_bh->b_data,inode)->link_chain =
FILE_END(link_bh->b_data,link)->link_chain;
- FILE_END(link_bh->b_data,link)->link_chain = ntohl(inode->i_ino);
+ FILE_END(link_bh->b_data,link)->link_chain = cpu_to_be32(inode->i_ino);
affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
link->i_version = ++event;
mark_inode_dirty(link);
@@ -1032,32 +387,3 @@ addentry_done:
return retval;
}
-
-static struct file_system_type affs_fs_type = {
- "affs",
- FS_REQUIRES_DEV,
- affs_read_super,
- NULL
-};
-
-__initfunc(int init_affs_fs(void))
-{
- return register_filesystem(&affs_fs_type);
-}
-
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
-
-int
-init_module(void)
-{
- return register_filesystem(&affs_fs_type);
-}
-
-void
-cleanup_module(void)
-{
- unregister_filesystem(&affs_fs_type);
-}
-
-#endif
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index d82f13c7f..2ec0401d5 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -8,6 +8,7 @@
* (C) 1991 Linus Torvalds - minix filesystem
*/
+#define DEBUG 0
#include <linux/sched.h>
#include <linux/affs_fs.h>
#include <linux/kernel.h>
@@ -20,8 +21,6 @@
#include <linux/errno.h>
-static int affs_fixup(struct buffer_head *bh, struct inode *inode);
-
/* Simple toupper() for DOS\1 */
static inline unsigned int
@@ -45,7 +44,7 @@ affs_intl_toupper(unsigned int ch)
*/
static int
-affs_match(const char *name, int len, const char *compare, int dlen, int intl)
+affs_match(const unsigned char *name, int len, const unsigned char *compare, int dlen, int intl)
{
if (!compare)
return 0;
@@ -62,14 +61,14 @@ affs_match(const char *name, int len, const char *compare, int dlen, int intl)
return 0;
if (intl) {
while (dlen--) {
- if (affs_intl_toupper(*name & 0xFF) != affs_intl_toupper(*compare & 0xFF))
+ if (affs_intl_toupper(*name) != affs_intl_toupper(*compare))
return 0;
name++;
compare++;
}
} else {
while (dlen--) {
- if (affs_toupper(*name & 0xFF) != affs_toupper(*compare & 0xFF))
+ if (affs_toupper(*name) != affs_toupper(*compare))
return 0;
name++;
compare++;
@@ -79,7 +78,7 @@ affs_match(const char *name, int len, const char *compare, int dlen, int intl)
}
int
-affs_hash_name(const char *name, int len, int intl, int hashsize)
+affs_hash_name(const unsigned char *name, int len, int intl, int hashsize)
{
unsigned int i, x;
@@ -97,14 +96,15 @@ affs_hash_name(const char *name, int len, int intl, int hashsize)
}
static struct buffer_head *
-affs_find_entry(struct inode *dir, const char *name, int namelen,
- unsigned long *ino)
+affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
{
- struct buffer_head *bh;
- int intl;
- s32 key;
+ struct buffer_head *bh;
+ int intl;
+ s32 key;
+ const char *name = dentry->d_name.name;
+ int namelen = dentry->d_name.len;
- pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name);
+ pr_debug("AFFS: find_entry(\"%.*s\")\n",namelen,name);
intl = AFFS_I2FSTYPE(dir);
bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
@@ -123,7 +123,7 @@ affs_find_entry(struct inode *dir, const char *name, int namelen,
key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir)));
for (;;) {
- char *cname;
+ unsigned char *cname;
int cnamelen;
affs_brelse(bh);
@@ -137,154 +137,127 @@ affs_find_entry(struct inode *dir, const char *name, int namelen,
cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname);
if (affs_match(name,namelen,cname,cnamelen,intl))
break;
- key = htonl(FILE_END(bh->b_data,dir)->hash_chain);
+ key = be32_to_cpu(FILE_END(bh->b_data,dir)->hash_chain);
}
*ino = key;
return bh;
}
int
-affs_lookup(struct inode *dir, const char *name, int len, struct inode **result)
+affs_lookup(struct inode *dir, struct dentry *dentry)
{
- int res;
- unsigned long ino;
- struct buffer_head *bh;
-
- pr_debug("AFFS: lookup(%.*s)\n",len,name);
+ unsigned long ino;
+ struct buffer_head *bh;
+ struct inode *inode;
- *result = NULL;
- if (!dir)
- return -ENOENT;
+ pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name);
- res = -ENOENT;
- if (S_ISDIR(dir->i_mode)) {
- if ((bh = affs_find_entry(dir,name,len,&ino))) {
- if (FILE_END(bh->b_data,dir)->original)
- ino = htonl(FILE_END(bh->b_data,dir)->original);
- affs_brelse(bh);
- if ((*result = iget(dir->i_sb,ino)))
- res = 0;
- else
- res = -EACCES;
- }
+ inode = NULL;
+ bh = affs_find_entry(dir,dentry,&ino);
+ if (bh) {
+ if (FILE_END(bh->b_data,dir)->original)
+ ino = be32_to_cpu(FILE_END(bh->b_data,dir)->original);
+ affs_brelse(bh);
+ inode = iget(dir->i_sb,ino);
+ if (!inode)
+ return -EACCES;
}
- iput(dir);
- return res;
+ d_add(dentry,inode);
+ return 0;
}
int
-affs_unlink(struct inode *dir, const char *name, int len)
+affs_unlink(struct inode *dir, struct dentry *dentry)
{
int retval;
struct buffer_head *bh;
unsigned long ino;
struct inode *inode;
- pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,len,name);
+ pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,
+ (int)dentry->d_name.len,dentry->d_name.name);
bh = NULL;
- inode = NULL;
retval = -ENOENT;
- if (!(bh = affs_find_entry(dir,name,len,&ino))) {
- goto unlink_done;
- }
- if (!(inode = iget(dir->i_sb,ino))) {
+ if (!dir)
goto unlink_done;
- }
- if (S_ISDIR(inode->i_mode)) {
- retval = -EPERM;
+ if (!(bh = affs_find_entry(dir,dentry,&ino)))
goto unlink_done;
- }
- if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
- AFFS_I2HSIZE(dir)) + 6,ino,
- FILE_END(bh->b_data,dir)->hash_chain)))
+ inode = dentry->d_inode;
+ retval = -EPERM;
+ if (S_ISDIR(inode->i_mode))
goto unlink_done;
-
- if ((retval = affs_fixup(bh,inode)))
+ if (current->fsuid != inode->i_uid &&
+ current->fsuid != dir->i_uid && !fsuser())
goto unlink_done;
- inode->i_nlink=0;
- mark_inode_dirty(inode);
+ if ((retval = affs_remove_header(bh,inode)) < 0)
+ goto unlink_done;
+
+ inode->i_nlink = retval;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_version = ++event;
- mark_inode_dirty(dir);
+ mark_inode_dirty(inode);
+ retval = 0;
+ d_delete(dentry);
unlink_done:
affs_brelse(bh);
- iput(inode);
- iput(dir);
return retval;
}
int
-affs_create(struct inode *dir, const char *name, int len, int mode, struct inode **result)
+affs_create(struct inode *dir, struct dentry *dentry, int mode)
{
struct inode *inode;
int error;
- pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
+ pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len,
+ dentry->d_name.name,mode);
- *result = NULL;
- if (!dir || !dir->i_sb) {
- iput(dir);
- return -EINVAL;
- }
+ if (!dir)
+ return -ENOENT;
inode = affs_new_inode(dir);
- if (!inode) {
- iput (dir);
+ if (!inode)
return -ENOSPC;
- }
- inode->i_mode = mode;
+
+ pr_debug(" -- ino=%lu\n",inode->i_ino);
if (dir->i_sb->u.affs_sb.s_flags & SF_OFS)
inode->i_op = &affs_file_inode_operations_ofs;
else
inode->i_op = &affs_file_inode_operations;
- error = affs_add_entry(dir,NULL,inode,name,len,ST_FILE);
+ error = affs_add_entry(dir,NULL,inode,dentry,ST_FILE);
if (error) {
- iput(dir);
inode->i_nlink = 0;
mark_inode_dirty(inode);
iput(inode);
- return -ENOSPC;
+ return error;
}
+ inode->i_mode = mode;
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
-
- iput(dir);
- *result = inode;
+ dir->i_version = ++event;
+ mark_inode_dirty(dir);
+ d_instantiate(dentry,inode);
return 0;
}
int
-affs_mkdir(struct inode *dir, const char *name, int len, int mode)
+affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct inode *inode;
- struct buffer_head *bh;
- unsigned long i;
int error;
- pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
+ pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,
+ (int)dentry->d_name.len,dentry->d_name.name,mode);
- if (!dir || !dir->i_sb) {
- iput(dir);
- return -EINVAL;
- }
- bh = affs_find_entry(dir,name,len,&i);
- if (bh) {
- affs_brelse(bh);
- iput(dir);
- return -EEXIST;
- }
inode = affs_new_inode(dir);
- if (!inode) {
- iput (dir);
+ if (!inode)
return -ENOSPC;
- }
+
inode->i_op = &affs_dir_inode_operations;
- error = affs_add_entry(dir,NULL,inode,name,len,ST_USERDIR);
+ error = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR);
if (error) {
- iput(dir);
inode->i_nlink = 0;
mark_inode_dirty(inode);
iput(inode);
@@ -292,9 +265,9 @@ affs_mkdir(struct inode *dir, const char *name, int len, int mode)
}
inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
-
- iput(dir);
- iput(inode);
+ dir->i_version = ++event;
+ mark_inode_dirty(dir);
+ d_instantiate(dentry,inode);
return 0;
}
@@ -310,26 +283,29 @@ empty_dir(struct buffer_head *bh, int hashsize)
}
int
-affs_rmdir(struct inode *dir, const char *name, int len)
+affs_rmdir(struct inode *dir, struct dentry *dentry)
{
int retval;
unsigned long ino;
struct inode *inode;
struct buffer_head *bh;
- pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,len,name);
+ pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,
+ (int)dentry->d_name.len,dentry->d_name.name);
inode = NULL;
+ bh = NULL;
retval = -ENOENT;
- if (!(bh = affs_find_entry(dir,name,len,&ino))) {
+ if (!dir)
goto rmdir_done;
- }
- if (!(inode = iget(dir->i_sb,ino))) {
+ if (!(bh = affs_find_entry(dir,dentry,&ino)))
goto rmdir_done;
- }
+
+ inode = dentry->d_inode;
+
retval = -EPERM;
- if (!fsuser() && current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid)
+ if (current->fsuid != inode->i_uid &&
+ current->fsuid != dir->i_uid && !fsuser())
goto rmdir_done;
if (inode->i_dev != dir->i_dev)
goto rmdir_done;
@@ -339,6 +315,11 @@ affs_rmdir(struct inode *dir, const char *name, int len)
retval = -ENOTDIR;
goto rmdir_done;
}
+ down(&inode->i_sem);
+ if (dentry->d_count > 1) {
+ shrink_dcache_parent(dentry);
+ }
+ up(&inode->i_sem);
if (!empty_dir(bh,AFFS_I2HSIZE(inode))) {
retval = -ENOTEMPTY;
goto rmdir_done;
@@ -347,28 +328,21 @@ affs_rmdir(struct inode *dir, const char *name, int len)
retval = -EBUSY;
goto rmdir_done;
}
- if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
- AFFS_I2HSIZE(dir)) + 6,ino,
- FILE_END(bh->b_data,dir)->hash_chain)))
- goto rmdir_done;
-
- if ((retval = affs_fixup(bh,inode)))
+ if ((retval = affs_remove_header(bh,inode)) < 0)
goto rmdir_done;
-
- inode->i_nlink=0;
- mark_inode_dirty(inode);
+
+ inode->i_nlink = retval;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_version = ++event;
- mark_inode_dirty(dir);
+ retval = 0;
+ mark_inode_dirty(inode);
+ d_delete(dentry);
rmdir_done:
- iput(dir);
- iput(inode);
affs_brelse(bh);
return retval;
}
int
-affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
+affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
struct buffer_head *bh;
struct inode *inode;
@@ -377,20 +351,19 @@ affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
int i, maxlen;
char c, lc;
- pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
+ pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,
+ (int)dentry->d_name.len,dentry->d_name.name,symname);
maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
inode = affs_new_inode(dir);
- if (!inode) {
- iput(dir);
+ if (!inode)
return -ENOSPC;
- }
+
inode->i_op = &affs_symlink_inode_operations;
inode->i_mode = S_IFLNK | 0777;
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
if (!bh) {
- iput(dir);
inode->i_nlink = 0;
mark_inode_dirty(inode);
iput(inode);
@@ -427,157 +400,135 @@ affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
mark_buffer_dirty(bh,1);
affs_brelse(bh);
mark_inode_dirty(inode);
- bh = affs_find_entry(dir,name,len,&tmp);
+ bh = affs_find_entry(dir,dentry,&tmp);
if (bh) {
inode->i_nlink = 0;
iput(inode);
affs_brelse(bh);
- iput(dir);
return -EEXIST;
}
- i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK);
+ i = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK);
if (i) {
inode->i_nlink = 0;
mark_inode_dirty(inode);
iput(inode);
affs_brelse(bh);
- iput(dir);
return i;
}
- iput(dir);
- iput(inode);
+ dir->i_version = ++event;
+ d_instantiate(dentry,inode);
return 0;
}
int
-affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len)
+affs_link(struct inode *oldinode, struct inode *dir, struct dentry *dentry)
{
struct inode *inode;
struct buffer_head *bh;
unsigned long i;
int error;
- pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,len,name);
+ pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,
+ (int)dentry->d_name.len,dentry->d_name.name);
- bh = affs_find_entry(dir,name,len,&i);
+ bh = affs_find_entry(dir,dentry,&i);
if (bh) {
affs_brelse(bh);
- iput(oldinode);
- iput(dir);
return -EEXIST;
}
- if (oldinode->u.affs_i.i_hlink) {
- i = oldinode->u.affs_i.i_original;
- iput(oldinode);
- oldinode = iget(dir->i_sb,i);
- if (!oldinode) {
- affs_error(oldinode->i_sb,"link","Cannot get original from link");
- iput(dir);
- return -ENOENT;
- }
+ if (oldinode->u.affs_i.i_hlink) { /* Cannot happen */
+ affs_warning(dir->i_sb,"link","Impossible link to link");
+ return -EINVAL;
}
- inode = affs_new_inode(dir);
- if (!inode) {
- iput(oldinode);
- iput(dir);
+ if (!(inode = affs_new_inode(dir)))
return -ENOSPC;
- }
+
inode->i_op = oldinode->i_op;
- inode->i_mode = oldinode->i_mode;
- inode->i_uid = oldinode->i_uid;
- inode->i_gid = oldinode->i_gid;
- inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+ inode->u.affs_i.i_protect = mode_to_prot(oldinode->i_mode);
inode->u.affs_i.i_original = oldinode->i_ino;
inode->u.affs_i.i_hlink = 1;
+ inode->i_mtime = oldinode->i_mtime;
if (S_ISDIR(oldinode->i_mode))
- error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKDIR);
+ error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKDIR);
else
- error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE);
- if (error) {
+ error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKFILE);
+ if (error)
inode->i_nlink = 0;
- mark_inode_dirty(inode);
+ else {
+ dir->i_version = ++event;
+ mark_inode_dirty(oldinode);
+ oldinode->i_count++;
+ d_instantiate(dentry,oldinode);
}
- iput(dir);
+ mark_inode_dirty(inode);
iput(inode);
- iput(oldinode);
return error;
}
+/* This is copied from the ext2 fs. No need to reinvent the wheel. */
+
static int
-subdir(struct inode *new_inode, struct inode *old_inode)
+subdir(struct dentry * new_dentry, struct dentry * old_dentry)
{
- int ino;
- int result;
-
- new_inode->i_count++;
- result = 0;
- for (;;) {
- if (new_inode == old_inode) {
- result = 1;
- break;
+ int result;
+
+ result = 0;
+ for (;;) {
+ if (new_dentry != old_dentry) {
+ struct dentry * parent = new_dentry->d_parent;
+ if (parent == new_dentry)
+ break;
+ new_dentry = parent;
+ continue;
+ }
+ result = 1;
+ break;
}
- if (new_inode->i_dev != old_inode->i_dev)
- break;
- ino = new_inode->i_ino;
- if (affs_lookup(new_inode,"..",2,&new_inode))
- break;
- if (new_inode->i_ino == ino)
- break;
- }
- iput(new_inode);
- return result;
+ return result;
}
-/* I'm afraid this might not be race proof. Maybe next time. */
-
int
-affs_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len)
+affs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
{
- struct inode *old_inode;
- struct inode *new_inode;
+ struct inode *old_inode = old_dentry->d_inode;
+ struct inode *new_inode = new_dentry->d_inode;
struct buffer_head *old_bh;
struct buffer_head *new_bh;
unsigned long old_ino;
unsigned long new_ino;
int retval;
- pr_debug("AFFS: rename(old=%lu,\"%*s\" to new=%lu,\"%*s\")\n",old_dir->i_ino,old_len,old_name,
- new_dir->i_ino,new_len,new_name);
+ pr_debug("AFFS: rename(old=%lu,\"%*s\" (inode=%p) to new=%lu,\"%*s\" (inode=%p) )\n",
+ old_dir->i_ino,old_dentry->d_name.len,old_dentry->d_name.name,old_inode,
+ new_dir->i_ino,new_dentry->d_name.len,new_dentry->d_name.name,new_inode);
- if (new_len > 30)
- new_len = 30;
- goto start_up;
-retry:
- affs_brelse(old_bh);
- affs_brelse(new_bh);
- iput(new_inode);
- iput(old_inode);
- current->counter = 0;
- schedule();
-start_up:
- old_inode = new_inode = NULL;
- old_bh = new_bh = NULL;
- retval = -ENOENT;
-
- old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino);
+ if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len)))
+ return retval;
+
+ new_bh = NULL;
+ retval = -ENOENT;
+ old_bh = affs_find_entry(old_dir,old_dentry,&old_ino);
if (!old_bh)
goto end_rename;
- old_inode = iget(old_dir->i_sb,old_ino);
- if (!old_inode)
+
+ new_bh = affs_find_entry(new_dir,new_dentry,&new_ino);
+ if (new_bh && !new_inode) {
+ affs_error(old_inode->i_sb,"affs_rename",
+ "No inode for entry found (key=%lu)\n",new_ino);
goto end_rename;
- new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
- if (new_bh) {
- new_inode = iget(new_dir->i_sb,new_ino);
- if (!new_inode) { /* What does this mean? */
- affs_brelse(new_bh);
- new_bh = NULL;
- }
}
- if (new_inode == old_inode) { /* Won't happen */
+ if (new_inode == old_inode) {
+ if (old_ino == new_ino) { /* Filename might have changed case */
+ retval = new_dentry->d_name.len < 31 ? new_dentry->d_name.len : 30;
+ strncpy(DIR_END(old_bh->b_data,old_inode)->dir_name + 1,
+ new_dentry->d_name.name,retval);
+ DIR_END(old_bh->b_data,old_inode)->dir_name[0] = retval;
+ goto new_checksum;
+ }
retval = 0;
goto end_rename;
}
@@ -586,13 +537,13 @@ start_up:
if (!S_ISDIR(old_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (subdir(new_dir,old_inode))
+ if (subdir(new_dentry,old_dentry))
goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
goto end_rename;
retval = -EBUSY;
- if (new_inode->i_count > 1)
+ if (new_dentry->d_count > 1)
goto end_rename;
}
if (S_ISDIR(old_inode->i_mode)) {
@@ -600,142 +551,43 @@ start_up:
if (new_inode && !S_ISDIR(new_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (subdir(new_dir,old_inode))
+ if (subdir(new_dentry,old_dentry))
goto end_rename;
if (affs_parent_ino(old_inode) != old_dir->i_ino)
goto end_rename;
}
- /* Unlink destination if existent */
+ /* Unlink destination if it already exists */
if (new_inode) {
- if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len,
- AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6,
- new_ino,
- FILE_END(new_bh->b_data,new_dir)->hash_chain)))
- goto retry;
- if ((retval = affs_fixup(new_bh,new_inode)))
- goto retry;
- mark_buffer_dirty(new_bh,1);
- new_dir->i_version = ++event;
- mark_inode_dirty(new_dir);
- new_inode->i_nlink = 0;
+ if ((retval = affs_remove_header(new_bh,new_dir)) < 0)
+ goto end_rename;
+ new_inode->i_nlink = retval;
mark_inode_dirty(new_inode);
+ if (new_inode->i_ino == new_ino)
+ new_inode->i_nlink = 0;
}
- retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir),
- AFFS_I2HSIZE(old_dir)) + 6,old_ino,
- FILE_END(old_bh->b_data,old_dir)->hash_chain);
- if (retval)
- goto retry;
-
- retval = affs_add_entry(new_dir,NULL,old_inode,new_name,new_len,
- htonl(FILE_END(old_bh->b_data,old_dir)->secondary_type));
+ /* Remove header from its parent directory. */
+ if ((retval = affs_remove_hash(old_bh,old_dir)))
+ goto end_rename;
+ /* And insert it into the new directory with the new name. */
+ affs_copy_name(FILE_END(old_bh->b_data,old_inode)->file_name,new_dentry->d_name.name);
+ if ((retval = affs_insert_hash(new_dir->i_ino,old_bh,new_dir)))
+ goto end_rename;
+new_checksum:
+ affs_fix_checksum(AFFS_I2BSIZE(new_dir),old_bh->b_data,5);
- new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime
+ = old_dir->i_mtime = CURRENT_TIME;
new_dir->i_version = ++event;
old_dir->i_version = ++event;
+ retval = 0;
mark_inode_dirty(new_dir);
mark_inode_dirty(old_dir);
mark_buffer_dirty(old_bh,1);
+ d_move(old_dentry,new_dentry);
end_rename:
affs_brelse(old_bh);
affs_brelse(new_bh);
- iput(new_inode);
- iput(old_inode);
- iput(old_dir);
- iput(new_dir);
return retval;
}
-
-static int
-affs_fixup(struct buffer_head *bh, struct inode *inode)
-{
- s32 key, link_key;
- s32 type;
- struct buffer_head *nbh;
- struct inode *ofinode;
-
- type = htonl(FILE_END(bh->b_data,inode)->secondary_type);
- if (type == ST_LINKFILE || type == ST_LINKDIR) {
- key = htonl(LINK_END(bh->b_data,inode)->original);
- LINK_END(bh->b_data,inode)->original = 0;
- if (!key) {
- affs_error(inode->i_sb,"fixup","Hard link without original: ino=%lu",
- inode->i_ino);
- return -ENOENT;
- }
- if (!(ofinode = iget(inode->i_sb,key)))
- return -ENOENT;
- type = affs_fix_link_pred(ofinode,inode->i_ino,
- FILE_END(bh->b_data,inode)->link_chain);
- iput(ofinode);
- return type;
- } else if (type == ST_FILE || type == ST_USERDIR) {
- if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) {
- /* Get first link, turn it to a file */
- if (!(ofinode = iget(inode->i_sb,key))) {
- affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
- return -ENOENT;
- }
- if (!ofinode->u.affs_i.i_hlink) {
- affs_error(inode->i_sb,"fixup",
- "First link to %lu (%d) is not a link",
- inode->i_ino,key);
- iput(ofinode);
- return -ENOENT;
- }
- if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
- affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
- iput(ofinode);
- return -ENOENT;
- }
- lock_super(inode->i_sb);
- memcpy(nbh->b_data + 8,bh->b_data + 8,AFFS_I2BSIZE(inode) - 208);
- FILE_END(nbh->b_data,inode)->byte_size = FILE_END(bh->b_data,inode)->
- byte_size;
- FILE_END(nbh->b_data,inode)->extension = FILE_END(bh->b_data,inode)->
- extension;
- FILE_END(nbh->b_data,inode)->secondary_type = FILE_END(bh->b_data,inode)->
- secondary_type;
- FILE_END(nbh->b_data,inode)->original = 0;
-
- ofinode->u.affs_i.i_original = 0;
- ofinode->u.affs_i.i_hlink = 0;
- ofinode->i_size = inode->i_size;
- ofinode->i_uid = inode->i_uid;
- ofinode->i_gid = inode->i_gid;
- mark_inode_dirty(ofinode);
- link_key = ofinode->i_ino;
-
- /* Let all remaining links point to the new file */
- while (1) {
- affs_fix_checksum(AFFS_I2BSIZE(inode),nbh->b_data,5);
- mark_buffer_dirty(nbh,1);
- key = htonl(FILE_END(nbh->b_data,inode)->link_chain);
- affs_brelse(nbh);
- iput(ofinode);
- if (!key || !(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode))))
- break;
- if ((ofinode = iget(inode->i_sb,key))) {
- if (!ofinode->u.affs_i.i_hlink)
- affs_error(inode->i_sb,"fixup",
- "Inode %d in link chain is not a link",
- key);
- ofinode->u.affs_i.i_original = link_key;
- mark_inode_dirty(ofinode);
- FILE_END(nbh->b_data,inode)->original = htonl(link_key);
- } else
- affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
- }
- /* Turn old inode to a link */
- inode->u.affs_i.i_hlink = 1;
- unlock_super(inode->i_sb);
- }
- return 0;
- } else if (type == ST_SOFTLINK) {
- return 0;
- } else {
- affs_error(inode->i_sb,"fixup","Bad secondary type (%d)",type);
- return -EBADF;
- }
-}
diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c
index 24d1ed118..22042158a 100644
--- a/fs/affs/symlink.c
+++ b/fs/affs/symlink.c
@@ -19,7 +19,8 @@
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-static int affs_readlink(struct inode *, char *, int);
+static int affs_readlink(struct inode *, char *, int);
+static struct dentry *affs_follow_link(struct inode *inode, struct dentry *base);
struct inode_operations affs_symlink_inode_operations = {
NULL, /* no file-operations */
@@ -33,9 +34,13 @@ struct inode_operations affs_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
affs_readlink, /* readlink */
+ affs_follow_link, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL /* smap */
};
static int
@@ -46,21 +51,24 @@ affs_readlink(struct inode *inode, char *buffer, int buflen)
int i, j;
char c;
char lc;
+ char *pf;
pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen);
bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
- i = 0;
- j = 0;
if (!bh) {
- affs_error(inode->i_sb,"readlink","Cannot read block %lu\n",inode->i_ino);
- goto symlink_end;
+ affs_warning(inode->i_sb,"follow_link","Unable to read i-node block %lu\n",
+ inode->i_ino);
+ return -EIO;
}
lf = (struct slink_front *)bh->b_data;
lc = 0;
+ i = 0;
+ j = 0;
+ pf = inode->i_sb->u.affs_sb.s_prefix ? inode->i_sb->u.affs_sb.s_prefix : "/";
if (strchr(lf->symname,':')) { /* Handle assign or volume name */
- while (i < buflen && (c = inode->i_sb->u.affs_sb.s_prefix[i])) {
+ while (i < buflen && (c = pf[i])) {
put_user(c,buffer++);
i++;
}
@@ -84,8 +92,64 @@ affs_readlink(struct inode *inode, char *buffer, int buflen)
lc = c;
i++, j++;
}
-symlink_end:
- iput(inode);
affs_brelse(bh);
return i;
}
+
+static struct dentry *
+affs_follow_link(struct inode *inode, struct dentry *base)
+{
+ struct buffer_head *bh;
+ struct slink_front *lf;
+ char *buffer;
+ int i, j;
+ char c;
+ char lc;
+ char *pf;
+
+ pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino);
+
+ if (!(buffer = kmalloc(1024,GFP_KERNEL))) {
+ dput(base);
+ return ERR_PTR(-ENOSPC);
+ }
+ bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+ if (!bh) {
+ affs_warning(inode->i_sb,"follow_link","Unable to read i-node block %lu\n",
+ inode->i_ino);
+ kfree(buffer);
+ dput(base);
+ return ERR_PTR(-EIO);
+ }
+ i = 0;
+ j = 0;
+ lf = (struct slink_front *)bh->b_data;
+ lc = 0;
+ pf = inode->i_sb->u.affs_sb.s_prefix ? inode->i_sb->u.affs_sb.s_prefix : "/";
+
+ if (strchr(lf->symname,':')) { /* Handle assign or volume name */
+ while (i < 1023 && (c = pf[i]))
+ buffer[i++] = c;
+ while (i < 1023 && lf->symname[j] != ':')
+ buffer[i++] = lf->symname[j++];
+ if (i < 1023)
+ buffer[i++] = '/';
+ j++;
+ lc = '/';
+ }
+ while (i < 1023 && (c = lf->symname[j])) {
+ if (c == '/' && lc == '/' && i < 1020) { /* parent dir */
+ buffer[i++] = '.';
+ buffer[i++] = '.';
+ }
+ buffer[i++] = c;
+ lc = c;
+ j++;
+ }
+ buffer[i] = '\0';
+ affs_brelse(bh);
+ base = lookup_dentry(buffer,base,1);
+ kfree(buffer);
+ return base;
+}
+
diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c
index 7e4558d9d..607b4314e 100644
--- a/fs/autofs/waitq.c
+++ b/fs/autofs/waitq.c
@@ -42,31 +42,36 @@ void autofs_catatonic_mode(struct autofs_sb_info *sbi)
static int autofs_write(struct file *file, const void *addr, int bytes)
{
- unsigned long fs;
- unsigned long old_signal;
+ unsigned long sigpipe, flags;
+ mm_segment_t fs;
const char *data = (const char *)addr;
- int written = 0;
+ ssize_t wr = 0;
/** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/
+ sigpipe = sigismember(&current->signal, SIGPIPE);
+
/* Save pointer to user space and point back to kernel space */
fs = get_fs();
set_fs(KERNEL_DS);
- old_signal = current->signal;
-
- while ( bytes && (written = file->f_op->write(file,data,bytes,&file->f_pos)) > 0 ) {
- data += written;
- bytes -= written;
+ while (bytes &&
+ (wr = file->f_op->write(file,data,bytes,&file->f_pos)) > 0) {
+ data += wr;
+ bytes -= wr;
}
- if ( written == -EPIPE && !(old_signal & (1 << (SIGPIPE-1))) ) {
- /* Keep the currently executing process from receiving a
- SIGPIPE unless it was already supposed to get one */
- current->signal &= ~(1 << (SIGPIPE-1));
- }
set_fs(fs);
+ /* Keep the currently executing process from receiving a
+ SIGPIPE unless it was already supposed to get one */
+ if (wr == -EPIPE && !sigpipe) {
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ sigdelset(&current->signal, SIGPIPE);
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+ }
+
return (bytes > 0);
}
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 511dca04a..9a4a460e8 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -82,7 +82,7 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
struct dentry * dentry = NULL;
struct inode * inode = NULL;
struct file file;
- unsigned long fs;
+ mm_segment_t fs;
int has_dumped = 0;
char corefile[6+sizeof(current->comm)];
unsigned long dump_start, dump_size;
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index bb59cdfaf..47345a358 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -428,7 +428,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
unsigned int interpreter_type = INTERPRETER_NONE;
unsigned char ibcs2_interpreter;
int i;
- unsigned long old_fs;
+ mm_segment_t old_fs;
unsigned long error;
struct elf_phdr * elf_ppnt, *elf_phdata;
int elf_exec_fileno;
@@ -1082,7 +1082,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
struct file file;
struct dentry *dentry;
struct inode *inode;
- unsigned long fs;
+ mm_segment_t fs;
char corefile[6+sizeof(current->comm)];
int segs;
int i;
diff --git a/fs/buffer.c b/fs/buffer.c
index 1c8ab164e..941580f3e 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -582,21 +582,23 @@ struct buffer_head *efind_buffer(kdev_t dev, int block, int size)
*/
struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
{
+ struct buffer_head * bh;
for (;;) {
- struct buffer_head * bh;
-
- bh=find_buffer(dev,block,size);
+ bh = find_buffer(dev,block,size);
if (!bh)
- return bh;
+ break;
bh->b_count++;
bh->b_lru_time = jiffies;
- wait_on_buffer(bh);
+ if (!test_bit(BH_Lock, &bh->b_state))
+ break;
+ __wait_on_buffer(bh);
if (bh->b_dev == dev &&
bh->b_blocknr == block &&
bh->b_size == size)
- return bh;
+ break;
bh->b_count--;
}
+ return bh;
}
unsigned int get_hardblocksize(kdev_t dev)
@@ -790,50 +792,87 @@ repeat:
}
/*
- * If we achieved at least half of our goal, return now.
+ * If there are dirty buffers, do a non-blocking wake-up.
+ * This increases the chances of having buffers available
+ * for the next call ...
*/
- if (obtained >= (needed >> 1))
- return;
-
- /* Too bad, that was not enough. Try a little harder to grow some. */
- if (nr_free_pages > min_free_pages + 5) {
- if (grow_buffers(GFP_BUFFER, size)) {
- obtained += PAGE_SIZE;
- goto repeat;
- }
- }
+ if (nr_buffers_type[BUF_DIRTY])
+ wakeup_bdflush(0);
/*
- * Make one more attempt to allocate some buffers.
+ * Allocate buffers to reach half our goal, if possible.
+ * Since the allocation doesn't block, there's no reason
+ * to search the buffer lists again. Then return if there
+ * are _any_ free buffers.
*/
- if (grow_buffers(GFP_ATOMIC, size))
+ while (obtained < (needed >> 1) &&
+ nr_free_pages > min_free_pages + 5 &&
+ grow_buffers(GFP_BUFFER, size))
obtained += PAGE_SIZE;
+ if (free_list[BUFSIZE_INDEX(size)])
+ return;
+
+ /*
+ * If there are dirty buffers, wait while bdflush writes
+ * them out. The buffers become locked, but we can just
+ * wait for one to unlock ...
+ */
+ if (nr_buffers_type[BUF_DIRTY])
+ wakeup_bdflush(1);
+
+ /*
+ * In order to prevent a buffer shortage from exhausting
+ * the system's reserved pages, we force tasks to wait
+ * before using reserved pages for buffers. This is easily
+ * accomplished by waiting on an unused locked buffer.
+ */
+ if ((bh = lru_list[BUF_LOCKED]) != NULL) {
+ for (i = nr_buffers_type[BUF_LOCKED]; i--; bh = bh->b_next_free)
+ {
+ if (bh->b_size != size)
+ continue;
+ if (bh->b_count)
+ continue;
+ if (!buffer_locked(bh))
+ continue;
+ if (buffer_dirty(bh) || buffer_protected(bh))
+ continue;
+ if (MAJOR(bh->b_dev) == LOOP_MAJOR)
+ continue;
+ /*
+ * We've found an unused, locked, non-dirty buffer of
+ * the correct size. Claim it so no one else can,
+ * then wait for it to unlock.
+ */
+ bh->b_count++;
+ wait_on_buffer(bh);
+ bh->b_count--;
+ /*
+ * Loop back to harvest this (and maybe other) buffers.
+ */
+ goto repeat;
+ }
+ }
+
/*
- * If we got any buffers, or another task freed some,
- * return now to let this task proceed.
+ * Convert a reserved page into buffers ... should happen only rarely.
*/
- if (obtained || free_list[BUFSIZE_INDEX(size)]) {
+ if (nr_free_pages > (min_free_pages >> 1) &&
+ grow_buffers(GFP_ATOMIC, size)) {
#ifdef BUFFER_DEBUG
-printk("refill_freelist: obtained %d of %d, free list=%d\n",
-obtained, needed, free_list[BUFSIZE_INDEX(size)] != NULL);
+printk("refill_freelist: used reserve page\n");
#endif
return;
}
/*
- * System is _very_ low on memory ... wake up bdflush and wait.
+ * System is _very_ low on memory ... sleep and try later.
*/
#ifdef BUFFER_DEBUG
-printk("refill_freelist: waking bdflush\n");
+printk("refill_freelist: task %s waiting for buffers\n", current->comm);
#endif
- wakeup_bdflush(1);
- /*
- * While we slept, other tasks may have needed buffers and entered
- * refill_freelist. This could be a big problem ... reset the
- * needed amount to the absolute minimum.
- */
- needed = size;
+ schedule();
goto repeat;
}
@@ -1944,7 +1983,10 @@ int bdflush(void * unused)
/* If there are still a lot of dirty buffers around, skip the sleep
and flush some more */
if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) {
- current->signal = 0;
+ spin_lock_irq(&current->sigmask_lock);
+ flush_signals(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
interruptible_sleep_on(&bdflush_wait);
}
}
diff --git a/fs/dcache.c b/fs/dcache.c
index 6c59851c3..a2aaeeaec 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -129,7 +129,7 @@ out:
return;
}
- printk("Negative d_count (%d) for %s/%s\n",
+ printk(KERN_CRIT "Negative d_count (%d) for %s/%s\n",
count,
dentry->d_parent->d_name.name,
dentry->d_name.name);
@@ -378,7 +378,7 @@ resume:
if (!list_empty(&dentry->d_subdirs)) {
this_parent = dentry;
#ifdef DCACHE_DEBUG
-printk("select_parent: descending to %s/%s, found=%d\n",
+printk(KERN_DEBUG "select_parent: descending to %s/%s, found=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, found);
#endif
goto repeat;
@@ -391,7 +391,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, found);
next = this_parent->d_child.next;
this_parent = this_parent->d_parent;
#ifdef DCACHE_DEBUG
-printk("select_parent: ascending to %s/%s, found=%d\n",
+printk(KERN_DEBUG "select_parent: ascending to %s/%s, found=%d\n",
this_parent->d_parent->d_name.name, this_parent->d_name.name, found);
#endif
goto resume;
@@ -439,7 +439,7 @@ void check_dcache_memory()
goal = 50;
count = select_dcache(32, goal);
#ifdef DCACHE_DEBUG
-printk("check_dcache_memory: goal=%d, count=%d\n", goal, count);
+printk(KERN_DEBUG "check_dcache_memory: goal=%d, count=%d\n", goal, count);
#endif
if (count) {
prune_dcache(count);
@@ -678,7 +678,7 @@ void d_add(struct dentry * entry, struct inode * inode)
void d_move(struct dentry * dentry, struct dentry * target)
{
if (!dentry->d_inode)
- printk("VFS: moving negative dcache entry\n");
+ printk(KERN_WARNING "VFS: moving negative dcache entry\n");
/* Move the dentry to the target hash queue */
list_del(&dentry->d_hash);
diff --git a/fs/dquot.c b/fs/dquot.c
index cf2b91c0a..4e2c60162 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -222,7 +222,7 @@ static void write_dquot(struct dquot *dquot)
{
short type = dquot->dq_type;
struct file *filp = dquot->dq_mnt->mnt_quotas[type];
- unsigned long fs;
+ mm_segment_t fs;
loff_t offset;
if (!(dquot->dq_flags & DQ_MOD) || (filp == (struct file *)NULL))
@@ -246,7 +246,7 @@ static void read_dquot(struct dquot *dquot)
{
short type = dquot->dq_type;
struct file *filp = dquot->dq_mnt->mnt_quotas[type];
- unsigned long fs;
+ mm_segment_t fs;
loff_t offset;
if (filp == (struct file *)NULL)
diff --git a/fs/exec.c b/fs/exec.c
index 731d678aa..a358a3c45 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -261,7 +261,7 @@ unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
unsigned long p, int from_kmem)
{
char *str;
- unsigned long old_fs;
+ mm_segment_t old_fs;
if (!p)
return 0; /* bullet-proofing */
@@ -374,7 +374,7 @@ int read_exec(struct dentry *dentry, unsigned long offset,
} else
file.f_pos = offset;
if (to_kmem) {
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
set_fs(get_ds());
result = file.f_op->read(&file, addr, count, &file.f_pos);
set_fs(old_fs);
@@ -459,22 +459,29 @@ static inline int make_private_signals(void)
}
/*
+ * If make_private_signals() made a copy of the signal table, decrement the
+ * refcount of the original table, and free it if necessary.
+ * We don't do that in make_private_signals() so that we can back off
+ * in flush_old_exec() if an error occurs after calling make_private_signals().
+ */
+
+static inline void release_old_signals(struct signal_struct * oldsig)
+{
+ if (current->sig == oldsig)
+ return;
+ if (atomic_dec_and_test(&oldsig->count))
+ kfree(oldsig);
+}
+
+/*
* These functions flushes out all traces of the currently running executable
* so that a new one can be started
*/
-static inline void flush_old_signals(struct signal_struct *sig)
+static inline void flush_old_signals(struct task_struct *t)
{
- int i;
- struct sigaction * sa = sig->action;
-
- for (i=32 ; i != 0 ; i--) {
- sa->sa_mask = 0;
- sa->sa_flags = 0;
- if (sa->sa_handler != SIG_IGN)
- sa->sa_handler = NULL;
- sa++;
- }
+ flush_signals(t);
+ flush_signal_handlers(t);
}
static inline void flush_old_files(struct files_struct * files)
@@ -517,6 +524,9 @@ int flush_old_exec(struct linux_binprm * bprm)
retval = exec_mmap();
if (retval) goto flush_failed;
+ /* This is the point of no return */
+ release_old_signals(oldsig);
+
if (current->euid == current->uid && current->egid == current->gid)
current->dumpable = 1;
name = bprm->filename;
@@ -535,7 +545,7 @@ int flush_old_exec(struct linux_binprm * bprm)
permission(bprm->dentry->d_inode,MAY_READ))
current->dumpable = 0;
- flush_old_signals(current->sig);
+ flush_old_signals(current);
flush_old_files(current->files);
return 0;
diff --git a/fs/fat/file.c b/fs/fat/file.c
index f3a4f6cec..c1357f784 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -155,7 +155,7 @@ static void fat_prefetch (
/*
Read a file into user space
*/
-ssize_t fat_file_read(
+static ssize_t fat_file_read_text(
struct file *filp,
char *buf,
size_t count,
@@ -270,6 +270,17 @@ ssize_t fat_file_read(
return buf-start;
}
+ssize_t fat_file_read(
+ struct file *filp,
+ char *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ if (!MSDOS_I(inode)->i_binary)
+ return fat_file_read_text(filp, buf, count, ppos);
+ return generic_file_read(filp, buf, count, ppos);
+}
/*
Write to a file either from user space
*/
diff --git a/fs/fat/mmap.c b/fs/fat/mmap.c
index 545874a04..48cbc7b4f 100644
--- a/fs/fat/mmap.c
+++ b/fs/fat/mmap.c
@@ -60,7 +60,7 @@ static unsigned long fat_file_mmap_nopage(
filp.f_pos = pos;
need_read = PAGE_SIZE - clear;
{
- unsigned long cur_fs = get_fs();
+ mm_segment_t cur_fs = get_fs();
set_fs (KERNEL_DS);
cur_read = fat_file_read (&filp, (char*)page,
need_read, &filp.f_pos);
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 99561051d..8743916ee 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -178,7 +178,7 @@ static void send_sigio(int pid, uid_t uid, uid_t euid)
(euid ^ p->suid) && (euid ^ p->uid) &&
(uid ^ p->suid) && (uid ^ p->uid))
continue;
- p->signal |= 1 << (SIGIO-1);
+ send_sig(SIGIO, p, 1);
if (p->state == TASK_INTERRUPTIBLE && signal_pending(p))
wake_up_process(p);
}
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index b77e9facd..88cf1fd4a 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -33,6 +33,7 @@
* wrong information within the volume descriptors.
*/
#define IGNORE_WRONG_MULTI_VOLUME_SPECS
+#define BEQUIET
#ifdef LEAK_CHECK
static int check_malloc = 0;
@@ -237,7 +238,7 @@ static unsigned int isofs_get_last_session(kdev_t dev)
* we would destroy the kernels idea about FS on root
* mount in read_super... [chexum]
*/
- unsigned long old_fs=get_fs();
+ mm_segment_t old_fs=get_fs();
inode_fake.i_rdev=dev;
ms_info.addr_format=CDROM_LBA;
set_fs(KERNEL_DS);
@@ -500,7 +501,8 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */;
brelse(bh);
-
+
+#ifndef BEQUIET
printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n",
s->u.isofs_sb.s_max_size,
1UL << s->u.isofs_sb.s_log_zone_size);
@@ -509,6 +511,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
(isonum_733(rootp->extent) + isonum_711(rootp->ext_attr_length))
<< s -> u.isofs_sb.s_log_zone_size);
if(high_sierra) printk(KERN_DEBUG "Disc in High Sierra format.\n");
+#endif
unlock_super(s);
/* set up enough so that it can read an inode */
@@ -541,7 +544,9 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
}
}
set_blocksize(dev, opt.blocksize);
+#ifndef BEQUIET
printk(KERN_DEBUG "Forcing new log zone size:%d\n", opt.blocksize);
+#endif
}
#ifdef CONFIG_JOLIET
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 1bedcf9be..f638084b6 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -66,7 +66,7 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
unsigned int block, i, f_pos, offset,
inode_number = 0; /* shut gcc up */
- struct buffer_head * bh;
+ struct buffer_head * bh , * retval = NULL;
unsigned int old_offset;
int dlen, match;
char * dpnt;
@@ -86,7 +86,7 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
block = isofs_bmap(dir,f_pos >> bufbits);
if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
-
+
while (f_pos < dir->i_size) {
/* if de is in kmalloc'd memory, do not point to the
@@ -118,13 +118,14 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
+ ISOFS_BLOCK_SIZE);
}
brelse(bh);
+ bh = NULL;
if (f_pos >= dir->i_size)
- return 0;
+ break;
block = isofs_bmap(dir,f_pos>>bufbits);
if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
- return NULL;
+ break;
continue; /* Will kick out if past end of directory */
}
@@ -145,7 +146,7 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
block = isofs_bmap(dir,f_pos>>bufbits);
if (!block ||
!(bh_next = bread(dir->i_dev,block,bufsize)))
- return NULL;
+ break;
de = (struct iso_directory_record *)
kmalloc(offset - old_offset, GFP_KERNEL);
@@ -162,14 +163,14 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
if (dir->i_sb->u.isofs_sb.s_rock ||
dir->i_sb->u.isofs_sb.s_joliet_level) {
- page = (unsigned char *)
- __get_free_page(GFP_KERNEL);
- if (!page) return NULL;
+ if (! page) {
+ page = (unsigned char *)
+ __get_free_page(GFP_KERNEL);
+ if (!page) break;
+ }
}
if (dir->i_sb->u.isofs_sb.s_rock &&
((i = get_rock_ridge_filename(de, page, dir)))) {
- if (i == -1)
- goto out;/* Relocated deep directory */
dlen = i;
dpnt = page;
#ifdef CONFIG_JOLIET
@@ -203,8 +204,6 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
{
match = isofs_match(namelen,name,dpnt,dlen);
}
-
- if (page) free_page((unsigned long) page);
if (match) {
if(inode_number == -1) {
/* Should only happen for the '..' entry */
@@ -213,16 +212,16 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
find_rock_ridge_relocation(de,dir));
}
*ino = inode_number;
- if(de_not_in_buf)
- kfree(de);
- return bh;
+ retval = bh;
+ bh = NULL;
+ break;
}
}
- out:
- brelse(bh);
+ if (page) free_page((unsigned long) page);
+ if (bh) brelse(bh);
if(de_not_in_buf)
kfree(de);
- return NULL;
+ return retval;
}
int isofs_lookup(struct inode * dir, struct dentry * dentry)
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index c25a19c97..d0c70c276 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -90,7 +90,8 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
struct nfs_server *nfssrv = NFS_SERVER(inode);
struct nlm_host *host;
struct nlm_rqst reqst, *call = &reqst;
- unsigned long oldmask;
+ sigset_t oldset;
+ unsigned long flags;
int status;
/* Always use NLM version 1 over UDP for now... */
@@ -114,16 +115,21 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
}
/* Keep the old signal mask */
- oldmask = current->blocked;
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ oldset = current->blocked;
/* If we're cleaning up locks because the process is exiting,
* perform the RPC call asynchronously. */
if (cmd == F_SETLK && fl->fl_type == F_UNLCK
- && (current->flags & PF_EXITING)) {
- current->blocked = ~0UL; /* Mask all signals */
+ && (current->flags & PF_EXITING)) {
+ sigfillset(&current->blocked); /* Mask all signals */
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+
call = nlmclnt_alloc_call();
call->a_flags = RPC_TASK_ASYNC;
} else {
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
call->a_flags = 0;
}
call->a_host = host;
@@ -145,7 +151,10 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
if (status < 0 && (call->a_flags & RPC_TASK_ASYNC))
rpc_free(call);
- current->blocked = oldmask;
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ current->blocked = oldset;
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
done:
dprintk("lockd: clnt proc returns %d\n", status);
@@ -454,11 +463,16 @@ int
nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
{
struct nlm_rqst *req;
- unsigned long oldmask = current->blocked;
+ unsigned long flags;
+ sigset_t oldset;
int status;
/* Block all signals while setting up call */
- current->blocked = ~0UL;
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ oldset = current->blocked;
+ sigfillset(&current->blocked);
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
do {
req = (struct nlm_rqst *) rpc_allocate(RPC_TASK_ASYNC,
@@ -474,7 +488,11 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
if (status < 0)
rpc_free(req);
- current->blocked = oldmask;
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ current->blocked = oldset;
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+
return status;
}
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index c5f77ef89..e649cf633 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -37,8 +37,7 @@
#define NLMDBG_FACILITY NLMDBG_SVC
#define LOCKD_BUFSIZE (1024 + NLMSSVC_XDRSIZE)
-#define BLOCKABLE_SIGS (~(_S(SIGKILL) | _S(SIGSTOP)))
-#define _S(sig) (1 << ((sig) - 1))
+#define BLOCKABLE_SIGS (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
extern struct svc_program nlmsvc_program;
struct nlmsvc_binding * nlmsvc_ops = NULL;
@@ -65,7 +64,6 @@ static void
lockd(struct svc_rqst *rqstp)
{
struct svc_serv *serv = rqstp->rq_server;
- sigset_t oldsigmask;
int err = 0;
/* Lock module and set up kernel thread */
@@ -118,8 +116,11 @@ lockd(struct svc_rqst *rqstp)
*/
while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid)
{
- if (signalled())
- current->signal = 0;
+ if (signalled()) {
+ spin_lock_irq(&current->sigmask_lock);
+ flush_signals(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ }
/*
* Retry any blocked locks that have been notified by
@@ -162,10 +163,17 @@ lockd(struct svc_rqst *rqstp)
}
/* Process request with all signals blocked. */
- oldsigmask = current->blocked;
- current->blocked = BLOCKABLE_SIGS;
+ spin_lock_irq(&current->sigmask_lock);
+ siginitsetinv(&current->blocked, ~BLOCKABLE_SIGS);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
svc_process(serv, rqstp);
- current->blocked = oldsigmask;
+
+ spin_lock_irq(&current->sigmask_lock);
+ sigemptyset(&current->blocked);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
/* Unlock export hash tables */
if (nlmsvc_ops)
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 0c2380de3..ce405d8d5 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -24,24 +24,25 @@
* Global file hash table
*/
#define FILE_NRHASH 32
-#define FILE_HASH(dhash) ((dhash) & FILE_NRHASH)
+#define FILE_HASH_BITS 5
static struct nlm_file * nlm_files[FILE_NRHASH];
static struct semaphore nlm_file_sema = MUTEX;
+static unsigned int file_hash(dev_t dev, ino_t ino)
+{
+ unsigned long tmp = (unsigned long) ino | (unsigned long) dev;
+ tmp = tmp + (tmp >> FILE_HASH_BITS) + (tmp >> FILE_HASH_BITS*2);
+ return tmp & (FILE_NRHASH - 1);
+}
+
/*
* Lookup file info. If it doesn't exist, create a file info struct
* and open a (VFS) file for the given inode.
*
- * The NFS filehandle must have been validated prior to this call,
- * as we assume that the dentry pointer is valid.
- *
* FIXME:
* Note that we open the file O_RDONLY even when creating write locks.
* This is not quite right, but for now, we assume the client performs
* the proper R/W checking.
- *
- * The dentry in the FH may not be validated .. can we call this with
- * the full svc_fh?
*/
u32
nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
@@ -49,40 +50,38 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
{
struct nlm_file *file;
struct knfs_fh *fh = (struct knfs_fh *) f;
- struct dentry *dentry = fh->fh_dcookie;
- unsigned int hash = FILE_HASH(dentry->d_name.hash);
+ unsigned int hash = file_hash(fh->fh_dev, fh->fh_ino);
u32 nfserr;
- dprintk("lockd: nlm_file_lookup(%s/%s)\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
+ dprintk("lockd: nlm_file_lookup(%s/%ld)\n",
+ kdevname(fh->fh_dev), fh->fh_ino);
/* Lock file table */
down(&nlm_file_sema);
for (file = nlm_files[hash]; file; file = file->f_next) {
- if (file->f_handle.fh_dcookie == dentry
- && !memcmp(&file->f_handle, fh, sizeof(*fh)))
+ if (file->f_handle.fh_dcookie == fh->fh_dcookie &&
+ !memcmp(&file->f_handle, fh, sizeof(*fh)))
goto found;
}
- dprintk("lockd: creating file for %s/%s\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- if (!(file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL))) {
- up(&nlm_file_sema);
- return nlm_lck_denied_nolocks;
- }
+ dprintk("lockd: creating file for %s/%ld\n",
+ kdevname(fh->fh_dev), fh->fh_ino);
+ nfserr = nlm_lck_denied_nolocks;
+ file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL);
+ if (!file)
+ goto out_unlock;
memset(file, 0, sizeof(*file));
file->f_handle = *fh;
file->f_sema = MUTEX;
/* Open the file. Note that this must not sleep for too long, else
- * we would lock up lockd:-) So no NFS re-exports, folks. */
+ * we would lock up lockd:-) So no NFS re-exports, folks.
+ */
if ((nfserr = nlmsvc_ops->fopen(rqstp, fh, &file->f_file)) != 0) {
dprintk("lockd: open failed (nfserr %ld)\n", ntohl(nfserr));
- kfree(file);
- up(&nlm_file_sema);
- return nlm_lck_denied;
+ goto out_free;
}
file->f_next = nlm_files[hash];
@@ -91,9 +90,17 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
found:
dprintk("lockd: found file %p (count %d)\n", file, file->f_count);
*result = file;
- up(&nlm_file_sema);
file->f_count++;
- return 0;
+ nfserr = 0;
+
+out_unlock:
+ up(&nlm_file_sema);
+ return nfserr;
+
+out_free:
+ kfree(file);
+ nfserr = nlm_lck_denied;
+ goto out_unlock;
}
/*
@@ -102,11 +109,12 @@ found:
static inline void
nlm_delete_file(struct nlm_file *file)
{
- struct dentry *dentry = file->f_file.f_dentry;
+ struct inode *inode = file->f_file.f_dentry->d_inode;
struct nlm_file **fp, *f;
- dprintk("lockd: closing file %p\n", dentry);
- fp = nlm_files + FILE_HASH(dentry->d_name.hash);
+ dprintk("lockd: closing file %s/%ld\n",
+ kdevname(inode->i_dev), inode->i_ino);
+ fp = nlm_files + file_hash(inode->i_dev, inode->i_ino);
while ((f = *fp) != NULL) {
if (f == file) {
*fp = file->f_next;
diff --git a/fs/locks.c b/fs/locks.c
index 3f4c2c287..278193f56 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -402,11 +402,11 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
switch (flock.l_type) {
case F_RDLCK:
- if (!(filp->f_mode & 1))
+ if (!(filp->f_mode & FMODE_READ))
return (-EBADF);
break;
case F_WRLCK:
- if (!(filp->f_mode & 2))
+ if (!(filp->f_mode & FMODE_WRITE))
return (-EBADF);
break;
case F_UNLCK:
diff --git a/fs/namei.c b/fs/namei.c
index 242363824..2e7c4bff6 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -131,7 +131,7 @@ static inline int do_getname(const char *filename, char *page)
unsigned long len = PAGE_SIZE;
if ((unsigned long) filename >= TASK_SIZE) {
- if (get_fs() != KERNEL_DS)
+ if (!segment_eq(get_fs(), KERNEL_DS))
return -EFAULT;
} else if (TASK_SIZE - (unsigned long) filename < PAGE_SIZE)
len = TASK_SIZE - (unsigned long) filename;
@@ -737,10 +737,9 @@ static inline int do_mkdir(const char * pathname, int mode)
goto exit;
dir = lock_parent(dentry);
-
error = PTR_ERR(dir);
if (IS_ERR(dir))
- goto exit;
+ goto exit_dput;
error = -EEXIST;
if (dentry->d_inode)
@@ -765,6 +764,7 @@ static inline int do_mkdir(const char * pathname, int mode)
exit_lock:
unlock_dir(dir);
+exit_dput:
dput(dentry);
exit:
return error;
@@ -798,10 +798,9 @@ static inline int do_rmdir(const char * name)
goto exit;
dir = lock_parent(dentry);
-
error = PTR_ERR(dir);
if (IS_ERR(dir))
- goto exit;
+ goto exit_dput;
error = -ENOENT;
if (!dentry->d_inode)
@@ -838,6 +837,7 @@ static inline int do_rmdir(const char * name)
exit_lock:
unlock_dir(dir);
+exit_dput:
dput(dentry);
exit:
return error;
@@ -871,10 +871,9 @@ static inline int do_unlink(const char * name)
goto exit;
dir = lock_parent(dentry);
-
error = PTR_ERR(dir);
if (IS_ERR(dir))
- goto exit;
+ goto exit_dput;
error = -ENOENT;
if (!dentry->d_inode)
@@ -911,6 +910,7 @@ static inline int do_unlink(const char * name)
exit_lock:
unlock_dir(dir);
+exit_dput:
dput(dentry);
exit:
return error;
@@ -945,10 +945,9 @@ static inline int do_symlink(const char * oldname, const char * newname)
goto exit;
dir = lock_parent(dentry);
-
error = PTR_ERR(dir);
if (IS_ERR(dir))
- goto exit;
+ goto exit_dput;
error = -EEXIST;
if (dentry->d_inode)
@@ -972,6 +971,7 @@ static inline int do_symlink(const char * oldname, const char * newname)
exit_lock:
unlock_dir(dir);
+exit_dput:
dput(dentry);
exit:
return error;
@@ -1016,10 +1016,9 @@ static inline int do_link(const char * oldname, const char * newname)
goto exit_old;
dir = lock_parent(new_dentry);
-
error = PTR_ERR(dir);
if (IS_ERR(dir))
- goto exit;
+ goto exit_new;
error = -ENOENT;
inode = old_dentry->d_inode;
@@ -1059,6 +1058,7 @@ static inline int do_link(const char * oldname, const char * newname)
exit_lock:
unlock_dir(dir);
+exit_new:
dput(new_dentry);
exit_old:
dput(old_dentry);
diff --git a/fs/nametrans.c b/fs/nametrans.c
index 15c98ed70..fbd456045 100644
--- a/fs/nametrans.c
+++ b/fs/nametrans.c
@@ -168,7 +168,7 @@ char* env_transl(void)
int i;
if(current && current->mm && (env = (char*)current->mm->env_start)
- && get_ds() != get_fs()
+ && !segment_eq(get_ds(), get_fs())
&& current->mm->env_end>=current->mm->env_start+10
&& !verify_area(VERIFY_READ,env,10)) {
for(i=0; i<10; i++) {
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 56275034d..2a140ea55 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -40,7 +40,7 @@ static unsigned long ncp_file_mmap_nopage(struct vm_area_struct *area,
unsigned long tmp;
int bufsize;
int pos;
- unsigned long fs;
+ mm_segment_t fs;
page = __get_free_page(GFP_KERNEL);
if (!page)
diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c
index 08055ac5e..cc8326c05 100644
--- a/fs/ncpfs/sock.c
+++ b/fs/ncpfs/sock.c
@@ -75,14 +75,12 @@ static int _send(struct socket *sock, const void *buff, int len)
#define NCP_SLACK_SPACE 1024
-#define _S(nr) (1<<((nr)-1))
-
static int do_ncp_rpc_call(struct ncp_server *server, int size)
{
struct file *file;
struct inode *inode;
struct socket *sock;
- unsigned long fs;
+ mm_segment_t fs;
int result;
char *start = server->packet;
poll_table wait_table;
@@ -93,7 +91,8 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
int major_timeout_seen;
int acknowledge_seen;
int n;
- unsigned long old_mask;
+ sigset_t old_set;
+ unsigned long mask, flags;
/* We have to check the result, so store the complete header */
struct ncp_request_header request =
@@ -115,17 +114,25 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
retrans = server->m.retry_count;
major_timeout_seen = 0;
acknowledge_seen = 0;
- old_mask = current->blocked;
- current->blocked |= ~(_S(SIGKILL)
-#if 0
- | _S(SIGSTOP)
-#endif
- | ((server->m.flags & NCP_MOUNT_INTR)
- ? ((current->sig->action[SIGINT - 1].sa_handler == SIG_DFL
- ? _S(SIGINT) : 0)
- | (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL
- ? _S(SIGQUIT) : 0))
- : 0));
+
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ old_set = current->blocked;
+ mask = sigmask(SIGKILL) | sigmask(SIGSTOP);
+ if (server->m.flags & NCP_MOUNT_INTR) {
+ /* FIXME: This doesn't seem right at all. So, like,
+ we can't handle SIGINT and get whatever to stop?
+ What if we've blocked it ourselves? What about
+ alarms? Why, in fact, are we mucking with the
+ sigmask at all? -- r~ */
+ if (current->sig->action[SIGINT - 1].sa_handler == SIG_DFL)
+ mask |= sigmask(SIGINT);
+ if (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL)
+ mask |= sigmask(SIGQUIT);
+ }
+ siginitmaskinv(&current->blocked, mask);
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+
fs = get_fs();
set_fs(get_ds());
for (n = 0, timeout = init_timeout;; n++, timeout <<= 1) {
@@ -269,7 +276,12 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
printk(KERN_ERR "NCP: result=%d\n", result);
result = -EIO;
}
+
+ spin_lock_irqsave(&current->sigmask_lock, flags);
current->blocked = old_mask;
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+
set_fs(fs);
return result;
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 9e1d936dd..c74c73243 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -498,6 +498,12 @@ static int nfs_lookup(struct inode *dir, struct dentry * dentry)
error = -EACCES;
inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
if (inode) {
+#ifdef NFS_PARANOIA
+if (inode->i_count > 1)
+printk("nfs_lookup: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->i_ino, inode->i_count, inode->i_nlink);
+#endif
no_entry:
dentry->d_op = &nfs_dentry_operations;
d_add(dentry, inode);
@@ -512,14 +518,20 @@ out:
/*
* Code common to create, mkdir, and mknod.
*/
-static int nfs_instantiate(struct inode *dir, struct dentry *dentry,
- struct nfs_fattr *fattr, struct nfs_fh *fhandle)
+static int nfs_instantiate(struct dentry *dentry, struct nfs_fattr *fattr,
+ struct nfs_fh *fhandle)
{
struct inode *inode;
int error = -EACCES;
- inode = nfs_fhget(dir->i_sb, fhandle, fattr);
+ inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
if (inode) {
+#ifdef NFS_PARANOIA
+if (inode->i_count > 1)
+printk("nfs_instantiate: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->i_ino, inode->i_count, inode->i_nlink);
+#endif
d_instantiate(dentry, inode);
nfs_renew_times(dentry);
error = 0;
@@ -563,14 +575,9 @@ static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
dentry->d_name.name, &sattr, &fhandle, &fattr);
if (!error)
- error = nfs_instantiate(dir, dentry, &fattr, &fhandle);
- else {
-#ifdef NFS_PARANOIA
-printk("nfs_create: %s/%s failed, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, error);
-#endif
+ error = nfs_instantiate(dentry, &fattr, &fhandle);
+ else
d_drop(dentry);
- }
out:
return error;
}
@@ -606,14 +613,9 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
dentry->d_name.name, &sattr, &fhandle, &fattr);
if (!error)
- error = nfs_instantiate(dir, dentry, &fattr, &fhandle);
- else {
-#ifdef NFS_PARANOIA
-printk("nfs_mknod: %s/%s failed, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, error);
-#endif
+ error = nfs_instantiate(dentry, &fattr, &fhandle);
+ else
d_drop(dentry);
- }
return error;
}
@@ -645,13 +647,22 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
nfs_invalidate_dircache(dir);
error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
dentry->d_name.name, &sattr, &fhandle, &fattr);
- if (!error)
- error = nfs_instantiate(dir, dentry, &fattr, &fhandle);
- else {
-#ifdef NFS_PARANOIA
-printk("nfs_mkdir: %s/%s failed, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, error);
-#endif
+ if (!error) {
+ /*
+ * Some AIX servers reportedly fail to fill out the fattr.
+ * Check for a bad mode value and complain, then drop the
+ * dentry to force a new lookup.
+ */
+ if (!S_ISDIR(fattr.mode)) {
+ static int complain = 0;
+ if (!complain++)
+ printk("NFS: buggy server! fattr mode=%x\n",
+ fattr.mode);
+ goto drop;
+ }
+ error = nfs_instantiate(dentry, &fattr, &fhandle);
+ } else {
+ drop:
d_drop(dentry);
}
return error;
@@ -662,12 +673,12 @@ dentry->d_parent->d_name.name, dentry->d_name.name, error);
* use count prior to the operation, and return EBUSY if it has
* multiple users.
*
- * Update inode->i_nlink immediately after a successful operation.
- * (See comments for nfs_unlink.)
+ * We update inode->i_nlink and free the inode prior to the operation
+ * to avoid possible races if the server reuses the inode.
*/
static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{
- int error;
+ int error, rehash = 0;
dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
@@ -688,13 +699,31 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
if (dentry->d_count > 1)
goto out;
}
- /* Drop the dentry to force a new lookup */
- d_drop(dentry);
- error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
+#ifdef NFS_PARANOIA
+if (dentry->d_inode->i_count > 1)
+printk("nfs_rmdir: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+dentry->d_inode->i_count, dentry->d_inode->i_nlink);
+#endif
+ /*
+ * Unhash the dentry while we remove the directory.
+ */
+ if (!list_empty(&dentry->d_hash)) {
+ d_drop(dentry);
+ rehash = 1;
+ }
+ /*
+ * Update i_nlink and free the inode before unlinking.
+ */
+ if (dentry->d_inode->i_nlink)
+ dentry->d_inode->i_nlink --;
+ d_delete(dentry);
+ nfs_invalidate_dircache(dir);
+ error = nfs_proc_rmdir(NFS_SERVER(dir),
+ NFS_FH(dir), dentry->d_name.name);
if (!error) {
- if (dentry->d_inode->i_nlink)
- dentry->d_inode->i_nlink --;
- nfs_invalidate_dircache(dir);
+ if (rehash)
+ d_add(dentry, NULL);
nfs_renew_times(dentry);
}
out:
@@ -867,6 +896,12 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
#endif
goto out;
}
+#ifdef NFS_PARANOIA
+if (inode && inode->i_count > 1)
+printk("nfs_safe_remove: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->i_count, inode->i_nlink);
+#endif
/*
* Unhash the dentry while we remove the file ...
*/
@@ -874,29 +909,22 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
d_drop(dentry);
rehash = 1;
}
- error = nfs_proc_remove(NFS_SERVER(dir),
- NFS_FH(dir), dentry->d_name.name);
/*
- * ... then restore the hashed state. This ensures that the
- * dentry can't become busy after having its file deleted.
+ * Update i_nlink and free the inode before unlinking.
*/
- if (rehash) {
- d_add(dentry, inode);
- }
-#ifdef NFS_PARANOIA
-if (dentry->d_count > 1)
-printk("nfs_safe_remove: %s/%s busy after delete?? d_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
-if (inode && inode->i_count > 1)
-printk("nfs_safe_remove: %s/%s inode busy?? i_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_count);
-#endif
- if (!error) {
- nfs_invalidate_dircache(dir);
- if (inode && inode->i_nlink)
+ if (inode) {
+ if (inode->i_nlink)
inode->i_nlink --;
d_delete(dentry);
}
+ nfs_invalidate_dircache(dir);
+ error = nfs_proc_remove(NFS_SERVER(dir),
+ NFS_FH(dir), dentry->d_name.name);
+ /*
+ * Rehash the negative dentry if the operation succeeded.
+ */
+ if (!error && rehash)
+ d_add(dentry, NULL);
out:
return error;
}
@@ -1144,7 +1172,7 @@ do_rename:
*/
if (!list_empty(&new_dentry->d_hash)) {
d_drop(new_dentry);
- rehash = 1;
+ rehash = update;
}
error = nfs_proc_rename(NFS_SERVER(old_dir),
NFS_FH(old_dir), old_dentry->d_name.name,
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 0f3bd5ed3..7b53bc8ef 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -113,7 +113,8 @@ nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
ssize_t result;
dfprintk(VFS, "nfs: read(%x/%ld, %lu@%lu)\n",
- inode->i_dev, inode->i_ino, count,
+ inode->i_dev, inode->i_ino,
+ (unsigned long) count,
(unsigned long) *ppos);
result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
@@ -167,7 +168,7 @@ nfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
dfprintk(VFS, "nfs: write(%x/%ld (%d), %lu@%lu)\n",
inode->i_dev, inode->i_ino, inode->i_count,
- count, (unsigned long) *ppos);
+ (unsigned long) count, (unsigned long) *ppos);
if (!inode) {
printk("nfs_file_write: inode = NULL\n");
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 3b06d4c36..b7c7dfba7 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -229,7 +229,7 @@ __initfunc(static int
root_dev_chg_route(int op, struct device *dev, __u32 dest, __u32 mask, __u32 gw))
{
struct rtentry route;
- unsigned long oldfs;
+ mm_segment_t oldfs;
int err;
memset(&route, 0, sizeof(struct rtentry)); /* or else! */
@@ -608,7 +608,7 @@ root_bind_udp_sock(struct socket *sock, u32 addr, u16 port))
*/
static inline int root_send_udp(struct socket *sock, void *buf, int size)
{
- u32 oldfs;
+ mm_segment_t oldfs;
int result;
struct msghdr msg;
struct iovec iov;
@@ -632,7 +632,7 @@ static inline int root_send_udp(struct socket *sock, void *buf, int size)
*/
static inline int root_recv_udp(struct socket *sock, void *buf, int size)
{
- u32 oldfs;
+ mm_segment_t oldfs;
int result;
struct msghdr msg;
struct iovec iov;
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 6e161d62b..ccca2cc7c 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -16,6 +16,9 @@
#define NFSDDBG_FACILITY NFSDDBG_LOCKD
+/*
+ * Note: we hold the dentry use count while the file is open.
+ */
static u32
nlm_fopen(struct svc_rqst *rqstp, struct knfs_fh *f, struct file *filp)
{
@@ -27,6 +30,8 @@ nlm_fopen(struct svc_rqst *rqstp, struct knfs_fh *f, struct file *filp)
fh.fh_dverified = 0;
nfserr = nfsd_open(rqstp, &fh, S_IFREG, 0, filp);
+ if (!nfserr)
+ dget(filp->f_dentry);
fh_put(&fh);
return nfserr;
}
@@ -35,6 +40,7 @@ static void
nlm_fclose(struct file *filp)
{
nfsd_close(filp);
+ dput(filp->f_dentry);
}
struct nlmsvc_binding nfsd_nlm_ops = {
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 84d296834..051061add 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -35,9 +35,9 @@
#define NFSDDBG_FACILITY NFSDDBG_SVC
#define NFSD_BUFSIZE (1024 + NFSSVC_MAXBLKSIZE)
-#define BLOCKABLE_SIGS (~(_S(SIGKILL) | _S(SIGSTOP)))
-#define SHUTDOWN_SIGS (_S(SIGKILL)|_S(SIGINT)|_S(SIGTERM))
-#define _S(sig) (1 << ((sig) - 1))
+
+#define BLOCKABLE_SIGS (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
extern struct svc_program nfsd_program;
static void nfsd(struct svc_rqst *rqstp);
@@ -96,7 +96,6 @@ static void
nfsd(struct svc_rqst *rqstp)
{
struct svc_serv *serv = rqstp->rq_server;
- sigset_t oldsigmask;
int oldumask, err;
lock_kernel();
@@ -108,7 +107,7 @@ nfsd(struct svc_rqst *rqstp)
sprintf(current->comm, "nfsd");
oldumask = current->fs->umask; /* Set umask to 0. */
- current->blocked |= ~SHUTDOWN_SIGS;
+ siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
current->fs->umask = 0;
nfssvc_boot = xtime; /* record boot time */
lockd_up(); /* start lockd */
@@ -142,10 +141,17 @@ nfsd(struct svc_rqst *rqstp)
serv->sv_stats->rpcbadclnt++;
} else {
/* Process request with all signals blocked. */
- oldsigmask = current->blocked;
- current->blocked = BLOCKABLE_SIGS;
+ spin_lock_irq(&current->sigmask_lock);
+ siginitsetinv(&current->blocked, ~BLOCKABLE_SIGS);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
svc_process(serv, rqstp);
- current->blocked = oldsigmask;
+
+ spin_lock_irq(&current->sigmask_lock);
+ siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
}
/* Unlock export hash tables */
@@ -157,8 +163,9 @@ nfsd(struct svc_rqst *rqstp)
} else {
unsigned int signo;
- for (signo = 0; signo < 32; signo++)
- if (current->signal & current->blocked & (1<<signo))
+ for (signo = 1; signo <= _NSIG; signo++)
+ if (sigismember(&current->signal, signo) &&
+ !sigismember(&current->blocked, signo))
break;
printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo);
}
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 4579cddec..81b9a3f79 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -240,24 +240,24 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
int access, err;
access = wflag? MAY_WRITE : MAY_READ;
- if ((err = fh_verify(rqstp, fhp, type, access)) != 0)
+ err = fh_verify(rqstp, fhp, type, access);
+ if (err)
goto out;
dentry = fhp->fh_dentry;
inode = dentry->d_inode;
/* Disallow access to files with the append-only bit set or
- * with mandatory locking enabled */
+ * with mandatory locking enabled
+ */
err = nfserr_perm;
if (IS_APPEND(inode) || IS_ISMNDLK(inode))
goto out;
if (!inode->i_op || !inode->i_op->default_file_ops)
goto out;
- if (wflag && (err = get_write_access(inode)) != 0) {
- err = nfserrno(-err);
- goto out;
- }
+ if (wflag && (err = get_write_access(inode)) != 0)
+ goto out_nfserr;
memset(filp, 0, sizeof(*filp));
filp->f_op = inode->i_op->default_file_ops;
@@ -267,7 +267,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
filp->f_dentry = dentry;
err = 0;
- if (filp->f_op->open) {
+ if (filp->f_op && filp->f_op->open) {
err = filp->f_op->open(inode, filp);
if (err) {
if (wflag)
@@ -277,9 +277,11 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
* is really on callers stack frame. -DaveM
*/
filp->f_count--;
- err = nfserrno(-err);
}
}
+out_nfserr:
+ if (err)
+ err = nfserrno(-err);
out:
return err;
}
@@ -360,7 +362,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, char *buf,
struct dentry *dentry;
struct inode *inode;
struct file file;
- unsigned long oldfs;
+ mm_segment_t oldfs;
int err;
if ((err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_READ, &file)) != 0)
@@ -420,7 +422,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
struct file file;
struct dentry *dentry;
struct inode *inode;
- unsigned long oldfs;
+ mm_segment_t oldfs;
int err;
if (!cnt)
@@ -633,14 +635,16 @@ nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size)
struct iattr newattrs;
int err;
- if ((err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE|MAY_TRUNC)) != 0)
- return err;
+ err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC);
+ if (err)
+ goto out;
dentry = fhp->fh_dentry;
inode = dentry->d_inode;
- if ((err = get_write_access(inode)) != 0)
- goto out;
+ err = get_write_access(inode);
+ if (err)
+ goto out_nfserr;
/* Things look sane, lock and do it. */
fh_lock(fhp);
@@ -654,8 +658,11 @@ nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size)
}
put_write_access(inode);
fh_unlock(fhp);
+out_nfserr:
+ if (err)
+ err = nfserrno(-err);
out:
- return (err ? nfserrno(-err) : 0);
+ return err;
}
/*
@@ -668,10 +675,11 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
{
struct dentry *dentry;
struct inode *inode;
- unsigned long oldfs;
+ mm_segment_t oldfs;
int err;
- if ((err = fh_verify(rqstp, fhp, S_IFLNK, MAY_READ)) != 0)
+ err = fh_verify(rqstp, fhp, S_IFLNK, MAY_READ);
+ if (err)
goto out;
dentry = fhp->fh_dentry;
@@ -715,7 +723,8 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (!flen || !plen)
goto out;
- if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE)) != 0)
+ err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
+ if (err)
goto out;
dentry = fhp->fh_dentry;
@@ -762,17 +771,20 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
struct inode *dirp, *dest;
int err;
- if ((err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE) != 0) ||
- (err = fh_verify(rqstp, tfhp, S_IFREG, MAY_NOP)) != 0)
- return err;
+ err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE);
+ if (err)
+ goto out;
+ err = fh_verify(rqstp, tfhp, S_IFREG, MAY_NOP);
+ if (err)
+ goto out;
ddir = ffhp->fh_dentry;
dirp = ddir->d_inode;
- dnew = lookup_dentry(fname, dget(ddir), 1);
+ dnew = lookup_dentry(fname, dget(ddir), 0);
err = PTR_ERR(dnew);
if (IS_ERR(dnew))
- return nfserrno(-err);
+ goto out_nfserr;
err = -EEXIST;
if (dnew->d_inode)
@@ -805,7 +817,11 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
}
dput_and_out:
dput(dnew);
- return (err ? nfserrno(-err) : 0);
+out_nfserr:
+ if (err)
+ err = nfserrno(-err);
+out:
+ return err;
}
/* More "hidden treasure" from the generic VFS. -DaveM */
@@ -836,9 +852,12 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
struct inode *fdir, *tdir;
int err;
- if ((err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE) != 0)
- || (err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE)) != 0)
- return err;
+ err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE);
+ if (err)
+ goto out;
+ err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE);
+ if (err)
+ goto out;
fdentry = ffhp->fh_dentry;
fdir = fdentry->d_inode;
@@ -846,18 +865,19 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
tdentry = tfhp->fh_dentry;
tdir = tdentry->d_inode;
+ /* N.B. We shouldn't need this ... dentry layer handles it */
if (!flen || (fname[0] == '.' &&
(flen == 1 || (flen == 2 && fname[1] == '.'))) ||
!tlen || (tname[0] == '.' &&
(tlen == 1 || (tlen == 2 && tname[1] == '.'))))
return nfserr_perm;
- odentry = lookup_dentry(fname, dget(fdentry), 1);
+ odentry = lookup_dentry(fname, dget(fdentry), 0);
err = PTR_ERR(odentry);
if (IS_ERR(odentry))
goto out_no_unlock;
- ndentry = lookup_dentry(tname, dget(tdentry), 1);
+ ndentry = lookup_dentry(tname, dget(tdentry), 0);
err = PTR_ERR(ndentry);
if (IS_ERR(ndentry))
goto out_dput_old;
@@ -883,7 +903,10 @@ out_unlock:
out_dput_old:
dput(odentry);
out_no_unlock:
- return (err ? nfserrno(-err) : 0);
+ if (err)
+ err = nfserrno(-err);
+out:
+ return err;
}
/*
@@ -898,10 +921,13 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
struct inode *dirp;
int err;
+ /* N.B. We shouldn't need this test ... handled by dentry layer */
+ err = nfserr_acces;
if (!flen || isdotent(fname, flen))
- return nfserr_acces;
- if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE)) != 0)
- return err;
+ goto out;
+ err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE);
+ if (err)
+ goto out;
dentry = fhp->fh_dentry;
dirp = dentry->d_inode;
@@ -909,7 +935,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
rdentry = lookup_dentry(fname, dget(dentry), 0);
err = PTR_ERR(rdentry);
if (IS_ERR(rdentry))
- goto out;
+ goto out_nfserr;
fh_lock(fhp);
if (type == S_IFDIR) {
@@ -926,8 +952,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
dput(rdentry);
if (!err && EX_ISSYNC(fhp->fh_export))
write_inode_now(dirp);
+
+out_nfserr:
+ if (err)
+ err = nfserrno(-err);
out:
- return (err ? nfserrno(-err) : 0);
+ return err;
}
/*
@@ -1019,7 +1049,7 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct statfs *stat)
struct dentry *dentry;
struct inode *inode;
struct super_block *sb;
- unsigned long oldfs;
+ mm_segment_t oldfs;
int err;
err = fh_verify(rqstp, fhp, 0, MAY_NOP);
diff --git a/fs/pipe.c b/fs/pipe.c
index 8c476c34a..078d6be3b 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -12,8 +12,8 @@
#include <linux/termios.h>
#include <linux/mm.h>
#include <linux/file.h>
+#include <linux/poll.h>
-#include <asm/poll.h>
#include <asm/uaccess.h>
/*
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 4e22dfa16..88d10d2bc 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -48,6 +48,7 @@
#include <linux/swap.h>
#include <linux/slab.h>
#include <linux/smp.h>
+#include <linux/signal.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -664,37 +665,60 @@ static inline char * task_mem(struct task_struct *p, char *buffer)
return buffer;
}
-static inline char * task_sig(struct task_struct *p, char *buffer)
+char * render_sigset_t(sigset_t *set, char *buffer)
{
- buffer += sprintf(buffer,
- "SigPnd:\t%08lx\n"
- "SigBlk:\t%08lx\n",
- p->signal, p->blocked);
+ int i = _NSIG, x;
+ do {
+ i -= 4, x = 0;
+ if (sigismember(set, i+1)) x |= 1;
+ if (sigismember(set, i+2)) x |= 2;
+ if (sigismember(set, i+3)) x |= 4;
+ if (sigismember(set, i+4)) x |= 8;
+ *buffer++ = (x < 10 ? '0' : 'a' - 10) + x;
+ } while (i >= 4);
+ *buffer = 0;
+ return buffer;
+}
+
+static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
+ sigset_t *catch)
+{
+ struct k_sigaction *k;
+ int i;
+
+ sigemptyset(ign);
+ sigemptyset(catch);
+
if (p->sig) {
- struct sigaction * action = p->sig->action;
- unsigned long sig_ign = 0, sig_caught = 0;
- unsigned long bit = 1;
- int i;
-
- for (i = 0; i < 32; i++) {
- switch((unsigned long) action->sa_handler) {
- case 0:
- break;
- case 1:
- sig_ign |= bit;
- break;
- default:
- sig_caught |= bit;
- }
- bit <<= 1;
- action++;
+ k = p->sig->action;
+ for (i = 1; i <= _NSIG; ++i, ++k) {
+ if (k->sa.sa_handler == SIG_IGN)
+ sigaddset(ign, i);
+ else if (k->sa.sa_handler != SIG_DFL)
+ sigaddset(catch, i);
}
-
- buffer += sprintf(buffer,
- "SigIgn:\t%08lx\n"
- "SigCgt:\t%08lx\n",
- sig_ign, sig_caught);
}
+}
+
+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++ = '\n';
+ buffer += sprintf(buffer, "SigBlk:\t");
+ buffer = render_sigset_t(&p->blocked, buffer);
+ *buffer++ = '\n';
+
+ collect_sigign_sigcatch(p, &ign, &catch);
+ buffer += sprintf(buffer, "SigIgn:\t");
+ buffer = render_sigset_t(&ign, buffer);
+ *buffer++ = '\n';
+ buffer += sprintf(buffer, "SigCat:\t");
+ buffer = render_sigset_t(&catch, buffer);
+ *buffer++ = '\n';
+
return buffer;
}
@@ -715,10 +739,14 @@ static int get_status(int pid, char * buffer)
static int get_stat(int pid, char * buffer)
{
struct task_struct *tsk = find_task_by_pid(pid);
- unsigned long sigignore=0, sigcatch=0, wchan;
- unsigned long vsize, eip, esp;
+ unsigned long vsize, eip, esp, wchan;
long priority, nice;
- int i,tty_pgrp;
+ int tty_pgrp;
+ sigset_t sigign, sigcatch;
+ char signal_str[sizeof(sigset_t)*2+1];
+ char blocked_str[sizeof(sigset_t)*2+1];
+ char sigign_str[sizeof(sigset_t)*2+1];
+ char sigcatch_str[sizeof(sigset_t)*2+1];
char state;
if (!tsk)
@@ -737,22 +765,15 @@ static int get_stat(int pid, char * buffer)
eip = KSTK_EIP(tsk);
esp = KSTK_ESP(tsk);
}
+
wchan = get_wchan(tsk);
- if (tsk->sig) {
- unsigned long bit = 1;
- for(i=0; i<32; ++i) {
- switch((unsigned long) tsk->sig->action[i].sa_handler) {
- case 0:
- break;
- case 1:
- sigignore |= bit;
- break;
- default:
- sigcatch |= bit;
- }
- bit <<= 1;
- }
- }
+
+ collect_sigign_sigcatch(tsk, &sigign, &sigcatch);
+ render_sigset_t(&tsk->signal, signal_str);
+ render_sigset_t(&tsk->blocked, blocked_str);
+ render_sigset_t(&sigign, sigign_str);
+ render_sigset_t(&sigcatch, sigcatch_str);
+
if (tsk->tty)
tty_pgrp = tsk->tty->pgrp;
else
@@ -767,7 +788,7 @@ static int get_stat(int pid, char * buffer)
return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu\n",
+%lu %s %s %s %s %lu %lu %lu\n",
pid,
tsk->comm,
state,
@@ -798,10 +819,10 @@ static int get_stat(int pid, char * buffer)
tsk->mm ? tsk->mm->start_stack : 0,
esp,
eip,
- tsk->signal,
- tsk->blocked,
- sigignore,
- sigcatch,
+ signal_str,
+ blocked_str,
+ sigign_str,
+ sigcatch_str,
wchan,
tsk->nswap,
tsk->cnswap);
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
index 470b7bffb..9523ff9f0 100644
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -49,8 +49,10 @@ static int tty_drivers_read_proc(char *page, char **start, off_t off,
case TTY_DRIVER_TYPE_SYSTEM:
if (p->subtype == SYSTEM_TYPE_TTY)
type = "system:/dev/tty";
- else if (p->subtype == SYSTEM_TYPE_CONSOLE)
+ else if (p->subtype == SYSTEM_TYPE_SYSCONS)
type = "system:console";
+ else if (p->subtype == SYSTEM_TYPE_CONSOLE)
+ type = "system:vtmaster";
else
type = "system";
break;
diff --git a/fs/select.c b/fs/select.c
index d804d58b3..4c88f0437 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -24,10 +24,10 @@
#include <linux/malloc.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/system.h>
-#include <asm/poll.h>
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
@@ -39,9 +39,10 @@
* understand what I'm doing here, then you understand how the linux
* sleep/wakeup mechanism works.
*
- * Two very simple procedures, poll_wait() and free_wait() make all the work.
- * poll_wait() is an inline-function defined in <linux/sched.h>, as all select/poll
- * functions have to call it to add an entry to the poll table.
+ * Two very simple procedures, poll_wait() and free_wait() make all the
+ * work. poll_wait() is an inline-function defined in <linux/sched.h>,
+ * as all select/poll functions have to call it to add an entry to the
+ * poll table.
*/
/*
@@ -61,26 +62,6 @@ static void free_wait(poll_table * p)
}
}
-/*
- * For the kernel fd_set we use a fixed set-size for allocation purposes.
- * This set-size doesn't necessarily bear any relation to the size the user
- * uses, but should preferably obviously be larger than any possible user
- * size (NR_OPEN bits).
- *
- * We need 6 bitmaps (in/out/ex for both incoming and outgoing), and we
- * allocate one page for all the bitmaps. Thus we have 8*PAGE_SIZE bits,
- * to be divided by 6. And we'd better make sure we round to a full
- * long-word (in fact, we'll round to 64 bytes).
- */
-#define KFDS_64BLOCK ((PAGE_SIZE/(6*64))*64)
-#define KFDS_NR (KFDS_64BLOCK*8 > NR_OPEN ? NR_OPEN : KFDS_64BLOCK*8)
-typedef unsigned long kernel_fd_set[KFDS_NR/(8*sizeof(unsigned long))];
-
-typedef struct {
- kernel_fd_set in, out, ex;
- kernel_fd_set res_in, res_out, res_ex;
-} fd_set_buffer;
-
#define __IN(in) (in)
#define __OUT(in) (in + sizeof(kernel_fd_set)/sizeof(unsigned long))
#define __EX(in) (in + 2*sizeof(kernel_fd_set)/sizeof(unsigned long))
@@ -141,11 +122,28 @@ get_max:
#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
#define POLLEX_SET (POLLPRI)
-static int do_select(int n, fd_set_buffer *fds, poll_table *wait)
+int do_select(int n, fd_set_buffer *fds, unsigned long timeout)
{
+ poll_table wait_table, *wait;
int retval;
int i;
+ lock_kernel();
+
+ wait = NULL;
+ current->timeout = timeout;
+ if (timeout) {
+ struct poll_table_entry *entry = (struct poll_table_entry *)
+ __get_free_page(GFP_KERNEL);
+ if (!entry) {
+ retval = -ENOMEM;
+ goto out_nowait;
+ }
+ wait_table.nr = 0;
+ wait_table.entry = entry;
+ wait = &wait_table;
+ }
+
retval = max_select_fd(n, fds);
if (retval < 0)
goto out;
@@ -154,33 +152,36 @@ static int do_select(int n, fd_set_buffer *fds, poll_table *wait)
for (;;) {
struct file ** fd = current->files->fd;
current->state = TASK_INTERRUPTIBLE;
- for (i = 0 ; i < n ; i++,fd++) {
+ for (i = 0 ; i < n ; i++, fd++) {
unsigned long bit = BIT(i);
unsigned long *in = MEM(i,fds->in);
+ unsigned long mask;
+ struct file *file;
- if (bit & BITS(in)) {
- struct file * file = *fd;
- unsigned int mask = POLLNVAL;
- if (file) {
- mask = DEFAULT_POLLMASK;
- if (file->f_op && file->f_op->poll)
- mask = file->f_op->poll(file, wait);
- }
- if ((mask & POLLIN_SET) && ISSET(bit, __IN(in))) {
- SET(bit, __RES_IN(in));
- retval++;
- wait = NULL;
- }
- if ((mask & POLLOUT_SET) && ISSET(bit, __OUT(in))) {
- SET(bit, __RES_OUT(in));
- retval++;
- wait = NULL;
- }
- if ((mask & POLLEX_SET) && ISSET(bit, __EX(in))) {
- SET(bit, __RES_EX(in));
- retval++;
- wait = NULL;
- }
+ if (!(bit & BITS(in)))
+ continue;
+
+ file = *fd;
+ mask = POLLNVAL;
+ if (file) {
+ mask = DEFAULT_POLLMASK;
+ if (file->f_op && file->f_op->poll)
+ mask = file->f_op->poll(file, wait);
+ }
+ if ((mask & POLLIN_SET) && ISSET(bit, __IN(in))) {
+ SET(bit, __RES_IN(in));
+ retval++;
+ wait = NULL;
+ }
+ if ((mask & POLLOUT_SET) && ISSET(bit, __OUT(in))) {
+ SET(bit, __RES_OUT(in));
+ retval++;
+ wait = NULL;
+ }
+ if ((mask & POLLEX_SET) && ISSET(bit, __EX(in))) {
+ SET(bit, __RES_EX(in));
+ retval++;
+ wait = NULL;
}
}
wait = NULL;
@@ -189,82 +190,18 @@ static int do_select(int n, fd_set_buffer *fds, poll_table *wait)
schedule();
}
current->state = TASK_RUNNING;
-out:
- return retval;
-}
-
-/*
- * We do a VERIFY_WRITE here even though we are only reading this time:
- * we'll write to it eventually..
- *
- * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned.
- */
-static int __get_fd_set(unsigned long nr, unsigned long * fs_pointer, unsigned long * fdset)
-{
- /* round up nr to nearest "unsigned long" */
- nr = (nr + 8*sizeof(unsigned long)-1) / (8*sizeof(unsigned long));
- if (fs_pointer) {
- int error = verify_area(VERIFY_WRITE,fs_pointer,
- nr*sizeof(unsigned long));
- if (!error) {
- while (nr) {
- __get_user(*fdset, fs_pointer);
- nr--;
- fs_pointer++;
- fdset++;
- }
- }
- return error;
- }
- while (nr) {
- *fdset = 0;
- nr--;
- fdset++;
- }
- return 0;
-}
-static void __set_fd_set(long nr, unsigned long * fs_pointer, unsigned long * fdset)
-{
- if (!fs_pointer)
- return;
- while (nr >= 0) {
- __put_user(*fdset, fs_pointer);
- nr -= 8 * sizeof(unsigned long);
- fdset++;
- fs_pointer++;
+out:
+ if (timeout) {
+ free_wait(&wait_table);
+ free_page((unsigned long) wait_table.entry);
}
+out_nowait:
+ current->timeout = 0;
+ unlock_kernel();
+ return retval;
}
-/* We can do long accesses here, kernel fdsets are always long-aligned */
-static inline void __zero_fd_set(long nr, unsigned long * fdset)
-{
- while (nr >= 0) {
- *fdset = 0;
- nr -= 8 * sizeof(unsigned long);
- fdset++;
- }
-}
-
-/*
- * Note a few subtleties: we use "long" for the dummy, not int, and we do a
- * subtract by 1 on the nr of file descriptors. The former is better for
- * machines with long > int, and the latter allows us to test the bit count
- * against "zero or positive", which can mostly be just a sign bit test..
- *
- * Unfortunately this scheme falls apart on big endian machines where
- * sizeof(long) > sizeof(int) (ie. V9 Sparc). -DaveM
- */
-
-#define get_fd_set(nr,fsp,fdp) \
-__get_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp))
-
-#define set_fd_set(nr,fsp,fdp) \
-__set_fd_set((nr)-1, (unsigned long *) (fsp), (unsigned long *) (fdp))
-
-#define zero_fd_set(nr,fdp) \
-__zero_fd_set((nr)-1, (unsigned long *) (fdp))
-
/*
* We can actually return ERESTARTSYS instead of EINTR, but I'd
* like to be certain this leads to no problems. So I return
@@ -273,64 +210,50 @@ __zero_fd_set((nr)-1, (unsigned long *) (fdp))
* Update: ERESTARTSYS breaks at least the xview clock binary, so
* I'm trying ERESTARTNOHAND which restart only when you want to.
*/
-asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
+asmlinkage int
+sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
{
- int error;
fd_set_buffer *fds;
unsigned long timeout;
- poll_table wait_table, *wait;
+ int ret;
- lock_kernel();
timeout = ~0UL;
if (tvp) {
- error = -EFAULT;
- if (!access_ok(VERIFY_WRITE, tvp, sizeof(*tvp)))
- goto out_nowait;
- error = __get_user(timeout, &tvp->tv_usec);
- if (error)
- goto out_nowait;
- timeout = ROUND_UP(timeout,(1000000/HZ));
- {
- unsigned long tmp;
- error = __get_user(tmp, &tvp->tv_sec);
- if (error)
- goto out_nowait;
- timeout += tmp * (unsigned long) HZ;
- }
+ time_t sec, usec;
+
+ if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
+ || (ret = __get_user(sec, &tvp->tv_sec))
+ || (ret = __get_user(usec, &tvp->tv_usec)))
+ goto out_nofds;
+
+ timeout = ROUND_UP(usec, 1000000/HZ);
+ timeout += sec * (unsigned long) HZ;
if (timeout)
timeout += jiffies + 1;
}
- error = -ENOMEM;
- wait = NULL;
- current->timeout = timeout;
- if (timeout) {
- struct poll_table_entry *entry;
- entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
- if (!entry)
- goto out_nowait;
- wait_table.nr = 0;
- wait_table.entry = entry;
- wait = &wait_table;
- }
+ ret = -ENOMEM;
fds = (fd_set_buffer *) __get_free_page(GFP_KERNEL);
if (!fds)
goto out_nofds;
- error = -EINVAL;
+ ret = -EINVAL;
if (n < 0)
goto out;
if (n > KFDS_NR)
n = KFDS_NR;
- if ((error = get_fd_set(n, inp, &fds->in)) ||
- (error = get_fd_set(n, outp, &fds->out)) ||
- (error = get_fd_set(n, exp, &fds->ex))) goto out;
- zero_fd_set(n, &fds->res_in);
- zero_fd_set(n, &fds->res_out);
- zero_fd_set(n, &fds->res_ex);
- error = do_select(n, fds, wait);
+ if ((ret = get_fd_set(n, inp, fds->in)) ||
+ (ret = get_fd_set(n, outp, fds->out)) ||
+ (ret = get_fd_set(n, exp, fds->ex)))
+ goto out;
+ zero_fd_set(n, fds->res_in);
+ zero_fd_set(n, fds->res_out);
+ zero_fd_set(n, fds->res_ex);
+
+ ret = do_select(n, fds, timeout);
+
if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
unsigned long timeout = current->timeout - jiffies - 1;
- unsigned long sec = 0, usec = 0;
+ time_t sec = 0, usec = 0;
if ((long) timeout > 0) {
sec = timeout / HZ;
usec = timeout % HZ;
@@ -340,27 +263,24 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct
put_user(usec, &tvp->tv_usec);
}
current->timeout = 0;
- if (error < 0)
+
+ if (ret < 0)
goto out;
- if (!error) {
- error = -ERESTARTNOHAND;
+ if (!ret) {
+ ret = -ERESTARTNOHAND;
if (signal_pending(current))
goto out;
- error = 0;
+ ret = 0;
}
- set_fd_set(n, inp, &fds->res_in);
- set_fd_set(n, outp, &fds->res_out);
- set_fd_set(n, exp, &fds->res_ex);
+
+ set_fd_set(n, inp, fds->res_in);
+ set_fd_set(n, outp, fds->res_out);
+ set_fd_set(n, exp, fds->res_ex);
+
out:
free_page((unsigned long) fds);
out_nofds:
- if (wait) {
- free_wait(&wait_table);
- free_page((unsigned long) wait->entry);
- }
-out_nowait:
- unlock_kernel();
- return error;
+ return ret;
}
static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait)
diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c
index f14836199..45a0790fc 100644
--- a/fs/smbfs/sock.c
+++ b/fs/smbfs/sock.c
@@ -26,8 +26,6 @@
#define SMBFS_PARANOIA 1
/* #define SMBFS_DEBUG_VERBOSE 1 */
-#define _S(nr) (1<<((nr)-1))
-
static int
_recvfrom(struct socket *socket, unsigned char *ubuf, int size,
unsigned flags)
@@ -89,7 +87,7 @@ smb_data_callback(struct sock *sk, int len)
struct socket *socket = sk->socket;
unsigned char peek_buf[4];
int result;
- unsigned long fs;
+ mm_segment_t fs;
fs = get_fs();
set_fs(get_ds());
@@ -324,7 +322,7 @@ smb_get_length(struct socket *socket, unsigned char *header)
{
int result;
unsigned char peek_buf[4];
- unsigned long fs;
+ mm_segment_t fs;
re_recv:
fs = get_fs();
@@ -599,8 +597,9 @@ out_error:
int
smb_request(struct smb_sb_info *server)
{
- unsigned long old_mask;
- unsigned long fs;
+ unsigned long flags, sigpipe;
+ mm_segment_t fs;
+ sigset_t old_set;
int len, result;
unsigned char *buffer;
@@ -619,8 +618,13 @@ smb_request(struct smb_sb_info *server)
len = smb_len(buffer) + 4;
pr_debug("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
- old_mask = current->blocked;
- current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ sigpipe = sigismember(&current->signal, SIGPIPE);
+ old_set = current->blocked;
+ siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+
fs = get_fs();
set_fs(get_ds());
@@ -629,9 +633,15 @@ smb_request(struct smb_sb_info *server)
{
result = smb_receive(server);
}
+
/* read/write errors are handled by errno */
- current->signal &= ~_S(SIGPIPE);
- current->blocked = old_mask;
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ if (result == -EPIPE && !sigpipe)
+ sigdelset(&current->signal, SIGPIPE);
+ current->blocked = old_set;
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+
set_fs(fs);
if (result >= 0)
@@ -758,8 +768,9 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
int *lrdata, unsigned char **rdata,
int *lrparam, unsigned char **rparam)
{
- unsigned long old_mask;
- unsigned long fs;
+ sigset_t old_set;
+ unsigned long flags, sigpipe;
+ mm_segment_t fs;
int result;
pr_debug("smb_trans2_request: com=%d, ld=%d, lp=%d\n",
@@ -778,8 +789,13 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
if ((result = smb_dont_catch_keepalive(server)) != 0)
goto bad_conn;
- old_mask = current->blocked;
- current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ sigpipe = sigismember(&current->signal, SIGPIPE);
+ old_set = current->blocked;
+ siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+
fs = get_fs();
set_fs(get_ds());
@@ -790,9 +806,15 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
result = smb_receive_trans2(server,
lrdata, rdata, lrparam, rparam);
}
+
/* read/write errors are handled by errno */
- current->signal &= ~_S(SIGPIPE);
- current->blocked = old_mask;
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ if (result == -EPIPE && !sigpipe)
+ sigdelset(&current->signal, SIGPIPE);
+ current->blocked = old_set;
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+
set_fs(fs);
if (result >= 0)
diff --git a/fs/super.c b/fs/super.c
index b9e40e385..22c26a07e 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -461,7 +461,7 @@ asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf)
struct super_block *s;
struct ustat tmp;
struct statfs sbuf;
- unsigned long old_fs;
+ mm_segment_t old_fs;
int err = -EINVAL;
lock_kernel();
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index b3586b58f..bb8828efa 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -10,6 +10,11 @@
* sysv/namei.c
* Copyright (C) 1993 Bruno Haible
*/
+/*
+ 7 Dec 1997 - updated to use dentries by Krzysztof G. Baranowski
+ <kgb@manjak.knm.org.pl>
+ */
+
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -100,31 +105,29 @@ static struct buffer_head * sysv_find_entry(struct inode * dir,
return NULL;
}
-int sysv_lookup(struct inode * dir,const char * name, int len,
- struct inode ** result)
+int sysv_lookup(struct inode * dir, struct dentry * dentry)
{
int ino;
+ struct inode * inode = NULL;
struct sysv_dir_entry * de;
struct buffer_head * bh;
- *result = NULL;
if (!dir)
return -ENOENT;
if (!S_ISDIR(dir->i_mode)) {
- iput(dir);
return -ENOENT;
}
- if (!(bh = sysv_find_entry(dir,name,len,&de))) {
- iput(dir);
+ if (!(bh = sysv_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de))) {
return -ENOENT;
}
ino = de->inode;
brelse(bh);
- if (!(*result = iget(dir->i_sb,ino))) {
- iput(dir);
+ inode = iget(dir->i_sb,ino);
+
+ if (!inode)
return -EACCES;
- }
- iput(dir);
+ d_add(dentry, inode);
return 0;
}
@@ -201,42 +204,37 @@ static int sysv_add_entry(struct inode * dir,
return 0;
}
-int sysv_create(struct inode * dir,const char * name, int len, int mode,
- struct inode ** result)
+int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
{
int error;
struct inode * inode;
struct buffer_head * bh;
struct sysv_dir_entry * de;
- *result = NULL;
if (!dir)
return -ENOENT;
inode = sysv_new_inode(dir);
- if (!inode) {
- iput(dir);
+ if (!inode)
return -ENOSPC;
- }
inode->i_op = &sysv_file_inode_operations;
inode->i_mode = mode;
mark_inode_dirty(inode);
- error = sysv_add_entry(dir,name,len, &bh ,&de);
+ error = sysv_add_entry(dir,dentry->d_name.name,
+ dentry->d_name.len, &bh, &de);
if (error) {
inode->i_nlink--;
mark_inode_dirty(inode);
iput(inode);
- iput(dir);
return error;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
- iput(dir);
- *result = inode;
+ d_instantiate(dentry, inode);
return 0;
}
-int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
+int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
{
int error;
struct inode * inode;
@@ -245,17 +243,15 @@ int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rde
if (!dir)
return -ENOENT;
- bh = sysv_find_entry(dir,name,len,&de);
+ bh = sysv_find_entry(dir,dentry->d_name.name,
+ dentry->d_name.len,&de);
if (bh) {
brelse(bh);
- iput(dir);
return -EEXIST;
}
inode = sysv_new_inode(dir);
- if (!inode) {
- iput(dir);
+ if (!inode)
return -ENOSPC;
- }
inode->i_uid = current->fsuid;
inode->i_mode = mode;
inode->i_op = NULL;
@@ -277,53 +273,45 @@ int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rde
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = to_kdev_t(rdev);
mark_inode_dirty(inode);
- error = sysv_add_entry(dir, name, len, &bh, &de);
+ error = sysv_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de);
if (error) {
inode->i_nlink--;
mark_inode_dirty(inode);
iput(inode);
- iput(dir);
return error;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
- iput(dir);
- iput(inode);
+ d_instantiate(dentry, inode);
return 0;
}
-int sysv_mkdir(struct inode * dir, const char * name, int len, int mode)
+int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
{
int error;
struct inode * inode;
struct buffer_head * bh, *dir_block;
struct sysv_dir_entry * de;
- if (!dir) {
- iput(dir);
+ if (!dir)
return -EINVAL;
- }
- bh = sysv_find_entry(dir,name,len,&de);
+ bh = sysv_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (bh) {
brelse(bh);
- iput(dir);
return -EEXIST;
}
if (dir->i_nlink >= dir->i_sb->sv_link_max) {
- iput(dir);
return -EMLINK;
}
inode = sysv_new_inode(dir);
- if (!inode) {
- iput(dir);
+ if (!inode)
return -ENOSPC;
- }
inode->i_op = &sysv_dir_inode_operations;
inode->i_size = 2 * SYSV_DIRSIZE;
dir_block = sysv_file_bread(inode,0,1);
if (!dir_block) {
- iput(dir);
inode->i_nlink--;
mark_inode_dirty(inode);
iput(inode);
@@ -342,9 +330,9 @@ int sysv_mkdir(struct inode * dir, const char * name, int len, int mode)
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
mark_inode_dirty(inode);
- error = sysv_add_entry(dir, name, len, &bh, &de);
- if (error) {
- iput(dir);
+ error = sysv_add_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &bh, &de);
+ if (error) {
inode->i_nlink=0;
iput(inode);
return error;
@@ -353,10 +341,9 @@ int sysv_mkdir(struct inode * dir, const char * name, int len, int mode)
mark_buffer_dirty(bh, 1);
dir->i_nlink++;
mark_inode_dirty(dir);
- iput(dir);
- iput(inode);
brelse(bh);
- return 0;
+ d_instantiate(dentry, inode);
+ return 0;
}
/*
@@ -419,7 +406,7 @@ bad_dir:
return 1;
}
-int sysv_rmdir(struct inode * dir, const char * name, int len)
+int sysv_rmdir(struct inode * dir, struct dentry * dentry)
{
int retval;
struct inode * inode;
@@ -427,13 +414,14 @@ int sysv_rmdir(struct inode * dir, const char * name, int len)
struct sysv_dir_entry * de;
inode = NULL;
- bh = sysv_find_entry(dir,name,len,&de);
+ bh = sysv_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
retval = -ENOENT;
if (!bh)
goto end_rmdir;
retval = -EPERM;
- if (!(inode = iget(dir->i_sb, de->inode)))
- goto end_rmdir;
+ inode = dentry->d_inode;
+
if ((dir->i_mode & S_ISVTX) && !fsuser() &&
current->fsuid != inode->i_uid &&
current->fsuid != dir->i_uid)
@@ -467,15 +455,14 @@ int sysv_rmdir(struct inode * dir, const char * name, int len)
dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
+ d_delete(dentry);
retval = 0;
end_rmdir:
- iput(dir);
- iput(inode);
brelse(bh);
return retval;
}
-int sysv_unlink(struct inode * dir, const char * name, int len)
+int sysv_unlink(struct inode * dir, struct dentry * dentry)
{
int retval;
struct inode * inode;
@@ -485,16 +472,16 @@ int sysv_unlink(struct inode * dir, const char * name, int len)
repeat:
retval = -ENOENT;
inode = NULL;
- bh = sysv_find_entry(dir,name,len,&de);
+ bh = sysv_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (!bh)
goto end_unlink;
- if (!(inode = iget(dir->i_sb, de->inode)))
- goto end_unlink;
+ inode = dentry->d_inode;
+
retval = -EPERM;
if (S_ISDIR(inode->i_mode))
goto end_unlink;
if (de->inode != inode->i_ino) {
- iput(inode);
brelse(bh);
current->counter = 0;
schedule();
@@ -510,7 +497,7 @@ repeat:
}
if (!inode->i_nlink) {
printk("Deleting nonexistent file (%s:%lu), %d\n",
- kdevname(inode->i_dev),
+ kdevname(inode->i_dev),
inode->i_ino, inode->i_nlink);
inode->i_nlink=1;
}
@@ -521,15 +508,15 @@ repeat:
inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
mark_inode_dirty(inode);
+ d_delete(dentry);
retval = 0;
end_unlink:
brelse(bh);
- iput(inode);
- iput(dir);
return retval;
}
-int sysv_symlink(struct inode * dir, const char * name, int len, const char * symname)
+int sysv_symlink(struct inode * dir, struct dentry * dentry,
+ const char * symname)
{
struct sysv_dir_entry * de;
struct inode * inode;
@@ -540,15 +527,13 @@ int sysv_symlink(struct inode * dir, const char * name, int len, const char * sy
char c;
struct buffer_head * bh;
- if (!(inode = sysv_new_inode(dir))) {
- iput(dir);
+ if (!(inode = sysv_new_inode(dir)))
return -ENOSPC;
- }
+
inode->i_mode = S_IFLNK | 0777;
inode->i_op = &sysv_symlink_inode_operations;
name_block = sysv_file_bread(inode,0,1);
if (!name_block) {
- iput(dir);
inode->i_nlink--;
mark_inode_dirty(inode);
iput(inode);
@@ -564,94 +549,81 @@ int sysv_symlink(struct inode * dir, const char * name, int len, const char * sy
brelse(name_block);
inode->i_size = i;
mark_inode_dirty(inode);
- bh = sysv_find_entry(dir,name,len,&de);
+ bh = sysv_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (bh) {
inode->i_nlink--;
mark_inode_dirty(inode);
iput(inode);
brelse(bh);
- iput(dir);
return -EEXIST;
}
- i = sysv_add_entry(dir, name, len, &bh, &de);
+ i = sysv_add_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &bh, &de);
if (i) {
inode->i_nlink--;
mark_inode_dirty(inode);
iput(inode);
- iput(dir);
return i;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
- iput(dir);
- iput(inode);
+ d_instantiate(dentry, inode);
return 0;
}
-int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
+int sysv_link(struct inode * oldinode, struct inode * dir,
+ struct dentry * dentry)
{
int error;
struct sysv_dir_entry * de;
struct buffer_head * bh;
if (S_ISDIR(oldinode->i_mode)) {
- iput(oldinode);
- iput(dir);
return -EPERM;
}
if (oldinode->i_nlink >= oldinode->i_sb->sv_link_max) {
- iput(oldinode);
- iput(dir);
return -EMLINK;
}
- bh = sysv_find_entry(dir,name,len,&de);
+ bh = sysv_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (bh) {
brelse(bh);
- iput(dir);
- iput(oldinode);
return -EEXIST;
}
- error = sysv_add_entry(dir, name, len, &bh, &de);
+ error = sysv_add_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &bh, &de);
if (error) {
- iput(dir);
- iput(oldinode);
return error;
}
de->inode = oldinode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
- iput(dir);
oldinode->i_nlink++;
oldinode->i_ctime = CURRENT_TIME;
mark_inode_dirty(oldinode);
- iput(oldinode);
+ d_instantiate(dentry, oldinode);
return 0;
}
/* return 1 if `new' is a subdir of `old' on the same device */
-static int subdir(struct inode * new_inode, struct inode * old_inode)
+static int subdir(struct dentry * new_dentry, struct dentry * old_dentry)
{
- int ino;
- int result;
-
- new_inode->i_count++;
- result = 0;
- for (;;) {
- if (new_inode == old_inode) {
- result = 1;
- break;
- }
- if (new_inode->i_dev != old_inode->i_dev)
- break;
- ino = new_inode->i_ino;
- if (sysv_lookup(new_inode,"..",2,&new_inode))
- break;
- if (new_inode->i_ino == ino) /* root dir reached ? */
- break;
- }
- iput(new_inode);
- return result;
+ int result = 0;
+
+ for (;;) {
+ if (new_dentry != old_dentry) {
+ struct dentry * parent = new_dentry->d_parent;
+ if (parent == new_dentry)
+ break;
+ new_dentry = parent;
+ continue;
+ }
+ result = 1;
+ break;
+ }
+ return result;
}
#define PARENT_INO(buffer) \
@@ -716,7 +688,7 @@ start_up:
if (!S_ISDIR(old_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (subdir(new_dir, old_inode))
+ if (subdir(new_dentry, old_dentry))
goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
@@ -735,7 +707,7 @@ start_up:
if (new_inode && !S_ISDIR(new_inode->i_mode))
goto end_rename;
retval = -EINVAL;
- if (subdir(new_dir, old_inode))
+ if (subdir(new_dentry, old_dentry))
goto end_rename;
retval = -EIO;
dir_bh = sysv_file_bread(old_inode,0,0);
diff --git a/fs/ufs/Makefile b/fs/ufs/Makefile
index b5fa2bd48..0a74c36c7 100644
--- a/fs/ufs/Makefile
+++ b/fs/ufs/Makefile
@@ -9,7 +9,7 @@
O_TARGET := ufs.o
O_OBJS := ufs_dir.o ufs_file.o ufs_inode.o ufs_namei.o \
- ufs_super.o ufs_symlink.o
+ ufs_super.o ufs_symlink.o ufs_swab.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/ufs/ufs_dir.c b/fs/ufs/ufs_dir.c
index e91847df3..c64f38684 100644
--- a/fs/ufs/ufs_dir.c
+++ b/fs/ufs/ufs_dir.c
@@ -6,12 +6,13 @@
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_dir.c,v 1.10 1997/06/05 01:29:06 davem Exp $
+ * swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406
*
*/
#include <linux/fs.h>
-#include <linux/ufs_fs.h>
+
+#include "ufs_swab.h"
/*
* This is blatantly stolen from ext2fs
@@ -26,12 +27,18 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
struct buffer_head * bh;
struct ufs_direct * de;
struct super_block * sb;
+ int de_reclen;
+ __u32 s_flags, bytesex;
+ /* Isn't that already done but the upper layer??? */
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
+
sb = inode->i_sb;
+ s_flags = sb->u.ufs_sb.s_flags;
+ bytesex = s_flags & UFS_BYTESEX;
- if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+ if (s_flags & UFS_DEBUG) {
printk("ufs_readdir: ino %lu f_pos %lu\n",
inode->i_ino, (unsigned long) filp->f_pos);
ufs_print_inode(inode);
@@ -48,7 +55,8 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
bh = bread (sb->s_dev, blk, sb->s_blocksize);
if (!bh) {
/* XXX - error - skip to the next block */
- printk("ufs_readdir: dir inode %lu has a hole at offset %lu\n",
+ printk("ufs_readdir: "
+ "dir inode %lu has a hole at offset %lu\n",
inode->i_ino, (unsigned long int)filp->f_pos);
filp->f_pos += sb->s_blocksize - offset;
continue;
@@ -61,7 +69,7 @@ revalidate:
* to make sure. */
if (filp->f_version != inode->i_version) {
for (i = 0; i < sb->s_blocksize && i < offset; ) {
- de = (struct ufs_direct *)
+ de = (struct ufs_direct *)
(bh->b_data + i);
/* It's too expensive to do a full
* dirent test each time round this
@@ -69,28 +77,30 @@ revalidate:
* least that it is non-zero. A
* failure will be detected in the
* dirent test below. */
- if (ufs_swab16(de->d_reclen) < 1)
+ de_reclen = SWAB16(de->d_reclen);
+ if (de_reclen < 1)
break;
- i += ufs_swab16(de->d_reclen);
+ i += de_reclen;
}
offset = i;
filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
| offset;
filp->f_version = inode->i_version;
}
-
- while (!error && filp->f_pos < inode->i_size
+
+ while (!error && filp->f_pos < inode->i_size
&& offset < sb->s_blocksize) {
de = (struct ufs_direct *) (bh->b_data + offset);
/* XXX - put in a real ufs_check_dir_entry() */
- if ((ufs_swab16(de->d_reclen) == 0)
- || (ufs_swab16(de->d_namlen) == 0)) {
+ if ((de->d_reclen == 0) || (de->d_namlen == 0)) {
+ /* SWAB16() was unneeded -- compare to 0 */
filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize;
brelse(bh);
return stored;
}
#if 0
if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
+ /* XXX - beware about de having to be swabped somehow */
bh, offset)) {
/* On error, skip the f_pos to the
next block. */
@@ -100,8 +110,9 @@ revalidate:
return stored;
}
#endif /* XXX */
- offset += ufs_swab16(de->d_reclen);
- if (ufs_swab32(de->d_ino)) {
+ offset += SWAB16(de->d_reclen);
+ if (de->d_ino) {
+ /* SWAB16() was unneeded -- compare to 0 */
/* We might block in the next section
* if the data destination is
* currently swapped out. So, use a
@@ -110,18 +121,18 @@ revalidate:
* during the copy operation. */
unsigned long version = inode->i_version;
- if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+ if (s_flags & UFS_DEBUG) {
printk("ufs_readdir: filldir(%s,%u)\n",
- de->d_name, ufs_swab32(de->d_ino));
+ de->d_name, SWAB32(de->d_ino));
}
- error = filldir(dirent, de->d_name, ufs_swab16(de->d_namlen), filp->f_pos, ufs_swab32(de->d_ino));
+ error = filldir(dirent, de->d_name, SWAB16(de->d_namlen), filp->f_pos, SWAB32(de->d_ino));
if (error)
break;
if (version != inode->i_version)
goto revalidate;
stored ++;
}
- filp->f_pos += ufs_swab16(de->d_reclen);
+ filp->f_pos += SWAB16(de->d_reclen);
}
offset = 0;
brelse (bh);
@@ -140,7 +151,7 @@ static struct file_operations ufs_dir_operations = {
NULL, /* read */
NULL, /* write */
ufs_readdir, /* readdir */
- NULL, /* poll */
+ NULL, /* select */
NULL, /* ioctl */
NULL, /* mmap */
NULL, /* open */
diff --git a/fs/ufs/ufs_file.c b/fs/ufs/ufs_file.c
index 72161d2bd..7471156a0 100644
--- a/fs/ufs/ufs_file.c
+++ b/fs/ufs/ufs_file.c
@@ -18,7 +18,7 @@ static struct file_operations ufs_file_operations = {
generic_file_read, /* read */
NULL, /* write */
NULL, /* readdir */
- NULL, /* poll */
+ NULL, /* select */
NULL, /* ioctl */
generic_file_mmap, /* mmap */
NULL, /* open */
diff --git a/fs/ufs/ufs_inode.c b/fs/ufs/ufs_inode.c
index c55092d54..75329c584 100644
--- a/fs/ufs/ufs_inode.c
+++ b/fs/ufs/ufs_inode.c
@@ -6,7 +6,8 @@
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_inode.c,v 1.9 1997/07/17 02:24:14 davem Exp $
+ * Clean swab support on 19970406
+ * by Francois-Rene Rideau <rideau@ens.fr>
*
*/
@@ -14,6 +15,8 @@
#include <linux/ufs_fs.h>
#include <linux/sched.h>
+#include "ufs_swab.h"
+
void ufs_print_inode(struct inode * inode)
{
printk("ino %lu mode 0%6.6o lk %d uid %d gid %d"
@@ -41,14 +44,14 @@ static inline int block_bmap (struct inode *inode, int block, int nr)
{
struct buffer_head *bh;
int tmp;
-
+ __u32 bytesex = inode->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX;
/* XXX Split in fsize big blocks (Can't bread 8Kb). */
tmp = nr >> (inode->i_sb->u.ufs_sb.s_fshift - 2);
bh = bread (inode->i_dev, block + tmp, inode->i_sb->u.ufs_sb.s_fsize);
if (!bh)
return 0;
nr &= ~(inode->i_sb->u.ufs_sb.s_fmask) >> 2;
- tmp = ufs_swab32(((__u32 *)bh->b_data)[nr]);
+ tmp = SWAB32(((__u32 *)bh->b_data)[nr]);
brelse (bh);
return tmp;
}
@@ -113,6 +116,7 @@ void ufs_read_inode(struct inode * inode)
struct super_block * sb;
struct ufs_inode * ufsip;
struct buffer_head * bh;
+ __u32 bytesex = inode->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX;
sb = inode->i_sb;
@@ -144,8 +148,8 @@ void ufs_read_inode(struct inode * inode)
/*
* Copy data to the in-core inode.
*/
- inode->i_mode = ufs_swab16(ufsip->ui_mode);
- inode->i_nlink = ufs_swab16(ufsip->ui_nlink);
+ inode->i_mode = SWAB16(ufsip->ui_mode);
+ inode->i_nlink = SWAB16(ufsip->ui_nlink);
if (inode->i_nlink == 0) {
/* XXX */
printk("ufs_read_inode: zero nlink ino %lu dev %u/%u\n",
@@ -158,7 +162,7 @@ void ufs_read_inode(struct inode * inode)
MAJOR(inode->i_dev), MINOR(inode->i_dev));
}
/* XXX - debugging */
- if (ufs_swab32(ufsip->ui_gen) == 0) {
+ if (SWAB32(ufsip->ui_gen) == 0) {
printk("ufs_read_inode: zero gen ino %lu pblk %lu dev %u/%u\n",
inode->i_ino,
ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
@@ -172,33 +176,33 @@ void ufs_read_inode(struct inode * inode)
* random users can't get at these files, since they get dynamically
* "chown()ed" to root.
*/
- if (ufs_swab16(ufsip->ui_suid) == UFS_USEEFT) {
+ if (SWAB16(ufsip->ui_suid) == UFS_USEEFT) {
/* EFT */
inode->i_uid = 0;
printk("ufs_read_inode: EFT uid %u ino %lu dev %u/%u, using %u\n",
- ufs_swab32(ufsip->ui_uid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev),
+ SWAB32(ufsip->ui_uid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev),
inode->i_uid);
} else {
- inode->i_uid = ufs_swab16(ufsip->ui_suid);
+ inode->i_uid = SWAB16(ufsip->ui_suid);
}
- if (ufs_swab16(ufsip->ui_sgid) == UFS_USEEFT) {
+ if (SWAB16(ufsip->ui_sgid) == UFS_USEEFT) {
/* EFT */
inode->i_gid = 0;
printk("ufs_read_inode: EFT gid %u ino %lu dev %u/%u, using %u\n",
- ufs_swab32(ufsip->ui_gid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev),
+ SWAB32(ufsip->ui_gid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev),
inode->i_gid);
} else {
- inode->i_gid = ufs_swab16(ufsip->ui_sgid);
+ inode->i_gid = SWAB16(ufsip->ui_sgid);
}
/*
- * Linux i_size is 32 bits, so some files on a UFS filesystem may not
+ * Linux i_size is 32 bits on most architectures,
+ * so some files on a UFS filesystem may not
* be readable. I let people access the first 32 bits worth of them.
* for the rw code, we may want to mark these inodes as read-only.
* XXX - bug Linus to make i_size a __u64 instead of a __u32.
*/
- inode->u.ufs_i.i_size = ((__u64)(ufs_swab32(ufsip->ui_size.val[0]))<<32) |
- (__u64)(ufs_swab32(ufsip->ui_size.val[1]));
+ inode->u.ufs_i.i_size = SWAB64(ufsip->ui_size);
/* KRR - Just type cast inode->u.ufs_i.i_size into off_t and
* worry about overflow later
*/
@@ -210,11 +214,11 @@ void ufs_read_inode(struct inode * inode)
* want to keep this data, but for the moment I think I'll just write
* zeros for these fields when writing out inodes.
*/
- inode->i_atime = ufsip->ui_atime.tv_sec;
- inode->i_mtime = ufsip->ui_mtime.tv_sec;
- inode->i_ctime = ufsip->ui_ctime.tv_sec;
+ inode->i_atime = SWAB32(ufsip->ui_atime.tv_sec);
+ inode->i_mtime = SWAB32(ufsip->ui_mtime.tv_sec);
+ inode->i_ctime = SWAB32(ufsip->ui_ctime.tv_sec);
inode->i_blksize = sb->u.ufs_sb.s_fsize;
- inode->i_blocks = ufs_swab32(ufsip->ui_blocks);
+ inode->i_blocks = SWAB32(ufsip->ui_blocks);
inode->i_version = ++event; /* see linux/kernel/sched.c */
if (S_ISREG(inode->i_mode)) {
@@ -246,11 +250,11 @@ void ufs_read_inode(struct inode * inode)
int i;
for (i = 0; i < UFS_NDADDR; i++) {
- inode->u.ufs_i.i_data[i] = ufs_swab32(ufsip->ui_db[i]);
+ inode->u.ufs_i.i_data[i] = SWAB32(ufsip->ui_db[i]);
}
for (i = 0; i < UFS_NINDIR; i++) {
inode->u.ufs_i.i_data[UFS_IND_BLOCK + i] =
- ufs_swab32(ufsip->ui_ib[i]);
+ SWAB32(ufsip->ui_ib[i]);
}
}
@@ -261,18 +265,17 @@ void ufs_read_inode(struct inode * inode)
* the code.
*/
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
- inode->i_rdev = (kdev_t)((__u64)(ufs_swab32(ufsip->ui_db[0]))<<32) |
- (__u64)(ufs_swab32(ufsip->ui_db[1]));
+ inode->i_rdev = (kdev_t)SWAB64(*(__u64*)&ufsip->ui_db);
}
/* XXX - implement fast and slow symlinks */
- inode->u.ufs_i.i_flags = ufs_swab32(ufsip->ui_flags);
- inode->u.ufs_i.i_gen = ufs_swab32(ufsip->ui_gen); /* XXX - is this i_version? */
- inode->u.ufs_i.i_shadow = ufs_swab32(ufsip->ui_shadow); /* XXX */
- inode->u.ufs_i.i_uid = ufs_swab32(ufsip->ui_uid);
- inode->u.ufs_i.i_gid = ufs_swab32(ufsip->ui_gid);
- inode->u.ufs_i.i_oeftflag = ufs_swab32(ufsip->ui_oeftflag);
+ inode->u.ufs_i.i_flags = SWAB32(ufsip->ui_flags);
+ inode->u.ufs_i.i_gen = SWAB32(ufsip->ui_gen); /* XXX - is this i_version? */
+ inode->u.ufs_i.i_shadow = SWAB32(ufsip->ui_shadow); /* XXX */
+ inode->u.ufs_i.i_uid = SWAB32(ufsip->ui_uid);
+ inode->u.ufs_i.i_gid = SWAB32(ufsip->ui_gid);
+ inode->u.ufs_i.i_oeftflag = SWAB32(ufsip->ui_oeftflag);
brelse(bh);
@@ -307,4 +310,3 @@ void ufs_put_inode (struct inode * inode)
return;
}
-
diff --git a/fs/ufs/ufs_namei.c b/fs/ufs/ufs_namei.c
index ec9ec3119..6cf8c6c39 100644
--- a/fs/ufs/ufs_namei.c
+++ b/fs/ufs/ufs_namei.c
@@ -6,48 +6,62 @@
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_namei.c,v 1.9 1997/07/22 06:40:12 davem Exp $
+ * Clean swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406
+ * Ported to 2.1.62 by Francois-Rene Rideau <rideau@ens.fr> 19971109
*
*/
#include <linux/fs.h>
#include <linux/ufs_fs.h>
-
#include <linux/string.h>
+#include "ufs_swab.h"
/*
* NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
* stolen from ext2fs
*/
-static int ufs_match (int len, const char * const name, struct ufs_direct * d)
+static int ufs_match (int len, const char * const name, struct ufs_direct * d, __u32 bytesex)
{
if (!d || len > UFS_MAXNAMLEN) /* XXX - name space */
return 0;
/*
* "" means "." ---> so paths like "/usr/lib//libc.a" work
*/
- if (!len && (ufs_swab16(d->d_namlen) == 1) && (d->d_name[0] == '.') &&
- (d->d_name[1] == '\0'))
- return 1;
- if (len != ufs_swab16(d->d_namlen))
+ if (!len && (SWAB16(d->d_namlen) == 1) && (d->d_name[0] == '.') &&
+ (d->d_name[1] == '\0'))
+ return 1;
+ if (len != SWAB16(d->d_namlen))
return 0;
return !memcmp(name, d->d_name, len);
}
-/* XXX - this is a mess, especially for endianity */
-int ufs_lookup (struct inode * dir, struct qstr *qname,
- struct inode ** result)
+int ufs_lookup (struct inode *dir, struct dentry *dentry)
{
+ /* XXX - this is all fucked up! */
+ /* XXX - and it's been broken since linux has this new dentry interface:
+ * allows reading of files, but screws the whole dcache, even outside
+ * of the ufs partition, so that umount'ing won't suffice to fix it --
+ * reboot needed
+ */
unsigned long int lfragno, fragno;
struct buffer_head * bh;
struct ufs_direct * d;
- const char *name = qname->name;
- int len = qname->len;
+ const char *name = dentry->d_name.name;
+ int len = dentry->d_name.len;
+ __u32 bytesex;
+ struct inode *inode;
+
+ /* XXX - isn't that already done by the upper layer? */
+ if (!dir || !S_ISDIR(dir->i_mode))
+ return -EBADF;
+
+ bytesex = dir->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX;
if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG)
printk("Passed name: %s\nPassed length: %d\n", name, len);
- /*
+
+ /* debugging hacks:
* Touching /xyzzy in a filesystem toggles debugging messages.
*/
if ((len == 5) && !(memcmp(name, "xyzzy", len)) &&
@@ -56,8 +70,8 @@ int ufs_lookup (struct inode * dir, struct qstr *qname,
printk("UFS debugging %s\n",
(dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) ?
"on": "off");
- iput(dir);
- return(-ENOENT);
+ goto not_found;
+ /*return(-ENOENT);*/
}
/*
@@ -69,8 +83,8 @@ int ufs_lookup (struct inode * dir, struct qstr *qname,
printk("UFS inode debugging %s\n",
(dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ?
"on": "off");
- iput(dir);
- return(-ENOENT);
+ goto not_found;
+ /*return(-ENOENT);*/
}
if ((len == 7) && !(memcmp(name, "xyzzy.n", len)) &&
@@ -79,8 +93,8 @@ int ufs_lookup (struct inode * dir, struct qstr *qname,
printk("UFS namei debugging %s\n",
(dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ?
"on": "off");
- iput(dir);
- return(-ENOENT);
+ goto not_found;
+ /*return(-ENOENT);*/
}
if ((len == 7) && !(memcmp(name, "xyzzy.l", len)) &&
@@ -89,10 +103,13 @@ int ufs_lookup (struct inode * dir, struct qstr *qname,
printk("UFS symlink debugging %s\n",
(dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ?
"on": "off");
- iput(dir);
- return(-ENOENT);
+ goto not_found;
+ /*return(-ENOENT);*/
}
+
+ /* Now for the real thing */
+
if (dir->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) {
printk("ufs_lookup: called for ino %lu name %s\n",
dir->i_ino, name);
@@ -109,21 +126,22 @@ int ufs_lookup (struct inode * dir, struct qstr *qname,
}
if (fragno == 0) {
/* XXX - bug bug bug */
- iput(dir);
- return(-ENOENT);
+ goto not_found;
+ /*return(-ENOENT);*/
}
bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize);
if (bh == NULL) {
- printk("ufs_lookup: bread failed: ino %lu, lfragno %lu",
+ printk("ufs_lookup: bread failed: "
+ "ino %lu, lfragno %lu",
dir->i_ino, lfragno);
- iput(dir);
return(-EIO);
}
d = (struct ufs_direct *)(bh->b_data);
- while (((char *)d - bh->b_data + ufs_swab16(d->d_reclen)) <=
+ while (((char *)d - bh->b_data + SWAB16(d->d_reclen)) <=
dir->i_sb->s_blocksize) {
/* XXX - skip block if d_reclen or d_namlen is 0 */
- if ((ufs_swab16(d->d_reclen) == 0) || (ufs_swab16(d->d_namlen) == 0)) {
+ if ((d->d_reclen == 0) || (d->d_namlen == 0)) {
+ /* no need to SWAB16(): test against 0 */
if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
printk("ufs_lookup: skipped space in directory, ino %lu\n",
dir->i_ino);
@@ -131,32 +149,43 @@ int ufs_lookup (struct inode * dir, struct qstr *qname,
break;
}
if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
- printk("lfragno 0x%lx direct d 0x%x d_ino %u "
- "d_reclen %u d_namlen %u d_name `%s'\n",
- lfragno, (unsigned int)((unsigned long)d),
- ufs_swab32(d->d_ino), ufs_swab16(d->d_reclen),
- ufs_swab16(d->d_namlen), d->d_name);
+ printk("lfragno 0x%lx "
+ "direct d 0x%x "
+ "d_ino %u "
+ "d_reclen %u "
+ "d_namlen %u d_name `%s'\n",
+ lfragno,
+ (unsigned int)((unsigned long)d),
+ SWAB32(d->d_ino),
+ SWAB16(d->d_reclen),
+ SWAB16(d->d_namlen),d->d_name);
}
- if ((ufs_swab16(d->d_namlen) == len) &&
+ if ((SWAB16(d->d_namlen) == len) &&
/* XXX - don't use strncmp() - see ext2fs */
- (ufs_match(len, name, d))) {
+ (ufs_match(len, name, d, bytesex))) {
/* We have a match */
- *result = iget(dir->i_sb, ufs_swab32(d->d_ino));
- brelse(bh);
- iput(dir);
+/* XXX - I only superficially understand how things work,
+ * so use at your own risk... -- Fare'
+ */
+ inode = iget(dir->i_sb, SWAB32(d->d_ino));
+ brelse(bh);
+ if(!inode) { return -EACCES; }
+ d_add(dentry,inode);
return(0);
} else {
/* XXX - bounds checking */
if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
- printk("ufs_lookup: wanted (%s,%d) got (%s,%d)\n",
- name, len, d->d_name, ufs_swab16(d->d_namlen));
+ printk("ufs_lookup: "
+ "wanted (%s,%d) got (%s,%d)\n",
+ name, len,
+ d->d_name, SWAB16(d->d_namlen));
}
}
- d = (struct ufs_direct *)((char *)d + ufs_swab16(d->d_reclen));
+ d = (struct ufs_direct *)((char *)d + SWAB16(d->d_reclen));
}
brelse(bh);
}
- iput(dir);
- return(-ENOENT);
+ not_found:
+ d_add(dentry,NULL);
+ return(0);
}
-
diff --git a/fs/ufs/ufs_super.c b/fs/ufs/ufs_super.c
index c2ee0ded7..a3c32ccce 100644
--- a/fs/ufs/ufs_super.c
+++ b/fs/ufs/ufs_super.c
@@ -8,8 +8,6 @@
*
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
*
- * $Id: ufs_super.c,v 1.25 1997/07/17 02:24:15 davem Exp $
- *
*/
/*
@@ -18,6 +16,9 @@
*
* Module usage counts added on 96/04/29 by
* Gertjan van Wingerde <gertjan@cs.vu.nl>
+ *
+ * Clean swab support on 19970406 by
+ * Francois-Rene Rideau <rideau@ens.fr>
*/
#include <linux/config.h>
@@ -28,20 +29,20 @@
#include <linux/ufs_fs.h>
#include <linux/locks.h>
#include <linux/init.h>
-
#include <asm/uaccess.h>
-int ufs_need_swab = 0;
+#include "ufs_swab.h"
struct super_block * ufs_read_super(struct super_block * sb, void * data, int silent);
void ufs_put_super (struct super_block * sb);
-void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsize);
+int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsize);
static struct super_operations ufs_super_ops = {
ufs_read_inode,
- NULL, /* notify_change() */
NULL, /* XXX - ufs_write_inode() */
ufs_put_inode,
+ NULL, /* XXX - ufs_delete_inode() */
+ NULL, /* notify_change() */
ufs_put_super,
NULL, /* XXX - ufs_write_super() */
ufs_statfs,
@@ -113,8 +114,9 @@ ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb)
struct super_block *
ufs_read_super(struct super_block * sb, void * data, int silent)
{
- struct ufs_superblock * usb;
+ struct ufs_superblock * usb; /* normalized to local byteorder */
struct buffer_head * bh1, *bh2;
+ __u32 bytesex = 0;
/* sb->s_dev and sb->s_flags are set by our caller
* data is the mystery argument to sys_mount()
@@ -132,9 +134,7 @@ ufs_read_super(struct super_block * sb, void * data, int silent)
if (!(bh1 = bread(sb->s_dev, UFS_SBLOCK/BLOCK_SIZE, BLOCK_SIZE)) ||
!(bh2 = bread(sb->s_dev, (UFS_SBLOCK + BLOCK_SIZE)/BLOCK_SIZE,
BLOCK_SIZE))) {
- if (bh1) {
- brelse(bh1);
- }
+ brelse(bh1);
printk ("ufs_read_super: unable to read superblock\n");
goto ufs_read_super_lose;
@@ -156,32 +156,35 @@ ufs_read_super(struct super_block * sb, void * data, int silent)
brelse(bh1);
brelse(bh2);
- ufs_need_swab = 0;
- sb->s_magic = ufs_swab32(usb->fs_magic);
- if (sb->s_magic != UFS_MAGIC) {
- ufs_need_swab = 1;
- sb->s_magic = ufs_swab32(usb->fs_magic);
- if (sb->s_magic != UFS_MAGIC) {
- printk ("ufs_read_super: bad magic number 0x%8.8lx "
- "on dev %d/%d\n", sb->s_magic,
+ switch (le32_to_cpup(&usb->fs_magic)) {
+ case UFS_MAGIC:
+ bytesex = UFS_LITTLE_ENDIAN;
+ ufs_superblock_le_to_cpus(usb);
+ break;
+ case UFS_CIGAM:
+ bytesex = UFS_BIG_ENDIAN;
+ ufs_superblock_be_to_cpus(usb);
+ break;
+ /* usb is now normalized to local byteorder */
+ default:
+ printk ("ufs_read_super: bad magic number 0x%8.8x "
+ "on dev %d/%d\n", usb->fs_magic,
MAJOR(sb->s_dev), MINOR(sb->s_dev));
-
goto ufs_read_super_lose;
- }
}
/* We found a UFS filesystem on this device. */
/* XXX - parse args */
- if (ufs_swab32(usb->fs_bsize) != UFS_BSIZE) {
- printk("ufs_read_super: fs_bsize %d != %d\n", ufs_swab32(usb->fs_bsize),
+ if (usb->fs_bsize != UFS_BSIZE) {
+ printk("ufs_read_super: fs_bsize %d != %d\n", usb->fs_bsize,
UFS_BSIZE);
goto ufs_read_super_lose;
}
- if (ufs_swab32(usb->fs_fsize) != UFS_FSIZE) {
- printk("ufs_read_super: fs_fsize %d != %d\n", ufs_swab32(usb->fs_fsize),
+ if (usb->fs_fsize != UFS_FSIZE) {
+ printk("ufs_read_super: fs_fsize %d != %d\n", usb->fs_fsize,
UFS_FSIZE);
goto ufs_read_super_lose;
}
@@ -190,7 +193,7 @@ ufs_read_super(struct super_block * sb, void * data, int silent)
printk("ufs_read_super: fs last mounted on \"%s\"\n", usb->fs_fsmnt);
#endif
- if (ufs_swab32(usb->fs_state) == UFS_FSOK - ufs_swab32(usb->fs_time)) {
+ if (usb->fs_state == UFS_FSOK - usb->fs_time) {
switch(usb->fs_clean) {
case UFS_FSCLEAN:
#ifdef DEBUG_UFS_SUPER
@@ -225,35 +228,35 @@ ufs_read_super(struct super_block * sb, void * data, int silent)
/* XXX - sanity check sb fields */
/* KRR - Why are we not using fs_bsize for blocksize? */
- sb->s_blocksize = ufs_swab32(usb->fs_fsize);
- sb->s_blocksize_bits = ufs_swab32(usb->fs_fshift);
+ sb->s_blocksize = usb->fs_fsize;
+ sb->s_blocksize_bits = usb->fs_fshift;
/* XXX - sb->s_lock */
sb->s_op = &ufs_super_ops;
sb->dq_op = 0; /* XXX */
- /* KRR - defined above - sb->s_magic = usb->fs_magic; */
+ sb->s_magic = usb->fs_magic;
/* sb->s_time */
/* sb->s_wait */
/* XXX - sb->u.ufs_sb */
sb->u.ufs_sb.s_raw_sb = usb; /* XXX - maybe move this to the top */
- sb->u.ufs_sb.s_flags = 0;
- sb->u.ufs_sb.s_ncg = ufs_swab32(usb->fs_ncg);
- sb->u.ufs_sb.s_ipg = ufs_swab32(usb->fs_ipg);
- sb->u.ufs_sb.s_fpg = ufs_swab32(usb->fs_fpg);
- sb->u.ufs_sb.s_fsize = ufs_swab32(usb->fs_fsize);
- sb->u.ufs_sb.s_fmask = ufs_swab32(usb->fs_fmask);
- sb->u.ufs_sb.s_fshift = ufs_swab32(usb->fs_fshift);
- sb->u.ufs_sb.s_bsize = ufs_swab32(usb->fs_bsize);
- sb->u.ufs_sb.s_bmask = ufs_swab32(usb->fs_bmask);
- sb->u.ufs_sb.s_bshift = ufs_swab32(usb->fs_bshift);
- sb->u.ufs_sb.s_iblkno = ufs_swab32(usb->fs_iblkno);
- sb->u.ufs_sb.s_dblkno = ufs_swab32(usb->fs_dblkno);
- sb->u.ufs_sb.s_cgoffset = ufs_swab32(usb->fs_cgoffset);
- sb->u.ufs_sb.s_cgmask = ufs_swab32(usb->fs_cgmask);
- sb->u.ufs_sb.s_inopb = ufs_swab32(usb->fs_inopb);
- sb->u.ufs_sb.s_lshift = ufs_swab32(usb->fs_bshift) - ufs_swab32(usb->fs_fshift);
- sb->u.ufs_sb.s_lmask = ~((ufs_swab32(usb->fs_fmask) - ufs_swab32(usb->fs_bmask))
- >> ufs_swab32(usb->fs_fshift));
- sb->u.ufs_sb.s_fsfrag = ufs_swab32(usb->fs_frag); /* XXX - rename this later */
+ sb->u.ufs_sb.s_flags = bytesex | UFS_DEBUG_INITIAL ;
+ sb->u.ufs_sb.s_ncg = usb->fs_ncg;
+ sb->u.ufs_sb.s_ipg = usb->fs_ipg;
+ sb->u.ufs_sb.s_fpg = usb->fs_fpg;
+ sb->u.ufs_sb.s_fsize = usb->fs_fsize;
+ sb->u.ufs_sb.s_fmask = usb->fs_fmask;
+ sb->u.ufs_sb.s_fshift = usb->fs_fshift;
+ sb->u.ufs_sb.s_bsize = usb->fs_bsize;
+ sb->u.ufs_sb.s_bmask = usb->fs_bmask;
+ sb->u.ufs_sb.s_bshift = usb->fs_bshift;
+ sb->u.ufs_sb.s_iblkno = usb->fs_iblkno;
+ sb->u.ufs_sb.s_dblkno = usb->fs_dblkno;
+ sb->u.ufs_sb.s_cgoffset = usb->fs_cgoffset;
+ sb->u.ufs_sb.s_cgmask = usb->fs_cgmask;
+ sb->u.ufs_sb.s_inopb = usb->fs_inopb;
+ sb->u.ufs_sb.s_lshift = usb->fs_bshift - usb->fs_fshift;
+ sb->u.ufs_sb.s_lmask = ~((usb->fs_fmask - usb->fs_bmask)
+ >> usb->fs_fshift);
+ sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */
sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
#ifdef DEBUG_UFS_SUPER
@@ -285,6 +288,7 @@ void ufs_put_super (struct super_block * sb)
sb->s_dev = 0;
/* XXX - free allocated kernel memory */
+ /* includes freeing usb page */
unlock_super (sb);
MOD_DEC_USE_COUNT;
@@ -292,11 +296,12 @@ void ufs_put_super (struct super_block * sb)
return;
}
-void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz)
+int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz)
{
struct statfs tmp;
struct statfs *sp = &tmp;
struct ufs_superblock *fsb = sb->u.ufs_sb.s_raw_sb;
+ /* fsb was already normalized during mounting */
unsigned long used, avail;
if (sb->u.ufs_sb.s_flags & UFS_DEBUG) {
@@ -305,13 +310,13 @@ void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz)
sp->f_type = sb->s_magic;
sp->f_bsize = sb->s_blocksize;
- sp->f_blocks = ufs_swab32(fsb->fs_dsize);
- sp->f_bfree = ufs_swab32(fsb->fs_cstotal.cs_nbfree) *
- ufs_swab32(fsb->fs_frag) +
- ufs_swab32(fsb->fs_cstotal.cs_nffree);
+ sp->f_blocks = fsb->fs_dsize;
+ sp->f_bfree = fsb->fs_cstotal.cs_nbfree *
+ fsb->fs_frag +
+ fsb->fs_cstotal.cs_nffree;
avail = sp->f_blocks - (sp->f_blocks / 100) *
- ufs_swab32(fsb->fs_minfree);
+ fsb->fs_minfree;
used = sp->f_blocks - sp->f_bfree;
if (avail > used)
sp->f_bavail = avail - used;
@@ -319,11 +324,10 @@ void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz)
sp->f_bavail = 0;
sp->f_files = sb->u.ufs_sb.s_ncg * sb->u.ufs_sb.s_ipg;
- sp->f_ffree = ufs_swab32(fsb->fs_cstotal.cs_nifree);
- sp->f_fsid.val[0] = ufs_swab32(fsb->fs_id[0]);
- sp->f_fsid.val[1] = ufs_swab32(fsb->fs_id[1]);
+ sp->f_ffree = fsb->fs_cstotal.cs_nifree;
+ sp->f_fsid.val[0] = fsb->fs_id[0];
+ sp->f_fsid.val[1] = fsb->fs_id[1];
sp->f_namelen = UFS_MAXNAMLEN;
- copy_to_user(buf, sp, bufsiz);
- return;
+ return copy_to_user(buf, sp, bufsiz) ? -EFAULT : 0;
}
diff --git a/fs/ufs/ufs_symlink.c b/fs/ufs/ufs_symlink.c
index d98f99ff7..76d5fbf11 100644
--- a/fs/ufs/ufs_symlink.c
+++ b/fs/ufs/ufs_symlink.c
@@ -6,7 +6,7 @@
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_symlink.c,v 1.9 1997/06/05 01:29:11 davem Exp $
+ * Ported to 2.1.62 by Francois-Rene Rideau <rideau@ens.fr> 19971109
*
*/
@@ -16,6 +16,8 @@
#include <asm/uaccess.h>
+extern int ufs_bmap (struct inode *, int);
+
static int
ufs_readlink(struct inode * inode, char * buffer, int buflen)
{
@@ -30,6 +32,10 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen)
inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
}
+ if (!S_ISLNK(inode->i_mode)) {
+ return -EINVAL;
+ }
+
if (buflen > inode->i_sb->s_blocksize - 1)
buflen = inode->i_sb->s_blocksize - 1;
if (inode->i_blocks) {
@@ -38,16 +44,16 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen)
if (inode->i_sb->u.ufs_sb.s_flags &(UFS_DEBUG|UFS_DEBUG_LINKS)) {
printk("ufs_readlink: bmap got %lu for ino %lu\n",
block, inode->i_ino);
- }
+ }
bh = bread(inode->i_dev, block, BLOCK_SIZE);
if (!bh) {
- iput (inode);
printk("ufs_readlink: can't read block 0 for ino %lu on dev %u/%u\n",
inode->i_ino, MAJOR(inode->i_dev),
MINOR(inode->i_dev));
return 0;
}
link = bh->b_data;
+ /* no need to bswap */
}
else {
link = (char *)&(inode->u.ufs_i.i_data[0]);
@@ -57,18 +63,54 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen)
i++;
put_user (c, buffer++);
}
- iput (inode);
- if (bh)
- brelse (bh);
+ brelse (bh);
return i;
}
+/*
+ * XXX - blatantly stolen from minix fs
+ */
+static struct dentry *
+ufs_follow_link(struct inode * inode, struct dentry * base)
+{
+ unsigned long int block;
+ struct buffer_head * bh = NULL;
+ char * link;
+
+ if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
+ printk("ufs_follow_link: called on ino %lu dev %u/%u\n",
+ inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
+ }
+
+ if (inode->i_blocks) {
+ /* read the link from disk */
+ /* XXX - error checking */
+ block = ufs_bmap(inode, 0);
+ bh = bread(inode->i_dev, block, BLOCK_SIZE);
+ if (bh == NULL) {
+ printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n",
+ inode->i_ino, MAJOR(inode->i_dev),
+ MINOR(inode->i_dev));
+ dput(base);
+ return ERR_PTR(-EIO);
+ }
+ link = bh->b_data;
+ } else {
+ /* fast symlink */
+ link = (char *)&(inode->u.ufs_i.i_data[0]);
+ }
+ base = lookup_dentry(link, base, 1);
+ brelse (bh);
+ return base;
+}
+
+
static struct file_operations ufs_symlink_operations = {
NULL, /* lseek */
NULL, /* read */
NULL, /* write */
NULL, /* readdir */
- NULL, /* poll */
+ NULL, /* select */
NULL, /* ioctl */
NULL, /* mmap */
NULL, /* open */
@@ -90,12 +132,11 @@ struct inode_operations ufs_symlink_inode_operations = {
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
- ufs_readlink, /* readlink */
+ &ufs_readlink, /* readlink */
+ &ufs_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL, /* permission */
- NULL, /* smap */
};
-
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c
index a40f3bbeb..86002ddeb 100644
--- a/fs/umsdos/emd.c
+++ b/fs/umsdos/emd.c
@@ -29,7 +29,7 @@ long umsdos_file_read_kmem (struct inode *inode,
unsigned long count)
{
int ret;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = fat_file_read(inode,filp,buf,count);
set_fs (old_fs);
@@ -44,7 +44,7 @@ long umsdos_file_write_kmem (struct inode *inode,
unsigned long count)
{
int ret;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = fat_file_write(inode,filp,buf,count);
set_fs (old_fs);
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index c1ff4176c..8aacb6dfd 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -5,7 +5,7 @@
*
* Windows95/Windows NT compatible extended MSDOS filesystem
* by Gordon Chaffee Copyright (C) 1995. Send bug reports for the
- * VFAT filesystem to <chaffee@plateau.cs.berkeley.edu>. Specify
+ * VFAT filesystem to <chaffee@cs.berkeley.edu>. Specify
* what file operation caused you trouble and if you can duplicate
* the problem, send a script that demonstrates it.
*/
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/ctype.h>
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/malloc.h>
@@ -38,12 +39,6 @@
# define CHECK_STACK check_stack(__FILE__, __LINE__)
#endif
-/*
- * XXX: It would be better to use the tolower from linux/ctype.h,
- * but _ctype is needed and it is not exported.
- */
-#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c))
-
struct vfat_find_info {
const char *name;
int len;
@@ -229,10 +224,15 @@ static void dump_de(struct msdos_dir_entry *de)
/* MS-DOS "device special files" */
-static const char *reserved_names[] = {
- "CON ","PRN ","NUL ","AUX ",
- "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
- "COM1 ","COM2 ","COM3 ","COM4 ",
+static const char *reserved3_names[] = {
+ "con ", "prn ", "nul ", "aux ", NULL
+};
+
+static const char *reserved4_names[] = {
+ "com1 ", "com2 ", "com3 ", "com4 ", "com5 ",
+ "com6 ", "com7 ", "com8 ", "com9 ",
+ "lpt1 ", "lpt2 ", "lpt3 ", "lpt4 ", "lpt5 ",
+ "lpt6 ", "lpt7 ", "lpt8 ", "lpt9 ",
NULL };
@@ -245,16 +245,32 @@ static int vfat_find(struct inode *dir,struct qstr* name,
int find_long,int new_filename,int is_dir,
struct slot_info *sinfo_out);
-/* Checks the validity of an long MS-DOS filename */
+static int strnicmp(const char *s1, const char *s2, int len)
+{
+ int n = 0;
+ while (*s1 && *s2 && (tolower(*s1) == tolower(*s2))) {
+ s1++; s2++; n++;
+ if (n == len) return 0;
+ }
+ if (*s1 == 0 && *s2 == 0) return 0;
+ if (*s1 && *s2) {
+ if (*s1 > *s2) return 1;
+ return -1;
+ }
+ if (*s1) return 1;
+ return -1;
+}
+
+/* Checks the validity of a long MS-DOS filename */
/* Returns negative number on error, 0 for a normal
* return, and 1 for . or .. */
static int vfat_valid_longname(const char *name, int len, int dot_dirs,
int xlate)
{
- const char **reserved;
+ const char **reserved, *walk;
unsigned char c;
- int i;
+ int i, baselen;
if (IS_FREE(name)) return -EINVAL;
if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
@@ -271,9 +287,21 @@ static int vfat_valid_longname(const char *name, int len, int dot_dirs,
return -EINVAL;
}
}
- if (len == 3 || len == 4) {
- for (reserved = reserved_names; *reserved; reserved++)
- if (!strncmp(name,*reserved,8)) return -EINVAL;
+ if (len < 3) return 0;
+
+ for (walk = name; *walk != 0 && *walk != '.'; walk++);
+ baselen = walk - name;
+
+ if (baselen == 3) {
+ for (reserved = reserved3_names; *reserved; reserved++) {
+ if (!strnicmp(name,*reserved,baselen))
+ return -EINVAL;
+ }
+ } else if (baselen == 4) {
+ for (reserved = reserved4_names; *reserved; reserved++) {
+ if (!strnicmp(name,*reserved,baselen))
+ return -EINVAL;
+ }
}
return 0;
}
@@ -284,6 +312,7 @@ static int vfat_valid_shortname(const char *name,int len,
const char *walk, **reserved;
unsigned char c;
int space;
+ int baselen;
if (IS_FREE(name)) return -EINVAL;
if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
@@ -312,7 +341,9 @@ static int vfat_valid_shortname(const char *name,int len,
if (c != '.') return -EINVAL;
}
while (c != '.' && len--) c = *walk++;
+ baselen = walk - name;
if (c == '.') {
+ baselen--;
if (len >= 4) return -EINVAL;
while (len > 0 && walk-name < (MSDOS_NAME+1)) {
c = *walk++;
@@ -329,8 +360,13 @@ static int vfat_valid_shortname(const char *name,int len,
if (space) return -EINVAL;
if (len) return -EINVAL;
}
- for (reserved = reserved_names; *reserved; reserved++)
- if (!strncmp(name,*reserved,8)) return -EINVAL;
+ if (baselen == 3) {
+ for (reserved = reserved3_names; *reserved; reserved++)
+ if (!strnicmp(name,*reserved,baselen)) return -EINVAL;
+ } else if (baselen == 4) {
+ for (reserved = reserved4_names; *reserved; reserved++)
+ if (!strnicmp(name,*reserved,baselen)) return -EINVAL;
+ }
return 0;
}
@@ -341,7 +377,7 @@ static int vfat_valid_shortname(const char *name,int len,
*/
static int vfat_format_name(const char *name,int len,char *res,
- int dot_dirs,int utf8)
+ int dot_dirs,int utf8)
{
char *walk;
const char **reserved;
@@ -396,8 +432,10 @@ static int vfat_format_name(const char *name,int len,char *res,
if (len) return -EINVAL;
}
while (walk-res < MSDOS_NAME) *walk++ = ' ';
- for (reserved = reserved_names; *reserved; reserved++)
- if (!strncmp(res,*reserved,8)) return -EINVAL;
+ for (reserved = reserved3_names; *reserved; reserved++)
+ if (!strnicmp(res,*reserved,8)) return -EINVAL;
+ for (reserved = reserved4_names; *reserved; reserved++)
+ if (!strnicmp(res,*reserved,8)) return -EINVAL;
return 0;
}
@@ -605,8 +643,8 @@ static loff_t vfat_find_free_slots(struct inode *dir,int slots)
/* Directory slots of busy deleted files aren't available yet. */
done = !MSDOS_I(inode)->i_busy;
/* PRINTK(("inode %d still busy\n", ino)); */
+ iput(inode);
}
- iput(inode);
}
if (done) {
row++;
@@ -995,7 +1033,6 @@ cleanup:
int vfat_lookup(struct inode *dir,struct dentry *dentry)
{
int res;
- struct inode *next;
struct slot_info sinfo;
struct inode *result;
@@ -1014,7 +1051,7 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry)
if (!result->i_sb ||
(result->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
/* crossed a mount point into a non-msdos fs */
- d_add(dentry,result);
+ d_add(dentry,NULL);
return 0;
}
if (MSDOS_I(result)->i_busy) { /* mkdir in progress */
@@ -1023,18 +1060,7 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry)
return 0;
}
PRINTK (("vfat_lookup 6\n"));
- while (MSDOS_I(result)->i_old) {
- next = MSDOS_I(result)->i_old;
- iput(result);
- if (!(result = iget(next->i_sb,next->i_ino))) {
- fat_fs_panic(dir->i_sb,"vfat_lookup: Can't happen");
- iput(dir);
- return -ENOENT;
- }
- }
- PRINTK (("vfat_lookup 7\n"));
d_add(dentry,result);
- PRINTK (("vfat_lookup 8\n"));
return 0;
}
@@ -1091,10 +1117,12 @@ int vfat_create(struct inode *dir,struct dentry* dentry,int mode)
result=NULL;
fat_lock_creation();
res = vfat_create_entry(dir,&dentry->d_name,0,&result);
- if (res < 0) PRINTK(("vfat_create: unable to get new entry\n"));
-
fat_unlock_creation();
- d_instantiate(dentry,result);
+ if (res < 0) {
+ PRINTK(("vfat_create: unable to get new entry\n"));
+ } else {
+ d_instantiate(dentry,result);
+ }
return res;
}
@@ -1123,9 +1151,10 @@ static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent,
de->adate = de->cdate = de->date;
de->size = 0;
fat_mark_buffer_dirty(sb, bh, 1);
- if ((dot = iget(dir->i_sb,ino)) != NULL)
- vfat_read_inode(dot);
- if (!dot) return -EIO;
+ dot = iget(dir->i_sb,ino);
+ if (!dot)
+ return -EIO;
+ vfat_read_inode(dot);
dot->i_mtime = dot->i_atime = CURRENT_TIME;
mark_inode_dirty(dot);
if (isdot) {
@@ -1192,8 +1221,15 @@ static int vfat_empty(struct inode *dir)
struct buffer_head *bh;
struct msdos_dir_entry *de;
- if (dir->i_count > 1)
+ /*
+ * Prune any child dentries, then verify that
+ * the directory is empty and not in use.
+ */
+ shrink_dcache_sb(sb); /* should be child prune */
+
+ if (dir->i_count > 1) {
return -EBUSY;
+ }
if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
pos = 0;
bh = NULL;
@@ -1288,7 +1324,6 @@ static int vfat_remove_entry(struct inode *dir,struct slot_info *sinfo,
for (i = sinfo->long_slots; i > 0; --i) {
res = fat_get_entry(dir, &offset, bh, &de);
if (res < 0) {
- printk("vfat_remove_entry: problem 1\n");
continue;
}
de->name[0] = DELETED_FLAG;
@@ -1306,24 +1341,17 @@ static int vfat_rmdirx(struct inode *dir,struct dentry* dentry)
struct buffer_head *bh;
struct slot_info sinfo;
- bh = NULL;
- res = -EPERM;
- if (dentry->d_name.name[0] == '.' &&
- (dentry->d_name.len == 1 || (dentry->d_name.len == 2 &&
- dentry->d_name.name[1] == '.')))
- goto rmdir_done;
res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo);
if (res >= 0 && sinfo.total_slots > 0) {
+ bh = NULL;
res = vfat_remove_entry(dir,&sinfo,&bh,dentry,1,0);
if (res > 0) {
res = 0;
}
dir->i_version = ++event;
+ if (bh) fat_brelse(sb, bh);
}
-
-rmdir_done:
- fat_brelse(sb, bh);
return res;
}
@@ -1331,9 +1359,10 @@ rmdir_done:
int vfat_rmdir(struct inode *dir,struct dentry* dentry)
{
int res;
-
res = vfat_rmdirx(dir, dentry);
- d_delete(dentry);
+ if (res >= 0) {
+ d_delete(dentry);
+ }
return res;
}
@@ -1357,7 +1386,7 @@ static int vfat_unlinkx(
}
}
- fat_brelse(sb, bh);
+ if (bh) fat_brelse(sb, bh);
return res;
}
@@ -1394,7 +1423,9 @@ int vfat_unlink(struct inode *dir,struct dentry* dentry)
int res;
res = vfat_unlinkx (dir,dentry,1);
- d_delete(dentry);
+ if (res >= 0) {
+ d_delete(dentry);
+ }
return res;
}
@@ -1633,22 +1664,3 @@ void cleanup_module(void)
}
#endif /* ifdef MODULE */
-
-
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */