summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
commitdb7d4daea91e105e3859cf461d7e53b9b77454b2 (patch)
tree9bb65b95440af09e8aca63abe56970dd3360cc57 /fs
parent9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff)
Merge with Linux 2.2.8.
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in8
-rw-r--r--fs/adfs/dir.c2
-rw-r--r--fs/adfs/inode.c64
-rw-r--r--fs/adfs/namei.c10
-rw-r--r--fs/adfs/super.c227
-rw-r--r--fs/affs/Changes9
-rw-r--r--fs/affs/dir.c3
-rw-r--r--fs/affs/inode.c3
-rw-r--r--fs/affs/namei.c28
-rw-r--r--fs/affs/super.c1
-rw-r--r--fs/autofs/dir.c4
-rw-r--r--fs/autofs/root.c43
-rw-r--r--fs/autofs/waitq.c6
-rw-r--r--fs/binfmt_aout.c48
-rw-r--r--fs/binfmt_elf.c46
-rw-r--r--fs/buffer.c412
-rw-r--r--fs/coda/dir.c96
-rw-r--r--fs/coda/inode.c3
-rw-r--r--fs/coda/sysctl.c11
-rw-r--r--fs/coda/upcall.c1
-rw-r--r--fs/dcache.c10
-rw-r--r--fs/devpts/root.c26
-rw-r--r--fs/dquot.c98
-rw-r--r--fs/exec.c1
-rw-r--r--fs/ext2/dir.c2
-rw-r--r--fs/ext2/inode.c22
-rw-r--r--fs/ext2/namei.c103
-rw-r--r--fs/ext2/super.c20
-rw-r--r--fs/fat/cvf.c31
-rw-r--r--fs/fat/dir.c23
-rw-r--r--fs/fat/fatfs_syms.c1
-rw-r--r--fs/fat/file.c4
-rw-r--r--fs/fat/inode.c22
-rw-r--r--fs/fat/misc.c6
-rw-r--r--fs/fat/mmap.c2
-rw-r--r--fs/file_table.c4
-rw-r--r--fs/hfs/ChangeLog10
-rw-r--r--fs/hfs/catalog.c11
-rw-r--r--fs/hfs/dir.c2
-rw-r--r--fs/hfs/dir_cap.c10
-rw-r--r--fs/hfs/dir_dbl.c10
-rw-r--r--fs/hfs/dir_nat.c10
-rw-r--r--fs/hfs/file_hdr.c67
-rw-r--r--fs/hfs/sysdep.c4
-rw-r--r--fs/hpfs/hpfs_fs.c19
-rw-r--r--fs/inode.c158
-rw-r--r--fs/ioctl.c14
-rw-r--r--fs/isofs/dir.c3
-rw-r--r--fs/isofs/file.c1
-rw-r--r--fs/isofs/namei.c13
-rw-r--r--fs/lockd/clntproc.c46
-rw-r--r--fs/lockd/host.c2
-rw-r--r--fs/lockd/svc.c3
-rw-r--r--fs/lockd/svclock.c25
-rw-r--r--fs/lockd/svcproc.c2
-rw-r--r--fs/lockd/svcsubs.c9
-rw-r--r--fs/lockd/xdr.c50
-rw-r--r--fs/locks.c10
-rw-r--r--fs/minix/dir.c2
-rw-r--r--fs/minix/inode.c13
-rw-r--r--fs/minix/namei.c84
-rw-r--r--fs/msdos/namei.c331
-rw-r--r--fs/namei.c141
-rw-r--r--fs/ncpfs/Config.in5
-rw-r--r--fs/ncpfs/Makefile2
-rw-r--r--fs/ncpfs/dir.c397
-rw-r--r--fs/ncpfs/inode.c165
-rw-r--r--fs/ncpfs/ioctl.c65
-rw-r--r--fs/ncpfs/mmap.c2
-rw-r--r--fs/ncpfs/ncplib_kernel.c54
-rw-r--r--fs/ncpfs/ncplib_kernel.h93
-rw-r--r--fs/ncpfs/sock.c2
-rw-r--r--fs/ncpfs/symlink.c212
-rw-r--r--fs/nfs/dir.c215
-rw-r--r--fs/nfs/file.c52
-rw-r--r--fs/nfs/inode.c151
-rw-r--r--fs/nfs/nfs2xdr.c1
-rw-r--r--fs/nfs/symlink.c7
-rw-r--r--fs/nfs/write.c93
-rw-r--r--fs/nfsd/nfs3proc.c5
-rw-r--r--fs/nfsd/nfsfh.c52
-rw-r--r--fs/nfsd/nfsproc.c7
-rw-r--r--fs/nfsd/nfssvc.c16
-rw-r--r--fs/nfsd/vfs.c10
-rw-r--r--fs/nls/Config.in2
-rw-r--r--fs/ntfs/Makefile2
-rw-r--r--fs/ntfs/attr.c136
-rw-r--r--fs/ntfs/attr.h4
-rw-r--r--fs/ntfs/dir.c45
-rw-r--r--fs/ntfs/dir.h1
-rw-r--r--fs/ntfs/fs.c21
-rw-r--r--fs/ntfs/inode.c101
-rw-r--r--fs/ntfs/inode.h2
-rw-r--r--fs/ntfs/ntfsendian.h17
-rw-r--r--fs/ntfs/ntfstypes.h8
-rw-r--r--fs/ntfs/super.c36
-rw-r--r--fs/ntfs/super.h2
-rw-r--r--fs/ntfs/support.c4
-rw-r--r--fs/open.c35
-rw-r--r--fs/proc/array.c32
-rw-r--r--fs/proc/fd.c16
-rw-r--r--fs/proc/link.c2
-rw-r--r--fs/proc/openpromfs.c13
-rw-r--r--fs/proc/root.c31
-rw-r--r--fs/qnx4/dir.c3
-rw-r--r--fs/qnx4/file.c2
-rw-r--r--fs/qnx4/namei.c28
-rw-r--r--fs/romfs/inode.c11
-rw-r--r--fs/smbfs/cache.c5
-rw-r--r--fs/smbfs/dir.c28
-rw-r--r--fs/smbfs/file.c11
-rw-r--r--fs/super.c16
-rw-r--r--fs/sysv/CHANGES26
-rw-r--r--fs/sysv/dir.c4
-rw-r--r--fs/sysv/ialloc.c2
-rw-r--r--fs/sysv/inode.c8
-rw-r--r--fs/sysv/namei.c63
-rw-r--r--fs/ufs/dir.c7
-rw-r--r--fs/ufs/namei.c109
-rw-r--r--fs/ufs/super.c59
-rw-r--r--fs/ufs/util.h90
-rw-r--r--fs/umsdos/dir.c72
-rw-r--r--fs/umsdos/emd.c4
-rw-r--r--fs/umsdos/inode.c13
-rw-r--r--fs/umsdos/namei.c305
-rw-r--r--fs/umsdos/rdir.c13
-rw-r--r--fs/vfat/namei.c127
127 files changed, 2814 insertions, 2758 deletions
diff --git a/fs/Config.in b/fs/Config.in
index 1fdf8acd7..d9c8c08cd 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -105,10 +105,6 @@ fi
endmenu
fi
-if [ "$CONFIG_AFFS_FS" != "n" ]; then
- define_bool CONFIG_AMIGA_PARTITION y
-fi
-
mainmenu_option next_comment
comment 'Partition Types'
@@ -124,6 +120,10 @@ fi
endmenu
+if [ "$CONFIG_AFFS_FS" != "n" ]; then
+ define_bool CONFIG_AMIGA_PARTITION y
+fi
+
source fs/nls/Config.in
endmenu
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 12f7f6f6d..ac81954d7 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -280,8 +280,6 @@ static int adfs_readdir (struct file *filp, void *dirent, filldir_t filldir)
unsigned long parent_object_id, dir_object_id;
int buffers, pos;
- if (!inode || !S_ISDIR(inode->i_mode))
- return -EBADF;
sb = inode->i_sb;
if (filp->f_pos > ADFS_NUM_DIR_ENTRIES + 2)
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 37daaa3c3..6c8814567 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -27,7 +27,7 @@
#define inode_dirindex(idx) (((idx) & 0xff) * 26 - 21)
#define frag_id(x) (((x) >> 8) & 0x7fff)
-#define off(x) (((x) & 0xff) ? ((x) & 0xff) - 1 : 0)
+#define off(x) (((x) & 0xff) ? (((x) & 0xff) - 1) << sb->u.adfs_sb.s_dr->log2sharesize : 0)
static inline int adfs_inode_validate_no (struct super_block *sb, unsigned int inode_no)
{
@@ -83,11 +83,20 @@ int adfs_bmap (struct inode *inode, int block)
return 0;
}
+ if (block < 0) {
+ adfs_error(sb, "adfs_bmap", "block(%d) < 0", block);
+ return 0;
+ }
+
+ if (block > inode->i_blocks)
+ return 0;
+
+ block += off(inode->u.adfs_i.file_id);
+
if (frag_id(inode->u.adfs_i.file_id) == ADFS_ROOT_FRAG)
- blk = sb->u.adfs_sb.s_map_block + off(inode_frag (inode->i_ino)) + block;
+ blk = sb->u.adfs_sb.s_map_block + block;
else
- blk = adfs_map_lookup (sb, frag_id(inode->u.adfs_i.file_id),
- off (inode->u.adfs_i.file_id) + block);
+ blk = adfs_map_lookup (sb, frag_id(inode->u.adfs_i.file_id), block);
return blk;
}
@@ -105,13 +114,13 @@ unsigned int adfs_parent_bmap (struct inode *inode, int block)
fragment = inode_frag (inode->i_ino);
if (frag_id (fragment) == ADFS_ROOT_FRAG)
- blk = sb->u.adfs_sb.s_map_block + off (fragment) + block;
+ blk = sb->u.adfs_sb.s_map_block + off(fragment) + block;
else
- blk = adfs_map_lookup (sb, frag_id (fragment), off (fragment) + block);
+ blk = adfs_map_lookup (sb, frag_id (fragment), off(fragment) + block);
return blk;
}
-static int adfs_atts2mode (unsigned char mode, unsigned int filetype)
+static int adfs_atts2mode(struct super_block *sb, unsigned char mode, unsigned int filetype)
{
int omode = 0;
@@ -120,24 +129,29 @@ static int adfs_atts2mode (unsigned char mode, unsigned int filetype)
S_IRGRP|S_IWGRP|S_IXGRP|
S_IROTH|S_IWOTH|S_IXOTH;
} else {
- if (mode & ADFS_NDA_DIRECTORY)
- omode |= S_IFDIR|S_IRUSR|S_IXUSR|S_IXGRP|S_IXOTH;
- else
+ if (mode & ADFS_NDA_DIRECTORY) {
+ omode |= S_IRUGO & sb->u.adfs_sb.s_owner_mask;
+ omode |= S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH;
+ } else
omode |= S_IFREG;
+
if (mode & ADFS_NDA_OWNER_READ) {
- omode |= S_IRUSR;
+ omode |= S_IRUGO & sb->u.adfs_sb.s_owner_mask;
if (filetype == 0xfe6 /* UnixExec */)
- omode |= S_IXUSR;
+ omode |= S_IXUGO & sb->u.adfs_sb.s_owner_mask;
}
+
if (mode & ADFS_NDA_OWNER_WRITE)
- omode |= S_IWUSR;
+ omode |= S_IWUGO & sb->u.adfs_sb.s_owner_mask;
+
if (mode & ADFS_NDA_PUBLIC_READ) {
- omode |= S_IRGRP | S_IROTH;
- if (filetype == 0xfe6)
- omode |= S_IXGRP | S_IXOTH;
+ omode |= S_IRUGO & sb->u.adfs_sb.s_other_mask;
+ if (filetype == 0xfe6 /* UnixExec */)
+ omode |= S_IXUGO & sb->u.adfs_sb.s_other_mask;
}
+
if (mode & ADFS_NDA_PUBLIC_WRITE)
- omode |= S_IWGRP | S_IWOTH;
+ omode |= S_IWUGO & sb->u.adfs_sb.s_other_mask;
}
return omode;
}
@@ -150,8 +164,8 @@ void adfs_read_inode (struct inode *inode)
int buffers;
sb = inode->i_sb;
- inode->i_uid = 0;
- inode->i_gid = 0;
+ inode->i_uid = sb->u.adfs_sb.s_uid;
+ inode->i_gid = sb->u.adfs_sb.s_gid;
inode->i_version = ++event;
if (adfs_inode_validate_no (sb, inode->i_ino & 0xffffff00)) {
@@ -186,7 +200,7 @@ void adfs_read_inode (struct inode *inode)
goto bad;
}
adfs_dir_free (bh, buffers);
- inode->i_mode = adfs_atts2mode (ide.mode, ide.filetype);
+ inode->i_mode = adfs_atts2mode(sb, ide.mode, ide.filetype);
inode->i_nlink = 2;
inode->i_size = ide.size;
inode->i_blksize = PAGE_SIZE;
@@ -204,13 +218,5 @@ void adfs_read_inode (struct inode *inode)
return;
bad:
- inode->i_mode = 0;
- inode->i_nlink = 1;
- inode->i_size = 0;
- inode->i_blksize = 0;
- inode->i_blocks = 0;
- inode->i_mtime =
- inode->i_atime =
- inode->i_ctime = 0;
- inode->i_op = NULL;
+ make_bad_inode(inode);
}
diff --git a/fs/adfs/namei.c b/fs/adfs/namei.c
index 24f0565d9..df3b5e457 100644
--- a/fs/adfs/namei.c
+++ b/fs/adfs/namei.c
@@ -46,7 +46,7 @@ static int adfs_find_entry (struct inode *dir, const char * const name, int name
unsigned long parent_object_id, dir_object_id;
int buffers, pos;
- if (!dir || !S_ISDIR(dir->i_mode))
+ if (!S_ISDIR(dir->i_mode))
return 0;
sb = dir->i_sb;
@@ -98,22 +98,22 @@ static int adfs_find_entry (struct inode *dir, const char * const name, int name
return 0;
}
-int adfs_lookup (struct inode *dir, struct dentry *dentry)
+struct dentry *adfs_lookup (struct inode *dir, struct dentry *dentry)
{
struct inode *inode = NULL;
struct adfs_idir_entry de;
unsigned long ino;
if (dentry->d_name.len > ADFS_NAME_LEN)
- return -ENAMETOOLONG;
+ return ERR_PTR(-ENAMETOOLONG);
if (adfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de)) {
ino = de.inode_no;
inode = iget (dir->i_sb, ino);
if (!inode)
- return -EACCES;
+ return ERR_PTR(-EACCES);
}
d_add(dentry, inode);
- return 0;
+ return NULL;
}
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 234d8cf21..8c2fbe8fa 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -21,25 +21,26 @@
#include <stdarg.h>
-static void adfs_put_super (struct super_block *sb);
-static int adfs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz);
-void adfs_read_inode (struct inode *inode);
+static void adfs_put_super(struct super_block *sb);
+static int adfs_remount(struct super_block *sb, int *flags, char *data);
+static int adfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+void adfs_read_inode(struct inode *inode);
-void adfs_error (struct super_block *sb, const char *function, const char *fmt, ...)
+void adfs_error(struct super_block *sb, const char *function, const char *fmt, ...)
{
char error_buf[128];
va_list args;
- va_start (args, fmt);
- vsprintf (error_buf, fmt, args);
- va_end (args);
+ va_start(args, fmt);
+ vsprintf(error_buf, fmt, args);
+ va_end(args);
- printk (KERN_CRIT "ADFS-fs error (device %s)%s%s: %s\n",
- kdevname (sb->s_dev), function ? ": " : "",
+ printk(KERN_CRIT "ADFS-fs error (device %s)%s%s: %s\n",
+ kdevname(sb->s_dev), function ? ": " : "",
function ? function : "", error_buf);
}
-unsigned char adfs_calccrosscheck (struct super_block *sb, char *map)
+static unsigned char adfs_calczonecheck(struct super_block *sb, char *map)
{
unsigned int v0, v1, v2, v3;
int i;
@@ -63,7 +64,7 @@ unsigned char adfs_calccrosscheck (struct super_block *sb, char *map)
return v0 ^ v1 ^ v2 ^ v3;
}
-static int adfs_checkmap (struct super_block *sb)
+static int adfs_checkmap(struct super_block *sb)
{
unsigned char crosscheck = 0, zonecheck = 1;
int i;
@@ -72,14 +73,14 @@ static int adfs_checkmap (struct super_block *sb)
char *map;
map = sb->u.adfs_sb.s_map[i]->b_data;
- if (adfs_calccrosscheck (sb, map) != map[0]) {
- adfs_error (sb, "adfs_checkmap", "zone %d fails zonecheck", i);
+ if (adfs_calczonecheck(sb, map) != map[0]) {
+ adfs_error(sb, "adfs_checkmap", "zone %d fails zonecheck", i);
zonecheck = 0;
}
crosscheck ^= map[3];
}
if (crosscheck != 0xff)
- adfs_error (sb, "adfs_checkmap", "crosscheck != 0xff");
+ adfs_error(sb, "adfs_checkmap", "crosscheck != 0xff");
return crosscheck == 0xff && zonecheck;
}
@@ -92,21 +93,73 @@ static struct super_operations adfs_sops = {
adfs_put_super,
NULL,
adfs_statfs,
- NULL
+ adfs_remount
};
-static void adfs_put_super (struct super_block *sb)
+static void adfs_put_super(struct super_block *sb)
{
int i;
for (i = 0; i < sb->u.adfs_sb.s_map_size; i++)
- brelse (sb->u.adfs_sb.s_map[i]);
- kfree (sb->u.adfs_sb.s_map);
- brelse (sb->u.adfs_sb.s_sbh);
+ brelse(sb->u.adfs_sb.s_map[i]);
+ kfree(sb->u.adfs_sb.s_map);
+ brelse(sb->u.adfs_sb.s_sbh);
MOD_DEC_USE_COUNT;
}
-struct super_block *adfs_read_super (struct super_block *sb, void *data, int silent)
+static int parse_options(struct super_block *sb, char *options)
+{
+ char *value, *opt;
+
+ if (!options)
+ return 0;
+
+ for (opt = strtok(options, ","); opt != NULL; opt = strtok(NULL, ",")) {
+ value = strchr(opt, '=');
+ if (value)
+ *value++ = '\0';
+
+ if (!strcmp(opt, "uid")) { /* owner of all files */
+ if (!value || !*value)
+ return -EINVAL;
+ sb->u.adfs_sb.s_uid = simple_strtoul(value, &value, 0);
+ if (*value)
+ return -EINVAL;
+ } else
+ if (!strcmp(opt, "gid")) { /* group owner of all files */
+ if (!value || !*value)
+ return -EINVAL;
+ sb->u.adfs_sb.s_gid = simple_strtoul(value, &value, 0);
+ if (*value)
+ return -EINVAL;
+ } else
+ if (!strcmp(opt, "ownmask")) { /* owner permission mask */
+ if (!value || !*value)
+ return -EINVAL;
+ sb->u.adfs_sb.s_owner_mask = simple_strtoul(value, &value, 8);
+ if (*value)
+ return -EINVAL;
+ } else
+ if (!strcmp(opt, "othmask")) { /* others permission mask */
+ if (!value || !*value)
+ return -EINVAL;
+ sb->u.adfs_sb.s_other_mask = simple_strtoul(value, &value, 8);
+ if (*value)
+ return -EINVAL;
+ } else { /* eh? say again. */
+ printk("ADFS-fs: unrecognised mount option %s\n", opt);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int adfs_remount(struct super_block *sb, int *flags, char *data)
+{
+ return parse_options(sb, data);
+}
+
+struct super_block *adfs_read_super(struct super_block *sb, void *data, int silent)
{
struct adfs_discrecord *dr;
struct buffer_head *bh;
@@ -114,28 +167,30 @@ struct super_block *adfs_read_super (struct super_block *sb, void *data, int sil
kdev_t dev = sb->s_dev;
int i, j;
+ /* set default options */
+ sb->u.adfs_sb.s_uid = 0;
+ sb->u.adfs_sb.s_gid = 0;
+ sb->u.adfs_sb.s_owner_mask = S_IRWXU;
+ sb->u.adfs_sb.s_other_mask = S_IRWXG | S_IRWXO;
+
+ if (parse_options(sb, data))
+ goto error;
+
MOD_INC_USE_COUNT;
- lock_super (sb);
- set_blocksize (dev, BLOCK_SIZE);
- if (!(bh = bread (dev, ADFS_DISCRECORD / BLOCK_SIZE, BLOCK_SIZE))) {
- unlock_super (sb);
- adfs_error (sb, NULL, "unable to read superblock");
- MOD_DEC_USE_COUNT;
- return NULL;
+ lock_super(sb);
+ set_blocksize(dev, BLOCK_SIZE);
+ if (!(bh = bread(dev, ADFS_DISCRECORD / BLOCK_SIZE, BLOCK_SIZE))) {
+ adfs_error(sb, NULL, "unable to read superblock");
+ goto error_unlock;
}
b_data = bh->b_data + (ADFS_DISCRECORD % BLOCK_SIZE);
- if (adfs_checkbblk (b_data)) {
+ if (adfs_checkbblk(b_data)) {
if (!silent)
- printk ("VFS: Can't find an adfs filesystem on dev "
+ printk("VFS: Can't find an adfs filesystem on dev "
"%s.\n", kdevname(dev));
-failed_mount:
- unlock_super (sb);
- if (bh)
- brelse (bh);
- MOD_DEC_USE_COUNT;
- return NULL;
+ goto error_free_bh;
}
dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
@@ -145,26 +200,26 @@ failed_mount:
(sb->s_blocksize == 512 || sb->s_blocksize == 1024 ||
sb->s_blocksize == 2048 || sb->s_blocksize == 4096)) {
- brelse (bh);
- set_blocksize (dev, sb->s_blocksize);
- bh = bread (dev, ADFS_DISCRECORD / sb->s_blocksize, sb->s_blocksize);
+ brelse(bh);
+ set_blocksize(dev, sb->s_blocksize);
+ bh = bread(dev, ADFS_DISCRECORD / sb->s_blocksize, sb->s_blocksize);
if (!bh) {
- adfs_error (sb, NULL, "couldn't read superblock on "
+ adfs_error(sb, NULL, "couldn't read superblock on "
"2nd try.");
- goto failed_mount;
+ goto error_unlock;
}
b_data = bh->b_data + (ADFS_DISCRECORD % sb->s_blocksize);
- if (adfs_checkbblk (b_data)) {
- adfs_error (sb, NULL, "disc record mismatch, very weird!");
- goto failed_mount;
+ if (adfs_checkbblk(b_data)) {
+ adfs_error(sb, NULL, "disc record mismatch, very weird!");
+ goto error_free_bh;
}
dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
}
if (sb->s_blocksize != bh->b_size) {
if (!silent)
- printk (KERN_ERR "VFS: Unsupported blocksize on dev "
- "%s.\n", kdevname (dev));
- goto failed_mount;
+ printk(KERN_ERR "VFS: Unsupported blocksize on dev "
+ "%s.\n", kdevname(dev));
+ goto error_free_bh;
}
/* blocksize on this device should now be set to the adfs log2secsize */
@@ -202,71 +257,81 @@ failed_mount:
else
sb->u.adfs_sb.s_map_block >>= -sb->u.adfs_sb.s_map2blk;
- printk (KERN_DEBUG "ADFS: zone size %d, IDs per zone %d, map address %X size %d sectors\n",
+ printk(KERN_DEBUG "ADFS: zone size %d, IDs per zone %d, map address %X size %d sectors\n",
sb->u.adfs_sb.s_zone_size, sb->u.adfs_sb.s_ids_per_zone,
sb->u.adfs_sb.s_map_block, sb->u.adfs_sb.s_map_size);
- printk (KERN_DEBUG "ADFS: sector size %d, map bit size %d\n",
- 1 << dr->log2secsize, 1 << dr->log2bpmb);
+ printk(KERN_DEBUG "ADFS: sector size %d, map bit size %d, share size %d\n",
+ 1 << dr->log2secsize, 1 << dr->log2bpmb,
+ 1 << (dr->log2secsize + dr->log2sharesize));
sb->s_magic = ADFS_SUPER_MAGIC;
- sb->s_flags |= MS_RDONLY; /* we don't support writing yet */
- sb->u.adfs_sb.s_map = kmalloc (sb->u.adfs_sb.s_map_size *
- sizeof (struct buffer_head *), GFP_KERNEL);
+ sb->u.adfs_sb.s_map = kmalloc(sb->u.adfs_sb.s_map_size *
+ sizeof(struct buffer_head *), GFP_KERNEL);
if (sb->u.adfs_sb.s_map == NULL) {
- adfs_error (sb, NULL, "not enough memory");
- goto failed_mount;
+ adfs_error(sb, NULL, "not enough memory");
+ goto error_free_bh;
}
for (i = 0; i < sb->u.adfs_sb.s_map_size; i++) {
- sb->u.adfs_sb.s_map[i] = bread (dev,
+ sb->u.adfs_sb.s_map[i] = bread(dev,
sb->u.adfs_sb.s_map_block + i,
sb->s_blocksize);
if (!sb->u.adfs_sb.s_map[i]) {
for (j = 0; j < i; j++)
- brelse (sb->u.adfs_sb.s_map[j]);
- kfree (sb->u.adfs_sb.s_map);
- adfs_error (sb, NULL, "unable to read map");
- goto failed_mount;
+ brelse(sb->u.adfs_sb.s_map[j]);
+ kfree(sb->u.adfs_sb.s_map);
+ adfs_error(sb, NULL, "unable to read map");
+ goto error_free_bh;
}
}
- if (!adfs_checkmap (sb)) {
+ if (!adfs_checkmap(sb)) {
for (i = 0; i < sb->u.adfs_sb.s_map_size; i++)
- brelse (sb->u.adfs_sb.s_map[i]);
- adfs_error (sb, NULL, "map corrupted");
- goto failed_mount;
+ brelse(sb->u.adfs_sb.s_map[i]);
+ adfs_error(sb, NULL, "map corrupted");
+ goto error_free_bh;
}
dr = (struct adfs_discrecord *)(sb->u.adfs_sb.s_map[0]->b_data + 4);
- unlock_super (sb);
+ unlock_super(sb);
/*
* set up enough so that it can read an inode
*/
sb->s_op = &adfs_sops;
- sb->u.adfs_sb.s_root = adfs_inode_generate (dr->root, 0);
+ sb->u.adfs_sb.s_root = adfs_inode_generate(dr->root, 0);
sb->s_root = d_alloc_root(iget(sb, sb->u.adfs_sb.s_root), NULL);
if (!sb->s_root) {
- sb->s_dev = 0;
for (i = 0; i < sb->u.adfs_sb.s_map_size; i++)
- brelse (sb->u.adfs_sb.s_map[i]);
- brelse (bh);
- adfs_error (sb, NULL, "get root inode failed\n");
- MOD_DEC_USE_COUNT;
- return NULL;
+ brelse(sb->u.adfs_sb.s_map[i]);
+ brelse(bh);
+ adfs_error(sb, NULL, "get root inode failed\n");
+ goto error_dec_use;
}
return sb;
+
+error_free_bh:
+ if (bh)
+ brelse(bh);
+error_unlock:
+ unlock_super(sb);
+error_dec_use:
+ MOD_DEC_USE_COUNT;
+error:
+ sb->s_dev = 0;
+ return NULL;
}
-static int adfs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
+static int adfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
const unsigned int nidlen = sb->u.adfs_sb.s_idlen + 1;
tmp.f_type = ADFS_SUPER_MAGIC;
tmp.f_bsize = sb->s_blocksize;
- tmp.f_blocks = (sb->u.adfs_sb.s_dr->disc_size) >> (sb->s_blocksize_bits);
+ tmp.f_blocks = sb->u.adfs_sb.s_dr->disc_size_high << (32 - sb->s_blocksize_bits) |
+ sb->u.adfs_sb.s_dr->disc_size >> sb->s_blocksize_bits;
tmp.f_files = tmp.f_blocks >> nidlen;
{
unsigned int i, j = 0;
@@ -305,35 +370,35 @@ static int adfs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
if (freelink <= nidlen) break;
} while (mapindex < 8 * sb->s_blocksize);
if (mapindex > 8 * sb->s_blocksize)
- adfs_error (sb, NULL, "oversized free fragment\n");
+ adfs_error(sb, NULL, "oversized free fragment\n");
else if (freelink)
- adfs_error (sb, NULL, "undersized free fragment\n");
+ adfs_error(sb, NULL, "undersized free fragment\n");
}
tmp.f_bfree = tmp.f_bavail = j <<
(sb->u.adfs_sb.s_dr->log2bpmb - sb->s_blocksize_bits);
}
tmp.f_ffree = tmp.f_bfree >> nidlen;
tmp.f_namelen = ADFS_NAME_LEN;
- return copy_to_user (buf, &tmp, bufsiz) ? -EFAULT : 0;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
static struct file_system_type adfs_fs_type = {
"adfs", FS_REQUIRES_DEV, adfs_read_super, NULL
};
-__initfunc(int init_adfs_fs (void))
+__initfunc(int init_adfs_fs(void))
{
- return register_filesystem (&adfs_fs_type);
+ return register_filesystem(&adfs_fs_type);
}
#ifdef MODULE
-int init_module (void)
+int init_module(void)
{
return init_adfs_fs();
}
-void cleanup_module (void)
+void cleanup_module(void)
{
- unregister_filesystem (&adfs_fs_type);
+ unregister_filesystem(&adfs_fs_type);
}
#endif
diff --git a/fs/affs/Changes b/fs/affs/Changes
index 0432bdd0d..7a7faedd0 100644
--- a/fs/affs/Changes
+++ b/fs/affs/Changes
@@ -28,6 +28,15 @@ Known bugs:
Please direct bug reports to: hjw@zvw.de
+Version 3.10
+------------
+
+- Changed partition checker to allow devices
+ with physical blocks != 512 bytes.
+
+- The partition checker now also ignores the
+ word at 0xd0 that Windows likes to write to.
+
Version 3.9
-----------
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
index 51e45b682..3a1c78ef0 100644
--- a/fs/affs/dir.c
+++ b/fs/affs/dir.c
@@ -90,9 +90,6 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
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;
-
stored = 0;
dir_bh = NULL;
fh_bh = NULL;
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 80aad129c..9b05ec062 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -21,7 +21,6 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/locks.h>
-#include <linux/errno.h>
#include <linux/genhd.h>
#include <linux/amigaffs.h>
#include <linux/major.h>
@@ -293,7 +292,7 @@ affs_new_inode(const struct inode *dir)
sb = dir->i_sb;
inode->i_sb = sb;
- inode->i_flags = sb->s_flags;
+ inode->i_flags = 0;
if (!(block = affs_new_header((struct inode *)dir))) {
iput(inode);
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index a18c23a0f..48e951800 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -201,7 +201,7 @@ affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
return bh;
}
-int
+struct dentry *
affs_lookup(struct inode *dir, struct dentry *dentry)
{
unsigned long ino;
@@ -218,11 +218,11 @@ affs_lookup(struct inode *dir, struct dentry *dentry)
affs_brelse(bh);
inode = iget(dir->i_sb,ino);
if (!inode)
- return -EACCES;
+ return ERR_PTR(-EACCES);
}
dentry->d_op = &affs_dentry_operations;
d_add(dentry,inode);
- return 0;
+ return NULL;
}
int
@@ -548,32 +548,14 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
"No inode for entry found (key=%lu)\n",new_ino);
goto end_rename;
}
- 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;
- }
if (S_ISDIR(old_inode->i_mode)) {
- retval = -EINVAL;
- if (is_subdir(new_dentry, old_dentry))
- goto end_rename;
if (new_inode) {
- if (new_dentry->d_count > 1)
- shrink_dcache_parent(new_dentry);
- retval = -EBUSY;
- if (new_dentry->d_count > 1)
- goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
goto end_rename;
}
+ retval = -ENOENT;
if (affs_parent_ino(old_inode) != old_dir->i_ino)
goto end_rename;
}
@@ -593,7 +575,6 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
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
@@ -604,7 +585,6 @@ new_checksum:
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);
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 464b6df8a..0c2a838f5 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -22,7 +22,6 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/locks.h>
-#include <linux/errno.h>
#include <linux/genhd.h>
#include <linux/amigaffs.h>
#include <linux/major.h>
diff --git a/fs/autofs/dir.c b/fs/autofs/dir.c
index 63efe9b87..d6944e889 100644
--- a/fs/autofs/dir.c
+++ b/fs/autofs/dir.c
@@ -38,10 +38,10 @@ static int autofs_dir_readdir(struct file *filp,
/*
* No entries except for "." and "..", both of which are handled by the VFS layer
*/
-static int autofs_dir_lookup(struct inode *dir, struct dentry * dentry)
+static struct dentry *autofs_dir_lookup(struct inode *dir,struct dentry *dentry)
{
d_add(dentry, NULL);
- return 0;
+ return NULL;
}
static struct file_operations autofs_dir_operations = {
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 561904318..c0caee9df 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -16,7 +16,7 @@
#include "autofs_i.h"
static int autofs_root_readdir(struct file *,void *,filldir_t);
-static int autofs_root_lookup(struct inode *,struct dentry *);
+static struct dentry *autofs_root_lookup(struct inode *,struct dentry *);
static int autofs_root_symlink(struct inode *,struct dentry *,const char *);
static int autofs_root_unlink(struct inode *,struct dentry *);
static int autofs_root_rmdir(struct inode *,struct dentry *);
@@ -168,7 +168,7 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
* yet completely filled in, and revalidate has to delay such
* lookups..
*/
-static int autofs_revalidate(struct dentry * dentry)
+static int autofs_revalidate(struct dentry * dentry, int flags)
{
struct inode * dir = dentry->d_parent->d_inode;
struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
@@ -209,7 +209,7 @@ static struct dentry_operations autofs_dentry_operations = {
NULL, /* d_compare */
};
-static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
+static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentry)
{
struct autofs_sb_info *sbi;
int oz_mode;
@@ -217,8 +217,8 @@ static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
DPRINTK(("autofs_root_lookup: name = "));
autofs_say(dentry->d_name.name,dentry->d_name.len);
- if (!S_ISDIR(dir->i_mode))
- return -ENOTDIR;
+ if (dentry->d_name.len > NAME_MAX)
+ return ERR_PTR(-ENOENT);/* File name too long to exist */
sbi = autofs_sbi(dir->i_sb);
@@ -241,7 +241,7 @@ static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
d_add(dentry, NULL);
up(&dir->i_sem);
- autofs_revalidate(dentry);
+ autofs_revalidate(dentry, 0);
down(&dir->i_sem);
/*
@@ -250,7 +250,7 @@ static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
*/
if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
if (signal_pending(current))
- return -ERESTARTNOINTR;
+ return ERR_PTR(-ERESTARTNOINTR);
}
/*
@@ -260,9 +260,9 @@ static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
* be OK for the operations we permit from an autofs.
*/
if ( dentry->d_inode && list_empty(&dentry->d_hash) )
- return -ENOENT;
+ return ERR_PTR(-ENOENT);
- return 0;
+ return NULL;
}
static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
@@ -278,7 +278,10 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c
autofs_say(dentry->d_name.name,dentry->d_name.len);
if ( !autofs_oz_mode(sbi) )
- return -EPERM;
+ return -EACCES;
+
+ if ( dentry->d_name.len > NAME_MAX )
+ return -ENAMETOOLONG;
if ( autofs_hash_lookup(dh, &dentry->d_name) )
return -EEXIST;
@@ -343,17 +346,20 @@ static int autofs_root_unlink(struct inode *dir, struct dentry *dentry)
struct autofs_dir_ent *ent;
unsigned int n;
- if ( !autofs_oz_mode(sbi) )
- return -EPERM;
+ /* This allows root to remove symlinks */
+ if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+ return -EACCES;
ent = autofs_hash_lookup(dh, &dentry->d_name);
if ( !ent )
return -ENOENT;
n = ent->ino - AUTOFS_FIRST_SYMLINK;
- if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap) )
- return -EINVAL; /* Not a symlink inode, can't unlink */
-
+ if ( n >= AUTOFS_MAX_SYMLINKS )
+ return -EISDIR; /* It's a directory, dummy */
+ if ( !test_bit(n,sbi->symlink_bitmap) )
+ return -EINVAL; /* Nonexistent symlink? Shouldn't happen */
+
dentry->d_time = (unsigned long)(struct autofs_dirhash *)NULL;
autofs_hash_delete(ent);
clear_bit(n,sbi->symlink_bitmap);
@@ -370,7 +376,7 @@ static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry)
struct autofs_dir_ent *ent;
if ( !autofs_oz_mode(sbi) )
- return -EPERM;
+ return -EACCES;
ent = autofs_hash_lookup(dh, &dentry->d_name);
if ( !ent )
@@ -399,7 +405,10 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
ino_t ino;
if ( !autofs_oz_mode(sbi) )
- return -EPERM;
+ return -EACCES;
+
+ if ( dentry->d_name.len > NAME_MAX )
+ return -ENAMETOOLONG;
ent = autofs_hash_lookup(dh, &dentry->d_name);
if ( ent )
diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c
index 81c68af46..f9cccbd44 100644
--- a/fs/autofs/waitq.c
+++ b/fs/autofs/waitq.c
@@ -99,7 +99,7 @@ static void autofs_notify_daemon(struct autofs_sb_info *sbi, struct autofs_wait_
autofs_catatonic_mode(sbi);
}
-int autofs_wait(struct autofs_sb_info *sbi, struct qstr * name)
+int autofs_wait(struct autofs_sb_info *sbi, struct qstr *name)
{
struct autofs_wait_queue *wq;
int status;
@@ -107,6 +107,10 @@ int autofs_wait(struct autofs_sb_info *sbi, struct qstr * name)
/* In catatonic mode, we don't wait for nobody */
if ( sbi->catatonic )
return -ENOENT;
+
+ /* We shouldn't be able to get here, but just in case */
+ if ( name->len > NAME_MAX )
+ return -ENOENT;
for ( wq = sbi->queues ; wq ; wq = wq->next ) {
if ( wq->hash == name->hash &&
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index c7925b235..a4ed4eb34 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -58,14 +58,25 @@ static void set_brk(unsigned long start, unsigned long end)
* These are the only things you should do on a core-file: use only these
* macros to write out all the necessary info.
*/
-#define DUMP_WRITE(addr,nr) \
-while (file.f_op->write(&file,(char *)(addr),(nr),&file.f_pos) != (nr)) goto close_coredump
+
+static int dump_write(struct file *file, const void *addr, int nr)
+{
+ int r;
+ down(&file->f_dentry->d_inode->i_sem);
+ r = file->f_op->write(file, addr, nr, &file->f_pos) == nr;
+ up(&file->f_dentry->d_inode->i_sem);
+ return r;
+}
+
+#define DUMP_WRITE(addr, nr) \
+ if (!dump_write(file, (void *)(addr), (nr))) \
+ goto close_coredump;
#define DUMP_SEEK(offset) \
-if (file.f_op->llseek) { \
- if (file.f_op->llseek(&file,(offset),0) != (offset)) \
+if (file->f_op->llseek) { \
+ if (file->f_op->llseek(file,(offset),0) != (offset)) \
goto close_coredump; \
-} else file.f_pos = (offset)
+} else file->f_pos = (offset)
/*
* Routine writes a core dump image in the current directory.
@@ -82,7 +93,7 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
{
struct dentry * dentry = NULL;
struct inode * inode = NULL;
- struct file file;
+ struct file * file;
mm_segment_t fs;
int has_dumped = 0;
char corefile[6+sizeof(current->comm)];
@@ -116,21 +127,16 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
#else
corefile[4] = '\0';
#endif
- dentry = open_namei(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
- if (IS_ERR(dentry)) {
- dentry = NULL;
+ file = filp_open(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
+ if (IS_ERR(file))
goto end_coredump;
- }
+ dentry = file->f_dentry;
inode = dentry->d_inode;
if (!S_ISREG(inode->i_mode))
- goto end_coredump;
+ goto close_coredump;
if (!inode->i_op || !inode->i_op->default_file_ops)
- goto end_coredump;
- if (get_write_access(inode))
- goto end_coredump;
- if (init_private_file(&file, dentry, 3))
- goto end_coredump_write;
- if (!file.f_op->write)
+ goto close_coredump;
+ if (!file->f_op->write)
goto close_coredump;
has_dumped = 1;
current->flags |= PF_DUMPCORE;
@@ -211,13 +217,9 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
set_fs(KERNEL_DS);
DUMP_WRITE(current,sizeof(*current));
close_coredump:
- if (file.f_op->release)
- file.f_op->release(inode,&file);
-end_coredump_write:
- put_write_access(inode);
+ filp_close(file, NULL);
end_coredump:
set_fs(fs);
- dput(dentry);
return has_dumped;
}
@@ -327,6 +329,8 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
}
if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
+ bprm->dentry->d_inode->i_op &&
+ bprm->dentry->d_inode->i_op->bmap &&
(fd_offset < bprm->dentry->d_inode->i_sb->s_blocksize)) {
printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
return -ENOEXEC;
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 8be2fc475..82f75d1e6 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -927,7 +927,11 @@ static int load_elf_library(int fd)
*/
static int dump_write(struct file *file, const void *addr, int nr)
{
- return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
+ int r;
+ down(&file->f_dentry->d_inode->i_sem);
+ r = file->f_op->write(file, addr, nr, &file->f_pos) == nr;
+ up(&file->f_dentry->d_inode->i_sem);
+ return r;
}
static int dump_seek(struct file *file, off_t off)
@@ -1032,10 +1036,10 @@ static int writenote(struct memelfnote *men, struct file *file)
#undef DUMP_SEEK
#define DUMP_WRITE(addr, nr) \
- if (!dump_write(&file, (addr), (nr))) \
+ if (!dump_write(file, (addr), (nr))) \
goto close_coredump;
#define DUMP_SEEK(off) \
- if (!dump_seek(&file, (off))) \
+ if (!dump_seek(file, (off))) \
goto close_coredump;
/*
* Actual dumper
@@ -1047,7 +1051,7 @@ static int writenote(struct memelfnote *men, struct file *file)
static int elf_core_dump(long signr, struct pt_regs * regs)
{
int has_dumped = 0;
- struct file file;
+ struct file *file;
struct dentry *dentry;
struct inode *inode;
mm_segment_t fs;
@@ -1118,30 +1122,28 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
fs = get_fs();
set_fs(KERNEL_DS);
+
memcpy(corefile,"core.",5);
#if 0
memcpy(corefile+5,current->comm,sizeof(current->comm));
#else
corefile[4] = '\0';
#endif
- dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
- if (IS_ERR(dentry)) {
- dentry = NULL;
+ file = filp_open(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
+ if (IS_ERR(file))
goto end_coredump;
- }
+ dentry = file->f_dentry;
inode = dentry->d_inode;
-
- if(inode->i_nlink > 1)
- goto end_coredump; /* multiple links - don't dump */
+ if (inode->i_nlink > 1)
+ goto close_coredump; /* multiple links - don't dump */
if (!S_ISREG(inode->i_mode))
- goto end_coredump;
+ goto close_coredump;
if (!inode->i_op || !inode->i_op->default_file_ops)
- goto end_coredump;
- if (init_private_file(&file, dentry, 3))
- goto end_coredump;
- if (!file.f_op->write)
goto close_coredump;
+ if (!file->f_op->write)
+ goto close_coredump;
+
has_dumped = 1;
current->flags |= PF_DUMPCORE;
@@ -1297,7 +1299,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
}
for(i = 0; i < numnote; i++)
- if (!writenote(&notes[i], &file))
+ if (!writenote(&notes[i], file))
goto close_coredump;
set_fs(fs);
@@ -1319,19 +1321,17 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
DUMP_WRITE((void *)addr, len);
}
- if ((off_t) file.f_pos != offset) {
+ if ((off_t) file->f_pos != offset) {
/* Sanity check */
- printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n",
- (off_t) file.f_pos, offset);
+ printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n",
+ (off_t) file->f_pos, offset);
}
close_coredump:
- if (file.f_op->release)
- file.f_op->release(inode,&file);
+ filp_close(file, NULL);
end_coredump:
set_fs(fs);
- dput(dentry);
#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
#endif
diff --git a/fs/buffer.c b/fs/buffer.c
index 2c874f742..afec12e55 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -76,6 +76,7 @@ static int nr_buffers = 0;
static int nr_buffers_type[NR_LIST] = {0,};
static int nr_buffer_heads = 0;
static int nr_unused_buffer_heads = 0;
+static int nr_hashed_buffers = 0;
/* This is used by some architectures to estimate available memory. */
int buffermem = 0;
@@ -99,7 +100,8 @@ union bdflush_param{
each time we call refill */
int nref_dirt; /* Dirty buffer threshold for activating bdflush
when trying to refill buffers. */
- int dummy1; /* unused */
+ int interval; /* Interval (seconds) between spontaneous
+ bdflush runs */
int age_buffer; /* Time for normal buffer to age before
we flush it */
int age_super; /* Time for superblock to age before we
@@ -108,10 +110,10 @@ union bdflush_param{
int dummy3; /* unused */
} b_un;
unsigned int data[N_PARAM];
-} bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
+} bdf_prm = {{40, 500, 64, 256, 5, 30*HZ, 5*HZ, 1884, 2}};
/* These are the min and max parameter values that we will allow to be assigned */
-int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 0, 1*HZ, 1*HZ, 1, 1};
+int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 1, 1*HZ, 1*HZ, 1, 1};
int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 600*HZ, 600*HZ, 2047, 5};
void wakeup_bdflush(int);
@@ -383,7 +385,9 @@ asmlinkage int sys_fdatasync(unsigned int fd)
goto out_putf;
/* this needs further work, at the moment it is identical to fsync() */
+ down(&inode->i_sem);
err = file->f_op->fsync(file, dentry);
+ up(&inode->i_sem);
out_putf:
fput(file);
@@ -432,6 +436,7 @@ static inline void remove_from_hash_queue(struct buffer_head * bh)
*pprev = next;
bh->b_pprev = NULL;
}
+ nr_hashed_buffers--;
}
static inline void remove_from_lru_list(struct buffer_head * bh)
@@ -482,33 +487,6 @@ static void remove_from_queues(struct buffer_head * bh)
remove_from_lru_list(bh);
}
-static inline void put_last_lru(struct buffer_head * bh)
-{
- if (bh) {
- struct buffer_head **bhp = &lru_list[bh->b_list];
-
- if (bh == *bhp) {
- *bhp = bh->b_next_free;
- return;
- }
-
- if(bh->b_dev == B_FREE)
- panic("Wrong block for lru list");
-
- /* Add to back of free list. */
- remove_from_lru_list(bh);
- if(!*bhp) {
- *bhp = bh;
- (*bhp)->b_prev_free = bh;
- }
-
- bh->b_next_free = *bhp;
- bh->b_prev_free = (*bhp)->b_prev_free;
- (*bhp)->b_prev_free->b_next_free = bh;
- (*bhp)->b_prev_free = bh;
- }
-}
-
static inline void put_last_free(struct buffer_head * bh)
{
if (bh) {
@@ -566,6 +544,7 @@ static void insert_into_queues(struct buffer_head * bh)
*bhp = bh;
bh->b_pprev = bhp;
}
+ nr_hashed_buffers++;
}
}
@@ -721,8 +700,6 @@ repeat:
bh = get_hash_table(dev, block, size);
if (bh) {
if (!buffer_dirty(bh)) {
- if (buffer_uptodate(bh))
- put_last_lru(bh);
bh->b_flushtime = 0;
}
return bh;
@@ -807,7 +784,7 @@ void refile_buffer(struct buffer_head * buf)
* If too high a percentage of the buffers are dirty...
*/
if (nr_buffers_type[BUF_DIRTY] > too_many)
- wakeup_bdflush(0);
+ wakeup_bdflush(1);
/* If this is a loop device, and
* more than half of the buffers are dirty...
@@ -828,6 +805,7 @@ void __brelse(struct buffer_head * buf)
/* If dirty, mark the time this buffer should be written back. */
set_writetime(buf, 0);
refile_buffer(buf);
+ touch_buffer(buf);
if (buf->b_count) {
buf->b_count--;
@@ -837,21 +815,21 @@ void __brelse(struct buffer_head * buf)
}
/*
- * bforget() is like brelse(), except it removes the buffer
- * from the hash-queues (so that it won't be re-used if it's
- * shared).
+ * bforget() is like brelse(), except it puts the buffer on the
+ * free list if it can.. We can NOT free the buffer if:
+ * - there are other users of it
+ * - it is locked and thus can have active IO
*/
void __bforget(struct buffer_head * buf)
{
- mark_buffer_clean(buf);
- clear_bit(BH_Protected, &buf->b_state);
- remove_from_hash_queue(buf);
- buf->b_dev = NODEV;
- refile_buffer(buf);
- if (!--buf->b_count)
+ if (buf->b_count != 1 || buffer_locked(buf)) {
+ __brelse(buf);
return;
- printk("VFS: forgot an in-use buffer! (count=%d)\n",
- buf->b_count);
+ }
+ buf->b_count = 0;
+ buf->b_state = 0;
+ remove_from_queues(buf);
+ put_last_free(buf);
}
/*
@@ -860,20 +838,16 @@ void __bforget(struct buffer_head * buf)
*/
struct buffer_head * bread(kdev_t dev, int block, int size)
{
- struct buffer_head * bh = getblk(dev, block, size);
+ struct buffer_head * bh;
- if (bh) {
- touch_buffer(bh);
- if (buffer_uptodate(bh))
- return bh;
- ll_rw_block(READ, 1, &bh);
- wait_on_buffer(bh);
- if (buffer_uptodate(bh))
- return bh;
- brelse(bh);
- return NULL;
- }
- printk("VFS: bread: impossible error\n");
+ bh = getblk(dev, block, size);
+ if (buffer_uptodate(bh))
+ return bh;
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ if (buffer_uptodate(bh))
+ return bh;
+ brelse(bh);
return NULL;
}
@@ -897,12 +871,12 @@ struct buffer_head * breada(kdev_t dev, int block, int bufsize,
if (pos >= filesize)
return NULL;
- if (block < 0 || !(bh = getblk(dev,block,bufsize)))
+ if (block < 0)
return NULL;
+ bh = getblk(dev, block, bufsize);
index = BUFSIZE_INDEX(bh->b_size);
- touch_buffer(bh);
if (buffer_uptodate(bh))
return(bh);
else ll_rw_block(READ, 1, &bh);
@@ -1008,9 +982,9 @@ static struct buffer_head * get_unused_buffer_head(int async)
/* This is critical. We can't swap out pages to get
* more buffer heads, because the swap-out may need
- * more buffer-heads itself. Thus SLAB_ATOMIC.
+ * more buffer-heads itself. Thus SLAB_BUFFER.
*/
- if((bh = kmem_cache_alloc(bh_cachep, SLAB_ATOMIC)) != NULL) {
+ if((bh = kmem_cache_alloc(bh_cachep, SLAB_BUFFER)) != NULL) {
memset(bh, 0, sizeof(*bh));
nr_buffer_heads++;
return bh;
@@ -1489,6 +1463,7 @@ void show_buffers(void)
printk("Buffer memory: %6dkB\n",buffermem>>10);
printk("Buffer heads: %6d\n",nr_buffer_heads);
printk("Buffer blocks: %6d\n",nr_buffers);
+ printk("Buffer hashed: %6d\n",nr_hashed_buffers);
for(nlist = 0; nlist < NR_LIST; nlist++) {
found = locked = dirty = used = lastused = protected = 0;
@@ -1522,13 +1497,27 @@ void show_buffers(void)
* Use gfp() for the hash table to decrease TLB misses, use
* SLAB cache for buffer heads.
*/
-void __init buffer_init(void)
+void __init buffer_init(unsigned long memory_size)
{
- int order = 5; /* Currently maximum order.. */
+ int order;
unsigned int nr_hash;
- nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct buffer_head *);
- hash_table = (struct buffer_head **) __get_free_pages(GFP_ATOMIC, order);
+ /* we need to guess at the right sort of size for a buffer cache.
+ the heuristic from working with large databases and getting
+ fsync times (ext2) manageable, is the following */
+
+ memory_size >>= 20;
+ for (order = 5; (1UL << order) < memory_size; order++);
+
+ /* try to allocate something until we get it or we're asking
+ for something that is really too small */
+
+ do {
+ nr_hash = (1UL << order) * PAGE_SIZE /
+ sizeof(struct buffer_head *);
+ hash_table = (struct buffer_head **)
+ __get_free_pages(GFP_ATOMIC, order);
+ } while (hash_table == NULL && --order > 4);
if (!hash_table)
panic("Failed to allocate buffer hash table\n");
@@ -1565,7 +1554,6 @@ void __init buffer_init(void)
* response to dirty buffers. Once this process is activated, we write back
* a limited number of buffers to the disks and then go back to sleep again.
*/
-static struct wait_queue * bdflush_wait = NULL;
static struct wait_queue * bdflush_done = NULL;
struct task_struct *bdflush_tsk = 0;
@@ -1573,7 +1561,7 @@ void wakeup_bdflush(int wait)
{
if (current == bdflush_tsk)
return;
- wake_up(&bdflush_wait);
+ wake_up_process(bdflush_tsk);
if (wait) {
run_task_queue(&tq_disk);
sleep_on(&bdflush_done);
@@ -1582,77 +1570,107 @@ void wakeup_bdflush(int wait)
/*
- * Here we attempt to write back old buffers. We also try to flush inodes
- * and supers as well, since this function is essentially "update", and
- * otherwise there would be no way of ensuring that these quantities ever
- * get written back. Ideally, we would have a timestamp on the inodes
- * and superblocks so that we could write back only the old ones as well
- */
+ * Here we attempt to write back old buffers.
+ * To prevent deadlocks for a loop device:
+ * 1) Do non-blocking writes to loop (avoids deadlock with running
+ * out of request blocks).
+ * 2) But do a blocking write if the only dirty buffers are loop buffers
+ * (otherwise we go into an infinite busy-loop).
+ * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
+ * with running out of free buffers for loop's "real" device).
+*/
-static int sync_old_buffers(void)
+static inline void sync_old_buffers(void)
{
int i;
- int ndirty, nwritten;
- int nlist;
- int ncount;
- struct buffer_head * bh, *next;
-
- sync_supers(0);
- sync_inodes(0);
-
- ncount = 0;
+ int ndirty = 0;
+ int wrta_cmd = WRITEA;
#ifdef DEBUG
- for(nlist = 0; nlist < NR_LIST; nlist++)
-#else
- for(nlist = BUF_DIRTY; nlist <= BUF_DIRTY; nlist++)
+ int ncount = 0, nwritten = 0;
#endif
- {
- ndirty = 0;
- nwritten = 0;
- repeat:
+ struct buffer_head * bh, *next;
- bh = lru_list[nlist];
- if(bh)
- for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
- /* We may have stalled while waiting for I/O to complete. */
- if(bh->b_list != nlist) goto repeat;
- next = bh->b_next_free;
- if(!lru_list[nlist]) {
- printk("Dirty list empty %d\n", i);
- break;
- }
-
- /* Clean buffer on dirty list? Refile it */
- if (nlist == BUF_DIRTY && !buffer_dirty(bh) && !buffer_locked(bh))
- {
- refile_buffer(bh);
- continue;
- }
-
- if (buffer_locked(bh) || !buffer_dirty(bh))
- continue;
- ndirty++;
- if(time_before(jiffies, bh->b_flushtime))
- continue;
- nwritten++;
- next->b_count++;
- bh->b_count++;
- bh->b_flushtime = 0;
#ifdef DEBUG
- if(nlist != BUF_DIRTY) ncount++;
+ bh = lru_list[BUF_CLEAN];
+ if(bh)
+ for(i = nr_buffers_type[BUF_CLEAN]; --i > 0; bh = next) {
+ next = bh->b_next_free;
+
+ /* Dirty/locked buffer on clean list? Refile it */
+ if (buffer_locked(bh) || buffer_dirty(bh)) {
+ ncount++;
+ refile_buffer(bh);
+ }
+ }
#endif
- ll_rw_block(WRITE, 1, &bh);
- bh->b_count--;
- next->b_count--;
- }
+
+ bh = lru_list[BUF_LOCKED];
+ if(bh)
+ for(i = nr_buffers_type[BUF_LOCKED]; --i > 0; bh = next) {
+ next = bh->b_next_free;
+
+ /* Unlocked buffer on locked list? Refile it */
+ if (!buffer_locked(bh))
+ refile_buffer(bh);
+ }
+
+ restart:
+ bh = lru_list[BUF_DIRTY];
+ if(bh)
+ for (i = nr_buffers_type[BUF_DIRTY];
+ i-- > 0 && ndirty < bdf_prm.b_un.ndirty;
+ bh = next) {
+ /* We may have stalled while waiting for
+ I/O to complete. */
+ if(bh->b_list != BUF_DIRTY)
+ goto restart;
+ next = bh->b_next_free;
+ if(!lru_list[BUF_DIRTY]) {
+ printk("Dirty list empty %d\n", i);
+ break;
+ }
+
+ /* Clean buffer on dirty list? Refile it */
+ if (!buffer_dirty(bh)) {
+ refile_buffer(bh);
+ continue;
+ }
+
+ if (buffer_locked(bh))
+ continue;
+ /* Should we write back buffers that are
+ shared or not?? Currently dirty buffers
+ are not shared, so it does not matter */
+ next->b_count++;
+ bh->b_count++;
+ ndirty++;
+ bh->b_flushtime = 0;
+ if (MAJOR(bh->b_dev) == LOOP_MAJOR) {
+ ll_rw_block(wrta_cmd,1, &bh);
+ wrta_cmd = WRITEA;
+ if (buffer_dirty(bh))
+ --ndirty;
+ }
+ else
+ ll_rw_block(WRITE, 1, &bh);
+ bh->b_count--;
+ next->b_count--;
+ }
+ /* If we didn't write anything, but there are still
+ * dirty buffers, then make the next write to a
+ * loop device to be a blocking write.
+ * This lets us block--which we _must_ do! */
+ if (ndirty == 0
+ && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
+ wrta_cmd = WRITE;
+ goto restart;
}
- run_task_queue(&tq_disk);
+
#ifdef DEBUG
if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount);
- printk("Wrote %d/%d buffers\n", nwritten, ndirty);
+ printk("wrote %d/%d buffers...", nwritten, ndirty);
#endif
run_task_queue(&tq_disk);
- return 0;
}
@@ -1669,10 +1687,12 @@ asmlinkage int sys_bdflush(int func, long data)
if (!capable(CAP_SYS_ADMIN))
goto out;
- if (func == 1) {
- error = sync_old_buffers();
- goto out;
- }
+ if (func == 1)
+ /* Func 1 used to call sync_old_buffers; a user space
+ daemon would call it periodically. This is no
+ longer necessary. Returning -EPERM here makes the
+ daemon silently exit. */
+ goto out;
/* Basically func 1 means read param 1, 2 means write param 1, etc */
if (func >= 2) {
@@ -1701,27 +1721,17 @@ out:
return error;
}
-/* This is the actual bdflush daemon itself. It used to be started from
- * the syscall above, but now we launch it ourselves internally with
- * kernel_thread(...) directly after the first thread in init/main.c */
+/* This is the actual bdflush daemon itself. It used to be started
+ * from the syscall above, but now we launch it ourselves internally
+ * with kernel_thread(...) directly after the first thread in
+ * init/main.c. Every so often, or when woken up by another task that
+ * needs memory, we call sync_old_buffers to partially clear the dirty list.
+ */
-/* To prevent deadlocks for a loop device:
- * 1) Do non-blocking writes to loop (avoids deadlock with running
- * out of request blocks).
- * 2) But do a blocking write if the only dirty buffers are loop buffers
- * (otherwise we go into an infinite busy-loop).
- * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
- * with running out of free buffers for loop's "real" device).
-*/
int bdflush(void * unused)
{
- int i;
- int ndirty;
- int nlist;
- int ncount;
- struct buffer_head * bh, *next;
- int major;
- int wrta_cmd = WRITEA; /* non-blocking write for LOOP */
+ long remaining = HZ * bdf_prm.b_un.interval;
+ struct task_struct *tsk = current;
/*
* We have a bare-bones task_struct, and really should fill
@@ -1729,10 +1739,12 @@ int bdflush(void * unused)
* display semi-sane things. Not real crucial though...
*/
- current->session = 1;
- current->pgrp = 1;
- sprintf(current->comm, "kflushd");
- bdflush_tsk = current;
+ tsk->session = 1;
+ tsk->pgrp = 1;
+ tsk->dumpable = 0; /* inhibit ptrace() */
+ strcpy(tsk->comm, "kflushd");
+ sigfillset(&tsk->blocked);
+ bdflush_tsk = tsk;
/*
* As a kernel thread we want to tamper with system buffers
@@ -1742,88 +1754,36 @@ int bdflush(void * unused)
lock_kernel();
for (;;) {
+ tsk->state = TASK_INTERRUPTIBLE;
+ remaining = schedule_timeout(remaining);
+
#ifdef DEBUG
printk("bdflush() activated...");
#endif
-
CHECK_EMERGENCY_SYNC
- ncount = 0;
-#ifdef DEBUG
- for(nlist = 0; nlist < NR_LIST; nlist++)
-#else
- for(nlist = BUF_DIRTY; nlist <= BUF_DIRTY; nlist++)
-#endif
- {
- ndirty = 0;
- repeat:
-
- bh = lru_list[nlist];
- if(bh)
- for (i = nr_buffers_type[nlist]; i-- > 0 && ndirty < bdf_prm.b_un.ndirty;
- bh = next) {
- /* We may have stalled while waiting for I/O to complete. */
- if(bh->b_list != nlist) goto repeat;
- next = bh->b_next_free;
- if(!lru_list[nlist]) {
- printk("Dirty list empty %d\n", i);
- break;
- }
-
- /* Clean buffer on dirty list? Refile it */
- if (nlist == BUF_DIRTY && !buffer_dirty(bh) && !buffer_locked(bh))
- {
- refile_buffer(bh);
- continue;
- }
-
- if (buffer_locked(bh) || !buffer_dirty(bh))
- continue;
- major = MAJOR(bh->b_dev);
- /* Should we write back buffers that are shared or not??
- currently dirty buffers are not shared, so it does not matter */
- next->b_count++;
- bh->b_count++;
- ndirty++;
- bh->b_flushtime = 0;
- if (major == LOOP_MAJOR) {
- ll_rw_block(wrta_cmd,1, &bh);
- wrta_cmd = WRITEA;
- if (buffer_dirty(bh))
- --ndirty;
- }
- else
- ll_rw_block(WRITE, 1, &bh);
-#ifdef DEBUG
- if(nlist != BUF_DIRTY) ncount++;
-#endif
- bh->b_count--;
- next->b_count--;
- }
- }
+ if (remaining == 0) {
+ /*
+ * Also try to flush inodes and supers, since
+ * otherwise there would be no way of ensuring
+ * that these quantities ever get written
+ * back. Ideally, we would have a timestamp
+ * on the inodes and superblocks so that we
+ * could write back only the old ones.
+ */
+ sync_supers(0);
+ sync_inodes(0);
+ remaining = HZ * bdf_prm.b_un.interval;
+ }
+
+ /* Keep flushing till there aren't very many dirty buffers */
+ do {
+ sync_old_buffers();
+ } while(nr_buffers_type[BUF_DIRTY] > nr_buffers * bdf_prm.b_un.nfract/100);
+
+ wake_up(&bdflush_done);
#ifdef DEBUG
- if (ncount) printk("sys_bdflush: %d dirty buffers not on dirty list\n", ncount);
printk("sleeping again.\n");
#endif
- /* If we didn't write anything, but there are still
- * dirty buffers, then make the next write to a
- * loop device to be a blocking write.
- * This lets us block--which we _must_ do! */
- if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
- wrta_cmd = WRITE;
- continue;
- }
- run_task_queue(&tq_disk);
- wake_up(&bdflush_done);
-
- /* 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) {
- spin_lock_irq(&current->sigmask_lock);
- flush_signals(current);
- spin_unlock_irq(&current->sigmask_lock);
-
- interruptible_sleep_on(&bdflush_wait);
- }
}
}
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 7ba943cd6..b3c0195a3 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -29,7 +29,7 @@
/* dir inode-ops */
static int coda_create(struct inode *dir, struct dentry *new, int mode);
static int coda_mknod(struct inode *dir, struct dentry *new, int mode, int rdev);
-static int coda_lookup(struct inode *dir, struct dentry *target);
+static struct dentry *coda_lookup(struct inode *dir, struct dentry *target);
static int coda_link(struct dentry *old_dentry, struct inode *dir_inode,
struct dentry *entry);
static int coda_unlink(struct inode *dir_inode, struct dentry *entry);
@@ -44,7 +44,7 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
/* dentry ops */
-static int coda_dentry_revalidate(struct dentry *de);
+static int coda_dentry_revalidate(struct dentry *de, int);
static void coda_dentry_delete(struct dentry *);
/* support routines */
@@ -107,7 +107,7 @@ struct file_operations coda_dir_operations = {
/* inode operations for directories */
/* acces routines: lookup, readlink, permission */
-static int coda_lookup(struct inode *dir, struct dentry *entry)
+static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry)
{
struct coda_inode_info *dircnp;
struct inode *res_inode = NULL;
@@ -125,16 +125,9 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
if ( length > CODA_MAXNAMLEN ) {
printk("name too long: lookup, %s (%*s)\n",
coda_f2s(&dircnp->c_fid), length, name);
- return -ENAMETOOLONG;
+ return ERR_PTR(-ENAMETOOLONG);
}
-
- if (!dir || !S_ISDIR(dir->i_mode)) {
- printk("coda_lookup: inode is NULL or not a directory\n");
- return -ENOTDIR;
- }
-
-
CDEBUG(D_INODE, "name %s, len %d in ino %ld, fid %s\n",
name, length, dir->i_ino, coda_f2s(&dircnp->c_fid));
@@ -160,11 +153,11 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
}
error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
if (error)
- return error;
+ return ERR_PTR(error);
} else if (error != -ENOENT) {
CDEBUG(D_INODE, "error for %s(%*s)%d\n",
coda_f2s(&dircnp->c_fid), length, name, error);
- return error;
+ return ERR_PTR(error);
}
CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n",
name, coda_f2s(&resfid), type, error, dropme);
@@ -178,7 +171,7 @@ exit:
ITOC(res_inode)->c_flags |= C_VATTR;
}
EXIT;
- return 0;
+ return NULL;
}
@@ -236,22 +229,11 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
CDEBUG(D_INODE, "name: %s, length %d, mode %o\n",name, length, mode);
- if (!dir || !S_ISDIR(dir->i_mode)) {
- printk("coda_create: inode is null or not a directory\n");
- return -ENOENT;
- }
-
if (coda_isroot(dir) && coda_iscontrol(name, length))
return -EPERM;
dircnp = ITOC(dir);
- if ( length > CODA_MAXNAMLEN ) {
- printk("name too long: create, %s(%s)\n",
- coda_f2s(&dircnp->c_fid), name);
- return -ENAMETOOLONG;
- }
-
error = venus_create(dir->i_sb, &(dircnp->c_fid), name, length,
0, mode, 0, &newfid, &attrs);
@@ -292,22 +274,11 @@ static int coda_mknod(struct inode *dir, struct dentry *de, int mode, int rdev)
CDEBUG(D_INODE, "name: %s, length %d, mode %o, rdev %x\n",name, length, mode, rdev);
- if (!dir || !S_ISDIR(dir->i_mode)) {
- printk("coda_mknod: inode is null or not a directory\n");
- return -ENOENT;
- }
-
if (coda_isroot(dir) && coda_iscontrol(name, length))
return -EPERM;
dircnp = ITOC(dir);
- if ( length > CODA_MAXNAMLEN ) {
- printk("name too long: mknod, %s(%s)\n",
- coda_f2s(&dircnp->c_fid), name);
- return -ENAMETOOLONG;
- }
-
error = venus_create(dir->i_sb, &(dircnp->c_fid), name, length,
0, mode, rdev, &newfid, &attrs);
@@ -344,14 +315,6 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
ENTRY;
coda_vfs_stat.mkdir++;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- printk("coda_mkdir: inode is NULL or not a directory\n");
- return -ENOENT;
- }
-
- if ( len > CODA_MAXNAMLEN )
- return -ENAMETOOLONG;
-
if (coda_isroot(dir) && coda_iscontrol(name, len))
return -EPERM;
@@ -409,11 +372,6 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
CDEBUG(D_INODE, "old: fid: %s\n", coda_f2s(&(cnp->c_fid)));
CDEBUG(D_INODE, "directory: %s\n", coda_f2s(&(dir_cnp->c_fid)));
- if ( len > CODA_MAXNAMLEN ) {
- printk("coda_link: name too long. \n");
- return -ENAMETOOLONG;
- }
-
error = venus_link(dir_inode->i_sb,&(cnp->c_fid), &(dir_cnp->c_fid),
(const char *)name, len);
@@ -448,9 +406,6 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
return -EPERM;
- if ( len > CODA_MAXNAMLEN )
- return -ENAMETOOLONG;
-
symlen = strlen(symname);
if ( symlen > CODA_MAXPATHLEN )
return -ENAMETOOLONG;
@@ -513,15 +468,8 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
ENTRY;
coda_vfs_stat.rmdir++;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- printk("coda_rmdir: inode is NULL or not a directory\n");
- return -ENOENT;
- }
dircnp = ITOC(dir);
- if (len > CODA_MAXNAMLEN)
- return -ENAMETOOLONG;
-
if (!list_empty(&de->d_hash))
return -EBUSY;
error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len);
@@ -545,7 +493,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
const char *new_name = new_dentry->d_name.name;
int old_length = old_dentry->d_name.len;
int new_length = new_dentry->d_name.len;
- struct inode *old_inode = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode;
struct coda_inode_info *new_cnp, *old_cnp;
int error;
@@ -553,10 +500,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
ENTRY;
coda_vfs_stat.rename++;
- if ( (old_length > CODA_MAXNAMLEN) || new_length > CODA_MAXNAMLEN ) {
- return -ENAMETOOLONG;
- }
-
old_cnp = ITOC(old_dir);
new_cnp = ITOC(new_dir);
@@ -565,21 +508,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
old_name, old_length, strlen(old_name), new_name, new_length,
strlen(new_name),old_dentry->d_count, new_dentry->d_count);
- if (new_inode == old_inode)
- return 0;
-
- /* make sure target is not in use */
- if (new_inode && S_ISDIR(new_inode->i_mode)) {
- /*
- * Prune any children before testing for busy.
- */
- if (new_dentry->d_count > 1)
- shrink_dcache_parent(new_dentry);
-
- if (new_dentry->d_count > 1)
- return -EBUSY;
- }
-
/* the C library will do unlink/create etc */
if ( coda_crossvol_rename == 0 &&
old_cnp->c_fid.Volume != new_cnp->c_fid.Volume )
@@ -599,7 +527,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
coda_flag_inode(new_dir, C_VATTR);
CDEBUG(D_INODE, "result %d\n", error);
- d_move(old_dentry, new_dentry);
EXIT;
return 0;
@@ -619,11 +546,6 @@ int coda_readdir(struct file *file, void *dirent, filldir_t filldir)
ENTRY;
coda_vfs_stat.readdir++;
- if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) {
- printk("coda_readdir: inode is NULL or not a directory\n");
- return -EBADF;
- }
-
cnp = ITOC(inode);
if ( !cnp->c_ovp ) {
CDEBUG(D_FILE, "open inode pointer = NULL.\n");
@@ -637,7 +559,9 @@ int coda_readdir(struct file *file, void *dirent, filldir_t filldir)
result = coda_venus_readdir(&open_file, dirent, filldir);
} else {
/* potemkin case: we are handed a directory inode */
+ down(&cnp->c_ovp->i_sem);
result = open_file.f_op->readdir(&open_file, dirent, filldir);
+ up(&cnp->c_ovp->i_sem);
}
coda_restore_codafile(inode, file, cnp->c_ovp, &open_file);
EXIT;
@@ -854,7 +778,7 @@ exit:
}
/* called when a cache lookup succeeds */
-static int coda_dentry_revalidate(struct dentry *de)
+static int coda_dentry_revalidate(struct dentry *de, int flags)
{
int valid = 1;
struct inode *inode = de->d_inode;
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 9c0846b02..55eed097a 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -23,9 +23,6 @@
#include <linux/fs.h>
#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/locks.h>
-#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <asm/segment.h>
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c
index 8f3bd532a..79a4c7ebb 100644
--- a/fs/coda/sysctl.c
+++ b/fs/coda/sysctl.c
@@ -24,6 +24,8 @@
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/utsname.h>
+#define __NO_VERSION__
+#include <linux/module.h>
#include <linux/coda.h>
#include <linux/coda_linux.h>
@@ -491,6 +493,14 @@ struct proc_dir_entry proc_coda_cache_inv = {
coda_cache_inv_stats_get_info
};
+static void coda_proc_modcount(struct inode *inode, int fill)
+{
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+}
+
#endif
@@ -504,6 +514,7 @@ void coda_sysctl_init()
#ifdef CONFIG_PROC_FS
proc_register(&proc_root_fs,&proc_fs_coda);
+ proc_fs_coda.fill_inode = &coda_proc_modcount;
proc_register(&proc_fs_coda,&proc_coda_vfs);
proc_register(&proc_fs_coda,&proc_coda_upcall);
proc_register(&proc_fs_coda,&proc_coda_permission);
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 4c640892d..d3f0161a3 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -30,7 +30,6 @@
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
-#include <asm/segment.h>
#include <linux/coda.h>
#include <linux/coda_linux.h>
diff --git a/fs/dcache.c b/fs/dcache.c
index 51c7869b3..aa299f61e 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2,7 +2,8 @@
* fs/dcache.c
*
* Complete reimplementation
- * (C) 1997 Thomas Schoebel-Theuer
+ * (C) 1997 Thomas Schoebel-Theuer,
+ * with heavy changes by Linus Torvalds
*/
/*
@@ -470,7 +471,12 @@ void shrink_dcache_parent(struct dentry * parent)
*/
void shrink_dcache_memory(int priority, unsigned int gfp_mask)
{
- prune_dcache(0);
+ if (gfp_mask & __GFP_IO) {
+ int count = 0;
+ if (priority)
+ count = dentry_stat.nr_unused / priority;
+ prune_dcache(count);
+ }
}
#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
diff --git a/fs/devpts/root.c b/fs/devpts/root.c
index f517367b9..c284f1d97 100644
--- a/fs/devpts/root.c
+++ b/fs/devpts/root.c
@@ -17,8 +17,8 @@
#include "devpts_i.h"
static int devpts_root_readdir(struct file *,void *,filldir_t);
-static int devpts_root_lookup(struct inode *,struct dentry *);
-static int devpts_revalidate(struct dentry *);
+static struct dentry *devpts_root_lookup(struct inode *,struct dentry *);
+static int devpts_revalidate(struct dentry *, int);
static struct file_operations devpts_root_operations = {
NULL, /* llseek */
@@ -81,9 +81,6 @@ static int devpts_root_readdir(struct file *filp, void *dirent, filldir_t filldi
off_t nr;
char numbuf[16];
- if (!inode || !S_ISDIR(inode->i_mode))
- return -ENOTDIR;
-
nr = filp->f_pos;
switch(nr)
@@ -119,7 +116,7 @@ static int devpts_root_readdir(struct file *filp, void *dirent, filldir_t filldi
* the pty really does still exist. Never revalidate negative dentries;
* for simplicity (fix later?)
*/
-static int devpts_revalidate(struct dentry * dentry)
+static int devpts_revalidate(struct dentry * dentry, int flags)
{
struct devpts_sb_info *sbi;
@@ -131,42 +128,39 @@ static int devpts_revalidate(struct dentry * dentry)
return ( sbi->inodes[dentry->d_inode->i_ino - 2] == dentry->d_inode );
}
-static int devpts_root_lookup(struct inode * dir, struct dentry * dentry)
+static struct dentry *devpts_root_lookup(struct inode * dir, struct dentry * dentry)
{
struct devpts_sb_info *sbi = SBI(dir->i_sb);
unsigned int entry;
int i;
const char *p;
- if (!S_ISDIR(dir->i_mode))
- return -ENOTDIR;
-
dentry->d_inode = NULL; /* Assume failure */
dentry->d_op = &devpts_dentry_operations;
if ( dentry->d_name.len == 1 && dentry->d_name.name[0] == '0' ) {
entry = 0;
} else if ( dentry->d_name.len < 1 ) {
- return 0;
+ return NULL;
} else {
p = dentry->d_name.name;
if ( *p < '1' || *p > '9' )
- return 0;
+ return NULL;
entry = *p++ - '0';
for ( i = dentry->d_name.len-1 ; i ; i-- ) {
unsigned int nentry = *p++ - '0';
if ( nentry > 9 )
- return 0;
+ return NULL;
nentry += entry * 10;
if (nentry < entry)
- return 0;
+ return NULL;
entry = nentry;
}
}
if ( entry >= sbi->max_ptys )
- return 0;
+ return NULL;
dentry->d_inode = sbi->inodes[entry];
if ( dentry->d_inode )
@@ -174,5 +168,5 @@ static int devpts_root_lookup(struct inode * dir, struct dentry * dentry)
d_add(dentry, dentry->d_inode);
- return 0;
+ return NULL;
}
diff --git a/fs/dquot.c b/fs/dquot.c
index 8b7d07295..76630352f 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -483,7 +483,10 @@ got_it:
if (dquot->dq_flags & (DQ_LOCKED | DQ_MOD)) {
wait_on_dquot(dquot);
if (dquot->dq_flags & DQ_MOD)
- write_dquot(dquot);
+ {
+ if(dquot->dq_mnt != (struct vfsmount *)NULL)
+ write_dquot(dquot);
+ }
/*
* The dquot may be back in use now, so we
* must recheck the free list.
@@ -1265,11 +1268,11 @@ out:
int quota_on(kdev_t dev, short type, char *path)
{
- struct file *filp = NULL;
- struct dentry *dentry;
+ struct file *f;
struct vfsmount *vfsmnt;
struct inode *inode;
struct dquot *dquot;
+ struct quota_mount_options *mnt_dquot;
char *tmp;
int error;
@@ -1278,69 +1281,48 @@ int quota_on(kdev_t dev, short type, char *path)
return -ENODEV;
if (is_enabled(vfsmnt, type))
- return(-EBUSY);
+ return -EBUSY;
+ mnt_dquot = &vfsmnt->mnt_dquot;
tmp = getname(path);
error = PTR_ERR(tmp);
if (IS_ERR(tmp))
return error;
- dentry = open_namei(tmp, O_RDWR, 0600);
+ f = filp_open(tmp, O_RDWR, 0600);
putname(tmp);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ /* sanity checks */
+ error = -EIO;
+ if (!f->f_op->read && !f->f_op->write)
+ goto cleanup;
+ inode = f->f_dentry->d_inode;
+ error = -EACCES;
+ if (!S_ISREG(inode->i_mode))
+ goto cleanup;
+ error = -EINVAL;
+ if (inode->i_size == 0 || (inode->i_size % sizeof(struct dqblk)) != 0)
+ goto cleanup;
+
+ /* OK, there we go */
+ set_enable_flags(vfsmnt, type);
+ mnt_dquot->files[type] = f;
+
+ dquot = dqget(dev, 0, type);
+ mnt_dquot->inode_expire[type] = (dquot) ? dquot->dq_itime : MAX_IQ_TIME;
+ mnt_dquot->block_expire[type] = (dquot) ? dquot->dq_btime : MAX_DQ_TIME;
+ dqput(dquot);
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- return error;
- inode = dentry->d_inode;
-
- if (!S_ISREG(inode->i_mode)) {
- dput(dentry);
- return -EACCES;
- }
-
- if (inode->i_size == 0 || (inode->i_size % sizeof(struct dqblk)) != 0) {
- dput(dentry);
- return(-EINVAL);
- }
-
- filp = get_empty_filp();
- if (filp != (struct file *)NULL) {
- filp->f_mode = (O_RDWR + 1) & O_ACCMODE;
- filp->f_flags = O_RDWR;
- filp->f_dentry = dentry;
- filp->f_pos = 0;
- filp->f_reada = 0;
- filp->f_op = inode->i_op->default_file_ops;
- if (filp->f_op->read || filp->f_op->write) {
- error = get_write_access(inode);
- if (!error) {
- if (filp->f_op && filp->f_op->open)
- error = filp->f_op->open(inode, filp);
- if (!error) {
- set_enable_flags(vfsmnt, type);
- vfsmnt->mnt_dquot.files[type] = filp;
-
- dquot = dqget(dev, 0, type);
- vfsmnt->mnt_dquot.inode_expire[type] = (dquot) ? dquot->dq_itime : MAX_IQ_TIME;
- vfsmnt->mnt_dquot.block_expire[type] = (dquot) ? dquot->dq_btime : MAX_DQ_TIME;
- dqput(dquot);
-
- vfsmnt->mnt_sb->dq_op = &dquot_operations;
- add_dquot_ref(dev, type);
-
- return(0);
- }
- put_write_access(inode);
- }
- } else
- error = -EIO;
- put_filp(filp);
- } else
- error = -EMFILE;
+ vfsmnt->mnt_sb->dq_op = &dquot_operations;
+ add_dquot_ref(dev, type);
- dput(dentry);
+ return(0);
- return(error);
+cleanup:
+ fput(f);
+ return error;
}
/*
@@ -1367,8 +1349,8 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
case Q_GETSTATS:
break;
case Q_GETQUOTA:
- if (((type == USRQUOTA && current->uid != id) ||
- (type == GRPQUOTA && current->gid != id)) &&
+ if (((type == USRQUOTA && current->euid != id) ||
+ (type == GRPQUOTA && current->egid != id)) &&
!capable(CAP_SYS_RESOURCE))
goto out;
break;
diff --git a/fs/exec.c b/fs/exec.c
index 943e97f49..cf5dc765b 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -29,7 +29,6 @@
#include <linux/a.out.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
-#include <linux/user.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 22af55334..a6753d276 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -115,8 +115,6 @@ static int ext2_readdir(struct file * filp,
int err;
struct inode *inode = filp->f_dentry->d_inode;
- if (!inode || !S_ISDIR(inode->i_mode))
- return -EBADF;
sb = inode->i_sb;
stored = 0;
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index f0f2ca98f..8bd5c9684 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -286,7 +286,8 @@ static struct buffer_head * block_getblk (struct inode * inode,
u32 * p;
struct buffer_head * result;
int blocks = inode->i_sb->s_blocksize / 512;
-
+ unsigned long limit;
+
if (!bh)
return NULL;
if (!buffer_uptodate(bh)) {
@@ -309,13 +310,22 @@ repeat:
brelse (result);
goto repeat;
}
- if (!create || new_block >=
- (current->rlim[RLIMIT_FSIZE].rlim_cur >>
- EXT2_BLOCK_SIZE_BITS(inode->i_sb))) {
+ *err = -EFBIG;
+ if (!create) {
brelse (bh);
- *err = -EFBIG;
return NULL;
}
+
+ limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit < RLIM_INFINITY) {
+ limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
+ if (new_block >= limit) {
+ brelse (bh);
+ send_sig(SIGXFSZ, current, 0);
+ return NULL;
+ }
+ }
+
if (inode->u.ext2_i.i_next_alloc_block == new_block)
goal = inode->u.ext2_i.i_next_alloc_goal;
if (!goal) {
@@ -697,7 +707,7 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
if (buffer_req(bh) && !buffer_uptodate(bh)) {
printk ("IO error syncing ext2 inode ["
"%s:%08lx]\n",
- kdevname(inode->i_dev), inode->i_ino);
+ bdevname(inode->i_dev), inode->i_ino);
err = -EIO;
}
}
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 5f66f5dab..7a309fa77 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -74,8 +74,6 @@ static struct buffer_head * ext2_find_entry (struct inode * dir,
int block, toread, i, err;
*res_dir = NULL;
- if (!dir)
- return NULL;
sb = dir->i_sb;
if (namelen > EXT2_NAME_LEN)
@@ -168,14 +166,14 @@ failure:
return NULL;
}
-int ext2_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry)
{
struct inode * inode;
struct ext2_dir_entry_2 * de;
struct buffer_head * bh;
if (dentry->d_name.len > EXT2_NAME_LEN)
- return -ENAMETOOLONG;
+ return ERR_PTR(-ENAMETOOLONG);
bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
inode = NULL;
@@ -185,10 +183,10 @@ int ext2_lookup(struct inode * dir, struct dentry *dentry)
inode = iget(dir->i_sb, ino);
if (!inode)
- return -EACCES;
+ return ERR_PTR(-EACCES);
}
d_add(dentry, inode);
- return 0;
+ return NULL;
}
/*
@@ -218,12 +216,6 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
return NULL;
sb = dir->i_sb;
- if (namelen > EXT2_NAME_LEN)
- {
- *err = -ENAMETOOLONG;
- return NULL;
- }
-
if (!namelen)
return NULL;
/*
@@ -409,10 +401,6 @@ int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
struct ext2_dir_entry_2 * de;
int err = -EIO;
- err = -ENAMETOOLONG;
- if (dentry->d_name.len > EXT2_NAME_LEN)
- goto out;
-
inode = ext2_new_inode (dir, mode, &err);
if (!inode)
goto out;
@@ -474,10 +462,6 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
struct ext2_dir_entry_2 * de;
int err;
- err = -ENAMETOOLONG;
- if (dentry->d_name.len > EXT2_NAME_LEN)
- goto out;
-
err = -EMLINK;
if (dir->i_nlink >= EXT2_LINK_MAX)
goto out;
@@ -618,10 +602,6 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
struct buffer_head * bh;
struct ext2_dir_entry_2 * de;
- retval = -ENAMETOOLONG;
- if (dentry->d_name.len > EXT2_NAME_LEN)
- goto out;
-
retval = -ENOENT;
bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
if (!bh)
@@ -634,14 +614,12 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
if (le32_to_cpu(de->inode) != inode->i_ino)
goto end_rmdir;
+ retval = -ENOTEMPTY;
if (!empty_dir (inode))
- retval = -ENOTEMPTY;
- else if (le32_to_cpu(de->inode) != inode->i_ino)
- retval = -ENOENT;
- else {
- retval = ext2_delete_entry (de, bh);
- dir->i_version = ++event;
- }
+ goto end_rmdir;
+
+ retval = ext2_delete_entry (de, bh);
+ dir->i_version = ++event;
if (retval)
goto end_rmdir;
mark_buffer_dirty(bh, 1);
@@ -665,7 +643,6 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
end_rmdir:
brelse (bh);
-out:
return retval;
}
@@ -676,10 +653,6 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry)
struct buffer_head * bh;
struct ext2_dir_entry_2 * de;
- retval = -ENAMETOOLONG;
- if (dentry->d_name.len > EXT2_NAME_LEN)
- goto out;
-
retval = -ENOENT;
bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
if (!bh)
@@ -718,7 +691,6 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry)
end_unlink:
brelse (bh);
-out:
return retval;
}
@@ -805,9 +777,6 @@ int ext2_link (struct dentry * old_dentry,
if (S_ISDIR(inode->i_mode))
return -EPERM;
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- return -EPERM;
-
if (inode->i_nlink >= EXT2_LINK_MAX)
return -EMLINK;
@@ -851,17 +820,10 @@ int ext2_link (struct dentry * old_dentry,
le16_to_cpu(((struct ext2_dir_entry_2 *) buffer)->rec_len)))->inode
/*
- * rename uses retrying to avoid race-conditions: at least they should be
- * minimal.
- * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
- * checks fail, it tries to restart itself again. Very practical - no changes
- * are done until we know everything works ok.. and then all the changes can be
- * done in one fell swoop when we have claimed all the buffers needed.
- *
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
+int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
struct inode * new_dir,struct dentry *new_dentry)
{
struct inode * old_inode, * new_inode;
@@ -870,9 +832,6 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
int retval;
old_bh = new_bh = dir_bh = NULL;
- retval = -ENAMETOOLONG;
- if (old_dentry->d_name.len > EXT2_NAME_LEN)
- goto end_rename;
old_bh = ext2_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
/*
@@ -897,24 +856,13 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
DQUOT_INIT(new_inode);
}
}
- retval = 0;
- if (new_inode == old_inode)
- goto end_rename;
if (S_ISDIR(old_inode->i_mode)) {
- retval = -EINVAL;
- if (is_subdir(new_dentry, old_dentry))
- goto end_rename;
if (new_inode) {
- /* Prune any children before testing for busy */
- if (new_dentry->d_count > 1)
- shrink_dcache_parent(new_dentry);
- retval = -EBUSY;
- if (new_dentry->d_count > 1)
- goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir (new_inode))
goto end_rename;
}
+ retval = -EIO;
dir_bh = ext2_bread (old_inode, 0, 0, &retval);
if (!dir_bh)
goto end_rename;
@@ -977,8 +925,6 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
wait_on_buffer (new_bh);
}
- /* Update the dcache */
- d_move(old_dentry, new_dentry);
retval = 0;
end_rename:
@@ -987,30 +933,3 @@ end_rename:
brelse (new_bh);
return retval;
}
-
-/*
- * Ok, rename also locks out other renames, as they can change the parent of
- * a directory, and we don't want any races. Other races are checked for by
- * "do_rename()", which restarts if there are inconsistencies.
- *
- * Note that there is no race between different filesystems: it's only within
- * the same device that races occur: many renames can happen at once, as long
- * as they are on different partitions.
- *
- * In the second extended file system, we use a lock flag stored in the memory
- * super-block. This way, we really lock other renames only if they occur
- * on the same file system
- */
-int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
- struct inode * new_dir, struct dentry *new_dentry)
-{
- int result;
-
- while (old_dir->i_sb->u.ext2_sb.s_rename_lock)
- sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
- old_dir->i_sb->u.ext2_sb.s_rename_lock = 1;
- result = do_ext2_rename (old_dir, old_dentry, new_dir, new_dentry);
- old_dir->i_sb->u.ext2_sb.s_rename_lock = 0;
- wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
- return result;
-}
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 674a5043c..b7c08a009 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -56,9 +56,9 @@ void ext2_error (struct super_block * sb, const char * function,
(le16_to_cpu(sb->u.ext2_sb.s_es->s_errors) == EXT2_ERRORS_PANIC &&
!test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_RO)))
panic ("EXT2-fs panic (device %s): %s: %s\n",
- kdevname(sb->s_dev), function, error_buf);
+ bdevname(sb->s_dev), function, error_buf);
printk (KERN_CRIT "EXT2-fs error (device %s): %s: %s\n",
- kdevname(sb->s_dev), function, error_buf);
+ bdevname(sb->s_dev), function, error_buf);
if (test_opt (sb, ERRORS_RO) ||
(le16_to_cpu(sb->u.ext2_sb.s_es->s_errors) == EXT2_ERRORS_RO &&
!test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_PANIC))) {
@@ -87,7 +87,7 @@ NORET_TYPE void ext2_panic (struct super_block * sb, const char * function,
sb->s_lock=0;
sb->s_flags |= MS_RDONLY;
panic ("EXT2-fs panic (device %s): %s: %s\n",
- kdevname(sb->s_dev), function, error_buf);
+ bdevname(sb->s_dev), function, error_buf);
}
void ext2_warning (struct super_block * sb, const char * function,
@@ -99,7 +99,7 @@ void ext2_warning (struct super_block * sb, const char * function,
vsprintf (error_buf, fmt, args);
va_end (args);
printk (KERN_WARNING "EXT2-fs warning (device %s): %s: %s\n",
- kdevname(sb->s_dev), function, error_buf);
+ bdevname(sb->s_dev), function, error_buf);
}
void ext2_put_super (struct super_block * sb)
@@ -444,7 +444,7 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
if (sb->s_magic != EXT2_SUPER_MAGIC) {
if (!silent)
printk ("VFS: Can't find an ext2 filesystem on dev "
- "%s.\n", kdevname(dev));
+ "%s.\n", bdevname(dev));
failed_mount:
sb->s_dev = 0;
unlock_super (sb);
@@ -457,14 +457,14 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
if (le32_to_cpu(es->s_feature_incompat) & ~EXT2_FEATURE_INCOMPAT_SUPP) {
printk("EXT2-fs: %s: couldn't mount because of "
"unsupported optional features.\n",
- kdevname(dev));
+ bdevname(dev));
goto failed_mount;
}
if (!(sb->s_flags & MS_RDONLY) &&
(le32_to_cpu(es->s_feature_ro_compat) & ~EXT2_FEATURE_RO_COMPAT_SUPP)) {
printk("EXT2-fs: %s: couldn't mount RDWR because of "
"unsupported optional features.\n",
- kdevname(dev));
+ bdevname(dev));
goto failed_mount;
}
}
@@ -543,8 +543,6 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
else
sb->u.ext2_sb.s_resgid = le16_to_cpu(es->s_def_resgid);
sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state);
- sb->u.ext2_sb.s_rename_lock = 0;
- sb->u.ext2_sb.s_rename_wait = NULL;
sb->u.ext2_sb.s_addr_per_block_bits =
log2 (EXT2_ADDR_PER_BLOCK(sb));
sb->u.ext2_sb.s_desc_per_block_bits =
@@ -553,13 +551,13 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
if (!silent)
printk ("VFS: Can't find an ext2 filesystem on dev "
"%s.\n",
- kdevname(dev));
+ bdevname(dev));
goto failed_mount;
}
if (sb->s_blocksize != bh->b_size) {
if (!silent)
printk ("VFS: Unsupported blocksize on dev "
- "%s.\n", kdevname(dev));
+ "%s.\n", bdevname(dev));
goto failed_mount;
}
diff --git a/fs/fat/cvf.c b/fs/fat/cvf.c
index 62b70b160..9dd70f8c5 100644
--- a/fs/fat/cvf.c
+++ b/fs/fat/cvf.c
@@ -1,8 +1,11 @@
-/*
+/*
* CVF extensions for fat-based filesystems
*
* written 1997,1998 by Frank Gockel <gockel@sent13.uni-duisburg.de>
*
+ * please do not remove the next line, dmsdos needs it for verifying patches
+ * CVF-FAT-VERSION-ID: 1.2.0
+ *
*/
#include<linux/sched.h>
@@ -11,6 +14,10 @@
#include<linux/msdos_fs_sb.h>
#include<linux/string.h>
#include<linux/fat_cvf.h>
+#include<linux/config.h>
+#ifdef CONFIG_KMOD
+#include<linux/kmod.h>
+#endif
#define MAX_CVF_FORMATS 3
@@ -95,6 +102,24 @@ int detect_cvf(struct super_block*sb,char*force)
int found_i=-1;
if(force)
+ if(strcmp(force,"autoload")==0)
+ {
+#ifdef CONFIG_KMOD
+ request_module("cvf_autoload");
+ force=NULL;
+#else
+ printk("cannot autoload CVF modules: kmod support is not compiled into kernel\n");
+ return -1;
+#endif
+ }
+
+#ifdef CONFIG_KMOD
+ if(force)
+ if(*force)
+ request_module(force);
+#endif
+
+ if(force)
{ if(*force)
{ for(i=0;i<MAX_CVF_FORMATS;++i)
{ if(cvf_formats[i])
@@ -102,6 +127,8 @@ int detect_cvf(struct super_block*sb,char*force)
return i;
}
}
+ printk("CVF format %s unknown (module not loaded?)\n",force);
+ return -1;
}
}
@@ -115,6 +142,6 @@ int detect_cvf(struct super_block*sb,char*force)
}
if(found==1)return found_i;
- if(found>1)printk("CVF detection ambiguous, use cvf_format=xxx option\n");
+ if(found>1)printk("CVF detection ambiguous, please use cvf_format=xxx option\n");
return -1;
}
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 1c44247a0..b6d6fb405 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -9,6 +9,7 @@
*
* VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
* Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
+ * Plugged buffer overrun in readdir(). AV
*/
#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
@@ -59,6 +60,7 @@ struct file_operations fat_dir_operations = {
* characters are a sort of uuencoded 16 bit Unicode value. This lets
* us do a full dump and restore of Unicode filenames. We could get
* into some trouble with long Unicode names, but ignore that right now.
+ * Ahem... Stack smashing in ring 0 isn't fun. Fixed.
*/
static int
uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate,
@@ -93,6 +95,11 @@ uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate,
*op++ = '?';
}
}
+ /* We have some slack there, so it's OK */
+ if (op>ascii+256) {
+ op = ascii + 256;
+ break;
+ }
}
*op = 0;
return (op - ascii);
@@ -138,8 +145,6 @@ int fat_readdirx(
unsigned char *unicode = NULL;
struct nls_table *nls = MSDOS_SB(sb)->nls_io;
- if (!inode || !S_ISDIR(inode->i_mode))
- return -EBADF;
/* Fake . and .. for the root directory. */
if (inode->i_ino == MSDOS_ROOT_INO) {
while (oldpos < 2) {
@@ -186,9 +191,17 @@ int fat_readdirx(
id = ds->id;
if (id & 0x40) {
slots = id & ~0x40;
- long_slots = slots;
- is_long = 1;
- alias_checksum = ds->alias_checksum;
+ /*
+ * Dirty, but not dirtier than the original,
+ * and plugs the hole.
+ */
+ if (slots > 20)
+ slots = 0;
+ else {
+ long_slots = slots;
+ is_long = 1;
+ alias_checksum = ds->alias_checksum;
+ }
}
get_new_entry = 1;
diff --git a/fs/fat/fatfs_syms.c b/fs/fat/fatfs_syms.c
index f57db8bf3..838c679d4 100644
--- a/fs/fat/fatfs_syms.c
+++ b/fs/fat/fatfs_syms.c
@@ -54,6 +54,7 @@ EXPORT_SYMBOL(lock_fat);
EXPORT_SYMBOL(unlock_fat);
EXPORT_SYMBOL(fat_dir_ioctl);
EXPORT_SYMBOL(fat_readpage);
+EXPORT_SYMBOL(fat_is_binary);
int init_fat_fs(void)
{
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 0ff5f187f..7c9518181 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -456,6 +456,10 @@ void fat_truncate(struct inode *inode)
/* Why no return value? Surely the disk could fail... */
if (IS_IMMUTABLE(inode))
return /* -EPERM */;
+ if(inode->i_sb->s_flags&MS_RDONLY) {
+ printk("FAT: fat_truncate called though fs is read-only, uhh...\n");
+ return /* -EROFS */;
+ }
cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
(void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index e018eb880..339bcb6f6 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -3,6 +3,10 @@
*
* Written 1992,1993 by Werner Almesberger
* VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner
+ *
+ * Fixes:
+ *
+ * Max Cohan: Fixed invalid FSINFO offset when info_sector is 0
*/
#include <linux/version.h>
@@ -328,7 +332,6 @@ fat_read_super(struct super_block *sb, void *data, int silent)
fat_brelse (sb, bh);
goto out_no_bread;
}
- set_blocksize(sb->s_dev, blksize);
/*
* The DOS3 partition size limit is *not* 32M as many people think.
@@ -362,8 +365,16 @@ fat_read_super(struct super_block *sb, void *data, int silent)
fat32 = 1;
MSDOS_SB(sb)->fat_length= CF_LE_W(b->fat32_length)*sector_mult;
MSDOS_SB(sb)->root_cluster = CF_LE_L(b->root_cluster);
- MSDOS_SB(sb)->fsinfo_offset =
- CF_LE_W(b->info_sector) * logical_sector_size + 0x1e0;
+
+ /* MC - if info_sector is 0, don't multiply by 0 */
+ if(CF_LE_W(b->info_sector) == 0) {
+ MSDOS_SB(sb)->fsinfo_offset =
+ logical_sector_size + 0x1e0;
+ } else {
+ MSDOS_SB(sb)->fsinfo_offset =
+ (CF_LE_W(b->info_sector) * logical_sector_size)
+ + 0x1e0;
+ }
if (MSDOS_SB(sb)->fsinfo_offset + sizeof(struct fat_boot_fsinfo) > sb->s_blocksize) {
printk("fat_read_super: Bad fsinfo_offset\n");
fat_brelse(sb, bh);
@@ -411,6 +422,7 @@ fat_read_super(struct super_block *sb, void *data, int silent)
|| !b->secs_track || !b->heads;
}
fat_brelse(sb, bh);
+ set_blocksize(sb->s_dev, blksize);
/*
This must be done after the brelse because the bh is a dummy
allocated by fat_bread (see buffer.c)
@@ -691,8 +703,8 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o
if(raw_entry->attr & ATTR_SYS)
if (MSDOS_SB(sb)->options.sys_immutable)
inode->i_flags |= S_IMMUTABLE;
- MSDOS_I(inode)->i_binary = is_binary(MSDOS_SB(sb)->options.conversion,
- raw_entry->ext);
+ MSDOS_I(inode)->i_binary =
+ fat_is_binary(MSDOS_SB(sb)->options.conversion, raw_entry->ext);
MSDOS_I(inode)->i_attrs = raw_entry->attr & ATTR_UNUSED;
/* this is as close to the truth as we can get ... */
inode->i_blksize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE;
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index b398a0bbd..1dfddd3c7 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -51,11 +51,11 @@ void fat_fs_panic(struct super_block *s,const char *msg)
/*
- * is_binary selects optional text conversion based on the conversion mode and
- * the extension part of the file name.
+ * fat_is_binary selects optional text conversion based on the conversion mode
+ * and the extension part of the file name.
*/
-int is_binary(char conversion,char *extension)
+int fat_is_binary(char conversion,char *extension)
{
char *walk;
diff --git a/fs/fat/mmap.c b/fs/fat/mmap.c
index 4cda79196..0494ad013 100644
--- a/fs/fat/mmap.c
+++ b/fs/fat/mmap.c
@@ -113,8 +113,6 @@ int fat_mmap(struct file * file, struct vm_area_struct * vma)
mark_inode_dirty(inode);
}
- vma->vm_file = file;
- file->f_count++;
vma->vm_ops = &fat_file_mmap;
return 0;
}
diff --git a/fs/file_table.c b/fs/file_table.c
index cbc33634a..f7679dba3 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -81,6 +81,8 @@ struct file * get_empty_filp(void)
memset(f, 0, sizeof(*f));
f->f_count = 1;
f->f_version = ++event;
+ f->f_uid = current->fsuid;
+ f->f_gid = current->fsgid;
put_inuse(f);
return f;
}
@@ -119,6 +121,8 @@ int init_private_file(struct file *filp, struct dentry *dentry, int mode)
filp->f_mode = mode;
filp->f_count = 1;
filp->f_dentry = dentry;
+ filp->f_uid = current->fsuid;
+ filp->f_gid = current->fsgid;
filp->f_op = dentry->d_inode->i_op->default_file_ops;
if (filp->f_op->open)
return filp->f_op->open(dentry->d_inode, filp);
diff --git a/fs/hfs/ChangeLog b/fs/hfs/ChangeLog
index c0b077f47..f97bd0086 100644
--- a/fs/hfs/ChangeLog
+++ b/fs/hfs/ChangeLog
@@ -1,3 +1,13 @@
+1999-01-30 a sun <asun@hecate.darksunrising.blah>
+
+ * catalog.c (hfs_cat_move): fixed corruption problem with
+ renames.
+
+1999-01-27 a sun <asun@hecate.darksunrising.blah>
+
+ * file_hdr.c (get/set_dates): got rid of broken afpd times. NOTE:
+ you must use netatalk-1.4b2+asun2.1.2 or newer for this.
+
1998-12-20 a sun <asun@hecate.darksunrising.blah>
* bdelete.c (del_root): assign bthLNode and bthFNode only if the
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
index 306c018e7..48577a9e6 100644
--- a/fs/hfs/catalog.c
+++ b/fs/hfs/catalog.c
@@ -1348,7 +1348,7 @@ int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir,
hfs_sleep_on(&mdb->rename_wait);
}
spin_lock(&entry_lock);
- mdb->rename_lock = 1;
+ mdb->rename_lock = 1; /* XXX: should be atomic_inc */
spin_unlock(&entry_lock);
/* keep readers from getting confused by changing dir size */
@@ -1385,7 +1385,6 @@ int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir,
restart:
/* see if the destination exists, getting it if it does */
dest = hfs_cat_get(mdb, new_key);
-
if (!dest) {
/* destination doesn't exist, so create it */
struct hfs_cat_rec new_record;
@@ -1408,14 +1407,16 @@ restart:
goto bail3;
}
- /* build the new record */
+ /* build the new record. make sure to zero out the
+ record. */
+ memset(&new_record, 0, sizeof(new_record));
new_record.cdrType = entry->type;
__write_entry(entry, &new_record);
/* insert the new record */
error = hfs_binsert(mdb->cat_tree, HFS_BKEY(new_key),
&new_record, is_dir ? 2 + sizeof(DIR_REC) :
- 2 + sizeof(FIL_REC));
+ 2 + sizeof(FIL_REC));
if (error == -EEXIST) {
delete_entry(dest);
unlock_entry(dest);
@@ -1565,7 +1566,7 @@ done:
}
end_write(new_dir);
spin_lock(&entry_lock);
- mdb->rename_lock = 0;
+ mdb->rename_lock = 0; /* XXX: should use atomic_dec */
hfs_wake_up(&mdb->rename_wait);
spin_unlock(&entry_lock);
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index f8d89227d..b355408c9 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -430,8 +430,6 @@ int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
update_dirs_plus(new_parent, is_dir);
}
- /* update dcache */
- d_move(old_dentry, new_dentry);
}
hfs_rename_put:
diff --git a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c
index 03fa7f7ae..0ab81d966 100644
--- a/fs/hfs/dir_cap.c
+++ b/fs/hfs/dir_cap.c
@@ -27,7 +27,7 @@
/*================ Forward declarations ================*/
-static int cap_lookup(struct inode *, struct dentry *);
+static struct dentry *cap_lookup(struct inode *, struct dentry *);
static int cap_readdir(struct file *, void *, filldir_t);
/*================ Global variables ================*/
@@ -147,7 +147,7 @@ struct inode_operations hfs_cap_rdir_inode_operations = {
* inode corresponding to an entry in a directory, given the inode for
* the directory and the name (and its length) of the entry.
*/
-static int cap_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *cap_lookup(struct inode * dir, struct dentry *dentry)
{
ino_t dtype;
struct hfs_name cname;
@@ -155,10 +155,6 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry)
struct hfs_cat_key key;
struct inode *inode = NULL;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- return -ENOENT;
- }
-
dentry->d_op = &hfs_dentry_operations;
entry = HFS_I(dir)->entry;
dtype = HFS_ITYPE(dir->i_ino);
@@ -207,7 +203,7 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry)
done:
d_add(dentry, inode);
- return 0;
+ return NULL;
}
/*
diff --git a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c
index 4e4e6fcc3..80e990627 100644
--- a/fs/hfs/dir_dbl.c
+++ b/fs/hfs/dir_dbl.c
@@ -23,7 +23,7 @@
/*================ Forward declarations ================*/
-static int dbl_lookup(struct inode *, struct dentry *);
+static struct dentry *dbl_lookup(struct inode *, struct dentry *);
static int dbl_readdir(struct file *, void *, filldir_t);
static int dbl_create(struct inode *, struct dentry *, int);
static int dbl_mkdir(struct inode *, struct dentry *, int);
@@ -130,17 +130,13 @@ static int is_hdr(struct inode *dir, const char *name, int len)
* the inode for the directory and the name (and its length) of the
* entry.
*/
-static int dbl_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *dbl_lookup(struct inode * dir, struct dentry *dentry)
{
struct hfs_name cname;
struct hfs_cat_entry *entry;
struct hfs_cat_key key;
struct inode *inode = NULL;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- return -ENOENT;
- }
-
dentry->d_op = &hfs_dentry_operations;
entry = HFS_I(dir)->entry;
@@ -173,7 +169,7 @@ static int dbl_lookup(struct inode * dir, struct dentry *dentry)
done:
d_add(dentry, inode);
- return 0;
+ return NULL;
}
/*
diff --git a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c
index a4078e891..5cff9d814 100644
--- a/fs/hfs/dir_nat.c
+++ b/fs/hfs/dir_nat.c
@@ -29,7 +29,7 @@
/*================ Forward declarations ================*/
-static int nat_lookup(struct inode *, struct dentry *);
+static struct dentry *nat_lookup(struct inode *, struct dentry *);
static int nat_readdir(struct file *, void *, filldir_t);
static int nat_rmdir(struct inode *, struct dentry *);
static int nat_hdr_unlink(struct inode *, struct dentry *);
@@ -136,7 +136,7 @@ struct inode_operations hfs_nat_hdir_inode_operations = {
* the inode corresponding to an entry in a directory, given the inode
* for the directory and the name (and its length) of the entry.
*/
-static int nat_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *nat_lookup(struct inode * dir, struct dentry *dentry)
{
ino_t dtype;
struct hfs_name cname;
@@ -144,10 +144,6 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry)
struct hfs_cat_key key;
struct inode *inode = NULL;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- return -ENOENT;
- }
-
dentry->d_op = &hfs_dentry_operations;
entry = HFS_I(dir)->entry;
dtype = HFS_ITYPE(dir->i_ino);
@@ -199,7 +195,7 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry)
done:
d_add(dentry, inode);
- return 0;
+ return NULL;
}
/*
diff --git a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c
index 3ae2d5b5d..9479fab08 100644
--- a/fs/hfs/file_hdr.c
+++ b/fs/hfs/file_hdr.c
@@ -303,16 +303,9 @@ static inline void adjust_forks(struct hfs_cat_entry *entry,
static void get_dates(const struct hfs_cat_entry *entry,
const struct inode *inode, hfs_u32 dates[3])
{
- if (HFS_SB(inode->i_sb)->s_afpd) {
- /* AFPD compatible: use un*x times */
- dates[0] = htonl(hfs_m_to_utime(entry->create_date));
- dates[1] = htonl(hfs_m_to_utime(entry->modify_date));
- dates[2] = htonl(hfs_m_to_utime(entry->backup_date));
- } else {
- dates[0] = hfs_m_to_htime(entry->create_date);
- dates[1] = hfs_m_to_htime(entry->modify_date);
- dates[2] = hfs_m_to_htime(entry->backup_date);
- }
+ dates[0] = hfs_m_to_htime(entry->create_date);
+ dates[1] = hfs_m_to_htime(entry->modify_date);
+ dates[2] = hfs_m_to_htime(entry->backup_date);
}
/*
@@ -322,43 +315,23 @@ static void set_dates(struct hfs_cat_entry *entry, struct inode *inode,
const hfs_u32 *dates)
{
hfs_u32 tmp;
- if (HFS_SB(inode->i_sb)->s_afpd) {
- /* AFPD compatible: use un*x times */
- tmp = hfs_u_to_mtime(ntohl(dates[0]));
- if (entry->create_date != tmp) {
- entry->create_date = tmp;
- hfs_cat_mark_dirty(entry);
- }
- tmp = hfs_u_to_mtime(ntohl(dates[1]));
- if (entry->modify_date != tmp) {
- entry->modify_date = tmp;
- inode->i_ctime = inode->i_atime = inode->i_mtime =
- ntohl(dates[1]);
- hfs_cat_mark_dirty(entry);
- }
- tmp = hfs_u_to_mtime(ntohl(dates[2]));
- if (entry->backup_date != tmp) {
- entry->backup_date = tmp;
- hfs_cat_mark_dirty(entry);
- }
- } else {
- tmp = hfs_h_to_mtime(dates[0]);
- if (entry->create_date != tmp) {
- entry->create_date = tmp;
- hfs_cat_mark_dirty(entry);
- }
- tmp = hfs_h_to_mtime(dates[1]);
- if (entry->modify_date != tmp) {
- entry->modify_date = tmp;
- inode->i_ctime = inode->i_atime = inode->i_mtime =
- hfs_h_to_utime(dates[1]);
- hfs_cat_mark_dirty(entry);
- }
- tmp = hfs_h_to_mtime(dates[2]);
- if (entry->backup_date != tmp) {
- entry->backup_date = tmp;
- hfs_cat_mark_dirty(entry);
- }
+
+ tmp = hfs_h_to_mtime(dates[0]);
+ if (entry->create_date != tmp) {
+ entry->create_date = tmp;
+ hfs_cat_mark_dirty(entry);
+ }
+ tmp = hfs_h_to_mtime(dates[1]);
+ if (entry->modify_date != tmp) {
+ entry->modify_date = tmp;
+ inode->i_ctime = inode->i_atime = inode->i_mtime =
+ hfs_h_to_utime(dates[1]);
+ hfs_cat_mark_dirty(entry);
+ }
+ tmp = hfs_h_to_mtime(dates[2]);
+ if (entry->backup_date != tmp) {
+ entry->backup_date = tmp;
+ hfs_cat_mark_dirty(entry);
}
}
diff --git a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c
index 0524808f7..fb68e9ab2 100644
--- a/fs/hfs/sysdep.c
+++ b/fs/hfs/sysdep.c
@@ -18,7 +18,7 @@
#include <linux/hfs_fs_i.h>
#include <linux/hfs_fs.h>
-static int hfs_revalidate_dentry(struct dentry *);
+static int hfs_revalidate_dentry(struct dentry *, int);
static int hfs_hash_dentry(struct dentry *, struct qstr *);
static int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
static void hfs_dentry_iput(struct dentry *, struct inode *);
@@ -89,7 +89,7 @@ static void hfs_dentry_iput(struct dentry *dentry, struct inode *inode)
iput(inode);
}
-static int hfs_revalidate_dentry(struct dentry *dentry)
+static int hfs_revalidate_dentry(struct dentry *dentry, int flags)
{
struct inode *inode = dentry->d_inode;
int diff;
diff --git a/fs/hpfs/hpfs_fs.c b/fs/hpfs/hpfs_fs.c
index feafa2861..cb1d0215b 100644
--- a/fs/hpfs/hpfs_fs.c
+++ b/fs/hpfs/hpfs_fs.c
@@ -192,7 +192,7 @@ static ssize_t hpfs_dir_read(struct file *filp, char *buf,
size_t count, loff_t *ppos);
static int hpfs_readdir(struct file *filp,
void *dirent, filldir_t filldir);
-static int hpfs_lookup(struct inode *, struct dentry *);
+static struct dentry *hpfs_lookup(struct inode *, struct dentry *);
static const struct file_operations hpfs_dir_ops =
{
@@ -1119,7 +1119,7 @@ static secno bplus_lookup(struct inode *inode, struct bplus_header *b,
* the boondocks.)
*/
-static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
+static struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
{
const char *name = dentry->d_name.name;
int len = dentry->d_name.len;
@@ -1129,14 +1129,6 @@ static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
int retval;
struct quad_buffer_head qbh;
- /* In case of madness */
-
- retval = -ENOTDIR;
- if (dir == 0)
- goto out;
- if (!S_ISDIR(dir->i_mode))
- goto out;
-
/*
* Read in the directory entry. "." is there under the name ^A^A .
* Always read the dir even for . and .. in case we need the dates.
@@ -1208,7 +1200,7 @@ static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
brelse4(&qbh);
out:
- return retval;
+ return ERR_PTR(retval);
}
/*
@@ -1374,11 +1366,6 @@ static int hpfs_readdir(struct file *filp, void * dirent,
long old_pos;
struct inode *inode = filp->f_dentry->d_inode;
- if (inode == 0
- || inode->i_sb == 0
- || !S_ISDIR(inode->i_mode))
- return -EBADF;
-
tempname = (char *) __get_free_page(GFP_KERNEL);
if (!tempname)
return -ENOMEM;
diff --git a/fs/inode.c b/fs/inode.c
index 72a23f858..ac1ef535d 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -62,9 +62,8 @@ spinlock_t inode_lock = SPIN_LOCK_UNLOCKED;
struct {
int nr_inodes;
int nr_free_inodes;
- int preshrink; /* pre-shrink dcache? */
- int dummy[4];
-} inodes_stat = {0, 0, 0,};
+ int dummy[5];
+} inodes_stat = {0, 0,};
int max_inodes;
@@ -196,6 +195,19 @@ void sync_inodes(kdev_t dev)
}
/*
+ * Called with the spinlock already held..
+ */
+static void sync_all_inodes(void)
+{
+ struct super_block * sb = sb_entry(super_blocks.next);
+ for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
+ if (!sb->s_dev)
+ continue;
+ sync_list(&sb->s_dirty);
+ }
+}
+
+/*
* Needed by knfsd
*/
void write_inode_now(struct inode *inode)
@@ -232,13 +244,15 @@ void clear_inode(struct inode *inode)
/*
* Dispose-list gets a local list, so it doesn't need to
- * worry about list corruption.
+ * worry about list corruption. It releases the inode lock
+ * while clearing the inodes.
*/
static void dispose_list(struct list_head * head)
{
struct list_head *next;
int count = 0;
+ spin_unlock(&inode_lock);
next = head->next;
for (;;) {
struct list_head * tmp = next;
@@ -256,7 +270,6 @@ static void dispose_list(struct list_head * head)
spin_lock(&inode_lock);
list_splice(head, &inode_unused);
inodes_stat.nr_free_inodes += count;
- spin_unlock(&inode_lock);
}
/*
@@ -305,65 +318,51 @@ int invalidate_inodes(struct super_block * sb)
spin_lock(&inode_lock);
busy = invalidate_list(&inode_in_use, sb, &throw_away);
busy |= invalidate_list(&sb->s_dirty, sb, &throw_away);
- spin_unlock(&inode_lock);
-
dispose_list(&throw_away);
+ spin_unlock(&inode_lock);
return busy;
}
/*
* This is called with the inode lock held. It searches
- * the in-use for the specified number of freeable inodes.
- * Freeable inodes are moved to a temporary list and then
- * placed on the unused list by dispose_list.
+ * the in-use for freeable inodes, which are moved to a
+ * temporary list and then placed on the unused list by
+ * dispose_list.
+ *
+ * We don't expect to have to call this very often.
*
- * Note that we do not expect to have to search very hard:
- * the freeable inodes will be at the old end of the list.
- *
- * N.B. The spinlock is released to call dispose_list.
+ * N.B. The spinlock is released during the call to
+ * dispose_list.
*/
#define CAN_UNUSE(inode) \
- (((inode)->i_count == 0) && \
- (!(inode)->i_state))
+ (((inode)->i_count | (inode)->i_state) == 0)
+#define INODE(entry) (list_entry(entry, struct inode, i_list))
-static int free_inodes(int goal)
+static int free_inodes(void)
{
- struct list_head *tmp, *head = &inode_in_use;
- LIST_HEAD(freeable);
- int found = 0, depth = goal << 1;
+ struct list_head list, *entry, *freeable = &list;
+ int found = 0;
+
+ INIT_LIST_HEAD(freeable);
+ entry = inode_in_use.next;
+ while (entry != &inode_in_use) {
+ struct list_head *tmp = entry;
- while ((tmp = head->prev) != head && depth--) {
- struct inode * inode = list_entry(tmp, struct inode, i_list);
+ entry = entry->next;
+ if (!CAN_UNUSE(INODE(tmp)))
+ continue;
list_del(tmp);
- if (CAN_UNUSE(inode)) {
- list_del(&inode->i_hash);
- INIT_LIST_HEAD(&inode->i_hash);
- list_add(tmp, &freeable);
- if (++found < goal)
- continue;
- break;
- }
- list_add(tmp, head);
+ list_del(&INODE(tmp)->i_hash);
+ INIT_LIST_HEAD(&INODE(tmp)->i_hash);
+ list_add(tmp, freeable);
+ found = 1;
}
- if (found) {
- spin_unlock(&inode_lock);
- dispose_list(&freeable);
- spin_lock(&inode_lock);
- }
- return found;
-}
-static void shrink_dentry_inodes(int goal)
-{
- int found;
+ if (found)
+ dispose_list(freeable);
- spin_unlock(&inode_lock);
- found = select_dcache(goal, 0);
- if (found < goal)
- found = goal;
- prune_dcache(found);
- spin_lock(&inode_lock);
+ return found;
}
/*
@@ -373,9 +372,23 @@ static void shrink_dentry_inodes(int goal)
*/
static void try_to_free_inodes(int goal)
{
- shrink_dentry_inodes(goal);
- if (!free_inodes(goal))
- shrink_dentry_inodes(goal);
+ /*
+ * First stry to just get rid of unused inodes.
+ *
+ * If we can't reach our goal that way, we'll have
+ * to try to shrink the dcache and sync existing
+ * inodes..
+ */
+ free_inodes();
+ goal -= inodes_stat.nr_free_inodes;
+ if (goal > 0) {
+ spin_unlock(&inode_lock);
+ select_dcache(goal, 0);
+ prune_dcache(goal);
+ spin_lock(&inode_lock);
+ sync_all_inodes();
+ free_inodes();
+ }
}
/*
@@ -385,17 +398,24 @@ static void try_to_free_inodes(int goal)
void free_inode_memory(int goal)
{
spin_lock(&inode_lock);
- free_inodes(goal);
+ free_inodes();
spin_unlock(&inode_lock);
}
-#define INODES_PER_PAGE PAGE_SIZE/sizeof(struct inode)
+
/*
* This is called with the spinlock held, but releases
* the lock when freeing or allocating inodes.
* Look out! This returns with the inode lock held if
* it got an inode..
+ *
+ * We do inode allocations two pages at a time to reduce
+ * fragmentation.
*/
+#define INODE_PAGE_ORDER 1
+#define INODE_ALLOCATION_SIZE (PAGE_SIZE << INODE_PAGE_ORDER)
+#define INODES_PER_ALLOCATION (INODE_ALLOCATION_SIZE/sizeof(struct inode))
+
static struct inode * grow_inodes(void)
{
struct inode * inode;
@@ -403,9 +423,9 @@ static struct inode * grow_inodes(void)
/*
* Check whether to restock the unused list.
*/
- if (inodes_stat.preshrink) {
+ if (inodes_stat.nr_inodes > max_inodes) {
struct list_head *tmp;
- try_to_free_inodes(8);
+ try_to_free_inodes(inodes_stat.nr_inodes >> 2);
tmp = inode_unused.next;
if (tmp != &inode_unused) {
inodes_stat.nr_free_inodes--;
@@ -416,14 +436,14 @@ static struct inode * grow_inodes(void)
}
spin_unlock(&inode_lock);
- inode = (struct inode *)__get_free_page(GFP_KERNEL);
+ inode = (struct inode *)__get_free_pages(GFP_KERNEL,INODE_PAGE_ORDER);
if (inode) {
int size;
struct inode * tmp;
- spin_lock(&inode_lock);
- size = PAGE_SIZE - 2*sizeof(struct inode);
+ size = INODE_ALLOCATION_SIZE - 2*sizeof(struct inode);
tmp = inode;
+ spin_lock(&inode_lock);
do {
tmp++;
init_once(tmp);
@@ -434,11 +454,8 @@ static struct inode * grow_inodes(void)
/*
* Update the inode statistics
*/
- inodes_stat.nr_inodes += INODES_PER_PAGE;
- inodes_stat.nr_free_inodes += INODES_PER_PAGE - 1;
- inodes_stat.preshrink = 0;
- if (inodes_stat.nr_inodes > max_inodes)
- inodes_stat.preshrink = 1;
+ inodes_stat.nr_inodes += INODES_PER_ALLOCATION;
+ inodes_stat.nr_free_inodes += INODES_PER_ALLOCATION - 1;
return inode;
}
@@ -447,10 +464,9 @@ static struct inode * grow_inodes(void)
* the dcache and then try again to free some inodes.
*/
prune_dcache(inodes_stat.nr_inodes >> 2);
- inodes_stat.preshrink = 1;
spin_lock(&inode_lock);
- free_inodes(inodes_stat.nr_inodes >> 2);
+ free_inodes();
{
struct list_head *tmp = inode_unused.next;
if (tmp != &inode_unused) {
@@ -506,20 +522,12 @@ void clean_inode(struct inode *inode)
inode->i_nlink = 1;
inode->i_writecount = 0;
inode->i_size = 0;
+ inode->i_generation = 0;
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
sema_init(&inode->i_sem, 1);
}
/*
- * This gets called with I_LOCK held: it needs
- * to read the inode and then unlock it
- */
-static inline void read_inode(struct inode *inode, struct super_block *sb)
-{
- sb->s_op->read_inode(inode);
-}
-
-/*
* This is called by things like the networking layer
* etc that want to get an inode without any inode
* number, or filesystems that allocate new inodes with
@@ -588,7 +596,7 @@ add_new_inode:
spin_unlock(&inode_lock);
clean_inode(inode);
- read_inode(inode, sb);
+ sb->s_op->read_inode(inode);
/*
* This is special! We do not need the spinlock
@@ -741,7 +749,7 @@ int bmap(struct inode * inode, int block)
* Initialize the hash tables and default
* value for max inodes
*/
-#define MAX_INODE (8192)
+#define MAX_INODE (16384)
void __init inode_init(void)
{
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 9ac7c3bf2..8d18e453a 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -74,14 +74,20 @@ asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
filp->f_flags &= ~flag;
break;
- case FIOASYNC: /* O_SYNC is not yet implemented,
- but it's here for completeness. */
+ case FIOASYNC:
if ((error = get_user(on, (int *)arg)) != 0)
break;
+ flag = on ? FASYNC : 0;
+
+ /* Did FASYNC state change ? */
+ if ((flag ^ filp->f_flags) & FASYNC) {
+ if (filp->f_op && filp->f_op->fasync)
+ filp->f_op->fasync(fd, filp, on);
+ }
if (on)
- filp->f_flags |= O_SYNC;
+ filp->f_flags |= FASYNC;
else
- filp->f_flags &= ~O_SYNC;
+ filp->f_flags &= ~FASYNC;
break;
default:
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index a57f9680c..23ca159c7 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -295,9 +295,6 @@ static int isofs_readdir(struct file *filp,
struct iso_directory_record * tmpde;
struct inode *inode = filp->f_dentry->d_inode;
- if (!inode || !S_ISDIR(inode->i_mode))
- return -EBADF;
-
tmpname = (char *) __get_free_page(GFP_KERNEL);
if (!tmpname)
return -ENOMEM;
diff --git a/fs/isofs/file.c b/fs/isofs/file.c
index 0a508c90b..e2b4405d9 100644
--- a/fs/isofs/file.c
+++ b/fs/isofs/file.c
@@ -16,7 +16,6 @@
#include <linux/stat.h>
#include <linux/locks.h>
#include <linux/fs.h>
-#include <linux/iso_fs.h>
/*
* We have mostly NULLs here: the current defaults are OK for
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 364698dc2..7d4ca4e98 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -74,7 +74,6 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
char c;
*ino = 0;
- if (!dir) return NULL;
if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
@@ -228,7 +227,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
return retval;
}
-int isofs_lookup(struct inode * dir, struct dentry * dentry)
+struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry)
{
unsigned long ino;
struct buffer_head * bh;
@@ -237,12 +236,6 @@ int isofs_lookup(struct inode * dir, struct dentry * dentry)
#ifdef DEBUG
printk("lookup: %x %s\n",dir->i_ino, dentry->d_name.name);
#endif
- if (!dir)
- return -ENOENT;
-
- if (!S_ISDIR(dir->i_mode))
- return -ENOENT;
-
dentry->d_op = dir->i_sb->s_root->d_op;
bh = isofs_find_entry(dir, dentry, &ino);
@@ -253,8 +246,8 @@ int isofs_lookup(struct inode * dir, struct dentry * dentry)
inode = iget(dir->i_sb,ino);
if (!inode)
- return -EACCES;
+ return ERR_PTR(-EACCES);
}
d_add(dentry, inode);
- return 0;
+ return NULL;
}
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index d50df7eac..8df091923 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -30,6 +30,14 @@ static int nlm_stat_to_errno(u32 stat);
*/
static u32 nlm_cookie = 0x1234;
+static inline void nlmclnt_next_cookie(struct nlm_cookie *c)
+{
+ memcpy(c->data, &nlm_cookie, 4);
+ memset(c->data+4, 0, 4);
+ c->len=4;
+ nlm_cookie++;
+}
+
/*
* Initialize arguments for TEST/LOCK/UNLOCK/CANCEL calls
*/
@@ -40,7 +48,7 @@ nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
struct nlm_lock *lock = &argp->lock;
memset(argp, 0, sizeof(*argp));
- argp->cookie = nlm_cookie++;
+ nlmclnt_next_cookie(&argp->cookie);
argp->state = nsm_local_state;
lock->fh = *NFS_FH(fl->fl_file->f_dentry);
lock->caller = system_utsname.nodename;
@@ -57,7 +65,7 @@ nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
int
nlmclnt_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
{
- call->a_args.cookie = nlm_cookie++;
+ nlmclnt_next_cookie(&call->a_args.cookie);
call->a_args.lock = *lock;
call->a_args.lock.caller = system_utsname.nodename;
@@ -230,9 +238,24 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
/* Perform the RPC call. If an error occurs, try again */
if ((status = rpc_call(clnt, proc, argp, resp, 0)) < 0) {
dprintk("lockd: rpc_call returned error %d\n", -status);
- if (status == -ERESTARTSYS)
- return status;
- nlm_rebind_host(host);
+ switch (status) {
+ case -EPROTONOSUPPORT:
+ status = -EINVAL;
+ break;
+ case -ECONNREFUSED:
+ case -ETIMEDOUT:
+ case -ENOTCONN:
+ status = -EAGAIN;
+ break;
+ case -ERESTARTSYS:
+ return signalled () ? -EINTR : status;
+ default:
+ break;
+ }
+ if (req->a_args.block)
+ nlm_rebind_host(host);
+ else
+ break;
} else
if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) {
dprintk("lockd: server in grace period\n");
@@ -248,9 +271,18 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
/* Back off a little and try again */
interruptible_sleep_on_timeout(&host->h_gracewait, 15*HZ);
- } while (!signalled());
- return -ERESTARTSYS;
+ /* When the lock requested by F_SETLKW isn't available,
+ we will wait until the request can be satisfied. If
+ a signal is received during wait, we should return
+ -EINTR. */
+ if (signalled ()) {
+ status = -EINTR;
+ break;
+ }
+ } while (1);
+
+ return status;
}
/*
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 2bbc005ce..4072221af 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -134,7 +134,7 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
host->h_addr.sin_port = 0; /* ouch! */
host->h_version = version;
host->h_proto = proto;
- host->h_authflavor = RPC_AUTH_NULL;
+ host->h_authflavor = RPC_AUTH_UNIX;
host->h_rpcclnt = NULL;
host->h_sema = MUTEX;
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index be9e0a5f3..d61db4302 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -64,6 +64,7 @@ lockd(struct svc_rqst *rqstp)
{
struct svc_serv *serv = rqstp->rq_server;
int err = 0;
+ unsigned long grace_period_expire;
/* Lock module and set up kernel thread */
MOD_INC_USE_COUNT;
@@ -111,7 +112,7 @@ lockd(struct svc_rqst *rqstp)
}
#endif
- nlmsvc_grace_period += jiffies;
+ grace_period_expire = nlmsvc_grace_period + jiffies;
nlmsvc_timeout = nlm_timeout * HZ;
/*
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index b1f1f5588..10c66ed4d 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -111,16 +111,25 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove)
return NULL;
}
+static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b)
+{
+ if(a->len != b->len)
+ return 0;
+ if(memcmp(a->data,b->data,a->len))
+ return 0;
+ return 1;
+}
+
/*
* Find a block with a given NLM cookie.
*/
static inline struct nlm_block *
-nlmsvc_find_block(u32 cookie)
+nlmsvc_find_block(struct nlm_cookie *cookie)
{
struct nlm_block *block;
for (block = nlm_blocked; block; block = block->b_next) {
- if (block->b_call.a_args.cookie == cookie)
+ if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie))
break;
}
@@ -139,7 +148,7 @@ nlmsvc_find_block(u32 cookie)
*/
static inline struct nlm_block *
nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
- struct nlm_lock *lock, u32 cookie)
+ struct nlm_lock *lock, struct nlm_cookie *cookie)
{
struct nlm_block *block;
struct nlm_host *host;
@@ -160,7 +169,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
lock->fl.fl_notify = nlmsvc_notify_blocked;
if (!nlmclnt_setgrantargs(&block->b_call, lock))
goto failed_free;
- block->b_call.a_args.cookie = cookie; /* see above */
+ block->b_call.a_args.cookie = *cookie; /* see above */
dprintk("lockd: created block %p...\n", block);
@@ -267,7 +276,7 @@ nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
*/
u32
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
- struct nlm_lock *lock, int wait, u32 cookie)
+ struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
{
struct file_lock *conflock;
struct nlm_block *block;
@@ -529,8 +538,8 @@ nlmsvc_grant_callback(struct rpc_task *task)
unsigned long timeout;
dprintk("lockd: GRANT_MSG RPC callback\n");
- if (!(block = nlmsvc_find_block(call->a_args.cookie))) {
- dprintk("lockd: no block for cookie %x\n", call->a_args.cookie);
+ if (!(block = nlmsvc_find_block(&call->a_args.cookie))) {
+ dprintk("lockd: no block for cookie %x\n", *(u32 *)(call->a_args.cookie.data));
return;
}
@@ -560,7 +569,7 @@ nlmsvc_grant_callback(struct rpc_task *task)
* block.
*/
void
-nlmsvc_grant_reply(u32 cookie, u32 status)
+nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status)
{
struct nlm_block *block;
struct nlm_file *file;
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 2077752f4..0e59754f3 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -151,7 +151,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Now try to lock the file */
resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
- argp->block, argp->cookie);
+ argp->block, &argp->cookie);
dprintk("lockd: LOCK status %ld\n", ntohl(resp->status));
nlm_release_host(host);
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 0c3306d43..4cac77aec 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -52,8 +52,6 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
struct nlm_file *file;
unsigned int hash;
u32 nfserr;
- uid_t saved_cr_uid;
- struct svc_cred *cred;
dprintk("lockd: nlm_file_lookup(%s/%u)\n",
kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_ino);
@@ -86,15 +84,10 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
* We have to make sure we have the right credential to open
* the file.
*/
- cred = &rqstp->rq_cred;
- saved_cr_uid = cred->cr_uid;
- cred->cr_uid = 0;
if ((nfserr = nlmsvc_ops->fopen(rqstp, fh, &file->f_file)) != 0) {
dprintk("lockd: open failed (nfserr %ld)\n", ntohl(nfserr));
- cred->cr_uid = saved_cr_uid;
goto out_free;
}
- cred->cr_uid = saved_cr_uid;
file->f_next = nlm_files[hash];
nlm_files[hash] = file;
@@ -134,7 +127,7 @@ nlm_delete_file(struct nlm_file *file)
kfree(file);
return;
}
- fp = &file->f_next;
+ fp = &f->f_next;
}
printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index 7d41c8a66..85fb7c729 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -53,28 +53,38 @@ nlmxdr_init(void)
/*
* XDR functions for basic NLM types
*/
-static inline u32 *
-nlm_decode_cookie(u32 *p, u32 *c)
+static inline u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c)
{
unsigned int len;
- if ((len = ntohl(*p++)) == 4) {
- *c = ntohl(*p++);
- } else if (len == 0) { /* hockeypux brain damage */
- *c = 0;
- } else {
+ len = ntohl(*p++);
+
+ if(len==0)
+ {
+ c->len=4;
+ memset(c->data, 0, 4); /* hockeypux brain damage */
+ }
+ else if(len<=8)
+ {
+ c->len=len;
+ memcpy(c->data, p, len);
+ p+=(len+3)>>2;
+ }
+ else
+ {
printk(KERN_NOTICE
- "lockd: bad cookie size %d (should be 4)\n", len);
+ "lockd: bad cookie size %d (only cookies under 8 bytes are supported.)\n", len);
return NULL;
}
return p;
}
static inline u32 *
-nlm_encode_cookie(u32 *p, u32 c)
+nlm_encode_cookie(u32 *p, struct nlm_cookie *c)
{
- *p++ = htonl(sizeof(c));
- *p++ = htonl(c);
+ *p++ = htonl(c->len);
+ memcpy(p, c->data, c->len);
+ p+=(c->len+3)>>2;
return p;
}
@@ -168,7 +178,7 @@ nlm_encode_lock(u32 *p, struct nlm_lock *lock)
static u32 *
nlm_encode_testres(u32 *p, struct nlm_res *resp)
{
- if (!(p = nlm_encode_cookie(p, resp->cookie)))
+ if (!(p = nlm_encode_cookie(p, &resp->cookie)))
return 0;
*p++ = resp->status;
@@ -308,7 +318,7 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
int
nlmsvc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
{
- if (!(p = nlm_encode_cookie(p, resp->cookie)))
+ if (!(p = nlm_encode_cookie(p, &resp->cookie)))
return 0;
*p++ = resp->status;
*p++ = xdr_zero; /* sequence argument */
@@ -318,7 +328,7 @@ nlmsvc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
int
nlmsvc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
{
- if (!(p = nlm_encode_cookie(p, resp->cookie)))
+ if (!(p = nlm_encode_cookie(p, &resp->cookie)))
return 0;
*p++ = resp->status;
return xdr_ressize_check(rqstp, p);
@@ -388,7 +398,7 @@ nlmclt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
- if (!(p = nlm_encode_cookie(p, argp->cookie)))
+ if (!(p = nlm_encode_cookie(p, &argp->cookie)))
return -EIO;
*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
if (!(p = nlm_encode_lock(p, lock)))
@@ -429,7 +439,7 @@ nlmclt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
- if (!(p = nlm_encode_cookie(p, argp->cookie)))
+ if (!(p = nlm_encode_cookie(p, &argp->cookie)))
return -EIO;
*p++ = argp->block? xdr_one : xdr_zero;
*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
@@ -446,7 +456,7 @@ nlmclt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
- if (!(p = nlm_encode_cookie(p, argp->cookie)))
+ if (!(p = nlm_encode_cookie(p, &argp->cookie)))
return -EIO;
*p++ = argp->block? xdr_one : xdr_zero;
*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
@@ -461,7 +471,7 @@ nlmclt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
- if (!(p = nlm_encode_cookie(p, argp->cookie)))
+ if (!(p = nlm_encode_cookie(p, &argp->cookie)))
return -EIO;
if (!(p = nlm_encode_lock(p, lock)))
return -EIO;
@@ -472,7 +482,7 @@ nlmclt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
static int
nlmclt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
{
- if (!(p = nlm_encode_cookie(p, resp->cookie)))
+ if (!(p = nlm_encode_cookie(p, &resp->cookie)))
return -EIO;
*p++ = resp->status;
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
@@ -501,7 +511,7 @@ nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
* Buffer requirements for NLM
*/
#define NLM_void_sz 0
-#define NLM_cookie_sz 2
+#define NLM_cookie_sz 3 /* 1 len , 2 data */
#define NLM_caller_sz 1+QUADLEN(sizeof(system_utsname.nodename))
#define NLM_netobj_sz 1+QUADLEN(XDR_MAX_NETOBJ)
/* #define NLM_owner_sz 1+QUADLEN(NLM_MAXOWNER) */
diff --git a/fs/locks.c b/fs/locks.c
index 38982227d..01d833eb8 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -111,7 +111,7 @@
#include <asm/uaccess.h>
-#define OFFSET_MAX ((off_t)0x7fffffff) /* FIXME: move elsewhere? */
+#define OFFSET_MAX ((off_t)LONG_MAX) /* FIXME: move elsewhere? */
static int flock_make_lock(struct file *filp, struct file_lock *fl,
unsigned int cmd);
@@ -263,16 +263,18 @@ static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait)
if (waiter->fl_notify)
waiter->fl_notify(waiter);
wake_up(&waiter->fl_wait);
- if (wait)
+ if (wait) {
/* Let the blocked process remove waiter from the
* block list when it gets scheduled.
*/
+ current->policy |= SCHED_YIELD;
schedule();
- else
+ } else {
/* Remove waiter from the block list, because by the
* time it wakes up blocker won't exist any more.
*/
locks_delete_block(blocker, waiter);
+ }
}
return;
}
@@ -1170,7 +1172,7 @@ static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
static char *lock_get_status(struct file_lock *fl, int id, char *pfx)
{
- static char temp[129];
+ static char temp[155];
char *p = temp;
struct inode *inode;
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index d7db754ff..187925903 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -68,8 +68,6 @@ static int minix_readdir(struct file * filp,
struct minix_sb_info * info;
struct inode *inode = filp->f_dentry->d_inode;
- if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode))
- return -EBADF;
info = &inode->i_sb->u.minix_sb;
if (filp->f_pos & (info->s_dirsize - 1))
return -EBADF;
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index e8b1e7660..60032292c 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -38,14 +38,13 @@ static void minix_delete_inode(struct inode *inode)
minix_free_inode(inode);
}
-static void minix_commit_super (struct super_block * sb,
- struct minix_super_block * ms)
+static void minix_commit_super(struct super_block * sb)
{
mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
sb->s_dirt = 0;
}
-static void minix_write_super (struct super_block * sb)
+static void minix_write_super(struct super_block * sb)
{
struct minix_super_block * ms;
@@ -54,7 +53,7 @@ static void minix_write_super (struct super_block * sb)
if (ms->s_state & MINIX_VALID_FS)
ms->s_state &= ~MINIX_VALID_FS;
- minix_commit_super (sb, ms);
+ minix_commit_super(sb);
}
sb->s_dirt = 0;
}
@@ -106,7 +105,7 @@ static int minix_remount (struct super_block * sb, int * flags, char * data)
ms->s_state = sb->u.minix_sb.s_mount_state;
mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
sb->s_dirt = 1;
- minix_commit_super (sb, ms);
+ minix_commit_super(sb);
}
else {
/* Mount a partition which is read-only, read-write. */
@@ -195,8 +194,8 @@ static struct super_block *minix_read_super(struct super_block *s, void *data,
s->u.minix_sb.s_ms = ms;
s->u.minix_sb.s_sbh = bh;
s->u.minix_sb.s_mount_state = ms->s_state;
- s->s_blocksize = 1024;
- s->s_blocksize_bits = 10;
+ s->s_blocksize = BLOCK_SIZE;
+ s->s_blocksize_bits = BLOCK_SIZE_BITS;
s->u.minix_sb.s_ninodes = ms->s_ninodes;
s->u.minix_sb.s_nzones = ms->s_nzones;
s->u.minix_sb.s_imap_blocks = ms->s_imap_blocks;
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 86f99c56d..e6d680ecf 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -45,7 +45,7 @@ static struct buffer_head * minix_find_entry(struct inode * dir,
struct minix_dir_entry *de;
*res_dir = NULL;
- if (!dir || !dir->i_sb)
+ if (!dir->i_sb)
return NULL;
info = &dir->i_sb->u.minix_sb;
if (namelen > info->s_namelen) {
@@ -116,7 +116,7 @@ struct dentry_operations minix_dentry_operations = {
0 /* compare */
};
-int minix_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry)
{
struct inode * inode = NULL;
struct minix_dir_entry * de;
@@ -132,10 +132,10 @@ int minix_lookup(struct inode * dir, struct dentry *dentry)
inode = iget(dir->i_sb, ino);
if (!inode)
- return -EACCES;
+ return ERR_PTR(-EACCES);
}
d_add(dentry, inode);
- return 0;
+ return NULL;
}
/*
@@ -221,8 +221,6 @@ int minix_create(struct inode * dir, struct dentry *dentry, int mode)
struct buffer_head * bh;
struct minix_dir_entry * de;
- if (!dir)
- return -ENOENT;
inode = minix_new_inode(dir);
if (!inode)
return -ENOSPC;
@@ -251,14 +249,6 @@ int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
struct buffer_head * bh;
struct minix_dir_entry * de;
- if (!dir)
- return -ENOENT;
- bh = minix_find_entry(dir, dentry->d_name.name,
- dentry->d_name.len, &de);
- if (bh) {
- brelse(bh);
- return -EEXIST;
- }
inode = minix_new_inode(dir);
if (!inode)
return -ENOSPC;
@@ -298,15 +288,7 @@ int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
struct minix_dir_entry * de;
struct minix_sb_info * info;
- if (!dir || !dir->i_sb)
- return -EINVAL;
info = &dir->i_sb->u.minix_sb;
- bh = minix_find_entry(dir, dentry->d_name.name,
- dentry->d_name.len, &de);
- if (bh) {
- brelse(bh);
- return -EEXIST;
- }
if (dir->i_nlink >= info->s_link_max)
return -EMLINK;
inode = minix_new_inode(dir);
@@ -530,15 +512,6 @@ int minix_symlink(struct inode * dir, struct dentry *dentry,
brelse(name_block);
inode->i_size = i;
mark_inode_dirty(inode);
- bh = minix_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);
- return -EEXIST;
- }
i = minix_add_entry(dir, dentry->d_name.name,
dentry->d_name.len, &bh, &de);
if (i) {
@@ -568,12 +541,6 @@ int minix_link(struct dentry * old_dentry, struct inode * dir,
if (inode->i_nlink >= inode->i_sb->u.minix_sb.s_link_max)
return -EMLINK;
- bh = minix_find_entry(dir, dentry->d_name.name,
- dentry->d_name.len, &de);
- if (bh) {
- brelse(bh);
- return -EEXIST;
- }
error = minix_add_entry(dir, dentry->d_name.name,
dentry->d_name.len, &bh, &de);
if (error) {
@@ -604,7 +571,7 @@ int minix_link(struct dentry * old_dentry, struct inode * dir,
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-static int do_minix_rename(struct inode * old_dir, struct dentry *old_dentry,
+int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
struct inode * new_dir, struct dentry *new_dentry)
{
struct inode * old_inode, * new_inode;
@@ -640,24 +607,11 @@ start_up:
new_bh = NULL;
}
}
- if (new_inode == old_inode) {
- retval = 0;
- goto end_rename;
- }
if (S_ISDIR(old_inode->i_mode)) {
- retval = -EINVAL;
- if (is_subdir(new_dentry, old_dentry))
- goto end_rename;
if (new_inode) {
- /* Prune any children before testing for busy */
- if (new_dentry->d_count > 1)
- shrink_dcache_parent(new_dentry);
- retval = -EBUSY;
- if (new_dentry->d_count > 1)
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto end_rename;
- retval = -EBUSY;
}
retval = -EIO;
dir_bh = minix_bread(old_inode,0,0);
@@ -713,8 +667,6 @@ start_up:
mark_inode_dirty(new_dir);
}
}
- /* Update the dcache */
- d_move(old_dentry, new_dentry);
retval = 0;
end_rename:
brelse(dir_bh);
@@ -722,29 +674,3 @@ end_rename:
brelse(new_bh);
return retval;
}
-
-/*
- * Ok, rename also locks out other renames, as they can change the parent of
- * a directory, and we don't want any races. Other races are checked for by
- * "do_rename()", which restarts if there are inconsistencies.
- *
- * Note that there is no race between different filesystems: it's only within
- * the same device that races occur: many renames can happen at once, as long
- * as they are on different partitions.
- */
-int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
- struct inode * new_dir, struct dentry *new_dentry)
-{
- static struct wait_queue * wait = NULL;
- static int lock = 0;
- int result;
-
- while (lock)
- sleep_on(&wait);
- lock = 1;
- result = do_minix_rename(old_dir, old_dentry,
- new_dir, new_dentry);
- lock = 0;
- wake_up(&wait);
- return result;
-}
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 055d700d9..dc9faa9a1 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -250,7 +250,7 @@ out_fail:
/***** Get inode using directory and name */
-int msdos_lookup(struct inode *dir,struct dentry *dentry)
+struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry)
{
struct super_block *sb = dir->i_sb;
struct inode *inode = NULL;
@@ -292,7 +292,7 @@ add:
d_add(dentry, inode);
res = 0;
out:
- return res;
+ return ERR_PTR(res);
}
@@ -327,6 +327,7 @@ static int msdos_create_entry(struct inode *dir, const char *name,
fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
de->size = 0;
fat_mark_buffer_dirty(sb, bh, 1);
+
if ((*result = iget(dir->i_sb,ino)) != NULL)
msdos_read_inode(*result);
fat_brelse(sb, bh);
@@ -405,23 +406,22 @@ static int msdos_empty(struct inode *dir)
struct msdos_dir_entry *de;
int result = 0;
- if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
- pos = 0;
- bh = NULL;
- while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
- /* Ignore vfat longname entries */
- if (de->attr == ATTR_EXT)
- continue;
- if (!IS_FREE(de->name) &&
- strncmp(de->name,MSDOS_DOT , MSDOS_NAME) &&
- strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) {
- result = -ENOTEMPTY;
- break;
- }
+ pos = 0;
+ bh = NULL;
+ while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
+ /* Ignore vfat longname entries */
+ if (de->attr == ATTR_EXT)
+ continue;
+ if (!IS_FREE(de->name) &&
+ strncmp(de->name,MSDOS_DOT , MSDOS_NAME) &&
+ strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) {
+ result = -ENOTEMPTY;
+ break;
}
- if (bh)
- fat_brelse(dir->i_sb, bh);
}
+ if (bh)
+ fat_brelse(dir->i_sb, bh);
+
return result;
}
@@ -444,13 +444,8 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry)
* whether it is empty.
*/
res = -EBUSY;
- if (!list_empty(&dentry->d_hash)) {
-#ifdef MSDOS_DEBUG
-printk("msdos_rmdir: %s/%s busy, d_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
-#endif
+ if (!list_empty(&dentry->d_hash))
goto rmdir_done;
- }
res = msdos_empty(inode);
if (res)
goto rmdir_done;
@@ -503,14 +498,6 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
dir->i_nlink++;
inode->i_nlink = 2; /* no need to mark them dirty */
-#ifdef whatfor
- /*
- * He's dead, Jim. We don't d_instantiate anymore. Should do it
- * from the very beginning, actually.
- */
- MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
-#endif
-
if ((res = fat_add_cluster(inode)) < 0)
goto mkdir_error;
if ((res = msdos_create_entry(inode,MSDOS_DOT,1,0,&dot)) < 0)
@@ -529,9 +516,6 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
dot->i_nlink = dir->i_nlink;
mark_inode_dirty(dot);
-#ifdef whatfor
- MSDOS_I(inode)->i_busy = 0;
-#endif
iput(dot);
d_instantiate(dentry, inode);
res = 0;
@@ -606,110 +590,9 @@ int msdos_unlink_umsdos(struct inode *dir,struct dentry *dentry)
return msdos_unlinkx (dir,dentry,0);
}
-#define MSDOS_CHECK_BUSY 1
-
-/***** Rename within a directory */
-static int msdos_rename_same(struct inode *old_dir,char *old_name,
- struct dentry *old_dentry,
- struct inode *new_dir,char *new_name,struct dentry *new_dentry,
- struct buffer_head *old_bh,
- struct msdos_dir_entry *old_de, int old_ino, int is_hid)
-{
- struct super_block *sb = old_dir->i_sb;
- struct buffer_head *new_bh;
- struct msdos_dir_entry *new_de;
- struct inode *new_inode,*old_inode;
- int new_ino, exists, error;
-
- if (!strncmp(old_name, new_name, MSDOS_NAME))
- goto set_hid;
- error = -ENOENT;
- if (*(unsigned char *) old_de->name == DELETED_FLAG)
- goto out;
-
- exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
- if (exists) {
- error = -EIO;
- new_inode = new_dentry->d_inode;
- /* Make sure it really exists ... */
- if (!new_inode) {
- printk(KERN_ERR
- "msdos_rename_same: %s/%s inode NULL, ino=%d\n",
- new_dentry->d_parent->d_name.name,
- new_dentry->d_name.name, new_ino);
- d_drop(new_dentry);
- goto out_error;
- }
- error = S_ISDIR(new_inode->i_mode)
- ? (old_de->attr & ATTR_DIR)
- ? msdos_empty(new_inode)
- : -EPERM
- : (old_de->attr & ATTR_DIR)
- ? -EPERM
- : 0;
- if (error)
- goto out_error;
- error = -EPERM;
- if ((old_de->attr & ATTR_SYS))
- goto out_error;
-
- if (S_ISDIR(new_inode->i_mode)) {
- /* make sure it's empty */
- error = msdos_empty(new_inode);
- if (error)
- goto out_error;
-#ifdef MSDOS_CHECK_BUSY
- /* check for a busy dentry */
- error = -EBUSY;
- shrink_dcache_parent(new_dentry);
- if (new_dentry->d_count > 1) {
-printk("msdos_rename_same: %s/%s busy, count=%d\n",
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
-new_dentry->d_count);
- goto out_error;
- }
-#endif
- new_dir->i_nlink--;
- mark_inode_dirty(new_dir);
- }
- new_inode->i_nlink = 0;
- MSDOS_I(new_inode)->i_busy = 1;
- mark_inode_dirty(new_inode);
- /*
- * Make it negative if it's not busy;
- * otherwise let d_move() drop it.
- */
- if (new_dentry->d_count == 1)
- d_delete(new_dentry);
-
- new_de->name[0] = DELETED_FLAG;
- fat_mark_buffer_dirty(sb, new_bh, 1);
- fat_brelse(sb, new_bh);
- }
- memcpy(old_de->name, new_name, MSDOS_NAME);
- /* Update the dcache */
- d_move(old_dentry, new_dentry);
-set_hid:
- old_de->attr = is_hid
- ? (old_de->attr | ATTR_HIDDEN)
- : (old_de->attr &~ ATTR_HIDDEN);
- fat_mark_buffer_dirty(sb, old_bh, 1);
- /* update binary info for conversion, i_attrs */
- old_inode = old_dentry->d_inode;
- MSDOS_I(old_inode)->i_attrs = is_hid
- ? (MSDOS_I(old_inode)->i_attrs | ATTR_HIDDEN)
- : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN);
- error = 0;
-out:
- return error;
-
-out_error:
- fat_brelse(sb, new_bh);
- goto out;
-}
-
+/* Now we could merge it with msdos_rename_same. Later */
/***** Rename across directories - a nonphysical move */
-static int msdos_rename_diff(struct inode *old_dir, char *old_name,
+static int do_msdos_rename(struct inode *old_dir, char *old_name,
struct dentry *old_dentry,
struct inode *new_dir,char *new_name, struct dentry *new_dentry,
struct buffer_head *old_bh,
@@ -718,30 +601,27 @@ static int msdos_rename_diff(struct inode *old_dir, char *old_name,
struct super_block *sb = old_dir->i_sb;
struct buffer_head *new_bh,*free_bh,*dotdot_bh;
struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
- struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode;
+ struct inode *old_inode,*new_inode,*dotdot_inode;
int new_ino,free_ino,dotdot_ino;
int error, exists;
- error = -EINVAL;
- if (old_ino == new_dir->i_ino)
- goto out;
- /* prevent moving directory below itself */
- if (is_subdir(new_dentry, old_dentry))
- goto out;
-
+ old_inode = old_dentry->d_inode;
+ if (old_dir==new_dir && !strncmp(old_name, new_name, MSDOS_NAME))
+ goto set_hid;
error = -ENOENT;
if (*(unsigned char *) old_de->name == DELETED_FLAG)
goto out;
/* find free spot */
- while ((error = fat_scan(new_dir, NULL, &free_bh, &free_de, &free_ino,
- SCAN_ANY)) < 0) {
- if (error != -ENOENT)
- goto out;
- error = fat_add_cluster(new_dir);
- if (error)
- goto out;
- }
+ if (new_dir!=old_dir)
+ while ((error = fat_scan(new_dir, NULL, &free_bh, &free_de,
+ &free_ino, SCAN_ANY)) < 0) {
+ if (error != -ENOENT)
+ goto out;
+ error = fat_add_cluster(new_dir);
+ if (error)
+ goto out;
+ }
exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
if (exists) { /* Trash the old file! */
@@ -750,40 +630,17 @@ static int msdos_rename_diff(struct inode *old_dir, char *old_name,
/* Make sure it really exists ... */
if (!new_inode) {
printk(KERN_ERR
- "msdos_rename_diff: %s/%s inode NULL, ino=%d\n",
+ "msdos_rename: %s/%s inode NULL, ino=%d\n",
new_dentry->d_parent->d_name.name,
new_dentry->d_name.name, new_ino);
d_drop(new_dentry);
goto out_new;
}
- error = S_ISDIR(new_inode->i_mode)
- ? (old_de->attr & ATTR_DIR)
- ? msdos_empty(new_inode)
- : -EPERM
- : (old_de->attr & ATTR_DIR)
- ? -EPERM
- : 0;
- if (error)
- goto out_new;
error = -EPERM;
if ((old_de->attr & ATTR_SYS))
goto out_new;
-#ifdef MSDOS_CHECK_BUSY
- /* check for a busy dentry */
- error = -EBUSY;
- if (new_dentry->d_count > 1) {
- shrink_dcache_parent(new_dentry);
- if (new_dentry->d_count > 1) {
-printk("msdos_rename_diff: target %s/%s busy, count=%d\n",
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
-new_dentry->d_count);
- goto out_new;
- }
- }
-#endif
if (S_ISDIR(new_inode->i_mode)) {
- /* make sure it's empty */
error = msdos_empty(new_inode);
if (error)
goto out_new;
@@ -793,18 +650,26 @@ new_dentry->d_count);
new_inode->i_nlink = 0;
MSDOS_I(new_inode)->i_busy = 1;
mark_inode_dirty(new_inode);
- /*
- * Make it negative if it's not busy;
- * otherwise let d_move() drop it.
- */
- if (new_dentry->d_count == 1)
- d_delete(new_dentry);
+
new_de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, new_bh, 1);
fat_brelse(sb, new_bh);
}
- old_inode = old_dentry->d_inode;
+ if (old_dir==new_dir) {
+ memcpy(old_de->name, new_name, MSDOS_NAME);
+set_hid:
+ old_de->attr = is_hid
+ ? (old_de->attr | ATTR_HIDDEN)
+ : (old_de->attr &~ ATTR_HIDDEN);
+ fat_mark_buffer_dirty(sb, old_bh, 1);
+ MSDOS_I(old_inode)->i_attrs = is_hid
+ ? (MSDOS_I(old_inode)->i_attrs | ATTR_HIDDEN)
+ : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN);
+ error = 0;
+ goto out;
+ }
+
/* Get the dotdot inode if we'll need it ... */
dotdot_bh = NULL;
dotdot_inode = NULL;
@@ -824,73 +689,37 @@ new_dentry->d_count);
goto out_dotdot;
}
- /* get an inode for the new name */
+ /*
+ * Potential race here. It will go away when we'll switch to
+ * sane inumbers (along with a frigging lot of other races).
+ */
+
+ /* set new entry */
memcpy(free_de, old_de, sizeof(struct msdos_dir_entry));
memcpy(free_de->name, new_name, MSDOS_NAME);
free_de->attr = is_hid
? (free_de->attr|ATTR_HIDDEN)
: (free_de->attr&~ATTR_HIDDEN);
- error = -EIO;
- free_inode = iget(sb, free_ino);
- if (!free_inode)
- goto out_iput;
- /* make sure it's not busy! */
- if (MSDOS_I(free_inode)->i_busy)
- printk(KERN_ERR "msdos_rename_diff: new inode %ld busy!\n",
- (ino_t) free_ino);
- if (!list_empty(&free_inode->i_dentry))
- printk("msdos_rename_diff: free inode has aliases??\n");
- msdos_read_inode(free_inode);
-
- /*
- * Make sure the old dentry isn't busy,
- * as we need to change inodes ...
- */
- error = -EBUSY;
- if (old_dentry->d_count > 1) {
- shrink_dcache_parent(old_dentry);
- if (old_dentry->d_count > 1) {
-printk("msdos_rename_diff: source %s/%s busy, count=%d\n",
-old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
-old_dentry->d_count);
- goto out_iput;
- }
- }
-
- /* keep the inode for a bit ... */
- old_inode->i_count++;
- d_delete(old_dentry);
-
- free_inode->i_mode = old_inode->i_mode;
- free_inode->i_nlink = old_inode->i_nlink;
- free_inode->i_size = old_inode->i_size;
- free_inode->i_blocks = old_inode->i_blocks;
- free_inode->i_mtime = old_inode->i_mtime;
- free_inode->i_atime = old_inode->i_atime;
- free_inode->i_ctime = old_inode->i_ctime;
- MSDOS_I(free_inode)->i_ctime_ms = MSDOS_I(old_inode)->i_ctime_ms;
-
- MSDOS_I(free_inode)->i_start = MSDOS_I(old_inode)->i_start;
- MSDOS_I(free_inode)->i_logstart = MSDOS_I(old_inode)->i_logstart;
- MSDOS_I(free_inode)->i_attrs = MSDOS_I(old_inode)->i_attrs;
-
- /* release the old inode's resources */
- MSDOS_I(old_inode)->i_start = 0;
- MSDOS_I(old_inode)->i_logstart = 0;
- old_inode->i_nlink = 0;
-
/*
- * Install the new inode ...
+ * Now the tricky part. We need to change i_ino. icache ignores
+ * i_ino for unhashed inodes, so we'll remove inode from hash,
+ * change what we want to change and reinsert it back. NB: we
+ * don't have to invalidate FAT cache here - all we need is to
+ * flip i_ino in relevant cache entries. Later.
*/
- d_instantiate(old_dentry, free_inode);
+ remove_inode_hash(old_inode);
- fat_mark_buffer_dirty(sb, free_bh, 1);
fat_cache_inval_inode(old_inode);
- mark_inode_dirty(old_inode);
+ old_inode->i_version = ++event;
+ MSDOS_I(old_inode)->i_binary =
+ fat_is_binary(MSDOS_SB(sb)->options.conversion, free_de->ext);
+ old_inode->i_ino = free_ino;
+ fat_mark_buffer_dirty(sb, free_bh, 1);
old_de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, old_bh, 1);
- iput(old_inode);
+
+ insert_inode_hash(old_inode);
/* a directory? */
if (dotdot_bh) {
@@ -908,8 +737,6 @@ old_dentry->d_count);
fat_brelse(sb, dotdot_bh);
}
- /* Update the dcache */
- d_move(old_dentry, new_dentry);
error = 0;
rename_done:
@@ -917,14 +744,6 @@ rename_done:
out:
return error;
-out_iput:
- free_de->name[0] = DELETED_FLAG;
- /*
- * Don't mark free_bh as dirty. Both states
- * are supposed to be equivalent.
- */
- iput(free_inode); /* may be NULL */
- iput(dotdot_inode);
out_dotdot:
fat_brelse(sb, dotdot_bh);
goto rename_done;
@@ -944,9 +763,6 @@ int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
int is_hid,old_hid; /* if new file and old file are hidden */
char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
- error = -EINVAL;
- if (sb != new_dir->i_sb)
- goto rename_done;
error = msdos_format_name(MSDOS_SB(sb)->options.name_check,
old_dentry->d_name.name, old_dentry->d_name.len,
old_msdos_name, 1,MSDOS_SB(sb)->options.dotsOK);
@@ -966,14 +782,9 @@ int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
goto rename_done;
fat_lock_creation();
- if (old_dir == new_dir)
- error = msdos_rename_same(old_dir, old_msdos_name, old_dentry,
- new_dir, new_msdos_name, new_dentry,
- old_bh, old_de, (ino_t)old_ino, is_hid);
- else
- error = msdos_rename_diff(old_dir, old_msdos_name, old_dentry,
- new_dir, new_msdos_name, new_dentry,
- old_bh, old_de, (ino_t)old_ino, is_hid);
+ error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
+ new_dir, new_msdos_name, new_dentry,
+ old_bh, old_de, (ino_t)old_ino, is_hid);
fat_unlock_creation();
fat_brelse(sb, old_bh);
diff --git a/fs/namei.c b/fs/namei.c
index d89d6d64c..b91b43a1f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -23,18 +23,6 @@
#include <asm/page.h>
#include <asm/pgtable.h>
-/*
- * The bitmask for a lookup event:
- * - follow links at the end
- * - require a directory
- * - ending slashes ok even for nonexistent files
- * - internal "there are more path compnents" flag
- */
-#define LOOKUP_FOLLOW (1)
-#define LOOKUP_DIRECTORY (2)
-#define LOOKUP_SLASHOK (4)
-#define LOOKUP_CONTINUE (8)
-
#include <asm/namei.h>
/* This can be removed after the beta phase. */
@@ -225,12 +213,12 @@ static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * nam
/*
* Internal lookup() using the new generic dcache.
*/
-static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name)
+static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags)
{
struct dentry * dentry = d_lookup(parent, name);
if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
- if (!dentry->d_op->d_revalidate(dentry) && !d_invalidate(dentry)) {
+ if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
dput(dentry);
dentry = NULL;
}
@@ -245,7 +233,7 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name)
* We get the directory semaphore, and after getting that we also
* make sure that nobody added the entry to the dcache in the meantime..
*/
-static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
+static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags)
{
struct dentry * result;
struct inode *dir = parent->d_inode;
@@ -258,17 +246,16 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
* FIXME! This could use version numbering or similar to
* avoid unnecessary cache lookups.
*/
- result = cached_lookup(parent, name);
+ result = cached_lookup(parent, name, flags);
if (!result) {
struct dentry * dentry = d_alloc(parent, name);
result = ERR_PTR(-ENOMEM);
if (dentry) {
- int error = dir->i_op->lookup(dir, dentry);
- result = dentry;
- if (error) {
+ result = dir->i_op->lookup(dir, dentry);
+ if (result)
dput(dentry);
- result = ERR_PTR(error);
- }
+ else
+ result = dentry;
}
}
up(&dir->i_sem);
@@ -279,7 +266,8 @@ static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry
{
struct inode * inode = dentry->d_inode;
- if (inode && inode->i_op && inode->i_op->follow_link) {
+ if ((follow & LOOKUP_FOLLOW)
+ && inode && inode->i_op && inode->i_op->follow_link) {
if (current->link_count < 5) {
struct dentry * result;
@@ -392,9 +380,9 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned
/* This does the actual lookups.. */
dentry = reserved_lookup(base, &this);
if (!dentry) {
- dentry = cached_lookup(base, &this);
+ dentry = cached_lookup(base, &this, flags);
if (!dentry) {
- dentry = real_lookup(base, &this);
+ dentry = real_lookup(base, &this, flags);
if (IS_ERR(dentry))
break;
}
@@ -403,9 +391,6 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned
/* Check mountpoints.. */
dentry = follow_mount(dentry);
- if (!(flags & LOOKUP_FOLLOW))
- break;
-
base = do_follow_link(base, dentry, flags);
if (IS_ERR(base))
goto return_base;
@@ -1034,17 +1019,13 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
int error;
error = may_delete(dir, dentry, 0);
- if (error)
- goto exit_lock;
-
- if (!dir->i_op || !dir->i_op->unlink)
- goto exit_lock;
-
- DQUOT_INIT(dir);
-
- error = dir->i_op->unlink(dir, dentry);
-
-exit_lock:
+ if (!error) {
+ error = -EPERM;
+ if (dir->i_op && dir->i_op->unlink) {
+ DQUOT_INIT(dir);
+ error = dir->i_op->unlink(dir, dentry);
+ }
+ }
return error;
}
@@ -1231,15 +1212,16 @@ asmlinkage int sys_link(const char * oldname, const char * newname)
return error;
}
-int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
int error;
- int isdir;
+ int need_rehash = 0;
- isdir = S_ISDIR(old_dentry->d_inode->i_mode);
+ if (old_dentry->d_inode == new_dentry->d_inode)
+ return 0;
- error = may_delete(old_dir, old_dentry, isdir); /* XXX */
+ error = may_delete(old_dir, old_dentry, 1);
if (error)
return error;
@@ -1249,20 +1231,91 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (!new_dentry->d_inode)
error = may_create(new_dir, new_dentry);
else
- error = may_delete(new_dir, new_dentry, isdir);
+ error = may_delete(new_dir, new_dentry, 1);
if (error)
return error;
if (!old_dir->i_op || !old_dir->i_op->rename)
return -EPERM;
+ /*
+ * If we are going to change the parent - check write permissions,
+ * we'll need to flip '..'.
+ */
+ if (new_dir != old_dir) {
+ error = permission(old_dentry->d_inode, MAY_WRITE);
+ }
+ if (error)
+ return error;
+
DQUOT_INIT(old_dir);
DQUOT_INIT(new_dir);
+ down(&old_dir->i_sb->s_vfs_rename_sem);
+ error = -EINVAL;
+ if (is_subdir(new_dentry, old_dentry))
+ goto out_unlock;
+ if (new_dentry->d_inode) {
+ error = -EBUSY;
+ if (d_invalidate(new_dentry)<0)
+ goto out_unlock;
+ need_rehash = 1;
+ }
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
-
+ if (need_rehash)
+ d_rehash(new_dentry);
+ if (!error)
+ d_move(old_dentry,new_dentry);
+out_unlock:
+ up(&old_dir->i_sb->s_vfs_rename_sem);
return error;
}
+int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+{
+ int error;
+
+ if (old_dentry->d_inode == new_dentry->d_inode)
+ return 0;
+
+ error = may_delete(old_dir, old_dentry, 0);
+ if (error)
+ return error;
+
+ if (new_dir->i_dev != old_dir->i_dev)
+ return -EXDEV;
+
+ if (!new_dentry->d_inode)
+ error = may_create(new_dir, new_dentry);
+ else
+ error = may_delete(new_dir, new_dentry, 0);
+ if (error)
+ return error;
+
+ if (!old_dir->i_op || !old_dir->i_op->rename)
+ return -EPERM;
+
+ DQUOT_INIT(old_dir);
+ DQUOT_INIT(new_dir);
+ error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+ if (error)
+ return error;
+ /* The following d_move() should become unconditional */
+ if (!(old_dir->i_sb->s_flags & MS_ODD_RENAME)) {
+ d_move(old_dentry, new_dentry);
+ }
+ return 0;
+}
+
+int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+{
+ if (S_ISDIR(old_dentry->d_inode->i_mode))
+ return vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
+ else
+ return vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
+}
+
static inline int do_rename(const char * oldname, const char * newname)
{
int error;
diff --git a/fs/ncpfs/Config.in b/fs/ncpfs/Config.in
index 21a7af854..11a1b1d36 100644
--- a/fs/ncpfs/Config.in
+++ b/fs/ncpfs/Config.in
@@ -6,5 +6,10 @@ bool ' Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING
bool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG
bool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS
bool ' Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS
+if [ "$CONFIG_NCPFS_OS2_NS" = "y" ]; then
+ bool ' Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS
+fi
bool ' Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR
# bool ' NDS interserver authentication support' CONFIG_NCPFS_NDS_DOMAINS
+bool ' Use Native Language Support' CONFIG_NCPFS_NLS
+bool ' Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS
diff --git a/fs/ncpfs/Makefile b/fs/ncpfs/Makefile
index 109091ef0..2fb40609c 100644
--- a/fs/ncpfs/Makefile
+++ b/fs/ncpfs/Makefile
@@ -9,7 +9,7 @@
O_TARGET := ncpfs.o
O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o \
- ncpsign_kernel.o
+ symlink.o ncpsign_kernel.o
M_OBJS := $(O_TARGET)
# If you want debugging output, please uncomment the following line
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 9ef53c41a..cacc0d5c5 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -4,6 +4,7 @@
* Copyright (C) 1995, 1996 by Volker Lendecke
* Modified for big endian by J.F. Chadima and David S. Miller
* Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
+ * Modified 1998 Wolfram Pienkoss for NLS
*
*/
@@ -22,6 +23,7 @@
#include <linux/locks.h>
#include <linux/ncp_fs.h>
+
#include "ncplib_kernel.h"
struct ncp_dirent {
@@ -48,13 +50,16 @@ static ssize_t ncp_dir_read(struct file *, char *, size_t, loff_t *);
static int ncp_readdir(struct file *, void *, filldir_t);
static int ncp_create(struct inode *, struct dentry *, int);
-static int ncp_lookup(struct inode *, struct dentry *);
+static struct dentry *ncp_lookup(struct inode *, struct dentry *);
static int ncp_unlink(struct inode *, struct dentry *);
static int ncp_mkdir(struct inode *, struct dentry *, int);
static int ncp_rmdir(struct inode *, struct dentry *);
static int ncp_rename(struct inode *, struct dentry *,
struct inode *, struct dentry *);
-
+#ifdef CONFIG_NCPFS_EXTRAS
+extern int ncp_symlink(struct inode *, struct dentry *, const char *);
+#endif
+
static struct file_operations ncp_dir_operations =
{
NULL, /* lseek - default */
@@ -77,7 +82,11 @@ struct inode_operations ncp_dir_inode_operations =
ncp_lookup, /* lookup */
NULL, /* link */
ncp_unlink, /* unlink */
+#ifdef CONFIG_NCPFS_EXTRAS
+ ncp_symlink, /* symlink */
+#else
NULL, /* symlink */
+#endif
ncp_mkdir, /* mkdir */
ncp_rmdir, /* rmdir */
NULL, /* mknod */
@@ -103,14 +112,14 @@ ncp_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
/*
* Dentry operations routines
*/
-static int ncp_lookup_validate(struct dentry *);
+static int ncp_lookup_validate(struct dentry *, int);
static int ncp_hash_dentry(struct dentry *, struct qstr *);
static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
static void ncp_delete_dentry(struct dentry *);
struct dentry_operations ncp_dentry_operations =
{
- ncp_lookup_validate, /* d_validate(struct dentry *) */
+ ncp_lookup_validate, /* d_revalidate(struct dentry *, int) */
ncp_hash_dentry, /* d_hash */
ncp_compare_dentry, /* d_compare */
ncp_delete_dentry /* d_delete(struct dentry *) */
@@ -191,14 +200,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
}
}
-/* Here we encapsulate the inode number handling that depends upon the
- * mount mode: When we mount a complete server, the memory address of
- * the ncp_inode_info is used as the inode number. When only a single
- * volume is mounted, then the dirEntNum is used as the inode
- * number. As this is unique for the complete volume, this should
- * enable the NFS exportability of a ncpfs-mounted volume.
- */
-
/*
* Generate a unique inode number.
*/
@@ -253,37 +254,30 @@ static int
ncp_force_unlink(struct inode *dir, struct dentry* dentry)
{
int res=0x9c,res2;
- struct iattr ia;
+ struct nw_modify_dos_info info;
+ __u32 old_nwattr;
+ struct inode *inode;
+ memset(&info, 0, sizeof(info));
+
/* remove the Read-Only flag on the NW server */
+ inode = dentry->d_inode;
- memset(&ia,0,sizeof(struct iattr));
- ia.ia_mode = dentry->d_inode->i_mode;
- ia.ia_mode |= NCP_SERVER(dir)->m.file_mode & 0222; /* set write bits */
- ia.ia_valid = ATTR_MODE;
-
- res2=ncp_notify_change(dentry, &ia);
- if (res2)
- {
- goto leave_me;
- }
+ old_nwattr = NCP_FINFO(inode)->nwattr;
+ info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
+ res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
+ if (res2)
+ goto leave_me;
/* now try again the delete operation */
-
res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
if (res) /* delete failed, set R bit again */
{
- memset(&ia,0,sizeof(struct iattr));
- ia.ia_mode = dentry->d_inode->i_mode;
- ia.ia_mode &= ~(NCP_SERVER(dir)->m.file_mode & 0222); /* clear write bits */
- ia.ia_valid = ATTR_MODE;
-
- res2=ncp_notify_change(dentry, &ia);
- if (res2)
- {
+ info.attributes = old_nwattr;
+ res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
+ if (res2)
goto leave_me;
- }
}
leave_me:
return(res);
@@ -293,68 +287,65 @@ leave_me:
#ifdef CONFIG_NCPFS_STRONG
static int
ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
- struct inode *new_dir, struct dentry* new_dentry, char *_new_name,
- int *done_flag)
+ struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
{
+ struct nw_modify_dos_info info;
int res=0x90,res2;
- struct iattr ia;
+ struct inode *old_inode = old_dentry->d_inode;
+ __u32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
+ __u32 new_nwattr = 0; /* shut compiler warning */
+ int old_nwattr_changed = 0;
+ int new_nwattr_changed = 0;
+ memset(&info, 0, sizeof(info));
+
/* remove the Read-Only flag on the NW server */
- memset(&ia,0,sizeof(struct iattr));
- ia.ia_mode = old_dentry->d_inode->i_mode;
- ia.ia_mode |= NCP_SERVER(old_dir)->m.file_mode & 0222; /* set write bits */
- ia.ia_valid = ATTR_MODE;
-
- res2=ncp_notify_change(old_dentry, &ia);
- if (res2)
- {
- goto leave_me;
- }
-
+ info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
+ res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
+ if (!res2)
+ old_nwattr_changed = 1;
+ if (new_dentry && new_dentry->d_inode) {
+ new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr;
+ info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
+ res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
+ if (!res2)
+ new_nwattr_changed = 1;
+ }
/* now try again the rename operation */
- res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
- old_dir, _old_name,
- new_dir, _new_name);
-
- if (!res) {
- ncp_invalid_dir_cache(old_dir);
- ncp_invalid_dir_cache(new_dir);
- d_move(old_dentry,new_dentry);
- *done_flag=1;
-
- if (!old_dentry->d_inode) {
- DPRINTK(KERN_INFO "ncpfs: no inode -- file remains rw\n");
- goto leave_me;
- }
- if ((res2=ncp_lookup_validate(old_dentry))) {
- DPRINTK(KERN_DEBUG "ncpfs: ncp_lookup_validate returned %d\n",res2);
- }
- }
-
- memset(&ia,0,sizeof(struct iattr));
- ia.ia_mode = old_dentry->d_inode->i_mode;
- ia.ia_mode &= ~(NCP_SERVER(old_dentry->d_inode)->m.file_mode & 0222); /* clear write bits */
- ia.ia_valid = ATTR_MODE;
-
- DPRINTK(KERN_INFO "calling ncp_notify_change() with %s/%s\n",
- old_dentry->d_parent->d_name.name,old_dentry->d_name.name);
-
- res2=ncp_notify_change(old_dentry, &ia);
- if (res2)
- {
- printk(KERN_INFO "ncpfs: ncp_notify_change (2) failed: %08x\n",res2);
- /* goto leave_me; */
- }
-
- leave_me:
+ /* but only if something really happened */
+ if (new_nwattr_changed || old_nwattr_changed) {
+ res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
+ old_dir, _old_name,
+ new_dir, _new_name);
+ }
+ if (res)
+ goto leave_me;
+ /* file was successfully renamed, so:
+ do not set attributes on old file - it no longer exists
+ copy attributes from old file to new */
+ new_nwattr_changed = old_nwattr_changed;
+ new_nwattr = old_nwattr;
+ old_nwattr_changed = 0;
+
+leave_me:;
+ if (old_nwattr_changed) {
+ info.attributes = old_nwattr;
+ res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
+ /* ignore errors */
+ }
+ if (new_nwattr_changed) {
+ info.attributes = new_nwattr;
+ res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
+ /* ignore errors */
+ }
return(res);
}
#endif /* CONFIG_NCPFS_STRONG */
static int
-ncp_lookup_validate(struct dentry * dentry)
+ncp_lookup_validate(struct dentry * dentry, int flags)
{
struct ncp_server *server;
struct inode *dir = dentry->d_parent->d_inode;
@@ -384,11 +375,6 @@ ncp_lookup_validate(struct dentry * dentry)
printk(KERN_DEBUG "ncp_lookup_validate: %s, len %d\n", __name, len);
#endif
- if (!ncp_preserve_case(dir)) {
- str_lower(__name);
- down_case = 1;
- }
-
/* If the file is in the dir cache, we do not have to ask the
server. */
@@ -398,17 +384,14 @@ dentry->d_parent->d_name.name, __name);
#endif
if (ncp_is_server_root(dir))
{
- str_upper(__name);
+ io2vol(server, __name, 1);
down_case = 1;
res = ncp_lookup_volume(server, __name,
&(finfo.nw_info.i));
} else
{
- if (!ncp_preserve_case(dir))
- {
- str_upper(__name);
- down_case = 1;
- }
+ down_case = !ncp_preserve_case(dir);
+ io2vol(server, __name, down_case);
res = ncp_obtain_info(server, dir, __name,
&(finfo.nw_info.i));
}
@@ -427,6 +410,9 @@ dentry->d_parent->d_name.name, __name, res);
else
printk(KERN_DEBUG "ncp_lookup_validate: found, but dirEntNum changed\n");
#endif
+ vol2io(server, finfo.nw_info.i.entryName,
+ !ncp_preserve_entry_case(dir,
+ finfo.nw_info.i.NSCreator));
ncp_update_inode2(dentry->d_inode, &finfo.nw_info);
}
if (!val) ncp_invalid_dir_cache(dir);
@@ -454,11 +440,6 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
DDPRINTK(KERN_DEBUG "ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
inode->i_ino, c_ino);
- result = -EBADF;
- if (!inode || !S_ISDIR(inode->i_mode)) {
- printk(KERN_WARNING "ncp_readdir: inode is NULL or not a directory\n");
- goto out;
- }
result = -EIO;
if (!ncp_conn_valid(server))
goto out;
@@ -533,10 +514,11 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
c_last_returned_index = 0;
index = 0;
- if (!ncp_preserve_case(inode)) {
- for (i = 0; i < c_size; i++) {
- str_lower(c_entry[i].i.entryName);
- }
+ for (i = 0; i < c_size; i++)
+ {
+ vol2io(server, c_entry[i].i.entryName,
+ !ncp_preserve_entry_case(inode,
+ c_entry[i].i.NSCreator));
}
}
}
@@ -728,7 +710,7 @@ int ncp_conn_logged_in(struct ncp_server *server)
struct dentry* dent;
result = -ENOENT;
- str_upper(server->m.mounted_vol);
+ io2vol(server, server->m.mounted_vol, 1);
if (ncp_lookup_volume(server, server->m.mounted_vol,
&(server->root.finfo.i)) != 0) {
#ifdef NCPFS_PARANOIA
@@ -736,7 +718,7 @@ printk(KERN_DEBUG "ncp_conn_logged_in: %s not found\n", server->m.mounted_vol);
#endif
goto out;
}
- str_lower(server->root.finfo.i.entryName);
+ vol2io(server, server->root.finfo.i.entryName, 1);
dent = server->root_dentry;
if (dent) {
struct inode* ino = dent->d_inode;
@@ -757,7 +739,7 @@ out:
return result;
}
-static int ncp_lookup(struct inode *dir, struct dentry *dentry)
+static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
{
struct ncp_server *server;
struct inode *inode = NULL;
@@ -767,11 +749,6 @@ static int ncp_lookup(struct inode *dir, struct dentry *dentry)
struct ncpfs_inode_info finfo;
__u8 __name[dentry->d_name.len + 1];
- error = -ENOENT;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- printk(KERN_WARNING "ncp_lookup: inode is NULL or not a directory.\n");
- goto finished;
- }
server = NCP_SERVER(dir);
error = -EIO;
@@ -784,11 +761,6 @@ static int ncp_lookup(struct inode *dir, struct dentry *dentry)
printk(KERN_DEBUG "ncp_lookup: %s, len %d\n", __name, len);
#endif
- if (!ncp_preserve_case(dir)) {
- str_lower(__name);
- down_case = 1;
- }
-
/* If the file is in the dir cache, we do not have to ask the
server. */
@@ -828,17 +800,14 @@ dentry->d_parent->d_name.name, __name);
#endif
if (ncp_is_server_root(dir))
{
- str_upper(__name);
+ io2vol(server, __name, 1);
down_case = 1;
res = ncp_lookup_volume(server, __name,
&(finfo.nw_info.i));
} else
{
- if (!ncp_preserve_case(dir))
- {
- str_upper(__name);
- down_case = 1;
- }
+ down_case = !ncp_preserve_case(dir);
+ io2vol(server, __name, down_case);
res = ncp_obtain_info(server, dir, __name,
&(finfo.nw_info.i));
}
@@ -849,8 +818,11 @@ dentry->d_parent->d_name.name, __name, res);
/*
* If we didn't find an entry, make a negative dentry.
*/
- if (res != 0)
+ if (res != 0) {
goto add_entry;
+ } else vol2io(server, finfo.nw_info.i.entryName,
+ !ncp_preserve_entry_case(dir,
+ finfo.nw_info.i.NSCreator));
}
/*
@@ -872,7 +844,7 @@ finished:
#ifdef NCPFS_PARANOIA
printk(KERN_DEBUG "ncp_lookup: result=%d\n", error);
#endif
- return error;
+ return ERR_PTR(error);
}
/*
@@ -904,20 +876,17 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
goto out;
}
-static int ncp_create(struct inode *dir, struct dentry *dentry, int mode)
+int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
+ int attributes)
{
int error, result;
struct ncpfs_inode_info finfo;
__u8 _name[dentry->d_name.len + 1];
-
+
#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_create: creating %s/%s, mode=%x\n",
+printk(KERN_DEBUG "ncp_create_new: creating %s/%s, mode=%x\n",
dentry->d_parent->d_name.name, dentry->d_name.name, mode);
#endif
- if (!dir || !S_ISDIR(dir->i_mode)) {
- printk(KERN_WARNING "ncp_create: inode is NULL or not a directory\n");
- return -ENOENT;
- }
error = -EIO;
if (!ncp_conn_valid(NCP_SERVER(dir)))
goto out;
@@ -925,14 +894,12 @@ dentry->d_parent->d_name.name, dentry->d_name.name, mode);
strncpy(_name, dentry->d_name.name, dentry->d_name.len);
_name[dentry->d_name.len] = '\0';
- if (!ncp_preserve_case(dir)) {
- str_upper(_name);
- }
+ io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
error = -EACCES;
result = ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
- 0, AR_READ | AR_WRITE, &finfo.nw_info);
+ attributes, AR_READ | AR_WRITE, &finfo.nw_info);
if (!result) {
finfo.nw_info.access = O_RDWR;
error = ncp_instantiate(dir, dentry, &finfo);
@@ -946,6 +913,11 @@ out:
return error;
}
+static int ncp_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+ return ncp_create_new(dir, dentry, mode, 0);
+}
+
static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int error;
@@ -954,20 +926,13 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
DPRINTK(KERN_DEBUG "ncp_mkdir: making %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
- error = -ENOTDIR;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- printk(KERN_WARNING "ncp_mkdir: inode is NULL or not a directory\n");
- goto out;
- }
error = -EIO;
if (!ncp_conn_valid(NCP_SERVER(dir)))
goto out;
strncpy(_name, dentry->d_name.name, dentry->d_name.len);
_name[dentry->d_name.len] = '\0';
- if (!ncp_preserve_case(dir)) {
- str_upper(_name);
- }
+ io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
error = -EACCES;
if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
@@ -987,13 +952,6 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
DPRINTK(KERN_DEBUG "ncp_rmdir: removing %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
-
- error = -ENOENT;
- if (!dir || !S_ISDIR(dir->i_mode))
- {
- printk(KERN_WARNING "ncp_rmdir: inode is NULL or not a directory\n");
- goto out;
- }
error = -EIO;
if (!ncp_conn_valid(NCP_SERVER(dir)))
@@ -1006,17 +964,34 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
strncpy(_name, dentry->d_name.name, dentry->d_name.len);
_name[dentry->d_name.len] = '\0';
- if (!ncp_preserve_case(dir))
- {
- str_upper(_name);
- }
- error = -EACCES;
+ io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
result = ncp_del_file_or_subdir(NCP_SERVER(dir), dir, _name);
- if (!result)
- {
- ncp_invalid_dir_cache(dir);
- error = 0;
- }
+ switch (result) {
+ case 0x00:
+ ncp_invalid_dir_cache(dir);
+ error = 0;
+ break;
+ case 0x85: /* unauthorized to delete file */
+ case 0x8A: /* unauthorized to delete file */
+ error = -EACCES;
+ break;
+ case 0x8F:
+ case 0x90: /* read only */
+ error = -EPERM;
+ break;
+ case 0x9F: /* in use by another client */
+ error = -EBUSY;
+ break;
+ case 0xA0: /* directory not empty */
+ error = -ENOTEMPTY;
+ break;
+ case 0xFF: /* someone deleted file */
+ error = -ENOENT;
+ break;
+ default:
+ error = -EACCES;
+ break;
+ }
out:
return error;
}
@@ -1029,11 +1004,6 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
DPRINTK(KERN_DEBUG "ncp_unlink: unlinking %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
- error = -ENOTDIR;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- printk(KERN_WARNING "ncp_unlink: inode is NULL or not a directory\n");
- goto out;
- }
error = -EIO;
if (!ncp_conn_valid(NCP_SERVER(dir)))
goto out;
@@ -1050,19 +1020,38 @@ printk(KERN_DEBUG "ncp_unlink: closing file\n");
error = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
#ifdef CONFIG_NCPFS_STRONG
+ /* 9C is Invalid path.. It should be 8F, 90 - read only, but
+ it is not :-( */
if (error == 0x9C && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) { /* R/O */
error = ncp_force_unlink(dir, dentry);
}
#endif
- if (!error) {
- DPRINTK(KERN_DEBUG "ncp: removed %s/%s\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- ncp_invalid_dir_cache(dir);
- d_delete(dentry);
- } else if (error == 0xFF) {
- error = -ENOENT;
- } else {
- error = -EACCES;
+ switch (error) {
+ case 0x00:
+ DPRINTK(KERN_DEBUG "ncp: removed %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ ncp_invalid_dir_cache(dir);
+ d_delete(dentry);
+ break;
+ case 0x85:
+ case 0x8A:
+ error = -EACCES;
+ break;
+ case 0x8D: /* some files in use */
+ case 0x8E: /* all files in use */
+ error = -EBUSY;
+ break;
+ case 0x8F: /* some read only */
+ case 0x90: /* all read only */
+ case 0x9C: /* !!! returned when in-use or read-only by NW4 */
+ error = -EPERM;
+ break;
+ case 0xFF:
+ error = -ENOENT;
+ break;
+ default:
+ error = -EACCES;
+ break;
}
out:
@@ -1074,7 +1063,7 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
{
int old_len = old_dentry->d_name.len;
int new_len = new_dentry->d_name.len;
- int error, done_flag=0;
+ int error;
char _old_name[old_dentry->d_name.len + 1];
char _new_name[new_dentry->d_name.len + 1];
@@ -1082,58 +1071,44 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
- error = -ENOTDIR;
- if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
- printk(KERN_WARNING "ncp_rename: old inode is NULL or not a directory\n");
- goto out;
- }
- if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
- printk(KERN_WARNING "ncp_rename: new inode is NULL or not a directory\n");
- goto out;
- }
error = -EIO;
if (!ncp_conn_valid(NCP_SERVER(old_dir)))
goto out;
strncpy(_old_name, old_dentry->d_name.name, old_len);
_old_name[old_len] = '\0';
- if (!ncp_preserve_case(old_dir)) {
- str_upper(_old_name);
- }
+ io2vol(NCP_SERVER(old_dir), _old_name, !ncp_preserve_case(old_dir));
strncpy(_new_name, new_dentry->d_name.name, new_len);
_new_name[new_len] = '\0';
- if (!ncp_preserve_case(new_dir)) {
- str_upper(_new_name);
- }
+ io2vol(NCP_SERVER(new_dir), _new_name, !ncp_preserve_case(new_dir));
error = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
old_dir, _old_name,
new_dir, _new_name);
#ifdef CONFIG_NCPFS_STRONG
- if (error == 0x90 && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) { /* RO */
+ if ((error == 0x90 || error == -EACCES) && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) { /* RO */
error = ncp_force_rename(old_dir, old_dentry, _old_name,
- new_dir, new_dentry, _new_name,
- &done_flag);
+ new_dir, new_dentry, _new_name);
}
#endif
- if (error == 0)
- {
- if (done_flag == 0) /* if 1, the following already happened */
- { /* in ncp_force_rename() */
- DPRINTK(KERN_DEBUG "ncp renamed %s -> %s.\n",
+ switch (error) {
+ case 0x00:
+ DPRINTK(KERN_DEBUG "ncp renamed %s -> %s.\n",
old_dentry->d_name.name,new_dentry->d_name.name);
- ncp_invalid_dir_cache(old_dir);
- ncp_invalid_dir_cache(new_dir);
- d_move(old_dentry,new_dentry);
- }
- } else {
- if (error == 0x9E)
+ ncp_invalid_dir_cache(old_dir);
+ ncp_invalid_dir_cache(new_dir);
+ /* d_move(old_dentry, new_dentry); */
+ break;
+ case 0x9E:
error = -ENAMETOOLONG;
- else if (error == 0xFF)
+ break;
+ case 0xFF:
error = -ENOENT;
- else
+ break;
+ default:
error = -EACCES;
+ break;
}
out:
return error;
@@ -1152,14 +1127,12 @@ extern struct timezone sys_tz;
static int utc2local(int time)
{
- return time - sys_tz.tz_minuteswest * 60 +
- (sys_tz.tz_dsttime ? 3600 : 0);
+ return time - sys_tz.tz_minuteswest * 60;
}
static int local2utc(int time)
{
- return time + sys_tz.tz_minuteswest * 60 -
- (sys_tz.tz_dsttime ? 3600 : 0);
+ return time + sys_tz.tz_minuteswest * 60;
}
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
@@ -1168,7 +1141,9 @@ ncp_date_dos2unix(unsigned short time, unsigned short date)
{
int month, year, secs;
- month = ((date >> 5) & 15) - 1;
+ /* first subtract and mask after that... Otherwise, if
+ date == 0, bad things happen */
+ month = ((date >> 5) - 1) & 15;
year = date >> 9;
secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 4a0459cdf..1afee6c7e 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -4,6 +4,7 @@
* Copyright (C) 1995, 1996 by Volker Lendecke
* Modified for big endian by J.F. Chadima and David S. Miller
* Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
+ * Modified 1998 Wolfram Pienkoss for NLS
*
*/
@@ -27,6 +28,7 @@
#include <linux/init.h>
#include <linux/ncp_fs.h>
+
#include "ncplib_kernel.h"
static void ncp_read_inode(struct inode *);
@@ -49,6 +51,10 @@ static struct super_operations ncp_sops =
};
extern struct dentry_operations ncp_dentry_operations;
+#ifdef CONFIG_NCPFS_EXTRAS
+extern struct inode_operations ncp_symlink_inode_operations;
+extern int ncp_symlink(struct inode*, struct dentry*, const char*);
+#endif
static struct nw_file_info *read_nwinfo = NULL;
static struct semaphore read_sem = MUTEX;
@@ -62,6 +68,12 @@ void ncp_update_inode(struct inode *inode, struct nw_file_info *nwinfo)
NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
+#ifdef CONFIG_NCPFS_SMALLDOS
+ NCP_FINFO(inode)->origNS = nwinfo->i.NSCreator;
+#endif
+#ifdef CONFIG_NCPFS_STRONG
+ NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
+#endif
NCP_FINFO(inode)->opened = nwinfo->opened;
NCP_FINFO(inode)->access = nwinfo->access;
NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle;
@@ -79,12 +91,42 @@ void ncp_update_inode2(struct inode* inode, struct nw_file_info *nwinfo)
struct ncp_server *server = NCP_SERVER(inode);
if (!NCP_FINFO(inode)->opened) {
+#ifdef CONFIG_NCPFS_STRONG
+ NCP_FINFO(inode)->nwattr = nwi->attributes;
+#endif
if (nwi->attributes & aDIR) {
inode->i_mode = server->m.dir_mode;
inode->i_size = 512;
} else {
inode->i_mode = server->m.file_mode;
inode->i_size = le32_to_cpu(nwi->dataStreamSize);
+#ifdef CONFIG_NCPFS_EXTRAS
+ if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) && (nwi->attributes & aSHARED)) {
+ switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
+ case aHIDDEN:
+ if (server->m.flags & NCP_MOUNT_SYMLINKS) {
+ if ((inode->i_size >= NCP_MIN_SYMLINK_SIZE)
+ && (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
+ inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
+ break;
+ }
+ }
+ /* FALLTHROUGH */
+ case 0:
+ if (server->m.flags & NCP_MOUNT_EXTRAS)
+ inode->i_mode |= 0444;
+ break;
+ case aSYSTEM:
+ if (server->m.flags & NCP_MOUNT_EXTRAS)
+ inode->i_mode |= (inode->i_mode >> 2) & 0111;
+ break;
+ /* case aSYSTEM|aHIDDEN: */
+ default:
+ /* reserved combination */
+ break;
+ }
+ }
+#endif
}
if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
}
@@ -114,6 +156,34 @@ static void ncp_set_attr(struct inode *inode, struct nw_file_info *nwinfo)
} else {
inode->i_mode = server->m.file_mode;
inode->i_size = le32_to_cpu(nwi->dataStreamSize);
+#ifdef CONFIG_NCPFS_EXTRAS
+ if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
+ && (nwi->attributes & aSHARED)) {
+ switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
+ case aHIDDEN:
+ if (server->m.flags & NCP_MOUNT_SYMLINKS) {
+ if ((inode->i_size >= NCP_MIN_SYMLINK_SIZE)
+ && (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
+ inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
+ break;
+ }
+ }
+ /* FALLTHROUGH */
+ case 0:
+ if (server->m.flags & NCP_MOUNT_EXTRAS)
+ inode->i_mode |= 0444;
+ break;
+ case aSYSTEM:
+ if (server->m.flags & NCP_MOUNT_EXTRAS)
+ inode->i_mode |= (inode->i_mode >> 2) & 0111;
+ break;
+ /* case aSYSTEM|aHIDDEN: */
+ default:
+ /* reserved combination */
+ break;
+ }
+ }
+#endif
}
if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
@@ -157,6 +227,10 @@ static void ncp_read_inode(struct inode *inode)
inode->i_op = &ncp_file_inode_operations;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ncp_dir_inode_operations;
+#ifdef CONFIG_NCPFS_EXTRAS
+ } else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &ncp_symlink_inode_operations;
+#endif
} else {
inode->i_op = NULL;
}
@@ -211,7 +285,6 @@ static void ncp_init_root(struct ncp_server *server,
{
struct ncp_inode_info *root = &(server->root);
struct nw_info_struct *i = &(root->finfo.i);
- unsigned short dummy;
DPRINTK(KERN_DEBUG "ncp_init_root: i = %x\n", (int) i);
@@ -219,15 +292,13 @@ static void ncp_init_root(struct ncp_server *server,
i->dataStreamSize= 1024;
i->dirEntNum = 0;
i->DosDirNum = 0;
+#ifdef CONFIG_NCPFS_SMALLDOS
+ i->NSCreator = NW_NS_DOS;
+#endif
i->volNumber = NCP_NUMBER_OF_VOLUMES + 1; /* illegal volnum */
- ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
- ncp_date_unix2dos(0, &(i->modifyTime ), &(i->modifyDate));
- ncp_date_unix2dos(0, &(dummy ), &(i->lastAccessDate));
- i->creationTime = le16_to_cpu(i->creationTime);
- i->creationDate = le16_to_cpu(i->creationDate);
- i->modifyTime = le16_to_cpu(i->modifyTime);
- i->modifyDate = le16_to_cpu(i->modifyDate);
- i->lastAccessDate= le16_to_cpu(i->lastAccessDate);
+ /* set dates of mountpoint to Jan 1, 1986; 00:00 */
+ i->creationTime = i->modifyTime = cpu_to_le16(0x0000);
+ i->creationDate = i->modifyDate = i->lastAccessDate = cpu_to_le16(0x0C21);
i->nameLen = 0;
i->entryName[0] = '\0';
@@ -308,6 +379,14 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
server->m.dir_mode = (server->m.dir_mode &
(S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFDIR;
+#ifdef CONFIG_NCPFS_NLS
+ /* load the default NLS charsets */
+ server->nls_charsets.codepage[0] = 0;
+ server->nls_charsets.iocharset[0] = 0;
+ server->nls_vol = load_nls_default();
+ server->nls_io = load_nls_default();
+#endif /* CONFIG_NCPFS_NLS */
+
server->packet_size = NCP_PACKET_SIZE;
server->packet = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL);
if (server->packet == NULL)
@@ -377,6 +456,10 @@ out_free_packet:
out_no_packet:
printk(KERN_ERR "ncp_read_super: could not alloc packet\n");
out_free_server:
+#ifdef CONFIG_NCPFS_NLS
+ unload_nls(server->nls_io);
+ unload_nls(server->nls_vol);
+#endif
ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
goto out_unlock;
out_no_server:
@@ -416,6 +499,20 @@ static void ncp_put_super(struct super_block *sb)
ncp_disconnect(server);
ncp_unlock_server(server);
+#ifdef CONFIG_NCPFS_NLS
+ /* unload the NLS charsets */
+ if (server->nls_vol)
+ {
+ unload_nls(server->nls_vol);
+ server->nls_vol = NULL;
+ }
+ if (server->nls_io)
+ {
+ unload_nls(server->nls_io);
+ server->nls_io = NULL;
+ }
+#endif /* CONFIG_NCPFS_NLS */
+
fput(server->ncp_filp);
kill_proc(server->m.wdog_pid, SIGTERM, 1);
@@ -457,9 +554,12 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
int result = 0;
int info_mask;
struct nw_modify_dos_info info;
+ struct ncp_server *server;
result = -EIO;
- if (!ncp_conn_valid(NCP_SERVER(inode)))
+
+ server = NCP_SERVER(inode);
+ if ((!server) || !ncp_conn_valid(server))
goto out;
result = inode_change_ok(inode, attr);
@@ -468,11 +568,11 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
result = -EPERM;
if (((attr->ia_valid & ATTR_UID) &&
- (attr->ia_uid != NCP_SERVER(inode)->m.uid)))
+ (attr->ia_uid != server->m.uid)))
goto out;
if (((attr->ia_valid & ATTR_GID) &&
- (attr->ia_uid != NCP_SERVER(inode)->m.gid)))
+ (attr->ia_gid != server->m.gid)))
goto out;
if (((attr->ia_valid & ATTR_MODE) &&
@@ -486,26 +586,53 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
#if 1
if ((attr->ia_valid & ATTR_MODE) != 0)
{
- if (!S_ISREG(inode->i_mode))
+ if (S_ISDIR(inode->i_mode)) {
+ umode_t newmode;
+
+ info_mask |= DM_ATTRIBUTES;
+ newmode = attr->ia_mode;
+ newmode &= NCP_SERVER(inode)->m.dir_mode;
+
+ if (newmode & 0222)
+ info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
+ else
+ info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
+ } else if (!S_ISREG(inode->i_mode))
{
return -EPERM;
}
else
{
umode_t newmode;
-
+#ifdef CONFIG_NCPFS_EXTRAS
+ int extras;
+
+ extras = server->m.flags & NCP_MOUNT_EXTRAS;
+#endif
info_mask |= DM_ATTRIBUTES;
newmode=attr->ia_mode;
- newmode &= NCP_SERVER(inode)->m.file_mode;
+#ifdef CONFIG_NCPFS_EXTRAS
+ if (!extras)
+#endif
+ newmode &= server->m.file_mode;
if (newmode & 0222) /* any write bit set */
{
- info.attributes &= ~0x60001;
+ info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
}
else
{
- info.attributes |= 0x60001;
+ info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
}
+#ifdef CONFIG_NCPFS_EXTRAS
+ if (extras) {
+ if (newmode & 0111) /* any execute bit set */
+ info.attributes |= aSHARED | aSYSTEM;
+ /* read for group/world and not in default file_mode */
+ else if (newmode & ~server->m.file_mode & 0444)
+ info.attributes |= aSHARED;
+ }
+#endif
}
}
#endif
@@ -546,6 +673,10 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
result = 0;
}
}
+#ifdef CONFIG_NCPFS_STRONG
+ if ((!result) && (info_mask & DM_ATTRIBUTES))
+ NCP_FINFO(inode)->nwattr = info.attributes;
+#endif
}
if ((attr->ia_valid & ATTR_SIZE) != 0) {
int written;
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 2df6fee09..8ada3752b 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 1995, 1996 by Volker Lendecke
* Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
+ * Modified 1998 Wolfram Pienkoss for NLS
*
*/
@@ -17,6 +18,7 @@
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
+
#include "ncplib_kernel.h"
/* maximum limit for ncp_objectname_ioctl */
@@ -485,6 +487,69 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
return 0;
}
#endif /* CONFIG_NCPFS_NDS_DOMAINS */
+
+#ifdef CONFIG_NCPFS_NLS
+/* Here we are select the iocharset and the codepage for NLS.
+ * Thanks Petr Vandrovec for idea and many hints.
+ */
+ case NCP_IOC_SETCHARSETS:
+ if ( (permission(inode, MAY_WRITE) != 0)
+ && (current->uid != server->m.mounted_uid))
+ {
+ return -EACCES;
+ }
+ if (server->root_setuped) return -EBUSY;
+ {
+ struct ncp_nls_ioctl user;
+ struct nls_table *codepage;
+ struct nls_table *iocharset;
+ struct nls_table *oldset_io;
+ struct nls_table *oldset_cp;
+
+ if (copy_from_user(&user,
+ (struct ncp_nls_ioctl*)arg,
+ sizeof(user))) return -EFAULT;
+
+ codepage = NULL;
+ if (!user.codepage[0]) {
+ codepage = load_nls_default();
+ }
+ else {
+ codepage = load_nls(user.codepage);
+ if (! codepage) {
+ return -EBADRQC;
+ }
+ }
+
+ iocharset = NULL;
+ if (user.iocharset[0] == 0) {
+ iocharset = load_nls_default();
+ }
+ else {
+ iocharset = load_nls(user.iocharset);
+ if (! iocharset) {
+ unload_nls(codepage);
+ return -EBADRQC;
+ }
+ }
+
+ oldset_cp = server->nls_vol;
+ server->nls_vol = codepage;
+ oldset_io = server->nls_io;
+ server->nls_io = iocharset;
+ server->nls_charsets = user;
+ if (oldset_cp) unload_nls(oldset_cp);
+ if (oldset_io) unload_nls(oldset_io);
+ return 0;
+ }
+
+ case NCP_IOC_GETCHARSETS: /* not tested */
+ if (copy_to_user((struct ncp_nls_ioctl*)arg,
+ &(server->nls_charsets),
+ sizeof(server->nls_charsets))) return -EFAULT;
+ return 0;
+#endif /* CONFIG_NCPFS_NLS */
+
default:
return -EINVAL;
}
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 2c7610d0b..6b321e6c9 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -137,8 +137,6 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma)
inode->i_atime = CURRENT_TIME;
}
- vma->vm_file = file;
- file->f_count++;
vma->vm_ops = &ncp_file_mmap;
return 0;
}
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index fc0bbf013..bb034a4e4 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -238,7 +238,8 @@ NCP_FINFO(inode)->volNumber, NCP_FINFO(inode)->dirEntNum, err);
}
static void ncp_add_handle_path(struct ncp_server *server, __u8 vol_num,
- __u32 dir_base, int have_dir_base, char *path)
+ __u32 dir_base, int have_dir_base,
+ const char *path)
{
ncp_add_byte(server, vol_num);
ncp_add_dword(server, dir_base);
@@ -468,12 +469,17 @@ ncp_lookup_volume(struct ncp_server *server, char *volname,
target->nameLen = strlen(volname);
strcpy(target->entryName, volname);
target->attributes = aDIR;
+ /* set dates to Jan 1, 1986 00:00 */
+ target->creationTime = target->modifyTime = cpu_to_le16(0x0000);
+ target->creationDate = target->modifyDate = target->lastAccessDate = cpu_to_le16(0x0C21);
return 0;
}
-int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
- struct inode *dir, __u32 info_mask,
- struct nw_modify_dos_info *info)
+int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *server,
+ struct inode *dir,
+ const char *path,
+ __u32 info_mask,
+ const struct nw_modify_dos_info *info)
{
__u8 volnum = NCP_FINFO(dir)->volNumber;
__u32 dirent = NCP_FINFO(dir)->dirEntNum;
@@ -487,13 +493,22 @@ int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
ncp_add_dword(server, info_mask);
ncp_add_mem(server, info, sizeof(*info));
- ncp_add_handle_path(server, volnum, dirent, 1, NULL);
+ ncp_add_handle_path(server, volnum, dirent, 1, path);
result = ncp_request(server, 87);
ncp_unlock_server(server);
return result;
}
+int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
+ struct inode *dir,
+ __u32 info_mask,
+ const struct nw_modify_dos_info *info)
+{
+ return ncp_modify_file_or_subdir_dos_info_path(server, dir, NULL,
+ info_mask, info);
+}
+
static int
ncp_DeleteNSEntry(struct ncp_server *server,
__u8 have_dir_base, __u8 volnum, __u32 dirent,
@@ -788,6 +803,35 @@ out:
return result;
}
+#ifdef CONFIG_NCPFS_EXTRAS
+int
+ncp_read_kernel(struct ncp_server *server, const char *file_id,
+ __u32 offset, __u16 to_read, char *target, int *bytes_read) {
+ int error;
+ mm_segment_t old_fs;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ error = ncp_read(server, file_id, offset, to_read, target, bytes_read);
+ set_fs(old_fs);
+ return error;
+}
+
+int
+ncp_write_kernel(struct ncp_server *server, const char *file_id,
+ __u32 offset, __u16 to_write,
+ const char *source, int *bytes_written) {
+ int error;
+ mm_segment_t old_fs;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ error = ncp_write(server, file_id, offset, to_write, source, bytes_written);
+ set_fs(old_fs);
+ return error;
+}
+#endif
+
#ifdef CONFIG_NCPFS_IOCTL_LOCKING
int
ncp_LogPhysicalRecord(struct ncp_server *server, const char *file_id,
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 7834c6c4f..cc1df1896 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -4,6 +4,7 @@
* Copyright (C) 1995, 1996 by Volker Lendecke
* Modified for big endian by J.F. Chadima and David S. Miller
* Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
+ * Modified 1998 Wolfram Pienkoss for NLS
*
*/
@@ -23,6 +24,10 @@
#include <asm/unaligned.h>
#include <asm/string.h>
+#ifdef CONFIG_NCPFS_NLS
+#include <linux/nls.h>
+#endif
+
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_fs_sb.h>
@@ -36,12 +41,19 @@ int ncp_close_file(struct ncp_server *, const char *);
int ncp_read(struct ncp_server *, const char *, __u32, __u16, char *, int *);
int ncp_write(struct ncp_server *, const char *, __u32, __u16,
const char *, int *);
+#ifdef CONFIG_NCPFS_EXTRAS
+int ncp_read_kernel(struct ncp_server *, const char *, __u32, __u16, char *, int *);
+int ncp_write_kernel(struct ncp_server *, const char *, __u32, __u16,
+ const char *, int *);
+#endif
int ncp_obtain_info(struct ncp_server *server, struct inode *, char *,
struct nw_info_struct *target);
int ncp_lookup_volume(struct ncp_server *, char *, struct nw_info_struct *);
int ncp_modify_file_or_subdir_dos_info(struct ncp_server *, struct inode *,
- __u32, struct nw_modify_dos_info *info);
+ __u32, const struct nw_modify_dos_info *info);
+int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *, struct inode *,
+ const char* path, __u32, const struct nw_modify_dos_info *info);
int ncp_del_file_or_subdir2(struct ncp_server *, struct dentry*);
int ncp_del_file_or_subdir(struct ncp_server *, struct inode *, char *);
@@ -75,4 +87,83 @@ int
ncp_mount_subdir(struct ncp_server* server, __u8 volNumber,
__u8 srcNS, __u32 srcDirEntNum);
#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */
+
+#ifdef CONFIG_NCPFS_NLS
+/* This are the NLS conversion routines with inspirations and code parts
+ * from the vfat file system and hints from Petr Vandrovec.
+ */
+
+/*
+ * It should be replaced by charset specifc conversion. Gordon Chaffee
+ * has prepared some things, but I don't know, what he thinks about it.
+ * The conversion tables for the io charsets should be generatable by
+ * Unicode table, shouldn't it? I have written so generation code for it.
+ * The tables for the vendor specific codepages...? Hmm. The Samba sources
+ * contains also any hints.
+ */
+
+#define toupperif(c, u) ((((u) != 0) && ((c) >= 'a') && ((c) <= 'z')) \
+ ? (c)-('a'-'A') : (c))
+#define tolowerif(c, u) ((((u) != 0) && ((c) >= 'A') && ((c) <= 'Z')) \
+ ? (c)-('A'-'a') : (c))
+
+static inline void
+io2vol(struct ncp_server *server, char *name, int case_trans)
+{
+ unsigned char nc;
+ unsigned char *np;
+ unsigned char *up;
+ struct nls_unicode uc;
+ struct nls_table *nls_in;
+ struct nls_table *nls_out;
+
+ nls_in = server->nls_io;
+ nls_out = server->nls_vol;
+ np = name;
+
+ while (*np)
+ {
+ nc = 0;
+ uc = nls_in->charset2uni[toupperif(*np, case_trans)];
+ up = nls_out->page_uni2charset[uc.uni2];
+ if (up != NULL) nc = up[uc.uni1];
+ if (nc != 0) *np = nc;
+ np++;
+ }
+}
+
+static inline void
+vol2io(struct ncp_server *server, char *name, int case_trans)
+{
+ unsigned char nc;
+ unsigned char *np;
+ unsigned char *up;
+ struct nls_unicode uc;
+ struct nls_table *nls_in;
+ struct nls_table *nls_out;
+
+ nls_in = server->nls_vol;
+ nls_out = server->nls_io;
+ np = name;
+
+ while (*np)
+ {
+ nc = 0;
+ uc = nls_in->charset2uni[*np];
+ up = nls_out->page_uni2charset[uc.uni2];
+ if (up != NULL) nc = up[uc.uni1];
+ if (nc == 0) nc = *np;
+ *np = tolowerif(nc, case_trans);
+ np++;
+ }
+}
+
+#else
+
+#define io2vol(S,N,U) if (U) str_upper(N)
+#define vol2io(S,N,U) if (U) str_lower(N)
+
+#endif /* CONFIG_NCPFS_NLS */
+
#endif /* _NCPLIB_H */
+
diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c
index cdcfc4220..865fc68a3 100644
--- a/fs/ncpfs/sock.c
+++ b/fs/ncpfs/sock.c
@@ -94,7 +94,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
poll_table wait_table;
struct poll_table_entry entry;
int init_timeout, max_timeout;
- int timeout; long tmp_timeout;
+ int timeout;
int retrans;
int major_timeout_seen;
int acknowledge_seen;
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
new file mode 100644
index 000000000..a923c218c
--- /dev/null
+++ b/fs/ncpfs/symlink.c
@@ -0,0 +1,212 @@
+/*
+ * linux/fs/ncpfs/symlink.c
+ *
+ * Code for allowing symbolic links on NCPFS (i.e. NetWare)
+ * Symbolic links are not supported on native NetWare, so we use an
+ * infrequently-used flag (Sh) and store a two-word magic header in
+ * the file to make sure we don't accidentally use a non-link file
+ * as a link.
+ *
+ * from linux/fs/ext2/symlink.c
+ *
+ * Copyright (C) 1998-99, Frank A. Vorstenbosch
+ *
+ * ncpfs symlink handling code
+ * NLS support (c) 1999 Petr Vandrovec
+ *
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_NCPFS_EXTRAS
+
+#include <asm/uaccess.h>
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ncp_fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/stat.h>
+#include "ncplib_kernel.h"
+
+
+/* these magic numbers must appear in the symlink file -- this makes it a bit
+ more resilient against the magic attributes being set on random files. */
+
+#define NCP_SYMLINK_MAGIC0 le32_to_cpu(0x6c6d7973) /* "symlnk->" */
+#define NCP_SYMLINK_MAGIC1 le32_to_cpu(0x3e2d6b6e)
+
+static int ncp_readlink(struct dentry *, char *, int);
+static struct dentry *ncp_follow_link(struct dentry *, struct dentry *, unsigned int);
+int ncp_create_new(struct inode *dir, struct dentry *dentry,
+ int mode,int attributes);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations ncp_symlink_inode_operations={
+ NULL, /* no file-operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ ncp_readlink, /* readlink */
+ ncp_follow_link, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
+
+/* ----- follow a symbolic link ------------------------------------------ */
+
+static struct dentry *ncp_follow_link(struct dentry *dentry,
+ struct dentry *base,
+ unsigned int follow)
+{
+ struct inode *inode=dentry->d_inode;
+ int error, length, cnt;
+ char *link;
+
+#ifdef DEBUG
+ printk("ncp_follow_link(dentry=%p,base=%p,follow=%u)\n",dentry,base,follow);
+#endif
+
+ if(!S_ISLNK(inode->i_mode)) {
+ dput(base);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if(ncp_make_open(inode,O_RDONLY)) {
+ dput(base);
+ return ERR_PTR(-EIO);
+ }
+
+ for (cnt = 0; (link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE+1, GFP_NFS))==NULL; cnt++) {
+ if (cnt > 10) {
+ dput(base);
+ return ERR_PTR(-EAGAIN); /* -ENOMEM? */
+ }
+ schedule();
+ }
+
+ error=ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
+ 0,NCP_MAX_SYMLINK_SIZE,link,&length);
+
+ if (error!=0 || length<NCP_MIN_SYMLINK_SIZE ||
+ ((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 || ((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) {
+ dput(base);
+ kfree(link);
+ return ERR_PTR(-EIO);
+ }
+
+ link[length]=0;
+
+ vol2io(NCP_SERVER(inode), link+8, 0);
+
+ /* UPDATE_ATIME(inode); */
+ base=lookup_dentry(link+8, base, follow);
+ kfree(link);
+
+ return base;
+}
+
+/* ----- read symbolic link ---------------------------------------------- */
+
+static int ncp_readlink(struct dentry * dentry, char * buffer, int buflen)
+{
+ struct inode *inode=dentry->d_inode;
+ char *link;
+ int length,error;
+
+#ifdef DEBUG
+ printk("ncp_readlink(dentry=%p,buffer=%p,buflen=%d)\n",dentry,buffer,buflen);
+#endif
+
+ if(!S_ISLNK(inode->i_mode))
+ return -EINVAL;
+
+ if(ncp_make_open(inode,O_RDONLY))
+ return -EIO;
+
+ if((link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE+1,GFP_NFS))==NULL)
+ return -ENOMEM;
+
+ error = ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
+ 0,NCP_MAX_SYMLINK_SIZE,link,&length);
+
+ if (error!=0 || length < NCP_MIN_SYMLINK_SIZE || buflen < (length-8) ||
+ ((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 ||((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) {
+ error = -EIO;
+ goto out;
+ }
+
+ link[length] = 0;
+
+ vol2io(NCP_SERVER(inode), link+8, 0);
+
+ error = length - 8;
+ if(copy_to_user(buffer, link+8, error))
+ error = -EFAULT;
+
+out:;
+ kfree(link);
+ return error;
+}
+
+/* ----- create a new symbolic link -------------------------------------- */
+
+int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
+ int i,length;
+ struct inode *inode;
+ char *link;
+
+#ifdef DEBUG
+ printk("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname);
+#endif
+
+ if (!(NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS))
+ return -EPERM; /* EPERM is returned by VFS if symlink procedure does not exist */
+
+ if ((length=strlen(symname))>NCP_MAX_SYMLINK_SIZE)
+ return -EINVAL;
+
+ if ((link=(char *)kmalloc(length+9,GFP_NFS))==NULL)
+ return -ENOMEM;
+
+ if (ncp_create_new(dir,dentry,0,aSHARED|aHIDDEN)) {
+ kfree(link);
+ return -EIO;
+ }
+
+ inode=dentry->d_inode;
+
+ ((__u32 *)link)[0]=NCP_SYMLINK_MAGIC0;
+ ((__u32 *)link)[1]=NCP_SYMLINK_MAGIC1;
+ memcpy(link+8, symname, length+1); /* including last zero for io2vol */
+
+ /* map to/from server charset, do not touch upper/lower case as
+ symlink can point out of ncp filesystem */
+ io2vol(NCP_SERVER(inode), link+8, 0);
+
+ if(ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
+ 0, length+8, link, &i) || i!=length+8) {
+ kfree(link);
+ return -EIO;
+ }
+
+ kfree(link);
+ return 0;
+}
+#endif
+
+/* ----- EOF ----- */
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index c71893476..ef5bc6ea9 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -51,10 +51,9 @@ struct nfs_dirent {
static int nfs_safe_remove(struct dentry *);
-static int nfs_dir_open(struct inode *, struct file *);
static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
static int nfs_readdir(struct file *, void *, filldir_t);
-static int nfs_lookup(struct inode *, struct dentry *);
+static struct dentry *nfs_lookup(struct inode *, struct dentry *);
static int nfs_create(struct inode *, struct dentry *, int);
static int nfs_mkdir(struct inode *, struct dentry *, int);
static int nfs_rmdir(struct inode *, struct dentry *);
@@ -73,9 +72,9 @@ static struct file_operations nfs_dir_operations = {
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
- nfs_dir_open, /* open - revalidate */
+ nfs_open, /* open */
NULL, /* flush */
- NULL, /* no special release code */
+ nfs_release, /* release */
NULL /* fsync */
};
@@ -102,16 +101,6 @@ struct inode_operations nfs_dir_inode_operations = {
nfs_revalidate, /* revalidate */
};
-static int
-nfs_dir_open(struct inode *dir, struct file *file)
-{
- struct dentry *dentry = file->f_dentry;
-
- dfprintk(VFS, "NFS: nfs_dir_open(%s/%s)\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- return nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
-}
-
static ssize_t
nfs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
{
@@ -147,11 +136,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
dfprintk(VFS, "NFS: nfs_readdir(%s/%s)\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
- result = -EBADF;
- if (!inode || !S_ISDIR(inode->i_mode)) {
- printk("nfs_readdir: inode is NULL or not a directory\n");
- goto out;
- }
result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
if (result < 0)
@@ -380,7 +364,48 @@ static inline void nfs_renew_times(struct dentry * dentry)
dentry->d_time = jiffies;
}
-#define NFS_REVALIDATE_INTERVAL (5*HZ)
+static inline int nfs_dentry_force_reval(struct dentry *dentry, int flags)
+{
+ struct inode *inode = dentry->d_inode;
+ unsigned long timeout = NFS_ATTRTIMEO(inode);
+
+ /*
+ * If it's the last lookup in a series, we use a stricter
+ * cache consistency check by looking at the parent mtime.
+ *
+ * If it's been modified in the last hour, be really strict.
+ * (This still means that we can avoid doing unnecessary
+ * work on directories like /usr/share/bin etc which basically
+ * never change).
+ */
+ if (!(flags & LOOKUP_CONTINUE)) {
+ long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
+
+ if (diff < 15*60)
+ timeout = 0;
+ }
+
+ return time_after(jiffies,dentry->d_time + timeout);
+}
+
+/*
+ * We judge how long we want to trust negative
+ * dentries by looking at the parent inode mtime.
+ *
+ * If mtime is close to present time, we revalidate
+ * more often.
+ */
+static inline int nfs_neg_need_reval(struct dentry *dentry)
+{
+ unsigned long timeout = 30 * HZ;
+ long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
+
+ if (diff < 5*60)
+ timeout = 1 * HZ;
+
+ return time_after(jiffies, dentry->d_time + timeout);
+}
+
/*
* This is called every time the dcache has a lookup hit,
* and we should check whether we can really trust that
@@ -393,43 +418,41 @@ static inline void nfs_renew_times(struct dentry * dentry)
* we do a new lookup and verify that the dentry is still
* correct.
*/
-static int nfs_lookup_revalidate(struct dentry * dentry)
+static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
{
struct dentry * parent = dentry->d_parent;
struct inode * inode = dentry->d_inode;
- unsigned long time = jiffies - dentry->d_time;
int error;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
/*
- * If we don't have an inode, let's just assume
- * a 5-second "live" time for negative dentries.
+ * If we don't have an inode, let's look at the parent
+ * directory mtime to get a hint about how often we
+ * should validate things..
*/
if (!inode) {
- if (time < NFS_REVALIDATE_INTERVAL)
- goto out_valid;
- goto out_bad;
+ if (nfs_neg_need_reval(dentry))
+ goto out_bad;
+ goto out_valid;
}
if (is_bad_inode(inode)) {
-#ifdef NFS_PARANOIA
-printk("nfs_lookup_validate: %s/%s has dud inode\n",
-parent->d_name.name, dentry->d_name.name);
-#endif
+ dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
+ parent->d_name.name, dentry->d_name.name);
goto out_bad;
}
- if (time < NFS_ATTRTIMEO(inode))
+ if (IS_ROOT(dentry))
goto out_valid;
- if (IS_ROOT(dentry))
+ if (!nfs_dentry_force_reval(dentry, flags))
goto out_valid;
/*
* Do a new lookup and check the dentry attributes.
*/
- error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent),
+ error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent),
dentry->d_name.name, &fhandle, &fattr);
if (error)
goto out_bad;
@@ -439,8 +462,10 @@ parent->d_name.name, dentry->d_name.name);
goto out_bad;
/* Filehandle matches? */
- if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh)))
- goto out_bad;
+ if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) {
+ if (dentry->d_count < 2)
+ goto out_bad;
+ }
/* Ok, remeber that we successfully checked it.. */
nfs_renew_times(dentry);
@@ -449,6 +474,10 @@ parent->d_name.name, dentry->d_name.name);
out_valid:
return 1;
out_bad:
+ if (dentry->d_parent->d_inode)
+ nfs_invalidate_dircache(dentry->d_parent->d_inode);
+ if (inode && S_ISDIR(inode->i_mode))
+ nfs_invalidate_dircache(inode);
return 0;
}
@@ -502,7 +531,7 @@ static void nfs_dentry_release(struct dentry *dentry)
}
struct dentry_operations nfs_dentry_operations = {
- nfs_lookup_revalidate, /* d_validate(struct dentry *) */
+ nfs_lookup_revalidate, /* d_revalidate(struct dentry *, int) */
NULL, /* d_hash */
NULL, /* d_compare */
nfs_dentry_delete, /* d_delete(struct dentry *) */
@@ -533,7 +562,7 @@ static void show_dentry(struct list_head * dlist)
}
#endif
-static int nfs_lookup(struct inode *dir, struct dentry * dentry)
+static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
{
struct inode *inode;
int error;
@@ -579,7 +608,7 @@ show_dentry(&inode->i_dentry);
}
}
out:
- return error;
+ return ERR_PTR(error);
}
/*
@@ -624,10 +653,6 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
- error = -ENAMETOOLONG;
- if (dentry->d_name.len > NFS_MAXNAMLEN)
- goto out;
-
sattr.mode = mode;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
@@ -642,7 +667,6 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
error = nfs_instantiate(dentry, &fhandle, &fattr);
if (error)
d_drop(dentry);
-out:
return error;
}
@@ -659,9 +683,6 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
- if (dentry->d_name.len > NFS_MAXNAMLEN)
- return -ENAMETOOLONG;
-
sattr.mode = mode;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
if (S_ISCHR(mode) || S_ISBLK(mode))
@@ -691,10 +712,6 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
- error = -ENAMETOOLONG;
- if (dentry->d_name.len > NFS_MAXNAMLEN)
- goto out;
-
sattr.mode = mode | S_IFDIR;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
@@ -709,21 +726,9 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
nfs_invalidate_dircache(dir);
error = nfs_proc_mkdir(NFS_DSERVER(dentry), NFS_FH(dentry->d_parent),
dentry->d_name.name, &sattr, &fhandle, &fattr);
-out:
return error;
}
-/*
- * To avoid retaining a stale inode reference, we check the dentry
- * use count prior to the operation, and return EBUSY if it has
- * multiple users.
- *
- * We update inode->i_nlink and free the inode prior to the operation
- * to avoid possible races if the server reuses the inode.
- *
- * FIXME! We don't do it anymore (2.1.131) - it interacts badly with
- * new rmdir(). -- AV
- */
static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{
int error;
@@ -731,14 +736,6 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
- error = -ENAMETOOLONG;
- if (dentry->d_name.len > NFS_MAXNAMLEN)
- goto out;
-
- error = -EBUSY;
- if (!list_empty(&dentry->d_hash))
- goto out;
-
#ifdef NFS_PARANOIA
if (dentry->d_inode->i_count > 1)
printk("nfs_rmdir: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
@@ -746,15 +743,17 @@ dentry->d_parent->d_name.name, dentry->d_name.name,
dentry->d_inode->i_count, dentry->d_inode->i_nlink);
#endif
- /*
- * Update i_nlink and free the inode before unlinking.
- */
- if (dentry->d_inode->i_nlink)
- dentry->d_inode->i_nlink --;
nfs_invalidate_dircache(dir);
error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
dentry->d_name.name);
-out:
+
+ /* Update i_nlink and invalidate dentry. */
+ if (!error) {
+ d_drop(dentry);
+ if (dentry->d_inode->i_nlink)
+ dentry->d_inode->i_nlink --;
+ }
+
return error;
}
@@ -794,7 +793,7 @@ struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen)
{
struct qstr sqstr;
struct dentry *sdentry;
- int error;
+ struct dentry *res;
sqstr.name = silly;
sqstr.len = slen;
@@ -804,10 +803,10 @@ struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen)
sdentry = d_alloc(parent, &sqstr);
if (sdentry == NULL)
return ERR_PTR(-ENOMEM);
- error = nfs_lookup(parent->d_inode, sdentry);
- if (error) {
+ res = nfs_lookup(parent->d_inode, sdentry);
+ if (res) {
dput(sdentry);
- return ERR_PTR(error);
+ return res;
}
}
return sdentry;
@@ -964,10 +963,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
- error = -ENAMETOOLONG;
- if (dentry->d_name.len > NFS_MAXNAMLEN)
- goto out;
-
error = nfs_sillyrename(dir, dentry);
if (error && error != -EBUSY) {
error = nfs_safe_remove(dentry);
@@ -975,7 +970,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
nfs_renew_times(dentry);
}
}
-out:
return error;
}
@@ -989,9 +983,6 @@ nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
error = -ENAMETOOLONG;
- if (dentry->d_name.len > NFS_MAXNAMLEN)
- goto out;
-
if (strlen(symname) > NFS_MAXPATHLEN)
goto out;
@@ -1038,10 +1029,6 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
dentry->d_parent->d_name.name, dentry->d_name.name);
- error = -ENAMETOOLONG;
- if (dentry->d_name.len > NFS_MAXNAMLEN)
- goto out;
-
/*
* Drop the dentry in advance to force a new lookup.
* Since nfs_proc_link doesn't return a file handle,
@@ -1058,7 +1045,6 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
*/
inode->i_nlink++;
}
-out:
return error;
}
@@ -1099,11 +1085,6 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
new_dentry->d_count);
- error = -ENAMETOOLONG;
- if (old_dentry->d_name.len > NFS_MAXNAMLEN ||
- new_dentry->d_name.len > NFS_MAXNAMLEN)
- goto out;
-
/*
* First check whether the target is busy ... we can't
* safely do _any_ rename if the target is in use.
@@ -1112,28 +1093,24 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
* silly-rename. If the silly-rename succeeds, the
* copied dentry is hashed and becomes the new target.
*
- * For directories, prune any unused children.
+ * With directories check is done in VFS.
*/
error = -EBUSY;
if (new_dentry->d_count > 1 && new_inode) {
- if (S_ISREG(new_inode->i_mode)) {
- int err;
- /* copy the target dentry's name */
- dentry = d_alloc(new_dentry->d_parent,
- &new_dentry->d_name);
- if (!dentry)
- goto out;
-
- /* silly-rename the existing target ... */
- err = nfs_sillyrename(new_dir, new_dentry);
- if (!err) {
- new_dentry = dentry;
- new_inode = NULL;
- /* hash the replacement target */
- d_add(new_dentry, NULL);
- }
- } else if (!list_empty(&new_dentry->d_subdirs)) {
- shrink_dcache_parent(new_dentry);
+ int err;
+ /* copy the target dentry's name */
+ dentry = d_alloc(new_dentry->d_parent,
+ &new_dentry->d_name);
+ if (!dentry)
+ goto out;
+
+ /* silly-rename the existing target ... */
+ err = nfs_sillyrename(new_dir, new_dentry);
+ if (!err) {
+ new_dentry = dentry;
+ new_inode = NULL;
+ /* hash the replacement target */
+ d_add(new_dentry, NULL);
}
/* dentry still busy? */
@@ -1208,7 +1185,7 @@ new_inode->i_count, new_inode->i_nlink);
error = nfs_proc_rename(NFS_DSERVER(old_dentry),
NFS_FH(old_dentry->d_parent), old_dentry->d_name.name,
NFS_FH(new_dentry->d_parent), new_dentry->d_name.name);
- if (!error) {
+ if (!error && !S_ISDIR(old_inode->i_mode)) {
/* Update the dcache if needed */
if (rehash)
d_add(new_dentry, NULL);
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 25caa03d3..1cf40d3ae 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -36,7 +36,6 @@ static int nfs_file_mmap(struct file *, struct vm_area_struct *);
static ssize_t nfs_file_read(struct file *, char *, size_t, loff_t *);
static ssize_t nfs_file_write(struct file *, const char *, size_t, loff_t *);
static int nfs_file_flush(struct file *);
-static int nfs_file_close(struct inode *, struct file *);
static int nfs_fsync(struct file *, struct dentry *dentry);
static struct file_operations nfs_file_operations = {
@@ -47,9 +46,9 @@ static struct file_operations nfs_file_operations = {
NULL, /* select - default */
NULL, /* ioctl - default */
nfs_file_mmap, /* mmap */
- NULL, /* no special open is needed */
+ nfs_open, /* open */
nfs_file_flush, /* flush */
- nfs_file_close, /* release */
+ nfs_release, /* release */
nfs_fsync, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
@@ -86,35 +85,23 @@ struct inode_operations nfs_file_inode_operations = {
#endif
/*
- * Sync the file..
- */
-static int
-nfs_file_close(struct inode *inode, struct file *file)
-{
- int status;
-
- dfprintk(VFS, "nfs: close(%x/%ld)\n", inode->i_dev, inode->i_ino);
-
- status = nfs_wb_all(inode);
- if (!status)
- status = nfs_write_error(inode);
- return status;
-}
-
-/*
* Flush all dirty pages, and check for write errors.
*
- * We should probably do this better - this does get called at every
- * close, so we should probably just flush the changes that "this"
- * file has done and report on only those.
- *
- * Right now we use the "flush everything" approach. Overkill, but
- * works.
*/
static int
nfs_file_flush(struct file *file)
{
- return nfs_file_close(file->f_dentry->d_inode, file);
+ struct inode *inode = file->f_dentry->d_inode;
+ int status;
+
+ dfprintk(VFS, "nfs: flush(%x/%ld)\n", inode->i_dev, inode->i_ino);
+
+ status = nfs_wb_file(inode, file);
+ if (!status) {
+ status = file->f_error;
+ file->f_error = 0;
+ }
+ return status;
}
static ssize_t
@@ -161,9 +148,11 @@ nfs_fsync(struct file *file, struct dentry *dentry)
dfprintk(VFS, "nfs: fsync(%x/%ld)\n", inode->i_dev, inode->i_ino);
- status = nfs_wb_pid(inode, current->pid);
- if (!status)
- status = nfs_write_error(inode);
+ status = nfs_wb_file(inode, file);
+ if (!status) {
+ status = file->f_error;
+ file->f_error = 0;
+ }
return status;
}
@@ -193,10 +182,7 @@ nfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
if (!count)
goto out;
- /* Check for an error from a previous async call */
- result = nfs_write_error(inode);
- if (!result)
- result = generic_file_write(file, buf, count, ppos);
+ result = generic_file_write(file, buf, count, ppos);
out:
return result;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 72130244a..c46eeb57b 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -37,6 +37,8 @@
#define NFS_PARANOIA 1
static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
+static void nfs_zap_caches(struct inode *);
+static void nfs_invalidate_inode(struct inode *);
static void nfs_read_inode(struct inode *);
static void nfs_put_inode(struct inode *);
@@ -224,6 +226,8 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
lock_super(sb);
+ sb->s_flags |= MS_ODD_RENAME; /* This should go away */
+
sb->s_magic = NFS_SUPER_MAGIC;
sb->s_op = &nfs_sops;
sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
@@ -232,6 +236,11 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
server->rsize = nfs_block_size(data->rsize, NULL);
server->wsize = nfs_block_size(data->wsize, NULL);
server->flags = data->flags;
+
+ if (data->flags & NFS_MOUNT_NOAC) {
+ data->acregmin = data->acregmax = 0;
+ data->acdirmin = data->acdirmax = 0;
+ }
server->acregmin = data->acregmin*HZ;
server->acregmax = data->acregmax*HZ;
server->acdirmin = data->acdirmin*HZ;
@@ -386,25 +395,61 @@ nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
* could cause file corruption. But since the dentry
* count is 0 and all pending IO for a dentry has been
* flushed when the count went to 0, we're safe here.
+ * Also returns the number of unhashed dentries
*/
-void nfs_free_dentries(struct inode *inode)
+static int
+nfs_free_dentries(struct inode *inode)
{
struct list_head *tmp, *head = &inode->i_dentry;
+ int unhashed;
restart:
tmp = head;
+ unhashed = 0;
while ((tmp = tmp->next) != head) {
struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
-printk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-dentry->d_count, !list_empty(&dentry->d_hash));
+ dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ dentry->d_count, !list_empty(&dentry->d_hash));
if (!dentry->d_count) {
dget(dentry);
d_drop(dentry);
dput(dentry);
goto restart;
}
+ if (!list_empty(&dentry->d_hash))
+ unhashed++;
}
+ return unhashed;
+}
+
+/*
+ * Invalidate the local caches
+ */
+static void
+nfs_zap_caches(struct inode *inode)
+{
+ NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+ NFS_CACHEINV(inode);
+
+ if (S_ISDIR(inode->i_mode))
+ nfs_invalidate_dircache(inode);
+ else
+ invalidate_inode_pages(inode);
+}
+
+/*
+ * Invalidate, but do not unhash, the inode
+ */
+static void
+nfs_invalidate_inode(struct inode *inode)
+{
+ umode_t save_mode = inode->i_mode;
+
+ make_bad_inode(inode);
+ inode->i_mode = save_mode;
+ nfs_inval(inode);
+ nfs_zap_caches(inode);
}
/*
@@ -506,7 +551,7 @@ static struct inode *
__nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
{
struct inode *inode;
- int max_count;
+ int max_count, stale_inode, unhashed = 0;
retry:
inode = iget(sb, fattr->fileid);
@@ -525,27 +570,30 @@ retry:
* as the inode may have become a different object.
* (We can probably handle modes changes here, too.)
*/
+ stale_inode = inode->i_mode &&
+ ((fattr->mode ^ inode->i_mode) & S_IFMT);
+ stale_inode |= inode->i_count && inode->i_count == unhashed;
max_count = S_ISDIR(fattr->mode) ? 1 : fattr->nlink;
- if (inode->i_count > max_count) {
-printk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
-inode->i_ino, inode->i_count, inode->i_nlink);
- nfs_free_dentries(inode);
- if (inode->i_count > max_count) {
-printk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
-inode->i_ino, inode->i_count);
+ if (stale_inode || inode->i_count > max_count + unhashed) {
+ dprintk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
+ inode->i_ino, inode->i_count, inode->i_nlink);
+ unhashed = nfs_free_dentries(inode);
+ if (stale_inode || inode->i_count > max_count + unhashed) {
+ printk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
+ inode->i_ino, inode->i_count);
if (!list_empty(&inode->i_dentry)) {
struct dentry *dentry;
dentry = list_entry(inode->i_dentry.next,
struct dentry, d_alias);
-printk("__nfs_fhget: killing %s/%s filehandle\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
- memset(dentry->d_fsdata, 0,
+ printk("__nfs_fhget: killing %s/%s filehandle\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name);
+ memset(dentry->d_fsdata, 0,
sizeof(struct nfs_fh));
- } else
- printk("NFS: inode %ld busy, no aliases?\n",
- inode->i_ino);
- make_bad_inode(inode);
+ }
remove_inode_hash(inode);
+ nfs_invalidate_inode(inode);
+ unhashed = 0;
}
iput(inode);
goto retry;
@@ -597,10 +645,8 @@ printk("nfs_notify_change: revalidate failed, error=%d\n", error);
sattr.gid = attr->ia_gid;
sattr.size = (u32) -1;
- if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode)) {
+ if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode))
sattr.size = attr->ia_size;
- nfs_flush_trunc(inode, sattr.size);
- }
sattr.mtime.seconds = sattr.mtime.useconds = (u32) -1;
if (attr->ia_valid & ATTR_MTIME) {
@@ -614,6 +660,10 @@ printk("nfs_notify_change: revalidate failed, error=%d\n", error);
sattr.atime.useconds = 0;
}
+ error = nfs_wb_all(inode);
+ if (error)
+ goto out;
+
error = nfs_proc_setattr(NFS_DSERVER(dentry), NFS_FH(dentry),
&sattr, &fattr);
if (error)
@@ -646,6 +696,22 @@ nfs_revalidate(struct dentry *dentry)
}
/*
+ * These are probably going to contain hooks for
+ * allocating and releasing RPC credentials for
+ * the file. I'll have to think about Tronds patch
+ * a bit more..
+ */
+int nfs_open(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+int nfs_release(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/*
* This function is called whenever some part of NFS notices that
* the cached attributes have to be refreshed.
*/
@@ -656,10 +722,6 @@ _nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
int status = 0;
struct nfs_fattr fattr;
- /* Don't bother revalidating if we've done it recently */
- if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode))
- goto out;
-
dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
inode->i_ino);
@@ -668,10 +730,9 @@ _nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
int error;
u32 *fh;
struct nfs_fh fhandle;
-#ifdef NFS_PARANOIA
-printk("nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status);
-#endif
+ dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name, inode->i_ino, status);
if (status != -ESTALE)
goto out;
/*
@@ -679,26 +740,25 @@ dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status);
* and find out what the filehandle should be.
*/
fh = (u32 *) NFS_FH(dentry);
- printk("NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
+ dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
error = nfs_proc_lookup(server, NFS_FH(dentry->d_parent),
dentry->d_name.name, &fhandle, &fattr);
if (error) {
- printk("NFS: lookup failed, error=%d\n", error);
+ dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error);
goto out;
}
fh = (u32 *) &fhandle;
- printk(" %08x%08x%08x%08x%08x%08x%08x%08x\n",
+ dfprintk(PAGECACHE, " %08x%08x%08x%08x%08x%08x%08x%08x\n",
fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
goto out;
}
status = nfs_refresh_inode(inode, &fattr);
if (status) {
-#ifdef NFS_PARANOIA
-printk("nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status);
-#endif
+ dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name, inode->i_ino, status);
goto out;
}
dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
@@ -804,29 +864,18 @@ out_changed:
printk("nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
inode->i_ino, inode->i_mode, fattr->mode);
#endif
- fattr->mode = inode->i_mode; /* save mode */
- make_bad_inode(inode);
- nfs_inval(inode);
- inode->i_mode = fattr->mode; /* restore mode */
/*
* No need to worry about unhashing the dentry, as the
* lookup validation will know that the inode is bad.
- * (But we fall through to invalidate the caches.)
*/
+ nfs_invalidate_inode(inode);
+ goto out;
out_invalid:
- /*
- * Invalidate the local caches
- */
#ifdef NFS_DEBUG_VERBOSE
printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
#endif
- if (!S_ISDIR(inode->i_mode))
- invalidate_inode_pages(inode);
- else
- nfs_invalidate_dircache(inode);
- NFS_CACHEINV(inode);
- NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+ nfs_zap_caches(inode);
goto out;
}
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 1c6a74a71..a4c4e86d5 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -612,6 +612,7 @@ static struct {
{ NFSERR_FBIG, EFBIG },
{ NFSERR_NOSPC, ENOSPC },
{ NFSERR_ROFS, EROFS },
+ { NFSERR_OPNOTSUPP, EOPNOTSUPP },
{ NFSERR_NAMETOOLONG, ENAMETOOLONG },
{ NFSERR_NOTEMPTY, ENOTEMPTY },
{ NFSERR_DQUOT, EDQUOT },
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index bf23ad8aa..9194c801f 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -54,13 +54,12 @@ static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen)
dfprintk(VFS, "nfs: readlink(%s/%s)\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
- if (buflen > NFS_MAXPATHLEN)
- buflen = NFS_MAXPATHLEN;
error = nfs_proc_readlink(NFS_DSERVER(dentry), NFS_FH(dentry),
- &mem, &res, &len, buflen);
+ &mem, &res, &len, NFS_MAXPATHLEN);
if (! error) {
+ if (len > buflen)
+ len = buflen;
copy_to_user(buffer, res, len);
- put_user('\0', buffer + len);
error = len;
kfree(mem);
}
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 3b30a6a5a..276064c5e 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -50,6 +50,7 @@
#include <linux/malloc.h>
#include <linux/swap.h>
#include <linux/pagemap.h>
+#include <linux/file.h>
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
@@ -237,17 +238,6 @@ update_write_request(struct nfs_wreq *req, unsigned int first,
if (rqlast < first || last < rqfirst)
return 0;
- /* Check the credentials associated with this write request.
- * If the buffer is owned by the same user, we can happily
- * add our data without risking server permission problems.
- * Note that I'm not messing around with RPC root override creds
- * here, because they're used by swap requests only which
- * always write out full pages. */
- if (!rpcauth_matchcred(&req->wb_task, req->wb_task.tk_cred)) {
- dprintk("NFS: update failed (cred mismatch)\n");
- return 0;
- }
-
if (first < rqfirst)
rqfirst = first;
if (rqlast < last)
@@ -271,9 +261,10 @@ free_write_request(struct nfs_wreq * req)
* Create and initialize a writeback request
*/
static inline struct nfs_wreq *
-create_write_request(struct dentry *dentry, struct inode *inode,
- struct page *page, unsigned int offset, unsigned int bytes)
+create_write_request(struct file * file, struct page *page, unsigned int offset, unsigned int bytes)
{
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct nfs_wreq *wreq;
struct rpc_task *task;
@@ -298,8 +289,7 @@ create_write_request(struct dentry *dentry, struct inode *inode,
goto out_req;
/* Put the task on inode's writeback request list. */
- wreq->wb_dentry = dentry;
- wreq->wb_inode = inode;
+ wreq->wb_file = file;
wreq->wb_pid = current->pid;
wreq->wb_page = page;
wreq->wb_offset = offset;
@@ -336,7 +326,9 @@ static inline int
schedule_write_request(struct nfs_wreq *req, int sync)
{
struct rpc_task *task = &req->wb_task;
- struct inode *inode = req->wb_inode;
+ struct file *file = req->wb_file;
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
if (NFS_CONGESTED(inode) || nr_write_requests >= NFS_WRITEBACK_MAX)
sync = 1;
@@ -367,7 +359,10 @@ schedule_write_request(struct nfs_wreq *req, int sync)
static int
wait_on_write_request(struct nfs_wreq *req)
{
- struct rpc_clnt *clnt = NFS_CLIENT(req->wb_inode);
+ struct file *file = req->wb_file;
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct wait_queue wait = { current, NULL };
sigset_t oldmask;
int retval;
@@ -435,7 +430,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
* page and retry the update.
*/
req = find_write_request(inode, page);
- if (req && update_write_request(req, offset, count))
+ if (req && req->wb_file == file && update_write_request(req, offset, count))
goto updated;
/*
@@ -446,7 +441,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
return nfs_writepage_sync(dentry, inode, page, offset, count);
/* Create the write request. */
- req = create_write_request(dentry, inode, page, offset, count);
+ req = create_write_request(file, page, offset, count);
if (!req)
return -ENOBUFS;
@@ -455,7 +450,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
* The IO completion will then free the page and the dentry.
*/
atomic_inc(&page->count);
- dget(dentry);
+ file->f_count++;
/* Schedule request */
synchronous = schedule_write_request(req, sync);
@@ -571,24 +566,12 @@ nfs_wb_page(struct inode *inode, struct page *page)
}
/*
- * Write back all pending writes for one user..
+ * Write back all pending writes from one file descriptor..
*/
int
-nfs_wb_pid(struct inode *inode, pid_t pid)
+nfs_wb_file(struct inode *inode, struct file *file)
{
- NFS_WB(inode, req->wb_pid == pid);
-}
-
-/*
- * Flush all write requests for truncation:
- * Simplification of the comparison has the side-effect of
- * causing all writes in an infested page to be waited upon.
- */
-int
-nfs_flush_trunc(struct inode *inode, unsigned long from)
-{
- from &= PAGE_MASK;
- NFS_WB(inode, req->wb_page->offset >= from);
+ NFS_WB(inode, req->wb_file == file);
}
void
@@ -598,16 +581,6 @@ nfs_inval(struct inode *inode)
}
/*
- * Check if a previous write operation returned an error
- */
-int
-nfs_check_error(struct inode *inode)
-{
- /* FIXME! */
- return 0;
-}
-
-/*
* The following procedures make up the writeback finite state machinery:
*
* 1. Try to lock the page if not yet locked by us,
@@ -618,7 +591,8 @@ nfs_wback_begin(struct rpc_task *task)
{
struct nfs_wreq *req = (struct nfs_wreq *) task->tk_calldata;
struct page *page = req->wb_page;
- struct dentry *dentry = req->wb_dentry;
+ struct file *file = req->wb_file;
+ struct dentry *dentry = file->f_dentry;
dprintk("NFS: %4d nfs_wback_begin (%s/%s, status=%d flags=%x)\n",
task->tk_pid, dentry->d_parent->d_name.name,
@@ -645,13 +619,15 @@ static void
nfs_wback_result(struct rpc_task *task)
{
struct nfs_wreq *req = (struct nfs_wreq *) task->tk_calldata;
- struct inode *inode = req->wb_inode;
- struct page *page = req->wb_page;
+ struct file *file = req->wb_file;
+ struct page *page = req->wb_page;
int status = task->tk_status;
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
dprintk("NFS: %4d nfs_wback_result (%s/%s, status=%d, flags=%x)\n",
- task->tk_pid, req->wb_dentry->d_parent->d_name.name,
- req->wb_dentry->d_name.name, status, req->wb_flags);
+ task->tk_pid, dentry->d_parent->d_name.name,
+ dentry->d_name.name, status, req->wb_flags);
/* Set the WRITE_COMPLETE flag, but leave WRITE_INPROGRESS set */
req->wb_flags |= NFS_WRITE_COMPLETE;
@@ -659,6 +635,7 @@ nfs_wback_result(struct rpc_task *task)
if (status < 0) {
req->wb_flags |= NFS_WRITE_INVALIDATE;
+ file->f_error = status;
} else if (!WB_CANCELLED(req)) {
struct nfs_fattr *fattr = &req->wb_fattr;
/* Update attributes as result of writeback.
@@ -696,22 +673,8 @@ nfs_wback_result(struct rpc_task *task)
__free_page(page);
remove_write_request(&NFS_WRITEBACK(inode), req);
nr_write_requests--;
- dput(req->wb_dentry);
+ fput(req->wb_file);
wake_up(&req->wb_wait);
-
- /*
- * FIXME!
- *
- * We should not free the request here if it has pending
- * error status on it. We should just leave it around, to
- * let the error be collected later. However, the error
- * collecting routines are too stupid for that right now,
- * so we just drop the error on the floor at this point
- * for any async writes.
- *
- * This should not be a major headache to fix, but I want
- * to validate basic operations first.
- */
free_write_request(req);
}
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 3e132a75b..5396a784f 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -339,8 +339,10 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
argp->tname, argp->tlen,
&newfh);
- if (nfserr)
+ if (!nfserr) {
+ argp->attrs.ia_valid &= ~ATTR_SIZE;
nfserr = nfsd_setattr(rqstp, &newfh, &argp->attrs);
+ }
fh_put(&argp->ffh);
fh_put(&newfh);
@@ -362,6 +364,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
SVCFH_INO(&argp->fh),
argp->name);
+ argp->attrs.ia_valid &= ~ATTR_SIZE;
nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
&argp->attrs, S_IFDIR, 0, &resp->fh);
fh_put(&argp->fh);
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 0a3cc3f8b..6f6b4a733 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -13,6 +13,7 @@
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/dcache.h>
+#include <asm/pgtable.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
@@ -235,7 +236,7 @@ retry:
/*
* Search for a path entry for the specified (dev, inode).
*/
-struct nfsd_path *get_path_entry(kdev_t dev, ino_t ino)
+static struct nfsd_path *get_path_entry(kdev_t dev, ino_t ino)
{
struct nfsd_path *pe;
struct list_head *tmp;
@@ -713,7 +714,6 @@ printk("find_dentry_by_ino: getting root dentry for %s\n", kdevname(dev));
dentry = dget(fhe->dentry);
goto out;
}
-
/*
* Search the path cache ...
*/
@@ -859,6 +859,34 @@ static struct dentry *nfsd_cached_lookup(struct knfs_fh *fh)
return NULL;
}
+void
+expire_all(void)
+{
+ if (time_after_eq(jiffies, nfsd_next_expire)) {
+ expire_old(NFSD_FILE_CACHE, 5*HZ);
+ expire_old(NFSD_DIR_CACHE , 60*HZ);
+ nfsd_next_expire = jiffies + 5*HZ;
+ }
+}
+
+/*
+ * Free cache after unlink/rmdir.
+ */
+void
+expire_by_dentry(struct dentry *dentry)
+{
+ struct fh_entry *fhe;
+
+ fhe = find_fhe(dentry, NFSD_FILE_CACHE, NULL);
+ if (fhe) {
+ expire_fhe(fhe, NFSD_FILE_CACHE);
+ }
+ fhe = find_fhe(dentry, NFSD_DIR_CACHE, NULL);
+ if (fhe) {
+ expire_fhe(fhe, NFSD_DIR_CACHE);
+ }
+}
+
/*
* The is the basic lookup mechanism for turning an NFS file handle
* into a dentry. There are several levels to the search:
@@ -997,15 +1025,8 @@ out:
add_to_lookup_cache(dentry, fh);
}
- /*
- * Perform any needed housekeeping ...
- * N.B. move this into one of the daemons ...
- */
- if (time_after_eq(jiffies, nfsd_next_expire)) {
- expire_old(NFSD_FILE_CACHE, 5*HZ);
- expire_old(NFSD_DIR_CACHE , 60*HZ);
- nfsd_next_expire = jiffies + 5*HZ;
- }
+ expire_all();
+
return dentry;
}
@@ -1133,7 +1154,7 @@ dprintk("fh_verify: no root_squashed access.\n");
#ifdef NFSD_PARANOIA
if (error)
printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, access, error);
+dentry->d_parent->d_name.name, dentry->d_name.name, access, (error >> 24));
#endif
out:
return error;
@@ -1260,11 +1281,8 @@ static int nfsd_d_validate(struct dentry *dentry)
goto bad_addr;
if ((dent_addr & ~align_mask) != dent_addr)
goto bad_align;
- /* XXX: Should test here, whether the address doesn't belong to
- a physical memory hole on sparc32/sparc64. Then it is not
- safe to dereference it. On the other side, the previous
- use of num_physpages instead of max_mapnr caused the same
- to happen, plus some valid addresses could get rejected. -jj */
+ if (!kern_addr_valid(dent_addr))
+ goto bad_addr;
/*
* Looks safe enough to dereference ...
*/
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 8b115ed3a..7c3e24817 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -382,8 +382,10 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
argp->tname, argp->tlen,
&newfh);
- if (!nfserr)
+ if (!nfserr) {
+ argp->attrs.ia_valid &= ~ATTR_SIZE;
nfserr = nfsd_setattr(rqstp, &newfh, &argp->attrs);
+ }
fh_put(&argp->ffh);
fh_put(&newfh);
@@ -407,6 +409,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
"nfsd_proc_mkdir: response already verified??\n");
}
+ argp->attrs.ia_valid &= ~ATTR_SIZE;
nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
&argp->attrs, S_IFDIR, 0, &resp->fh);
fh_put(&argp->fh);
@@ -515,7 +518,7 @@ struct svc_procedure nfsd_procedures2[18] = {
PROC(symlink, symlinkargs, void, none, RC_REPLSTAT),
PROC(mkdir, createargs, diropres, fhandle, RC_REPLBUFF),
PROC(rmdir, diropargs, void, none, RC_REPLSTAT),
- PROC(readdir, readdirargs, readdirres, none, RC_REPLSTAT),
+ PROC(readdir, readdirargs, readdirres, none, RC_REPLBUFF),
PROC(statfs, fhandle, statfsres, none, RC_NOCACHE),
};
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index ff1608a82..b7fa534e0 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -101,7 +101,7 @@ static void
nfsd(struct svc_rqst *rqstp)
{
struct svc_serv *serv = rqstp->rq_server;
- int oldumask, err;
+ int oldumask, err, first = 0;
/* Lock module and set up kernel thread */
MOD_INC_USE_COUNT;
@@ -115,8 +115,10 @@ nfsd(struct svc_rqst *rqstp)
oldumask = current->fs->umask; /* Set umask to 0. */
current->fs->umask = 0;
- if (!nfsd_active++)
+ if (!nfsd_active++) {
nfssvc_boot = xtime; /* record boot time */
+ first = 1;
+ }
lockd_up(); /* start lockd */
/*
@@ -133,8 +135,14 @@ nfsd(struct svc_rqst *rqstp)
* Find a socket with data available and call its
* recvfrom routine.
*/
- while ((err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT)) == -EAGAIN)
- ;
+ while ((err = svc_recv(serv, rqstp,
+ first?5*HZ:MAX_SCHEDULE_TIMEOUT)) == -EAGAIN) {
+ if (first && 1) {
+ exp_readlock();
+ expire_all();
+ exp_unlock();
+ }
+ }
if (err < 0)
break;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 109ed75ec..4ef61fe45 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -11,7 +11,7 @@
* So if you notice code paths that apparently fail to dput() the
* dentry, don't worry--they have been taken care of.
*
- * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1999 Olaf Kirch <okir@monad.swb.de>
*/
#include <linux/config.h>
@@ -734,7 +734,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
* directories via NFS.
*/
err = 0;
- if ((iap->ia_valid &= (ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
+ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
err = nfsd_setattr(rqstp, resfhp, iap);
out:
return err;
@@ -959,7 +959,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
goto out_unlock;
err = nfserr_perm;
- if (IS_IMMUTABLE(dest) /* || IS_APPEND(dest) */ )
+ if (IS_IMMUTABLE(dest) || IS_APPEND(dest))
goto out_unlock;
if (!dirp->i_op || !dirp->i_op->link)
goto out_unlock;
@@ -1139,8 +1139,11 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
goto out;
}
+ expire_by_dentry(rdentry);
+
if (type != S_IFDIR) {
/* It's UNLINK */
+
err = fh_lock_parent(fhp, rdentry);
if (err)
goto out;
@@ -1155,6 +1158,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
} else {
/* It's RMDIR */
/* See comments in fs/namei.c:do_rmdir */
+
rdentry->d_count++;
nfsd_double_down(&dirp->i_sem, &rdentry->d_inode->i_sem);
if (!fhp->fh_pre_mtime)
diff --git a/fs/nls/Config.in b/fs/nls/Config.in
index bf17009d9..7e591b82a 100644
--- a/fs/nls/Config.in
+++ b/fs/nls/Config.in
@@ -4,7 +4,7 @@
# msdos and Joliet want NLS
if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
- -o "$CONFIG_NTFS_FS" != "n" ]; then
+ -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" ]; then
define_bool CONFIG_NLS y
else
define_bool CONFIG_NLS n
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile
index 8546f0bde..f06e122aa 100644
--- a/fs/ntfs/Makefile
+++ b/fs/ntfs/Makefile
@@ -3,7 +3,7 @@
O_TARGET := ntfs.o
O_OBJS := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o
M_OBJS := $(O_TARGET)
-EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"990102\"
+EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"990411\"
include $(TOPDIR)/Rules.make
diff --git a/fs/ntfs/attr.c b/fs/ntfs/attr.c
index 3de728fb7..3b8277643 100644
--- a/fs/ntfs/attr.c
+++ b/fs/ntfs/attr.c
@@ -1,9 +1,10 @@
/*
* attr.c
*
- * Copyright (C) 1996-1998 Martin von Löwis
+ * Copyright (C) 1996-1999 Martin von Löwis
* Copyright (C) 1996-1997 Régis Duchesne
* Copyright (C) 1998 Joseph Malicki
+ * Copyright (C) 1999 Steve Dodd
*/
#include "ntfstypes.h"
@@ -11,6 +12,9 @@
#include "attr.h"
#include <linux/errno.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
#include "macros.h"
#include "support.h"
#include "util.h"
@@ -18,8 +22,9 @@
#include "inode.h"
/* Look if an attribute already exists in the inode, and if not, create it */
-static int
-new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos, int *found)
+int
+ntfs_new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos,
+ int *found, int do_search )
{
int do_insert=0;
int i;
@@ -28,15 +33,17 @@ new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos, int *found)
{
int n=min(namelen,ino->attrs[i].namelen);
int s=ntfs_uni_strncmp(ino->attrs[i].name,name,n);
- /*
- * We assume that each attribute can be uniquely
- * identified by inode
- * number, attribute type and attribute name.
- */
- if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){
- *found=1;
- *pos=i;
- return 0;
+ if( do_search ) {
+ /*
+ * We assume that each attribute can be uniquely
+ * identified by inode
+ * number, attribute type and attribute name.
+ */
+ if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){
+ *found=1;
+ *pos=i;
+ return 0;
+ }
}
/* attributes are ordered by type, then by name */
if(ino->attrs[i].type>type || (ino->attrs[i].type==type && s==1)){
@@ -48,17 +55,21 @@ new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos, int *found)
/* re-allocate space */
if(ino->attr_count % 8 ==0)
{
- ntfs_attribute* old=ino->attrs;
- ino->attrs = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)*
+ ntfs_attribute* new;
+ new = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)*
sizeof(ntfs_attribute));
- if(old){
- ntfs_memcpy(ino->attrs,old,ino->attr_count*sizeof(ntfs_attribute));
- ntfs_free(old);
+ if( !new )
+ return ENOMEM;
+ if( ino->attrs ) {
+ ntfs_memcpy( new, ino->attrs, ino->attr_count*sizeof(ntfs_attribute) );
+ ntfs_free( ino->attrs );
}
+ ino->attrs = new;
}
if(do_insert)
ntfs_memmove(ino->attrs+i+1,ino->attrs+i,(ino->attr_count-i)*
sizeof(ntfs_attribute));
+
ino->attr_count++;
ino->attrs[i].type=type;
ino->attrs[i].namelen=namelen;
@@ -81,19 +92,21 @@ ntfs_make_attr_resident(ntfs_inode *ino,ntfs_attribute *attr)
}
/* Store in the inode readable information about a run */
-static void
+void
ntfs_insert_run(ntfs_attribute *attr,int cnum,ntfs_cluster_t cluster,int len)
{
/* (re-)allocate space if necessary */
if(attr->d.r.len % 8 == 0) {
- ntfs_runlist* old;
- old=attr->d.r.runlist;
- attr->d.r.runlist=ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist));
- if(old) {
- ntfs_memcpy(attr->d.r.runlist,old,attr->d.r.len
+ ntfs_runlist* new;
+ new = ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist));
+ if( !new )
+ return;
+ if( attr->d.r.runlist ) {
+ ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len
*sizeof(ntfs_runlist));
- ntfs_free(old);
+ ntfs_free( attr->d.r.runlist );
}
+ attr->d.r.runlist = new;
}
if(attr->d.r.len>cnum)
ntfs_memmove(attr->d.r.runlist+cnum+1,attr->d.r.runlist+cnum,
@@ -103,6 +116,13 @@ ntfs_insert_run(ntfs_attribute *attr,int cnum,ntfs_cluster_t cluster,int len)
attr->d.r.len++;
}
+/* Extends an attribute. Another run will be added if necessary,
+ * but we try to extend the last run in the runlist first.
+ * FIXME: what if there isn't enough contiguous space, we don't create
+ * multiple runs?
+ *
+ * *len: the desired new length of the attr (_not_ the amount to extend by)
+ */
int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len,
int flags)
{
@@ -111,34 +131,46 @@ int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len,
int rlen;
ntfs_cluster_t cluster;
int clen;
+
if(attr->compressed)return EOPNOTSUPP;
if(ino->record_count>1)return EOPNOTSUPP;
+
if(attr->resident) {
error = ntfs_make_attr_nonresident(ino,attr);
if(error)
return error;
}
+ if( *len <= attr->allocated )
+ return 0; /* truely stupid things do sometimes happen */
+
rl=attr->d.r.runlist;
rlen=attr->d.r.len-1;
+
if(rlen>=0)
cluster=rl[rlen].cluster+rl[rlen].len;
else
/* no preference for allocation space */
cluster=0;
- /* round up to multiple of cluster size */
- clen=(*len+ino->vol->clustersize-1)/ino->vol->clustersize;
+
+ /* calculate the extra space we need, and round up to multiple of cluster
+ * size to get number of new clusters needed */
+
+ clen=( (*len - attr->allocated ) + ino->vol->clustersize - 1 ) /
+ ino->vol->clustersize;
if(clen==0)
return 0;
+
/* FIXME: try to allocate smaller pieces */
error=ntfs_allocate_clusters(ino->vol,&cluster,&clen,
flags|ALLOC_REQUIRE_SIZE);
if(error)return error;
attr->allocated += clen*ino->vol->clustersize;
- *len=clen*ino->vol->clustersize;
+ *len = attr->allocated;
+
/* contiguous chunk */
if(rlen>=0 && cluster==rl[rlen].cluster+rl[rlen].len){
- rl[rlen].len+=clen;
+ rl[rlen].len += clen;
return 0;
}
ntfs_insert_run(attr,rlen+1,cluster,clen);
@@ -208,8 +240,10 @@ int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
v=attr->d.data;
if(newsize){
attr->d.data=ntfs_malloc(newsize);
- if(!attr->d.data)
+ if(!attr->d.data) {
+ ntfs_free(v);
return ENOMEM;
+ }
if(newsize>oldsize)
ntfs_bzero((char*)attr->d.data+oldsize,
newsize-oldsize);
@@ -231,7 +265,7 @@ int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
newlen=i+1;
/* free unused clusters in current run, unless sparse */
newcount=count;
- if(rl[i].cluster!=-1){
+ if(rl[i].cluster!=MAX_CLUSTER_T){
int rounded=newsize-count*clustersize;
rounded=(rounded+clustersize-1)/clustersize;
error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster+rounded,
@@ -243,7 +277,7 @@ int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
}
/* free all other runs */
for(i++;i<attr->d.r.len;i++)
- if(rl[i].cluster!=-1){
+ if(rl[i].cluster!=MAX_CLUSTER_T){
error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster,(int)rl[i].len);
if(error)
return error; /* FIXME: incomplete operation */
@@ -279,12 +313,20 @@ int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
if(aname){
namelen=strlen(aname);
name=ntfs_malloc(2*namelen);
+ if( !name )
+ return ENOMEM;
ntfs_ascii2uni(name,aname,namelen);
}else{
name=0;
namelen=0;
}
- new_attr(ino,anum,name,namelen,&i,&found);
+
+ error = ntfs_new_attr(ino,anum,name,namelen,&i,&found,1);
+ if( error ) {
+ ntfs_free( name );
+ return error;
+ }
+
if(found){
ntfs_free(name);
return EEXIST;
@@ -309,6 +351,10 @@ int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
}else
attr->indexed=0;
attr->d.data=ntfs_malloc(dsize);
+
+ if( !attr->d.data )
+ return ENOMEM;
+
ntfs_memcpy(attr->d.data,data,dsize);
return 0;
}
@@ -366,6 +412,7 @@ int ntfs_insert_attribute(ntfs_inode *ino, unsigned char* attrdata)
int namelen;
void *data;
ntfs_attribute *attr;
+ int error;
type = NTFS_GETU32(attrdata);
namelen = NTFS_GETU8(attrdata+9);
@@ -376,15 +423,30 @@ int ntfs_insert_attribute(ntfs_inode *ino, unsigned char* attrdata)
{
/* 1 Unicode character fits in 2 bytes */
name=ntfs_malloc(2*namelen);
+ if( !name )
+ return ENOMEM;
+
ntfs_memcpy(name,attrdata+NTFS_GETU16(attrdata+10),2*namelen);
}
- new_attr(ino,type,name,namelen,&i,&found);
+
+ error = ntfs_new_attr(ino,type,name,namelen,&i,&found,1);
+ if( error ) {
+ if( name ) ntfs_free( name );
+ return error;
+ }
+
/* We can have in one inode two attributes with type 0x00000030 (File Name)
and without name */
if(found && /*FIXME*/type!=ino->vol->at_file_name)
{
ntfs_process_runs(ino,ino->attrs+i,attrdata);
return 0;
+ } else if( found ) {
+ /* Don't understand the above, but I know it leaks memory below
+ as it overwrites a found entry without freeing it. So here we
+ call ntfs_new_attr again but this time ask it to always allocate a
+ new entry */
+ ntfs_new_attr(ino,type,name,namelen,&i,&found,0);
}
attr=ino->attrs+i;
attr->resident=NTFS_GETU8(attrdata+8)==0;
@@ -395,6 +457,8 @@ int ntfs_insert_attribute(ntfs_inode *ino, unsigned char* attrdata)
attr->size=NTFS_GETU16(attrdata+0x10);
data=attrdata+NTFS_GETU16(attrdata+0x14);
attr->d.data = (void*)ntfs_malloc(attr->size);
+ if( !attr->d.data )
+ return ENOMEM;
ntfs_memcpy(attr->d.data,data,attr->size);
attr->indexed=NTFS_GETU16(attrdata+0x16);
}else{
@@ -468,7 +532,7 @@ int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
copied=0;
while(l){
chunk=0;
- if(cluster==-1){
+ if(cluster==MAX_CLUSTER_T){
/* sparse cluster */
int l1;
if((len-(s_vcn-vcn)) & 15)
@@ -503,9 +567,9 @@ int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
}
got+=l1;
comp1+=l1*clustersize;
- }while(cluster!=-1 && got<16); /* until empty run */
+ }while(cluster!=MAX_CLUSTER_T && got<16); /* until empty run */
chunk=16*clustersize;
- if(cluster!=-1 || got==16)
+ if(cluster!=MAX_CLUSTER_T || got==16)
/* uncompressible */
comp1=comp;
else{
diff --git a/fs/ntfs/attr.h b/fs/ntfs/attr.h
index 6ba6f5b27..1be5f8d0e 100644
--- a/fs/ntfs/attr.h
+++ b/fs/ntfs/attr.h
@@ -18,3 +18,7 @@ int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
int ntfs_read_zero(ntfs_io *dest,int size);
int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr);
int ntfs_attr_allnonresident(ntfs_inode *ino);
+int ntfs_new_attr( ntfs_inode *ino, int type, void *name, int namelen,
+ int *pos, int *found, int do_search );
+void ntfs_insert_run( ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster,
+ int len );
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
index ff18aa15c..6d92bce11 100644
--- a/fs/ntfs/dir.c
+++ b/fs/ntfs/dir.c
@@ -1,7 +1,9 @@
/*
* dir.c
*
- * Copyright (C) 1995-1997 Martin von Löwis
+ * Copyright (C) 1995-1997, 1999 Martin von Löwis
+ * Copyright (C) 1999 Steve Dodd
+ * Copyright (C) 1999 Joseph Malicki
*/
#include "ntfstypes.h"
@@ -67,7 +69,7 @@ static ntfs_u64 ntfs_push(ntfs_u64 stack,int i)
if(i<55)return (stack<<8)|((i-23)<<3)|3;
if(i<120)return (stack<<10)|((i-55)<<4)|7;
ntfs_error("Too many entries\n");
- return 0xFFFFFFFFFFFFFFFF;
+ return ~((ntfs_u64)0);
}
#if 0
@@ -166,6 +168,8 @@ static int ntfs_allocate_index_block(ntfs_iterate_s *walk)
int nr_fix = s1/vol->blocksize+1;
int hsize;
char *record=ntfs_malloc(s1);
+ if( !record )
+ return ENOMEM;
ntfs_bzero(record,s1);
/* magic */
ntfs_memcpy(record,"INDX",4);
@@ -356,8 +360,10 @@ static int ntfs_dir_insert(ntfs_iterate_s *walk, char *start, char* entry)
if(do_split){
error=ntfs_split_record(walk,start,blocksize,usedsize);
ntfs_free(start);
- }else
- ntfs_index_writeback(walk,start,walk->block,usedsize);
+ }else{
+ error=ntfs_index_writeback(walk,start,walk->block,usedsize);
+ if(error)return error;
+ }
return 0;
}
@@ -395,8 +401,9 @@ ntfs_split_indexroot(ntfs_inode *ino)
goto out;
}
index = ntfs_malloc(ino->vol->index_recordsize);
- if(!index)
- goto out;
+ if(!index) {
+ error = ENOMEM; goto out;
+ }
walk.dir = ino;
walk.block = -1;
walk.result = walk.new_entry = 0;
@@ -462,12 +469,12 @@ static int ntfs_my_strcmp(ntfs_iterate_s *walk, const unsigned char *entry)
ntfs_u16* name=(ntfs_u16*)(entry+0x52);
ntfs_volume *vol=walk->dir->vol;
for(i=0;i<lu && i<walk->namelen;i++)
- if(ntfs_my_toupper(vol,name[i])!=ntfs_my_toupper(vol,walk->name[i]))
+ if(ntfs_my_toupper(vol,NTFS_GETU16(name+i))!=ntfs_my_toupper(vol,NTFS_GETU16(walk->name+i)))
break;
if(i==lu && i==walk->namelen)return 0;
if(i==lu)return 1;
if(i==walk->namelen)return -1;
- if(ntfs_my_toupper(vol,name[i])<ntfs_my_toupper(vol,walk->name[i]))return 1;
+ if(ntfs_my_toupper(vol,NTFS_GETU16(name+i))<ntfs_my_toupper(vol,NTFS_GETU16(walk->name+i)))return 1;
return -1;
}
@@ -485,6 +492,9 @@ static int ntfs_getdir_record(ntfs_iterate_s *walk, int block)
int oldblock;
ntfs_io io;
+ if( !record )
+ return ENOMEM;
+
io.fn_put=ntfs_put;
io.param=record;
io.size=length;
@@ -607,7 +617,6 @@ ntfs_getdir_iterate_byposition(ntfs_iterate_s *walk,char* start,char *entry)
static int ntfs_getdir_iterate(ntfs_iterate_s *walk, char *start, char *entry)
{
int length;
- int retval=0;
int cmp;
if(walk->type==BY_POSITION)
@@ -647,7 +656,7 @@ static int ntfs_getdir_iterate(ntfs_iterate_s *walk, char *start, char *entry)
}
entry+=length;
}while(1);
- return retval;
+ return 0;
}
/* Tree walking is done using position numbers. The following numbers have
@@ -683,6 +692,9 @@ int ntfs_getdir(ntfs_iterate_s* walk)
char *root=ntfs_malloc(length);
ntfs_io io;
+ if( !root )
+ return ENOMEM;
+
io.fn_put=ntfs_put;
io.param=root;
io.size=length;
@@ -747,6 +759,8 @@ int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
/* are we still in the index root */
if(*p_high==0){
buf=ntfs_malloc(length=vol->mft_recordsize);
+ if( !buf )
+ return ENOMEM;
io.fn_put=ntfs_put;
io.param=buf;
io.size=length;
@@ -762,6 +776,8 @@ int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
}else{ /* we are in an index record */
length=ino->u.index.recordsize;
buf=ntfs_malloc(length);
+ if( !buf )
+ return ENOMEM;
io.fn_put=ntfs_put;
io.param=buf;
io.size=length;
@@ -821,6 +837,9 @@ int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
return 0;
}
buf=ntfs_malloc(length=attr->size);
+ if( !buf )
+ return ENOMEM;
+
io.param=buf;
io.size=length;
error=ntfs_read_attr(ino,vol->at_bitmap,I30,0,&io);
@@ -920,8 +939,8 @@ int ntfs_dir_add1(ntfs_inode *dir,const char* name,int namelen,ntfs_inode *ino)
/* Fills out and creates an INDEX_ROOT attribute. */
-static int
-add_index_root (ntfs_inode *ino, int type)
+int
+ntfs_add_index_root (ntfs_inode *ino, int type)
{
ntfs_attribute *da;
ntfs_u8 data[0x30]; /* 0x20 header, 0x10 last entry */
@@ -959,7 +978,7 @@ ntfs_mkdir(ntfs_inode* dir,const char* name,int namelen, ntfs_inode *result)
error = ntfs_alloc_inode(dir, result, name, namelen, NTFS_AFLAG_DIR);
if(error)
goto out;
- error = add_index_root(result, 0x30);
+ error = ntfs_add_index_root(result, 0x30);
if (error)
goto out;
/* Set directory bit */
diff --git a/fs/ntfs/dir.h b/fs/ntfs/dir.h
index 9c86e6063..db6dd0979 100644
--- a/fs/ntfs/dir.h
+++ b/fs/ntfs/dir.h
@@ -39,3 +39,4 @@ int ntfs_check_index_record(ntfs_inode *ino, char *record);
int ntfs_getdir_byposition(ntfs_iterate_s *walk);
int ntfs_mkdir(ntfs_inode* dir,const char* name,int namelen, ntfs_inode *ino);
int ntfs_split_indexroot(ntfs_inode *ino);
+int ntfs_add_index_root( ntfs_inode *ino, int type );
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index 016f45a06..f34de38d3 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -2,7 +2,7 @@
* fs.c
* NTFS driver for Linux 2.1
*
- * Copyright (C) 1995-1997 Martin von Löwis
+ * Copyright (C) 1995-1997, 1999 Martin von Löwis
* Copyright (C) 1996 Richard Russon
* Copyright (C) 1996-1997 Régis Duchesne
*/
@@ -215,7 +215,6 @@ static int ntfs_readdir(struct file* filp, void *dirent, filldir_t filldir)
ntfs_debug(DEBUG_OTHER, "ntfs_readdir ino %x mode %x\n",
(unsigned)dir->i_ino,(unsigned int)dir->i_mode);
- if(!dir || (dir->i_ino==0) || !S_ISDIR(dir->i_mode))return -EBADF;
ntfs_debug(DEBUG_OTHER, "readdir: Looking for file %x dircount %d\n",
(unsigned)filp->f_pos,dir->i_count);
@@ -373,7 +372,7 @@ static int parse_options(ntfs_volume* vol,char *opt)
return 0;
}
-static int ntfs_lookup(struct inode *dir, struct dentry *d)
+static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d)
{
struct inode *res=0;
char *item=0;
@@ -385,8 +384,10 @@ static int ntfs_lookup(struct inode *dir, struct dentry *d)
error=ntfs_decodeuni(NTFS_INO2VOL(dir),(char*)d->d_name.name,
d->d_name.len,&walk.name,&walk.namelen);
if(error)
- return error;
+ return ERR_PTR(-error);
item=ntfs_malloc(ITEM_SIZE);
+ if( !item )
+ return ERR_PTR(-ENOMEM);
/* ntfs_getdir will place the directory entry into item,
and the first long long is the MFT record number */
walk.type=BY_NAME;
@@ -400,7 +401,7 @@ static int ntfs_lookup(struct inode *dir, struct dentry *d)
ntfs_free(item);
ntfs_free(walk.name);
/* Always return success, the dcache will handle negative entries. */
- return 0;
+ return NULL;
}
static struct file_operations ntfs_file_operations_nommap = {
@@ -505,6 +506,7 @@ ntfs_create(struct inode* dir,struct dentry *d,int mode)
#endif
r->i_mode &= ~vol->umask;
+ insert_inode_hash(r);
d_instantiate(d,r);
return 0;
fail:
@@ -567,6 +569,7 @@ _linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode)
#endif
r->i_mode &= ~vol->umask;
+ insert_inode_hash(r);
d_instantiate(d, r);
error = 0;
out:
@@ -581,8 +584,6 @@ ntfs_bmap(struct inode *ino,int block)
int ret=ntfs_vcn_to_lcn(NTFS_LINO2NINO(ino),block);
ntfs_debug(DEBUG_OTHER, "bmap of %lx,block %x is %x\n",
ino->i_ino,block,ret);
- ntfs_error("bmap of %lx,block %x is %x\n", ino->i_ino,block,ret);
- ntfs_error("super %x\n", ino->i_sb->s_blocksize);
return (ret==-1) ? 0:ret;
}
@@ -707,6 +708,7 @@ static void ntfs_read_inode(struct inode* inode)
#ifdef NTFS_IN_LINUX_KERNEL
ino=&inode->u.ntfs_i;
#else
+ /* FIXME: check for ntfs_malloc failure */
ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
inode->u.generic_ip=ino;
#endif
@@ -816,6 +818,7 @@ static int ntfs_statfs(struct super_block *sb, struct statfs *sf, int bufsize)
struct statfs fs;
struct inode *mft;
ntfs_volume *vol;
+ int error;
ntfs_debug(DEBUG_OTHER, "ntfs_statfs\n");
vol=NTFS_SB2VOL(sb);
@@ -823,7 +826,9 @@ static int ntfs_statfs(struct super_block *sb, struct statfs *sf, int bufsize)
fs.f_type=NTFS_SUPER_MAGIC;
fs.f_bsize=vol->clustersize;
- fs.f_blocks=ntfs_get_volumesize(NTFS_SB2VOL(sb));
+ error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &fs.f_blocks );
+ if( error )
+ return -error;
fs.f_bfree=ntfs_get_free_cluster_count(vol->bitmap);
fs.f_bavail=fs.f_bfree;
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index a70205e2f..7fcc86754 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -5,13 +5,18 @@
* Copyright (C) 1996 Albert D. Cahalan
* Copyright (C) 1996-1997 Régis Duchesne
* Copyright (C) 1998 Joseph Malicki
+ * Copyright (C) 1999 Steve Dodd
*/
#include "ntfstypes.h"
+#include "ntfsendian.h"
#include "struct.h"
#include "inode.h"
#include <linux/errno.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
#include "macros.h"
#include "attr.h"
#include "super.h"
@@ -30,8 +35,8 @@ typedef struct {
ntfs_mft_record* records;
} ntfs_disk_inode;
-static void
-fill_mft_header(ntfs_u8*mft,int record_size,int blocksize,
+void
+ntfs_fill_mft_header(ntfs_u8*mft,int record_size,int blocksize,
int sequence_number)
{
int fixup_count = record_size / blocksize + 1;
@@ -98,7 +103,7 @@ ntfs_extend_mft(ntfs_volume *vol)
if(mdata->allocated<mdata->size+vol->mft_recordsize){
size=ntfs_get_free_cluster_count(vol->bitmap)*vol->clustersize;
block=vol->mft_recordsize;
- size=max(size/1000,block);
+ size=max(size/1000,mdata->size+vol->mft_recordsize);
size=((size+block-1)/block)*block;
/* require this to be a single chunk */
error=ntfs_extend_attr(vol->mft_ino,mdata,&size,
@@ -141,14 +146,18 @@ ntfs_extend_mft(ntfs_volume *vol)
/* now fill in the MFT header for the new block */
buf=ntfs_calloc(vol->mft_recordsize);
if(!buf)return ENOMEM;
- fill_mft_header(buf,vol->mft_recordsize,vol->blocksize,0);
+ ntfs_fill_mft_header(buf,vol->mft_recordsize,vol->blocksize,0);
ntfs_insert_fixups(buf,vol->blocksize);
io.param=buf;
io.size=vol->mft_recordsize;
+ io.fn_put = ntfs_put;
+ io.fn_get = ntfs_get;
error=ntfs_write_attr(vol->mft_ino,vol->at_data,0,
(rcount-1)*vol->mft_recordsize,&io);
if(error)return error;
if(io.size!=vol->mft_recordsize)return EIO;
+ error=ntfs_update_inode(vol->mft_ino);
+ if(error)return error;
return 0;
}
@@ -165,13 +174,16 @@ void ntfs_insert_mft_attributes(ntfs_inode* ino,char *mft,int mftno)
/* (re-)allocate space if necessary */
if(ino->record_count % 8==0)
{
- int *old=ino->records;
- ino->records=ntfs_malloc((ino->record_count+8)*sizeof(int));
- if(old) {
+ int *new;
+ new = ntfs_malloc((ino->record_count+8)*sizeof(int));
+ if( !new )
+ return;
+ if( ino->records ) {
for(i=0;i<ino->record_count;i++)
- ino->records[i]=old[i];
- ntfs_free(old);
+ new[i] = ino->records[i];
+ ntfs_free( ino->records );
}
+ ino->records = new;
}
ino->records[ino->record_count]=mftno;
ino->record_count++;
@@ -179,8 +191,10 @@ void ntfs_insert_mft_attributes(ntfs_inode* ino,char *mft,int mftno)
do{
type=NTFS_GETU32(it);
len=NTFS_GETU32(it+4);
- if(type!=-1)
+ if(type!=-1) {
+ /* FIXME: check ntfs_insert_attribute for failure (e.g. no mem)? */
ntfs_insert_attribute(ino,it);
+ }
it+=len;
}while(type!=-1); /* attribute list ends with type -1 */
}
@@ -195,6 +209,8 @@ static int parse_attributes(ntfs_inode *ino, ntfs_u8 *alist, int *plen)
int last_mft=-1;
int len=*plen;
mft=ntfs_malloc(ino->vol->mft_recordsize);
+ if( !mft )
+ return ENOMEM;
while(len>8)
{
l=NTFS_GETU16(alist+4);
@@ -239,6 +255,8 @@ static void ntfs_load_attributes(ntfs_inode* ino)
return;
}
buf=ntfs_malloc(1024);
+ if( !buf )
+ return;
delta=0;
for(offset=0;datasize;datasize-=len)
{
@@ -271,6 +289,8 @@ int ntfs_init_inode(ntfs_inode *ino,ntfs_volume *vol,int inum)
ino->i_number=inum;
ino->vol=vol;
ino->attr=buf=ntfs_malloc(vol->mft_recordsize);
+ if( !buf )
+ return ENOMEM;
error=ntfs_read_mft_record(vol,inum,ino->attr);
if(error){
ntfs_debug(DEBUG_OTHER, "init inode: %x failed\n",inum);
@@ -441,7 +461,7 @@ int ntfs_decompress_run(unsigned char **data, int *length, ntfs_cluster_t *clust
int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, int offset,
ntfs_io *dest)
{
- int datasize,rnum;
+ int rnum;
ntfs_cluster_t cluster,s_cluster,vcn,len;
int l,chunk,copied;
int s_vcn;
@@ -449,26 +469,39 @@ int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, int offset,
int error;
clustersize=ino->vol->clustersize;
- datasize=attr->size;
l=dest->size;
if(l==0)
return 0;
if(dest->do_read)
{
- if(offset>=datasize){
+ /* if read _starts_ beyond end of stream, return nothing */
+ if(offset>=attr->size){
dest->size=0;
return 0;
}
- if(offset+l>=datasize)
- l=dest->size=datasize-offset;
- }else { /* fixed by CSA: if writing beyond end, extend attribute */
- if (offset+l>datasize) {
+
+ /* if read _extends_ beyond end of stream, return as much
+ initialised data as we have */
+ if(offset+l>=attr->size)
+ l=dest->size=attr->size-offset;
+
+ }else {
+ /* fixed by CSA: if writing beyond end, extend attribute */
+
+ /* if write extends beyond _allocated_ size, extend attrib */
+ if (offset+l>attr->allocated) {
error=ntfs_resize_attr(ino,attr,offset+l);
if(error)
return error;
}
- if (offset+l > attr->initialized)
+
+ /* the amount of initialised data has increased; update */
+ /* FIXME: shouldn't we zero-out the section between the old
+ initialised length and the write start? */
+ if (offset+l > attr->initialized) {
attr->initialized = offset+l;
+ attr->size = offset+l;
+ }
}
if(attr->resident)
{
@@ -565,7 +598,6 @@ int ntfs_vcn_to_lcn(ntfs_inode *ino,int vcn)
{
int rnum;
ntfs_attribute *data;
- ntfs_error("bmap %x\n",vcn);
data=ntfs_find_attr(ino,ino->vol->at_data,0);
/* It's hard to give an error code */
if(!data)return -1;
@@ -583,7 +615,6 @@ int ntfs_vcn_to_lcn(ntfs_inode *ino,int vcn)
vcn>data->d.r.runlist[rnum].len;rnum++)
vcn-=data->d.r.runlist[rnum].len;
- ntfs_error("result %x\n",data->d.r.runlist[rnum].cluster+vcn);
return data->d.r.runlist[rnum].cluster+vcn;
}
@@ -655,7 +686,7 @@ layout_runs(ntfs_attribute *attr,char* rec,int* offs,int size)
*(rec+offset)|=coffs++;
- if(rl[i].cluster==0) /*compressed run*/
+ if(rl[i].cluster==MAX_CLUSTER_T) /*compressed run*/
/*nothing*/;
else if(rclus>-0x80 && rclus<0x7F){
*(rec+offset)|=0x10;
@@ -768,7 +799,8 @@ layout_attr(ntfs_attribute* attr,char*buf, int size,int *psize)
NTFS_PUTU16(buf+0xA,asize);
ntfs_memcpy(buf+asize,attr->name,2*attr->namelen);
asize+=2*attr->namelen;
- asize=(asize+7) & ~7;
+ /* SRD: you whaaa?
+ asize=(asize+7) & ~7;*/
}
/* asize points at the beginning of the data */
NTFS_PUTU16(buf+0x20,asize);
@@ -841,7 +873,12 @@ layout_inode(ntfs_inode *ino,ntfs_disk_inode *store)
if(error)
return error;
}
- next=(next+7) & ~7; /* align to DWORD */
+ /* SRD: umm..
+ next=(next+7) & ~7; */
+ /* is this setting the length? if so maybe we could get
+ away with rounding up so long as we set the length first..
+ ..except, is the length the only way to get to the next attr?
+ */
NTFS_PUTU16(rec+offset+4,next-offset);
offset=next;
#endif
@@ -1038,7 +1075,8 @@ new_inode (ntfs_volume* vol,int* result)
data=ntfs_find_attr(vol->mft_ino,vol->at_data,0);
length=data->size/vol->mft_recordsize;
- for (byte = 3; 8*byte < length; byte++)
+ /* SRD: start at byte 0: bits for system files _are_ already set in bitmap */
+ for (byte = 0; 8*byte < length; byte++)
{
value = buffer[byte];
if(value==0xFF)
@@ -1064,7 +1102,7 @@ add_mft_header (ntfs_inode *ino)
mft=ino->attr;
ntfs_bzero(mft, vol->mft_recordsize);
- fill_mft_header(mft,vol->mft_recordsize,vol->blocksize,
+ ntfs_fill_mft_header(mft,vol->mft_recordsize,vol->blocksize,
ino->sequence_number);
return 0;
}
@@ -1108,6 +1146,8 @@ add_filename (ntfs_inode* ino, ntfs_inode* dir,
/* work out the size */
size = 0x42 + 2 * length;
data = ntfs_malloc(size);
+ if( !data )
+ return ENOMEM;
ntfs_bzero(data,size);
/* search for a position */
@@ -1191,7 +1231,7 @@ int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result,
{
ntfs_io io;
int error;
- ntfs_u8 buffer[1];
+ ntfs_u8 buffer[2];
ntfs_volume* vol=dir->vol;
int byte,bit;
@@ -1230,7 +1270,7 @@ int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result,
*/
/* get the sequence number */
io.param = buffer;
- io.size = 0x10;
+ io.size = 2;
error = ntfs_read_attr(vol->mft_ino, vol->at_data, 0,
result->i_number*vol->mft_recordsize+0x10,&io);
if(error)
@@ -1238,10 +1278,17 @@ int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result,
result->sequence_number=NTFS_GETU16(buffer)+1;
result->vol=vol;
result->attr=ntfs_malloc(vol->mft_recordsize);
+ if( !result->attr )
+ return ENOMEM;
result->attr_count=0;
result->attrs=0;
result->record_count=1;
result->records=ntfs_malloc(8*sizeof(int));
+ if( !result->records ) {
+ ntfs_free( result->attr );
+ result->attr = 0;
+ return ENOMEM;
+ }
result->records[0]=result->i_number;
error=add_mft_header(result);
if(error)
diff --git a/fs/ntfs/inode.h b/fs/ntfs/inode.h
index 606944211..b3627f8cf 100644
--- a/fs/ntfs/inode.h
+++ b/fs/ntfs/inode.h
@@ -26,3 +26,5 @@ int ntfs_allocate_attr_number(ntfs_inode *ino, int *result);
int ntfs_decompress_run(unsigned char **data, int *length, ntfs_cluster_t *cluster,
int *ctype);
void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l);
+void ntfs_fill_mft_header( ntfs_u8 *mft, int recordsize, int blocksize,
+ int sequence_number );
diff --git a/fs/ntfs/ntfsendian.h b/fs/ntfs/ntfsendian.h
index 32d382d57..fc861bc70 100644
--- a/fs/ntfs/ntfsendian.h
+++ b/fs/ntfs/ntfsendian.h
@@ -1,8 +1,9 @@
/*
* ntfsendian.h
*
- * Copyright (C) 1998 Martin von Löwis
+ * Copyright (C) 1998, 1999 Martin von Löwis
* Copyright (C) 1998 Joseph Malicki
+ * Copyright (C) 1999 Werner Seiler
*/
#ifdef __linux__
@@ -36,9 +37,9 @@
#ifdef __BIG_ENDIAN
/* We hope its big-endian, not PDP-endian :) */
-#define CPU_TO_LE16(a) ((((a)&0xF) << 8)|((a) >> 8))
-#define CPU_TO_LE32(a) ((((a) & 0xF) << 24) | (((a) & 0xF0) << 8) | \
- (((a) & 0xF00) >> 8) | ((a) >> 24))
+#define CPU_TO_LE16(a) ((((a)&0xFF) << 8)|((a) >> 8))
+#define CPU_TO_LE32(a) ((((a) & 0xFF) << 24) | (((a) & 0xFF00) << 8) | \
+ (((a) & 0xFF0000) >> 8) | ((a) >> 24))
#define CPU_TO_LE64(a) ((CPU_TO_LE32(a)<<32)|CPU_TO_LE32((a)>>32)
#define LE16_TO_CPU(a) CPU_TO_LE16(a)
@@ -55,7 +56,7 @@
#define NTFS_GETU8(p) (*(ntfs_u8*)(p))
#define NTFS_GETU16(p) ((ntfs_u16)LE16_TO_CPU(*(ntfs_u16*)(p)))
-#define NTFS_GETU24(p) (NTFS_GETU32(p) & 0xFFFFFF)
+#define NTFS_GETU24(p) ((ntfs_u32)NTFS_GETU16(p) | ((ntfs_u32)NTFS_GETU8(((char*)(p))+2)<<16))
#define NTFS_GETU32(p) ((ntfs_u32)LE32_TO_CPU(*(ntfs_u32*)(p)))
#define NTFS_GETU40(p) ((ntfs_u64)NTFS_GETU32(p)|(((ntfs_u64)NTFS_GETU8(((char*)(p))+4))<<32))
#define NTFS_GETU48(p) ((ntfs_u64)NTFS_GETU32(p)|(((ntfs_u64)NTFS_GETU16(((char*)(p))+4))<<32))
@@ -75,9 +76,9 @@
#define NTFS_GETS16(p) ((ntfs_s16)LE16_TO_CPU(*(short*)(p)))
#define NTFS_GETS24(p) (NTFS_GETU24(p) < 0x800000 ? (int)NTFS_GETU24(p) : (int)(NTFS_GETU24(p) - 0x1000000))
#define NTFS_GETS32(p) ((ntfs_s32)LE32_TO_CPU(*(int*)(p)))
-#define NTFS_GETS40(p) (((ntfs_s64)NTFS_GETS32(p)) | (((ntfs_s64)NTFS_GETS8(((char*)(p))+4)) << 32))
-#define NTFS_GETS48(p) (((ntfs_s64)NTFS_GETS32(p)) | (((ntfs_s64)NTFS_GETS16(((char*)(p))+4)) << 32))
-#define NTFS_GETS56(p) (((ntfs_s64)NTFS_GETS32(p)) | (((ntfs_s64)NTFS_GETS24(((char*)(p))+4)) << 32))
+#define NTFS_GETS40(p) (((ntfs_s64)NTFS_GETU32(p)) | (((ntfs_s64)NTFS_GETS8(((char*)(p))+4)) << 32))
+#define NTFS_GETS48(p) (((ntfs_s64)NTFS_GETU32(p)) | (((ntfs_s64)NTFS_GETS16(((char*)(p))+4)) << 32))
+#define NTFS_GETS56(p) (((ntfs_s64)NTFS_GETU32(p)) | (((ntfs_s64)NTFS_GETS24(((char*)(p))+4)) << 32))
#define NTFS_GETS64(p) ((ntfs_s64)NTFS_GETU64(p))
#define NTFS_PUTS8(p,v) NTFS_PUTU8(p,v)
diff --git a/fs/ntfs/ntfstypes.h b/fs/ntfs/ntfstypes.h
index e88a4169b..075a60806 100644
--- a/fs/ntfs/ntfstypes.h
+++ b/fs/ntfs/ntfstypes.h
@@ -1,12 +1,12 @@
/*
- * types.h
+ * ntfstypes.h
* This file defines four things:
* - generic platform independent fixed-size types (e.g. ntfs_u32)
* - specific fixed-size types (e.g. ntfs_offset_t)
* - macros that read and write those types from and to byte arrays
* - types derived from OS specific ones
*
- * Copyright (C) 1996,1998 Martin von Löwis
+ * Copyright (C) 1996,1998, 1999 Martin von Löwis
*/
#ifdef NTFS_IN_LINUX_KERNEL
@@ -54,6 +54,10 @@ typedef u64 ntfs_time64_t;
typedef u32 ntfs_cluster_t;
#endif
+#ifndef MAX_CLUSTER_T
+#define MAX_CLUSTER_T (~((ntfs_cluster_t)0))
+#endif
+
/* architecture independent macros */
/* PUTU32 would not clear all bytes */
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 797a60791..51f14e72b 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -1,8 +1,9 @@
/*
* super.c
*
- * Copyright (C) 1995-1997 Martin von Löwis
+ * Copyright (C) 1995-1997, 1999 Martin von Löwis
* Copyright (C) 1996-1997 Régis Duchesne
+ * Copyright (C) 1999 Steve Dodd
*/
#include "ntfstypes.h"
@@ -113,12 +114,14 @@ ntfs_init_upcase(ntfs_inode *upcase)
ntfs_io io;
#define UPCASE_LENGTH 256
upcase->vol->upcase = ntfs_malloc(2*UPCASE_LENGTH);
- upcase->vol->upcase_length = UPCASE_LENGTH;
+ if( !upcase->vol->upcase )
+ return;
io.fn_put=ntfs_put;
io.fn_get=0;
io.param=(char*)upcase->vol->upcase;
io.size=2*UPCASE_LENGTH;
ntfs_read_attr(upcase,upcase->vol->at_data,0,0,&io);
+ upcase->vol->upcase_length = io.size;
}
static int
@@ -246,11 +249,22 @@ int ntfs_release_volume(ntfs_volume *vol)
return 0;
}
-int ntfs_get_volumesize(ntfs_volume *vol)
+/*
+ * Writes the volume size into vol_size. Returns 0 if successful
+ * or error.
+ */
+int ntfs_get_volumesize(ntfs_volume *vol, long *vol_size )
{
ntfs_io io;
- char *cluster0=ntfs_malloc(vol->clustersize);
ntfs_u64 size;
+ char *cluster0;
+
+ if( !vol_size )
+ return EFAULT;
+
+ cluster0=ntfs_malloc(vol->clustersize);
+ if( !cluster0 )
+ return ENOMEM;
io.fn_put=ntfs_put;
io.fn_get=ntfs_get;
@@ -262,7 +276,8 @@ int ntfs_get_volumesize(ntfs_volume *vol)
ntfs_free(cluster0);
/* FIXME: more than 2**32 cluster */
/* FIXME: gcc will emit udivdi3 if we don't truncate it */
- return ((unsigned int)size)/vol->clusterfactor;
+ *vol_size = ((unsigned long)size)/vol->clusterfactor;
+ return 0;
}
static int nc[16]={4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0};
@@ -337,7 +352,7 @@ search_bits(unsigned char* bits,ntfs_cluster_t *loc,int *cnt,int l)
int start,stop=0,in=0;
/* special case searching for a single block */
if(*cnt==1){
- while(l && *cnt==0xFF){
+ while(l && *bits==0xFF){
bits++;
*loc+=8;
l--;
@@ -398,7 +413,7 @@ ntfs_set_bitrange(ntfs_inode* bitmap,ntfs_cluster_t loc,int cnt,int bit)
io.fn_put=ntfs_put;
io.fn_get=ntfs_get;
- bsize=(cnt+(loc & 7)+7) & ~7; /* round up to multiple of 8*/
+ bsize=(cnt+(loc & 7)+7) >> 3; /* round up to multiple of 8*/
bits=ntfs_malloc(bsize);
io.param=bits;
io.size=bsize;
@@ -418,7 +433,7 @@ ntfs_set_bitrange(ntfs_inode* bitmap,ntfs_cluster_t loc,int cnt,int bit)
else
*it &= ~(1<<(locit%8));
cnt--;locit++;
- if(locit%8==7)
+ if(locit%8==0)
it++;
}
while(cnt>8){ /*process full bytes */
@@ -456,10 +471,13 @@ ntfs_search_bits(ntfs_inode* bitmap, ntfs_cluster_t *location, int *count, int f
unsigned char *bits;
ntfs_io io;
int error=0,found=0;
- int loc,cnt,bloc=-1,bcnt=0;
+ int cnt,bloc=-1,bcnt=0;
int start;
+ ntfs_cluster_t loc;
bits=ntfs_malloc(2048);
+ if( !bits )
+ return ENOMEM;
io.fn_put=ntfs_put;
io.fn_get=ntfs_get;
io.param=bits;
diff --git a/fs/ntfs/super.h b/fs/ntfs/super.h
index f90490136..b74772143 100644
--- a/fs/ntfs/super.h
+++ b/fs/ntfs/super.h
@@ -10,7 +10,7 @@
#define ALLOC_REQUIRE_SIZE 2
int ntfs_get_free_cluster_count(ntfs_inode *bitmap);
-int ntfs_get_volumesize(ntfs_volume *vol);
+int ntfs_get_volumesize(ntfs_volume *vol, long *vol_size );
int ntfs_init_volume(ntfs_volume *vol,char *boot);
int ntfs_load_special_files(ntfs_volume *vol);
int ntfs_release_volume(ntfs_volume *vol);
diff --git a/fs/ntfs/support.c b/fs/ntfs/support.c
index e0b79c8de..6ee3b332b 100644
--- a/fs/ntfs/support.c
+++ b/fs/ntfs/support.c
@@ -246,6 +246,10 @@ int ntfs_dupuni2map(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
if(!(vol->nct & nct_uni_xlate))goto inval;
/* realloc */
buf=ntfs_malloc(*out_len+3);
+ if( !buf ) {
+ ntfs_free( result );
+ return ENOMEM;
+ }
memcpy(buf,result,o);
ntfs_free(result);
result=buf;
diff --git a/fs/open.c b/fs/open.c
index 137eb4d5f..629008d4d 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -22,10 +22,11 @@ asmlinkage int sys_statfs(const char * path, struct statfs * buf)
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
struct inode * inode = dentry->d_inode;
+ struct super_block * sb = inode->i_sb;
- error = -ENOSYS;
- if (inode->i_sb->s_op->statfs)
- error = inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
+ error = -ENODEV;
+ if (sb && sb->s_op && sb->s_op->statfs)
+ error = sb->s_op->statfs(sb, buf, sizeof(struct statfs));
dput(dentry);
}
@@ -52,10 +53,8 @@ asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
if (!(inode = dentry->d_inode))
goto out_putf;
error = -ENODEV;
- if (!(sb = inode->i_sb))
- goto out_putf;
- error = -ENOSYS;
- if (sb->s_op->statfs)
+ sb = inode->i_sb;
+ if (sb && sb->s_op && sb->s_op->statfs)
error = sb->s_op->statfs(sb, buf, sizeof(struct statfs));
out_putf:
fput(file);
@@ -70,6 +69,10 @@ int do_truncate(struct dentry *dentry, unsigned long length)
int error;
struct iattr newattrs;
+ /* Not pretty: "inode->i_size" shouldn't really be "off_t". But it is. */
+ if ((off_t) length < 0)
+ return -EINVAL;
+
down(&inode->i_sem);
newattrs.ia_size = length;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
@@ -295,11 +298,16 @@ asmlinkage int sys_access(const char * filename, int mode)
/* Clear the capabilities if we switch to a non-root user */
if (current->uid)
cap_clear(current->cap_effective);
-
+ else
+ current->cap_effective = current->cap_permitted;
+
dentry = namei(filename);
res = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
res = permission(dentry->d_inode, mode);
+ /* SuS v2 requires we report a read only fs too */
+ if(!res && (mode & S_IWOTH) && IS_RDONLY(dentry->d_inode))
+ res = -EROFS;
dput(dentry);
}
@@ -752,12 +760,7 @@ out_error:
*/
asmlinkage int sys_creat(const char * pathname, int mode)
{
- int ret;
-
- lock_kernel();
- ret = sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
- unlock_kernel();
- return ret;
+ return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
}
#endif
@@ -782,7 +785,7 @@ void __fput(struct file *filp)
* "id" is the POSIX thread ID. We use the
* files pointer for this..
*/
-int close_fp(struct file *filp, fl_owner_t id)
+int filp_close(struct file *filp, fl_owner_t id)
{
int retval;
struct dentry *dentry = filp->f_dentry;
@@ -818,7 +821,7 @@ asmlinkage int sys_close(unsigned int fd)
files->fd[fd] = NULL;
put_unused_fd(fd);
FD_CLR(fd, &files->close_on_exec);
- error = close_fp(filp, files);
+ error = filp_close(filp, files);
}
unlock_kernel();
return error;
diff --git a/fs/proc/array.c b/fs/proc/array.c
index d845ca5d3..1ce95cdb4 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -565,7 +565,23 @@ static unsigned long get_wchan(struct task_struct *p)
} while (count++ < 16);
}
#elif defined(__powerpc__)
- return (p->tss.wchan);
+ {
+ unsigned long ip, sp;
+ unsigned long stack_page = (unsigned long) p;
+ int count = 0;
+
+ sp = p->tss.ksp;
+ do {
+ sp = *(unsigned long *)sp;
+ if (sp < stack_page || sp >= stack_page + 8188)
+ return 0;
+ if (count > 0) {
+ ip = *(unsigned long *)(sp + 4);
+ if (ip < first_sched || ip >= last_sched)
+ return ip;
+ }
+ } while (count++ < 16);
+ }
#elif defined (CONFIG_ARM)
{
unsigned long fp, lr;
@@ -902,7 +918,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 %d\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
pid,
tsk->comm,
state,
@@ -944,7 +960,8 @@ static int get_stat(int pid, char * buffer)
wchan,
tsk->nswap,
tsk->cnswap,
- tsk->exit_signal);
+ tsk->exit_signal,
+ tsk->processor);
}
static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
@@ -1369,6 +1386,7 @@ static int process_unauthorized(int type, int pid)
{
struct task_struct *p;
uid_t euid=0; /* Save the euid keep the lock short */
+ int ok = 0;
read_lock(&tasklist_lock);
@@ -1378,9 +1396,11 @@ static int process_unauthorized(int type, int pid)
*/
p = find_task_by_pid(pid);
- if(p)
- {
+ if (p) {
euid=p->euid;
+ ok = p->dumpable;
+ if(!cap_issubset(p->cap_permitted, current->cap_permitted))
+ ok=0;
if(!p->mm) /* Scooby scooby doo where are you ? */
p=NULL;
}
@@ -1400,7 +1420,7 @@ static int process_unauthorized(int type, int pid)
case PROC_PID_CPU:
return 0;
}
- if(capable(CAP_DAC_OVERRIDE) || current->fsuid == euid)
+ if(capable(CAP_DAC_OVERRIDE) || (current->fsuid == euid && ok))
return 0;
return 1;
}
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 8db99f7f4..1defdbae1 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -19,7 +19,7 @@
#include <asm/uaccess.h>
static int proc_readfd(struct file *, void *, filldir_t);
-static int proc_lookupfd(struct inode *, struct dentry *);
+static struct dentry *proc_lookupfd(struct inode *, struct dentry *);
static struct file_operations proc_fd_operations = {
NULL, /* lseek - default */
@@ -67,7 +67,7 @@ struct inode_operations proc_fd_inode_operations = {
*
* Thus just return -ENOENT instead.
*/
-static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
+static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
{
unsigned int ino, pid, fd, c;
struct task_struct * p;
@@ -77,13 +77,11 @@ static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
int len, err;
err = -ENOENT;
- if (!dir)
- goto out;
ino = dir->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
- if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode))
+ if (!pid || ino != PROC_PID_FD)
goto out;
fd = 0;
@@ -121,10 +119,10 @@ static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
if (inode) {
dentry->d_op = &proc_dentry_operations;
d_add(dentry, inode);
- err = 0;
+ return NULL;
}
out:
- return err;
+ return ERR_PTR(err);
}
#define NUMBUF 10
@@ -137,10 +135,6 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
int retval;
char buf[NUMBUF];
- retval = -EBADF;
- if (!inode || !S_ISDIR(inode->i_mode))
- goto out;
-
retval = 0;
ino = inode->i_ino;
pid = ino >> 16;
diff --git a/fs/proc/link.c b/fs/proc/link.c
index 70c31f21a..b12050767 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -158,7 +158,7 @@ static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen)
path = tmp;
} else {
path = d_path(dentry, tmp, PAGE_SIZE);
- len = tmp + PAGE_SIZE - path;
+ len = tmp + PAGE_SIZE - 1 - path;
}
if (len < buflen)
diff --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c
index 2c2c84784..dcb007f11 100644
--- a/fs/proc/openpromfs.c
+++ b/fs/proc/openpromfs.c
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.32 1998/11/18 06:15:20 davem Exp $
+/* $Id: openpromfs.c,v 1.33 1999/04/28 11:57:33 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -59,7 +59,7 @@ static struct openpromfs_dev **devices;
static int openpromfs_create (struct inode *, struct dentry *, int);
static int openpromfs_readdir(struct file *, void *, filldir_t);
-static int openpromfs_lookup(struct inode *, struct dentry *dentry);
+static struct dentry *openpromfs_lookup(struct inode *, struct dentry *dentry);
static int openpromfs_unlink (struct inode *, struct dentry *dentry);
static ssize_t nodenum_read(struct file *file, char *buf,
@@ -685,7 +685,7 @@ static int lookup_children(u16 n, const char * name, int len)
return 0;
}
-static int openpromfs_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentry)
{
int ino = 0;
#define OPFSL_DIR 0
@@ -776,11 +776,11 @@ static int openpromfs_lookup(struct inode * dir, struct dentry *dentry)
if (ino)
type = OPFSL_DIR;
else
- return -ENOENT;
+ return ERR_PTR(-ENOENT);
}
inode = proc_get_inode (dir->i_sb, ino, 0);
if (!inode)
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
switch (type) {
case OPFSL_DIR:
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
@@ -827,7 +827,7 @@ static int openpromfs_lookup(struct inode * dir, struct dentry *dentry)
inode->i_uid = 0;
d_add(dentry, inode);
- return 0;
+ return NULL;
}
static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
@@ -842,7 +842,6 @@ static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filld
struct openpromfs_dev *d;
char buffer2[64];
- if (!inode || !S_ISDIR (inode->i_mode)) return -ENOTDIR;
ino = inode->i_ino;
i = filp->f_pos;
switch (i) {
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 9c841a88e..82b3fd71d 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -28,7 +28,7 @@
#define FIRST_PROCESS_ENTRY 256
static int proc_root_readdir(struct file *, void *, filldir_t);
-static int proc_root_lookup(struct inode *,struct dentry *);
+static struct dentry *proc_root_lookup(struct inode *,struct dentry *);
static int proc_unlink(struct inode *, struct dentry *);
static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
@@ -181,14 +181,14 @@ struct proc_dir_entry proc_sys_root = {
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
static int (*proc_openprom_defreaddir_ptr)(struct file *, void *, filldir_t);
-static int (*proc_openprom_deflookup_ptr)(struct inode *, struct dentry *);
+static struct dentry * (*proc_openprom_deflookup_ptr)(struct inode *, struct dentry *);
void (*proc_openprom_use)(struct inode *, int) = 0;
static struct openpromfs_dev *proc_openprom_devices = NULL;
static ino_t proc_openpromdev_ino = PROC_OPENPROMD_FIRST;
struct inode_operations *
proc_openprom_register(int (*readdir)(struct file *, void *, filldir_t),
- int (*lookup)(struct inode *, struct dentry *),
+ struct dentry * (*lookup)(struct inode *, struct dentry *),
void (*use)(struct inode *, int),
struct openpromfs_dev ***devices)
{
@@ -250,7 +250,7 @@ proc_openprom_defreaddir(struct file * filp, void * dirent, filldir_t filldir)
}
#define OPENPROM_DEFREADDIR proc_openprom_defreaddir
-static int
+static struct dentry *
proc_openprom_deflookup(struct inode * dir, struct dentry *dentry)
{
request_module("openpromfs");
@@ -258,7 +258,7 @@ proc_openprom_deflookup(struct inode * dir, struct dentry *dentry)
proc_openprom_deflookup)
return proc_openprom_inode_operations.lookup
(dir, dentry);
- return -ENOENT;
+ return ERR_PTR(-ENOENT);
}
#define OPENPROM_DEFLOOKUP proc_openprom_deflookup
#else
@@ -779,16 +779,12 @@ struct dentry_operations proc_dentry_operations =
* Don't create negative dentries here, return -ENOENT by hand
* instead.
*/
-int proc_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry)
{
struct inode *inode;
struct proc_dir_entry * de;
int error;
- error = -ENOTDIR;
- if (!dir || !S_ISDIR(dir->i_mode))
- goto out;
-
error = -ENOENT;
inode = NULL;
de = (struct proc_dir_entry *) dir->u.generic_ip;
@@ -810,13 +806,12 @@ int proc_lookup(struct inode * dir, struct dentry *dentry)
if (inode) {
dentry->d_op = &proc_dentry_operations;
d_add(dentry, inode);
- error = 0;
+ return NULL;
}
-out:
- return error;
+ return ERR_PTR(error);
}
-static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
+static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry)
{
unsigned int pid, c;
struct task_struct *p;
@@ -836,7 +831,7 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
}
if (!proc_lookup(dir, dentry))
- return 0;
+ return NULL;
pid = 0;
name = dentry->d_name.name;
@@ -863,13 +858,13 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
unsigned long ino = (pid << 16) + PROC_PID_INO;
inode = proc_get_inode(dir->i_sb, ino, &proc_pid);
if (!inode)
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
inode->i_flags|=S_IMMUTABLE;
}
dentry->d_op = &proc_dentry_operations;
d_add(dentry, inode);
- return 0;
+ return NULL;
}
/*
@@ -889,8 +884,6 @@ int proc_readdir(struct file * filp,
int i;
struct inode *inode = filp->f_dentry->d_inode;
- if (!inode || !S_ISDIR(inode->i_mode))
- return -ENOTDIR;
ino = inode->i_ino;
de = (struct proc_dir_entry *) inode->u.generic_ip;
if (!de)
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
index 119930667..029fd9061 100644
--- a/fs/qnx4/dir.c
+++ b/fs/qnx4/dir.c
@@ -35,9 +35,6 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
blknum = inode->u.qnx4_i.i_first_xtnt.xtnt_blk - 1 +
((filp->f_pos >> 6) >> 3);
- if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) {
- return -EBADF;
- }
QNX4DEBUG(("qnx4_readdir:i_size = %ld\n", (long) inode->i_size));
QNX4DEBUG(("filp->f_pos = %ld\n", (long) filp->f_pos));
QNX4DEBUG(("BlkNum = %ld\n", (long) blknum));
diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c
index 499980126..ab923b7f0 100644
--- a/fs/qnx4/file.c
+++ b/fs/qnx4/file.c
@@ -33,8 +33,6 @@
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
-#include <linux/fs.h>
-#include <linux/qnx4_fs.h>
static int qnx4_readpage(struct file *file, struct page *page);
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
index 267ecb110..feb014b8e 100644
--- a/fs/qnx4/namei.c
+++ b/fs/qnx4/namei.c
@@ -70,12 +70,8 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
struct buffer_head *bh;
*res_dir = NULL;
- if (!dir || !dir->i_sb) {
- if (!dir) {
- printk("qnx4: NULL dir.\n");
- } else {
- printk("qnx4: no superblock on dir.\n");
- }
+ if (!dir->i_sb) {
+ printk("qnx4: no superblock on dir.\n");
return NULL;
}
bh = NULL;
@@ -108,7 +104,7 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
return NULL;
}
-int qnx4_lookup(struct inode *dir, struct dentry *dentry)
+struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry)
{
int ino;
struct qnx4_inode_entry *de;
@@ -116,17 +112,10 @@ int qnx4_lookup(struct inode *dir, struct dentry *dentry)
struct buffer_head *bh;
const char *name = dentry->d_name.name;
int len = dentry->d_name.len;
- struct inode *foundinode;
+ struct inode *foundinode = NULL;
- if (!dir) {
- return -EBADF;
- }
- if (!S_ISDIR(dir->i_mode)) {
- return -EBADF;
- }
- if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino))) {
- return -ENOENT;
- }
+ if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino)))
+ goto out;
/* The entry is linked, let's get the real info */
if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) {
lnk = (struct qnx4_link_info *) de;
@@ -137,11 +126,12 @@ int qnx4_lookup(struct inode *dir, struct dentry *dentry)
if ((foundinode = iget(dir->i_sb, ino)) == NULL) {
QNX4DEBUG(("qnx4: lookup->iget -> NULL\n"));
- return -EACCES;
+ return ERR_PTR(-EACCES);
}
+out:
d_add(dentry, foundinode);
- return 0;
+ return NULL;
}
#ifdef CONFIG_QNX4FS_RW
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 211563b1c..fd374842e 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -267,9 +267,6 @@ romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
int stored = 0;
char fsname[ROMFS_MAXFN]; /* XXX dynamic? */
- if (!i || !S_ISDIR(i->i_mode))
- return -EBADF;
-
maxoff = i->i_sb->u.romfs_sb.s_maxsize;
offset = filp->f_pos;
@@ -312,7 +309,7 @@ romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
}
-static int
+static struct dentry *
romfs_lookup(struct inode *dir, struct dentry *dentry)
{
unsigned long offset, maxoff;
@@ -323,10 +320,6 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
const char *name; /* got from dentry */
int len;
- res = -EBADF;
- if (!dir || !S_ISDIR(dir->i_mode))
- goto out;
-
res = 0; /* instead of ENOENT */
offset = dir->i_ino & ROMFH_MASK;
if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
@@ -379,7 +372,7 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
}
out:
- return res;
+ return ERR_PTR(res);
}
/*
diff --git a/fs/smbfs/cache.c b/fs/smbfs/cache.c
index 292493dac..36f1650ac 100644
--- a/fs/smbfs/cache.c
+++ b/fs/smbfs/cache.c
@@ -12,7 +12,6 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/mm.h>
-#include <linux/errno.h>
#include <linux/dirent.h>
#include <linux/smb_fs.h>
@@ -142,7 +141,7 @@ smb_add_to_cache(struct cache_head * cachep, struct cache_dirent *entry,
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_add_to_cache: cache inode %p, status %d, adding %s at %ld\n",
-inode, cachep->status, entry->d_name, fpos);
+inode, cachep->status, entry->name, fpos);
#endif
/*
* Don't do anything if we've had an error ...
@@ -171,7 +170,7 @@ inode, cachep->status, entry->d_name, fpos);
cachep->entries++;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_add_to_cache: added entry %s, len=%d, pos=%ld, entries=%d\n",
-entry->d_name, len, fpos, cachep->entries);
+entry->name, len, fpos, cachep->entries);
#endif
return;
}
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 30138872b..4f942db80 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -22,7 +22,7 @@ static ssize_t smb_dir_read(struct file *, char *, size_t, loff_t *);
static int smb_readdir(struct file *, void *, filldir_t);
static int smb_dir_open(struct inode *, struct file *);
-static int smb_lookup(struct inode *, struct dentry *);
+static struct dentry *smb_lookup(struct inode *, struct dentry *);
static int smb_create(struct inode *, struct dentry *, int);
static int smb_mkdir(struct inode *, struct dentry *, int);
static int smb_rmdir(struct inode *, struct dentry *);
@@ -191,14 +191,14 @@ file->f_dentry->d_name.name);
/*
* Dentry operations routines
*/
-static int smb_lookup_validate(struct dentry *);
+static int smb_lookup_validate(struct dentry *, int);
static int smb_hash_dentry(struct dentry *, struct qstr *);
static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
static void smb_delete_dentry(struct dentry *);
static struct dentry_operations smbfs_dentry_operations =
{
- smb_lookup_validate, /* d_validate(struct dentry *) */
+ smb_lookup_validate, /* d_revalidate(struct dentry *) */
smb_hash_dentry, /* d_hash */
smb_compare_dentry, /* d_compare */
smb_delete_dentry /* d_delete(struct dentry *) */
@@ -208,7 +208,7 @@ static struct dentry_operations smbfs_dentry_operations =
* This is the callback when the dcache has a lookup hit.
*/
static int
-smb_lookup_validate(struct dentry * dentry)
+smb_lookup_validate(struct dentry * dentry, int flags)
{
struct inode * inode = dentry->d_inode;
unsigned long age = jiffies - dentry->d_time;
@@ -324,7 +324,7 @@ smb_renew_times(struct dentry * dentry)
}
}
-static int
+static struct dentry *
smb_lookup(struct inode *dir, struct dentry *dentry)
{
struct smb_fattr finfo;
@@ -360,7 +360,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, error);
}
}
out:
- return error;
+ return ERR_PTR(error);
}
/*
@@ -423,9 +423,6 @@ smb_create(struct inode *dir, struct dentry *dentry, int mode)
printk("smb_create: creating %s/%s, mode=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, mode);
#endif
- error = -ENAMETOOLONG;
- if (dentry->d_name.len > SMB_MAXNAMELEN)
- goto out;
smb_invalid_dir_cache(dir);
error = smb_proc_create(dentry, 0, CURRENT_TIME, &fileid);
@@ -439,7 +436,6 @@ printk("smb_create: %s/%s failed, error=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, error);
#endif
}
-out:
return error;
}
@@ -449,17 +445,12 @@ smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int error;
- error = -ENAMETOOLONG;
- if (dentry->d_name.len > SMB_MAXNAMELEN)
- goto out;
-
smb_invalid_dir_cache(dir);
error = smb_proc_mkdir(dentry);
if (!error)
{
error = smb_instantiate(dentry, 0, 0);
}
-out:
return error;
}
@@ -514,11 +505,6 @@ smb_rename(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
- error = -ENAMETOOLONG;
- if (old_dentry->d_name.len > SMB_MAXNAMELEN ||
- new_dentry->d_name.len > SMB_MAXNAMELEN)
- goto out;
-
/*
* Close any open files, and check whether to delete the
* target before attempting the rename.
@@ -537,6 +523,7 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name, error);
#endif
goto out;
}
+ /* FIXME */
d_delete(new_dentry);
}
@@ -547,7 +534,6 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name, error);
{
smb_renew_times(old_dentry);
smb_renew_times(new_dentry);
- d_move(old_dentry, new_dentry);
}
out:
return error;
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index a6cf24ce1..aff45ef9b 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -144,7 +144,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, wsize);
result = smb_proc_write(dentry, offset, wsize, buffer);
if (result < 0)
- goto io_error;
+ break;
/* N.B. what if result < wsize?? */
#ifdef SMBFS_PARANOIA
if (result < wsize)
@@ -162,15 +162,7 @@ printk("smb_writepage_sync: short write, wsize=%d, result=%d\n", wsize, result);
inode->i_size = offset;
inode->u.smbfs_i.cache_valid |= SMB_F_LOCALWRITE;
} while (count);
-
-out:
- smb_unlock_page(page);
return written ? written : result;
-
-io_error:
- /* Must mark the page invalid after I/O error */
- clear_bit(PG_uptodate, &page->flags);
- goto out;
}
/*
@@ -190,6 +182,7 @@ smb_writepage(struct file *file, struct page *page)
set_bit(PG_locked, &page->flags);
atomic_inc(&page->count);
result = smb_writepage_sync(dentry, page, 0, PAGE_SIZE);
+ smb_unlock_page(page);
free_page(page_address(page));
return result;
}
diff --git a/fs/super.c b/fs/super.c
index 7c5d2904c..690807a26 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -559,6 +559,7 @@ static struct super_block * read_super(kdev_t dev,const char *name,int flags,
s->s_dev = dev;
s->s_flags = flags;
s->s_dirt = 0;
+ sema_init(&s->s_vfs_rename_sem,1);
/* N.B. Should lock superblock now ... */
if (!type->read_super(s, data, silent))
goto out_fail;
@@ -1130,6 +1131,7 @@ void __init mount_root(void)
sb = get_empty_super(); /* "can't fail" */
sb->s_dev = get_unnamed_dev();
sb->s_flags = root_mountflags;
+ sema_init(&sb->s_vfs_rename_sem,1);
vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
if (vfsmnt) {
if (nfs_root_mount(sb) >= 0) {
@@ -1155,12 +1157,22 @@ void __init mount_root(void)
#ifdef CONFIG_BLK_DEV_FD
if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
+#ifdef CONFIG_BLK_DEV_RAM
+ extern int rd_doload;
+#endif
floppy_eject();
#ifndef CONFIG_BLK_DEV_RAM
printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");
+#else
+ /* rd_doload is 2 for a dual initrd/ramload setup */
+ if(rd_doload==2)
+ rd_load_secondary();
+ else
#endif
- printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
- wait_for_keypress();
+ {
+ printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
+ wait_for_keypress();
+ }
}
#endif
diff --git a/fs/sysv/CHANGES b/fs/sysv/CHANGES
index 4dbff5b56..94507925c 100644
--- a/fs/sysv/CHANGES
+++ b/fs/sysv/CHANGES
@@ -1,45 +1,55 @@
-Mon Dec 15 1997 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
+Mon, 15 Dec 1997 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
* namei.c: struct sysv_dir_inode_operations updated to use dentries.
-Fri Jan 23 1998 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
+Fri, 23 Jan 1998 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
* inode.c: corrected 1 track offset setting (in sb->sv_block_base).
Originally it was overridden (by setting to zero)
in detected_[xenix,sysv4,sysv2,coherent]. Thanks
to Andrzej Krzysztofowicz <ankry@mif.pg.gda.pl>
for identifying the problem.
-Tue Jan 27 1998 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
+Tue, 27 Jan 1998 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
* inode.c: added 2048-byte block support to SystemV FS.
Merged detected_bs[512,1024,2048]() into one function:
void detected_bs (u_char type, struct super_block *sb).
Thanks to Andrzej Krzysztofowicz <ankry@mif.pg.gda.pl>
for the patch.
-Wed Feb 4 1998 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
+Wed, 4 Feb 1998 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
* namei.c: removed static subdir(); is_subdir() from dcache.c
is used instead. Cosmetic changes.
-Thu Dec 3 1998 Al Viro (viro@math.psu.edu)
+Thu, 3 Dec 1998 Al Viro (viro@math.psu.edu)
* namei.c (sysv_rmdir):
Bugectomy: old check for victim being busy
(inode->i_count) wasn't replaced (with checking
dentry->d_count) and escaped Linus in the last round
of changes. Shot and buried.
-Wed Dec 9 1998 AV
+Wed, 9 Dec 1998 AV
* namei.c (do_sysv_rename):
Fixed incorrect check for other owners + race.
Removed checks that went to VFS.
* namei.c (sysv_unlink):
Removed checks that went to VFS.
-Thu Dec 10 1998 AV
+Thu, 10 Dec 1998 AV
* namei.c (do_mknod):
Removed dead code - mknod is never asked to
create a symlink or directory. Incidentially,
it wouldn't do it right if it would be called.
-Sat Dec 26 1998 KGB
+Sat, 26 Dec 1998 KGB
* inode.c (detect_sysv4):
Added detection of expanded s_type field (0x10,
0x20 and 0x30). Forced read-only access in this case.
+
+Sun, 21 Mar 1999 AV
+ * namei.c (sysv_link):
+ Fixed i_count usage that resulted in dcache corruption.
+ * inode.c:
+ Filled ->delete_inode() method with sysv_delete_inode().
+ sysv_put_inode() is gone, as it tried to do ->delete_
+ _inode()'s job.
+ * ialloc.c: (sysv_free_inode):
+ Fixed race.
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index 9a1acc19e..a28a7ba8e 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -69,14 +69,12 @@ struct inode_operations sysv_dir_inode_operations = {
static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
struct inode *inode = filp->f_dentry->d_inode;
- struct super_block * sb;
+ struct super_block * sb = inode->i_sb;
unsigned int offset,i;
struct buffer_head * bh;
char* bh_data;
struct sysv_dir_entry * de, sde;
- if (!inode || !(sb = inode->i_sb) || !S_ISDIR(inode->i_mode))
- return -EBADF;
if ((unsigned long)(filp->f_pos) % SYSV_DIRSIZE)
return -EBADF;
while (filp->f_pos < inode->i_size) {
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index 8718b8b5a..2826286cc 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -86,6 +86,7 @@ void sysv_free_inode(struct inode * inode)
return;
}
raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1);
+ clear_inode(inode);
lock_super(sb);
if (*sb->sv_sb_fic_count < sb->sv_fic_size)
*sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)++) = ino;
@@ -97,7 +98,6 @@ void sysv_free_inode(struct inode * inode)
mark_buffer_dirty(bh, 1);
unlock_super(sb);
brelse(bh);
- clear_inode(inode);
}
struct inode * sysv_new_inode(const struct inode * dir)
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index d5af68176..f58560996 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -55,10 +55,8 @@ void sysv_print_inode(struct inode * inode)
}
#endif
-void sysv_put_inode(struct inode *inode)
+static void sysv_delete_inode(struct inode *inode)
{
- if (inode->i_nlink)
- return;
inode->i_size = 0;
sysv_truncate(inode);
sysv_free_inode(inode);
@@ -68,8 +66,8 @@ void sysv_put_inode(struct inode *inode)
static struct super_operations sysv_sops = {
sysv_read_inode,
sysv_write_inode,
- sysv_put_inode,
- NULL, /* delete_inode */
+ NULL, /* nothing special on put_inode() */
+ sysv_delete_inode,
sysv_notify_change,
sysv_put_super,
sysv_write_super,
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index 1ae336647..8cea266a8 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -67,8 +67,6 @@ static struct buffer_head * sysv_find_entry(struct inode * dir,
struct buffer_head * bh;
*res_dir = NULL;
- if (!dir)
- return NULL;
sb = dir->i_sb;
if (namelen > SYSV_NAMELEN) {
if (sb->sv_truncate)
@@ -103,17 +101,12 @@ static struct buffer_head * sysv_find_entry(struct inode * dir,
return NULL;
}
-int sysv_lookup(struct inode * dir, struct dentry * dentry)
+struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry)
{
struct inode * inode = NULL;
struct sysv_dir_entry * de;
struct buffer_head * bh;
- if (!dir)
- return -ENOENT;
- if (!S_ISDIR(dir->i_mode)) {
- return -ENOENT;
- }
bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
if (bh) {
@@ -122,10 +115,10 @@ int sysv_lookup(struct inode * dir, struct dentry * dentry)
inode = iget(dir->i_sb, ino);
if (!inode)
- return -EACCES;
+ return ERR_PTR(-EACCES);
}
d_add(dentry, inode);
- return 0;
+ return NULL;
}
/*
@@ -209,8 +202,6 @@ int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
struct buffer_head * bh;
struct sysv_dir_entry * de;
- if (!dir)
- return -ENOENT;
inode = sysv_new_inode(dir);
if (!inode)
return -ENOSPC;
@@ -239,8 +230,6 @@ int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
struct buffer_head * bh;
struct sysv_dir_entry * de;
- if (!dir)
- return -ENOENT;
bh = sysv_find_entry(dir, dentry->d_name.name,
dentry->d_name.len, &de);
if (bh) {
@@ -286,8 +275,6 @@ int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
struct buffer_head * bh, *dir_block;
struct sysv_dir_entry * de;
- if (!dir)
- return -EINVAL;
bh = sysv_find_entry(dir, dentry->d_name.name,
dentry->d_name.len, &de);
if (bh) {
@@ -576,6 +563,7 @@ int sysv_link(struct dentry * old_dentry, struct inode * dir,
oldinode->i_nlink++;
oldinode->i_ctime = CURRENT_TIME;
mark_inode_dirty(oldinode);
+ oldinode->i_count++;
d_instantiate(dentry, oldinode);
return 0;
}
@@ -593,8 +581,8 @@ int sysv_link(struct dentry * old_dentry, struct inode * dir,
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-static int do_sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
- struct inode * new_dir, struct dentry * new_dentry)
+int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
+ struct inode * new_dir, struct dentry * new_dentry)
{
struct inode * old_inode, * new_inode;
struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -627,20 +615,8 @@ start_up:
new_bh = NULL;
}
}
- if (new_inode == old_inode) {
- retval = 0;
- goto end_rename;
- }
if (S_ISDIR(old_inode->i_mode)) {
- retval = -EINVAL;
- if (is_subdir(new_dentry, old_dentry))
- goto end_rename;
if (new_inode) {
- if (new_dentry->d_count > 1)
- shrink_dcache_parent(new_dentry);
- retval = -EBUSY;
- if (new_dentry->d_count > 1)
- goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto end_rename;
@@ -695,7 +671,6 @@ start_up:
mark_inode_dirty(new_dir);
}
}
- d_move(old_dentry, new_dentry);
retval = 0;
end_rename:
brelse(dir_bh);
@@ -703,29 +678,3 @@ end_rename:
brelse(new_bh);
return retval;
}
-
-/*
- * Ok, rename also locks out other renames, as they can change the parent of
- * a directory, and we don't want any races. Other races are checked for by
- * "do_rename()", which restarts if there are inconsistencies.
- *
- * Note that there is no race between different filesystems: it's only within
- * the same device that races occur: many renames can happen at once, as long
- * as they are on different partitions.
- */
-int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
- struct inode * new_dir, struct dentry * new_dentry)
-{
- static struct wait_queue * wait = NULL;
- static int lock = 0;
- int result;
-
- while (lock)
- sleep_on(&wait);
- lock = 1;
- result = do_sysv_rename(old_dir, old_dentry,
- new_dir, new_dentry);
- lock = 0;
- wake_up(&wait);
- return result;
-}
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 24810fe48..6a79c4a5e 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -43,13 +43,6 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
int de_reclen;
unsigned flags, swab;
-
- /* Isn't that already done in the upper layer???
- * the VFS layer really needs some explicit documentation!
- */
- if (!inode || !S_ISDIR(inode->i_mode))
- return -EBADF;
-
sb = inode->i_sb;
swab = sb->u.ufs_sb.s_swab;
flags = sb->u.ufs_sb.s_flags;
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index dc5dccf4c..3daf77c57 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -91,8 +91,6 @@ static struct buffer_head * ufs_find_entry (struct inode * dir,
UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen))
*res_dir = NULL;
- if (!dir)
- return NULL;
sb = dir->i_sb;
flags = sb->u.ufs_sb.s_flags;
@@ -185,7 +183,7 @@ failed:
return NULL;
}
-int ufs_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry)
{
struct super_block * sb;
struct inode * inode;
@@ -199,7 +197,7 @@ int ufs_lookup(struct inode * dir, struct dentry *dentry)
swab = sb->u.ufs_sb.s_swab;
if (dentry->d_name.len > UFS_MAXNAMLEN)
- return -ENAMETOOLONG;
+ return ERR_PTR(-ENAMETOOLONG);
bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
inode = NULL;
@@ -208,11 +206,11 @@ int ufs_lookup(struct inode * dir, struct dentry *dentry)
brelse (bh);
inode = iget(sb, ino);
if (!inode)
- return -EACCES;
+ return ERR_PTR(-EACCES);
}
d_add(dentry, inode);
UFSD(("EXIT\n"))
- return 0;
+ return NULL;
}
/*
@@ -250,12 +248,6 @@ static struct buffer_head * ufs_add_entry (struct inode * dir,
swab = sb->u.ufs_sb.s_swab;
uspi = sb->u.ufs_sb.s_uspi;
- if (namelen > UFS_MAXNAMLEN)
- {
- *err = -ENAMETOOLONG;
- return NULL;
- }
-
if (!namelen)
return NULL;
/*
@@ -469,10 +461,6 @@ int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
sb = dir->i_sb;
flags = sb->u.ufs_sb.s_flags;
swab = sb->u.ufs_sb.s_swab;
-
- err = -ENAMETOOLONG;
- if (dentry->d_name.len > UFS_MAXNAMLEN)
- goto out;
inode = ufs_new_inode (dir, mode, &err);
if (!inode)
@@ -528,10 +516,6 @@ int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
sb = dir->i_sb;
flags = sb->u.ufs_sb.s_flags;
swab = sb->u.ufs_sb.s_swab;
-
- err = -ENAMETOOLONG;
- if (dentry->d_name.len > UFS_MAXNAMLEN)
- goto out;
err = -EMLINK;
if (dir->i_nlink >= UFS_LINK_MAX)
@@ -670,10 +654,6 @@ int ufs_rmdir (struct inode * dir, struct dentry *dentry)
swab = sb->u.ufs_sb.s_swab;
UFSD(("ENTER\n"))
-
- retval = -ENAMETOOLONG;
- if (dentry->d_name.len > UFS_MAXNAMLEN)
- goto out;
retval = -ENOENT;
bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
@@ -687,14 +667,12 @@ int ufs_rmdir (struct inode * dir, struct dentry *dentry)
if (SWAB32(de->d_ino) != inode->i_ino)
goto end_rmdir;
+ retval = -ENOTEMPTY;
if (!ufs_empty_dir (inode))
- retval = -ENOTEMPTY;
- else if (SWAB32(de->d_ino) != inode->i_ino)
- retval = -ENOENT;
- else {
- retval = ufs_delete_entry (dir, de, bh);
- dir->i_version = ++event;
- }
+ goto end_rmdir;
+
+ retval = ufs_delete_entry (dir, de, bh);
+ dir->i_version = ++event;
if (retval)
goto end_rmdir;
mark_buffer_dirty(bh, 1);
@@ -717,7 +695,6 @@ int ufs_rmdir (struct inode * dir, struct dentry *dentry)
end_rmdir:
brelse (bh);
-out:
UFSD(("EXIT\n"))
return retval;
@@ -735,10 +712,6 @@ int ufs_unlink(struct inode * dir, struct dentry *dentry)
sb = dir->i_sb;
flags = sb->u.ufs_sb.s_flags;
swab = sb->u.ufs_sb.s_swab;
-
- retval = -ENAMETOOLONG;
- if (dentry->d_name.len > UFS_MAXNAMLEN)
- goto out;
retval = -ENOENT;
bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
@@ -779,7 +752,6 @@ int ufs_unlink(struct inode * dir, struct dentry *dentry)
end_unlink:
brelse (bh);
-out:
return retval;
}
@@ -881,9 +853,6 @@ int ufs_link (struct dentry * old_dentry, struct inode * dir,
if (S_ISDIR(inode->i_mode))
return -EPERM;
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- return -EPERM;
-
if (inode->i_nlink >= UFS_LINK_MAX)
return -EMLINK;
@@ -912,17 +881,10 @@ int ufs_link (struct dentry * old_dentry, struct inode * dir,
((struct ufs_dir_entry *) ((char *) buffer + \
SWAB16(((struct ufs_dir_entry *) buffer)->d_reclen)))->d_ino
/*
- * rename uses retrying to avoid race-conditions: at least they should be
- * minimal.
- * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
- * checks fail, it tries to restart itself again. Very practical - no changes
- * are done until we know everything works ok.. and then all the changes can be
- * done in one fell swoop when we have claimed all the buffers needed.
- *
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-static int do_ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
+int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
struct inode * new_dir, struct dentry * new_dentry )
{
struct super_block * sb;
@@ -941,9 +903,6 @@ static int do_ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
old_inode = new_inode = NULL;
old_bh = new_bh = dir_bh = NULL;
new_de = NULL;
- retval = -ENAMETOOLONG;
- if (old_dentry->d_name.len > UFS_MAXNAMLEN)
- goto end_rename;
old_bh = ufs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
/*
@@ -967,25 +926,14 @@ static int do_ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
DQUOT_INIT(new_inode);
}
}
- retval = 0;
- if (new_inode == old_inode)
- goto end_rename;
if (S_ISDIR(old_inode->i_mode)) {
- retval = -EINVAL;
- if (is_subdir(new_dentry, old_dentry))
- goto end_rename;
if (new_inode) {
- /* Prune any children before testing for busy */
- if (new_dentry->d_count > 1)
- shrink_dcache_parent(new_dentry);
- retval = -EBUSY;
- if (new_dentry->d_count > 1)
- goto end_rename;
retval = -ENOTEMPTY;
if (!ufs_empty_dir (new_inode))
goto end_rename;
}
+ retval = -EIO;
dir_bh = ufs_bread (old_inode, 0, 0, &retval);
if (!dir_bh)
goto end_rename;
@@ -1042,8 +990,6 @@ static int do_ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
wait_on_buffer (new_bh);
}
- /* Update the dcache */
- d_move(old_dentry, new_dentry);
retval = 0;
end_rename:
brelse (dir_bh);
@@ -1054,36 +1000,3 @@ end_rename:
return retval;
}
-
-/*
- * Ok, rename also locks out other renames, as they can change the parent of
- * a directory, and we don't want any races. Other races are checked for by
- * "do_rename()", which restarts if there are inconsistencies.
- *
- * Note that there is no race between different filesystems: it's only within
- * the same device that races occur: many renames can happen at once, as long
- * as they are on different partitions.
- *
- * In the second extended file system, we use a lock flag stored in the memory
- * super-block. This way, we really lock other renames only if they occur
- * on the same file system
- */
-int ufs_rename (struct inode * old_dir, struct dentry *old_dentry,
- struct inode * new_dir, struct dentry *new_dentry )
-{
- int result;
-
- UFSD(("ENTER\n"))
-
- while (old_dir->i_sb->u.ufs_sb.s_rename_lock)
- sleep_on (&old_dir->i_sb->u.ufs_sb.s_rename_wait);
- old_dir->i_sb->u.ufs_sb.s_rename_lock = 1;
- result = do_ufs_rename (old_dir, old_dentry, new_dir, new_dentry);
- old_dir->i_sb->u.ufs_sb.s_rename_lock = 0;
- wake_up (&old_dir->i_sb->u.ufs_sb.s_rename_wait);
-
- UFSD(("EXIT\n"))
-
- return result;
-}
-
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 1abdbe038..4fe11c564 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -125,7 +125,7 @@ void ufs_print_super_stuff(struct ufs_super_block_first * usb1,
printk(" cssize: %u\n", SWAB32(usb1->fs_cssize));
printk(" cgsize: %u\n", SWAB32(usb1->fs_cgsize));
printk(" fstodb: %u\n", SWAB32(usb1->fs_fsbtodb));
- printk(" contigsumsize: %d\n", SWAB32(usb3->fs_u.fs_44.fs_contigsumsize));
+ printk(" contigsumsize: %d\n", SWAB32(usb3->fs_u2.fs_44.fs_contigsumsize));
printk(" postblformat: %u\n", SWAB32(usb3->fs_postblformat));
printk(" nrpos: %u\n", SWAB32(usb3->fs_nrpos));
printk(" ndir %u\n", SWAB32(usb1->fs_cstotal.cs_ndir));
@@ -269,10 +269,12 @@ static int ufs_parse_options (char * options, unsigned * mount_options)
ufs_set_opt (*mount_options, UFSTYPE_SUN);
else if (!strcmp (value, "44bsd"))
ufs_set_opt (*mount_options, UFSTYPE_44BSD);
- else if (!strcmp (value, "next"))
- ufs_set_opt (*mount_options, UFSTYPE_NEXT);
+ else if (!strcmp (value, "nextstep"))
+ ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP);
else if (!strcmp (value, "openstep"))
ufs_set_opt (*mount_options, UFSTYPE_OPENSTEP);
+ else if (!strcmp (value, "sunx86"))
+ ufs_set_opt (*mount_options, UFSTYPE_SUNx86);
else {
printk ("UFS-fs: Invalid type option: %s\n", value);
return 0;
@@ -463,7 +465,7 @@ struct super_block * ufs_read_super (struct super_block * sb, void * data,
}
if (!(sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE)) {
printk("You didn't specify the type of your ufs filesystem\n\n"
- " mount -t ufs -o ufstype=sun|44bsd|old|next|openstep ....\n\n"
+ " mount -t ufs -o ufstype=sun|sunx86|44bsd|old|nextstep|openstep ....\n\n"
">>>WARNING<<< Wrong ufstype may corrupt your filesystem, "
"default is ufstype=old\n");
ufs_set_opt (sb->u.ufs_sb.s_mount_opt, UFSTYPE_OLD);
@@ -495,6 +497,16 @@ struct super_block * ufs_read_super (struct super_block * sb, void * data,
flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUN | UFS_CG_SUN;
break;
+ case UFS_MOUNT_UFSTYPE_SUNx86:
+ UFSD(("ufstype=sunx86\n"))
+ uspi->s_fsize = block_size = 1024;
+ uspi->s_fmask = ~(1024 - 1);
+ uspi->s_fshift = 10;
+ uspi->s_sbsize = super_block_size = 2048;
+ uspi->s_sbbase = 0;
+ flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUNx86 | UFS_CG_SUN;
+ break;
+
case UFS_MOUNT_UFSTYPE_OLD:
UFSD(("ufstype=old\n"))
uspi->s_fsize = block_size = 1024;
@@ -509,8 +521,8 @@ struct super_block * ufs_read_super (struct super_block * sb, void * data,
}
break;
- case UFS_MOUNT_UFSTYPE_NEXT:
- UFSD(("ufstype=next\n"))
+ case UFS_MOUNT_UFSTYPE_NEXTSTEP:
+ UFSD(("ufstype=nextstep\n"))
uspi->s_fsize = block_size = 1024;
uspi->s_fmask = ~(1024 - 1);
uspi->s_fshift = 10;
@@ -518,7 +530,7 @@ struct super_block * ufs_read_super (struct super_block * sb, void * data,
uspi->s_sbbase = 0;
flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD;
if (!(sb->s_flags & MS_RDONLY)) {
- printk(KERN_INFO "ufstype=next is supported read-only\n");
+ printk(KERN_INFO "ufstype=nextstep is supported read-only\n");
sb->s_flags |= MS_RDONLY;
}
break;
@@ -579,10 +591,9 @@ again:
}
#endif
- if ((((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) ==
- UFS_MOUNT_UFSTYPE_NEXT) ||
- ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) ==
- UFS_MOUNT_UFSTYPE_OPENSTEP)) && uspi->s_sbbase < 256) {
+ if ((((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP)
+ || ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_OPENSTEP))
+ && uspi->s_sbbase < 256) {
ubh_brelse_uspi(uspi);
ubh = NULL;
uspi->s_sbbase += 8;
@@ -627,9 +638,10 @@ magic_found:
* If not, make it read only.
*/
if (((flags & UFS_ST_MASK) == UFS_ST_44BSD) ||
- ((flags & UFS_ST_MASK) == UFS_ST_OLD) ||
- (((flags & UFS_ST_MASK) == UFS_ST_SUN) &&
- (ufs_get_fs_state(usb3) == (UFS_FSOK - SWAB32(usb1->fs_time))))) {
+ ((flags & UFS_ST_MASK) == UFS_ST_OLD) ||
+ (((flags & UFS_ST_MASK) == UFS_ST_SUN ||
+ (flags & UFS_ST_MASK) == UFS_ST_SUNx86) &&
+ (ufs_get_fs_state(usb1, usb3) == (UFS_FSOK - SWAB32(usb1->fs_time))))) {
switch(usb1->fs_clean) {
case UFS_FSCLEAN:
UFSD(("fs is clean\n"))
@@ -649,8 +661,7 @@ magic_found:
sb->s_flags |= MS_RDONLY;
break;
default:
- printk("ufs_read_super: can't grok fs_clean 0x%x\n",
- usb1->fs_clean);
+ printk("ufs_read_super: can't grok fs_clean 0x%x\n", usb1->fs_clean);
sb->s_flags |= MS_RDONLY;
break;
}
@@ -694,7 +705,7 @@ magic_found:
uspi->s_nindir = SWAB32(usb1->fs_nindir);
uspi->s_inopb = SWAB32(usb1->fs_inopb);
uspi->s_nspf = SWAB32(usb1->fs_nspf);
- uspi->s_npsect = SWAB32(usb1->fs_npsect);
+ uspi->s_npsect = ufs_get_fs_npsect(usb1, usb3);
uspi->s_interleave = SWAB32(usb1->fs_interleave);
uspi->s_trackskew = SWAB32(usb1->fs_trackskew);
uspi->s_csaddr = SWAB32(usb1->fs_csaddr);
@@ -706,7 +717,7 @@ magic_found:
uspi->s_ipg = SWAB32(usb1->fs_ipg);
uspi->s_fpg = SWAB32(usb1->fs_fpg);
uspi->s_cpc = SWAB32(usb2->fs_cpc);
- uspi->s_contigsumsize = SWAB32(usb3->fs_u.fs_44.fs_contigsumsize);
+ uspi->s_contigsumsize = SWAB32(usb3->fs_u2.fs_44.fs_contigsumsize);
uspi->s_qbmask = ufs_get_fs_qbmask(usb3);
uspi->s_qfmask = ufs_get_fs_qfmask(usb3);
uspi->s_postblformat = SWAB32(usb3->fs_postblformat);
@@ -734,8 +745,6 @@ magic_found:
sb->u.ufs_sb.s_flags = flags;
sb->u.ufs_sb.s_swab = swab;
- sb->u.ufs_sb.s_rename_lock = 0;
- sb->u.ufs_sb.s_rename_wait = NULL;
sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
@@ -776,8 +785,9 @@ void ufs_write_super (struct super_block * sb) {
if (!(sb->s_flags & MS_RDONLY)) {
usb1->fs_time = SWAB32(CURRENT_TIME);
- if (usb1->fs_clean == UFS_FSCLEAN && (flags&UFS_ST_MASK) == UFS_ST_SUN)
- ufs_set_fs_state(usb3, UFS_FSOK - SWAB32(usb1->fs_time));
+ if ((flags & UFS_ST_MASK) == UFS_ST_SUN
+ || (flags & UFS_ST_MASK) == UFS_ST_SUNx86)
+ ufs_set_fs_state(usb1, usb3, UFS_FSOK - SWAB32(usb1->fs_time));
ubh_mark_buffer_dirty (USPI_UBH, 1);
}
sb->s_dirt = 0;
@@ -842,8 +852,9 @@ int ufs_remount (struct super_block * sb, int * mount_flags, char * data)
if (*mount_flags & MS_RDONLY) {
ufs_put_cylinder_structures(sb);
usb1->fs_time = SWAB32(CURRENT_TIME);
- if (usb1->fs_clean == UFS_FSCLEAN && (flags&UFS_ST_MASK) == UFS_ST_SUN)
- ufs_set_fs_state(usb3, UFS_FSOK - SWAB32(usb1->fs_time));
+ if ((flags & UFS_ST_MASK) == UFS_ST_SUN
+ || (flags & UFS_ST_MASK) == UFS_ST_SUNx86)
+ ufs_set_fs_state(usb1, usb3, UFS_FSOK - SWAB32(usb1->fs_time));
ubh_mark_buffer_dirty (USPI_UBH, 1);
sb->s_dirt = 0;
sb->s_flags |= MS_RDONLY;
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index 02e6fe98a..cf26773ef 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -31,24 +31,46 @@
/*
* macros used for accesing structures
*/
-#define ufs_get_fs_state(usb3) _ufs_get_fs_state_(usb3,flags,swab)
-static inline __s32 _ufs_get_fs_state_(struct ufs_super_block_third * usb3,
- unsigned flags, unsigned swab)
+#define ufs_get_fs_state(usb1,usb3) _ufs_get_fs_state_(usb1,usb3,flags,swab)
+static inline __s32 _ufs_get_fs_state_(struct ufs_super_block_first * usb1,
+ struct ufs_super_block_third * usb3, unsigned flags, unsigned swab)
{
- if ((flags & UFS_ST_MASK) == UFS_ST_SUN)
- return SWAB32((usb3)->fs_u.fs_sun.fs_state);
- else
- return SWAB32((usb3)->fs_u.fs_44.fs_state);
+ switch (flags & UFS_ST_MASK) {
+ case UFS_ST_SUN:
+ return SWAB32((usb3)->fs_u2.fs_sun.fs_state);
+ case UFS_ST_SUNx86:
+ return SWAB32((usb1)->fs_u1.fs_sunx86.fs_state);
+ case UFS_ST_44BSD:
+ default:
+ return SWAB32((usb3)->fs_u2.fs_44.fs_state);
+ }
+}
+
+#define ufs_set_fs_state(usb1,usb3,value) _ufs_set_fs_state_(usb1,usb3,value,flags,swab)
+static inline void _ufs_set_fs_state_(struct ufs_super_block_first * usb1,
+ struct ufs_super_block_third * usb3, __s32 value, unsigned flags, unsigned swab)
+{
+ switch (flags & UFS_ST_MASK) {
+ case UFS_ST_SUN:
+ (usb3)->fs_u2.fs_sun.fs_state = SWAB32(value);
+ break;
+ case UFS_ST_SUNx86:
+ (usb1)->fs_u1.fs_sunx86.fs_state = SWAB32(value);
+ break;
+ case UFS_ST_44BSD:
+ (usb3)->fs_u2.fs_44.fs_state = SWAB32(value);
+ break;
+ }
}
-#define ufs_set_fs_state(usb3,value) _ufs_set_fs_state_(usb3,value,flags,swab)
-static inline void _ufs_set_fs_state_(struct ufs_super_block_third * usb3,
- __s32 value, unsigned flags, unsigned swab)
+#define ufs_get_fs_npsect(usb1,usb3) _ufs_get_fs_npsect_(usb1,usb3,flags,swab)
+static inline __u32 _ufs_get_fs_npsect_(struct ufs_super_block_first * usb1,
+ struct ufs_super_block_third * usb3, unsigned flags, unsigned swab)
{
- if ((flags & UFS_ST_MASK) == UFS_ST_SUN)
- (usb3)->fs_u.fs_sun.fs_state = SWAB32(value);
- else
- (usb3)->fs_u.fs_44.fs_state = SWAB32(value);
+ if ((flags & UFS_ST_MASK) == UFS_ST_SUNx86)
+ return SWAB32((usb3)->fs_u2.fs_sunx86.fs_npsect);
+ else
+ return SWAB32((usb1)->fs_u1.fs_sun.fs_npsect);
}
#define ufs_get_fs_qbmask(usb3) _ufs_get_fs_qbmask_(usb3,flags,swab)
@@ -56,13 +78,19 @@ static inline __u64 _ufs_get_fs_qbmask_(struct ufs_super_block_third * usb3,
unsigned flags, unsigned swab)
{
__u64 tmp;
- if ((flags & UFS_ST_MASK) == UFS_ST_SUN) {
- ((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qbmask[0];
- ((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qbmask[1];
- }
- else {
- ((u32 *)&tmp)[0] = usb3->fs_u.fs_44.fs_qbmask[0];
- ((u32 *)&tmp)[1] = usb3->fs_u.fs_44.fs_qbmask[1];
+ switch (flags & UFS_ST_MASK) {
+ case UFS_ST_SUN:
+ ((u32 *)&tmp)[0] = usb3->fs_u2.fs_sun.fs_qbmask[0];
+ ((u32 *)&tmp)[1] = usb3->fs_u2.fs_sun.fs_qbmask[1];
+ break;
+ case UFS_ST_SUNx86:
+ ((u32 *)&tmp)[0] = usb3->fs_u2.fs_sunx86.fs_qbmask[0];
+ ((u32 *)&tmp)[1] = usb3->fs_u2.fs_sunx86.fs_qbmask[1];
+ break;
+ case UFS_ST_44BSD:
+ ((u32 *)&tmp)[0] = usb3->fs_u2.fs_44.fs_qbmask[0];
+ ((u32 *)&tmp)[1] = usb3->fs_u2.fs_44.fs_qbmask[1];
+ break;
}
return SWAB64(tmp);
}
@@ -72,13 +100,19 @@ static inline __u64 _ufs_get_fs_qfmask_(struct ufs_super_block_third * usb3,
unsigned flags, unsigned swab)
{
__u64 tmp;
- if ((flags & UFS_ST_MASK) == UFS_ST_SUN) {
- ((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qfmask[0];
- ((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qfmask[1];
- }
- else {
- ((u32 *)&tmp)[0] = usb3->fs_u.fs_44.fs_qfmask[0];
- ((u32 *)&tmp)[1] = usb3->fs_u.fs_44.fs_qfmask[1];
+ switch (flags & UFS_ST_MASK) {
+ case UFS_ST_SUN:
+ ((u32 *)&tmp)[0] = usb3->fs_u2.fs_sun.fs_qfmask[0];
+ ((u32 *)&tmp)[1] = usb3->fs_u2.fs_sun.fs_qfmask[1];
+ break;
+ case UFS_ST_SUNx86:
+ ((u32 *)&tmp)[0] = usb3->fs_u2.fs_sunx86.fs_qfmask[0];
+ ((u32 *)&tmp)[1] = usb3->fs_u2.fs_sunx86.fs_qfmask[1];
+ break;
+ case UFS_ST_44BSD:
+ ((u32 *)&tmp)[0] = usb3->fs_u2.fs_44.fs_qfmask[0];
+ ((u32 *)&tmp)[1] = usb3->fs_u2.fs_44.fs_qfmask[1];
+ break;
}
return SWAB64(tmp);
}
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index 6ab276ac4..799f685de 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -30,7 +30,7 @@ extern struct inode *pseudo_root;
*/
/* nothing for now ... */
-static int umsdos_dentry_validate(struct dentry *dentry)
+static int umsdos_dentry_validate(struct dentry *dentry, int flags)
{
return 1;
}
@@ -46,7 +46,7 @@ static void umsdos_dentry_dput(struct dentry *dentry)
struct dentry_operations umsdos_dentry_operations =
{
- umsdos_dentry_validate, /* d_validate(struct dentry *) */
+ umsdos_dentry_validate, /* d_revalidate(struct dentry *, int) */
NULL, /* d_hash */
NULL, /* d_compare */
umsdos_dentry_dput, /* d_delete(struct dentry *) */
@@ -210,8 +210,8 @@ filp->f_dentry->d_name.name, entry.name);
/*
* Do a real lookup on the short name.
*/
- dret = umsdos_lookup_dentry(filp->f_dentry, info.fake.fname,
- info.fake.len, 1);
+ dret = umsdos_covered(filp->f_dentry, info.fake.fname,
+ info.fake.len);
ret = PTR_ERR(dret);
if (IS_ERR(dret))
break;
@@ -459,7 +459,7 @@ int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry)
* entry from the EMD file, and return ENOENT.
*/
-int umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
+struct dentry *umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
{
struct dentry *dret = NULL;
struct inode *inode;
@@ -500,8 +500,7 @@ Printk (("lookup %.*s pos %lu ret %d len %d ",
info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
/* do a real lookup to get the short name ... */
- dret = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
- info.fake.len, 1);
+ dret = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
ret = PTR_ERR(dret);
if (IS_ERR(dret)) {
printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%d\n",
@@ -563,7 +562,7 @@ out_dput:
dput(dret);
out:
umsdos_endlookup (dir);
- return ret;
+ return ERR_PTR(ret);
out_remove:
printk(KERN_WARNING "UMSDOS: entry %s/%s out of sync, erased\n",
@@ -581,23 +580,48 @@ out_remove:
* Called by VFS; should fill dentry->d_inode via d_add.
*/
-int UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
+struct dentry *UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
{
- int ret;
+ struct dentry *ret;
ret = umsdos_lookup_x (dir, dentry, 0);
/* Create negative dentry if not found. */
- if (ret == -ENOENT) {
+ if (ret == ERR_PTR(-ENOENT)) {
Printk ((KERN_DEBUG
"UMSDOS_lookup: converting -ENOENT to negative\n"));
d_add (dentry, NULL);
dentry->d_op = &umsdos_dentry_operations;
- ret = 0;
+ ret = NULL;
}
return ret;
}
+struct dentry *umsdos_covered(struct dentry *parent, char *name, int len)
+{
+ struct dentry *result, *dentry;
+ struct qstr qstr;
+
+ qstr.name = name;
+ qstr.len = len;
+ qstr.hash = full_name_hash(name, len);
+ result = ERR_PTR(-ENOMEM);
+ dentry = d_alloc(parent, &qstr);
+ if (dentry) {
+ /* XXXXXXXXXXXXXXXXXXX Race alert! */
+ result = UMSDOS_rlookup(parent->d_inode, dentry);
+ d_drop(dentry);
+ if (result)
+ goto out_fail;
+ return dentry;
+ }
+out:
+ return result;
+
+out_fail:
+ dput(dentry);
+ goto out;
+}
/*
* Lookup or create a dentry from within the filesystem.
@@ -609,7 +633,6 @@ struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len,
int real)
{
struct dentry *result, *dentry;
- int error;
struct qstr qstr;
qstr.name = name;
@@ -620,20 +643,19 @@ struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len,
result = ERR_PTR(-ENOMEM);
dentry = d_alloc(parent, &qstr);
if (dentry) {
- result = dentry;
- error = real ?
- UMSDOS_rlookup(parent->d_inode, result) :
- UMSDOS_lookup(parent->d_inode, result);
- if (error)
+ result = real ?
+ UMSDOS_rlookup(parent->d_inode, dentry) :
+ UMSDOS_lookup(parent->d_inode, dentry);
+ if (result)
goto out_fail;
+ return dentry;
}
}
out:
return result;
out_fail:
- dput(result);
- result = ERR_PTR(error);
+ dput(dentry);
goto out;
}
@@ -706,11 +728,6 @@ hlink->d_parent->d_name.name, hlink->d_name.name, path);
len = (int) (pt - start);
if (*pt == '/') *pt++ = '\0';
- real = (dir->d_inode->u.umsdos_i.i_emd_dir == 0);
- /*
- * Hack alert! inode->u.umsdos_i.i_emd_dir isn't reliable,
- * so just check whether there's an EMD file ...
- */
real = 1;
demd = umsdos_get_emd_dentry(dir);
if (!IS_ERR(demd)) {
@@ -720,9 +737,8 @@ hlink->d_parent->d_name.name, hlink->d_name.name, path);
}
#ifdef UMSDOS_DEBUG_VERBOSE
-printk ("umsdos_solve_hlink: dir %s/%s, name=%s, emd_dir=%ld, real=%d\n",
-dir->d_parent->d_name.name, dir->d_name.name, start,
-dir->d_inode->u.umsdos_i.i_emd_dir, real);
+printk ("umsdos_solve_hlink: dir %s/%s, name=%s, real=%d\n",
+dir->d_parent->d_name.name, dir->d_name.name, start, real);
#endif
dentry_dst = umsdos_lookup_dentry(dir, start, len, real);
if (real)
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c
index 6a4e99c04..d5a7a9578 100644
--- a/fs/umsdos/emd.c
+++ b/fs/umsdos/emd.c
@@ -250,12 +250,8 @@ parent->d_name.name, demd->d_name.name));
printk (KERN_WARNING
"umsdos_make_emd: create %s/%s failed, err=%d\n",
parent->d_name.name, demd->d_name.name, err);
- goto out_dput;
}
out_set:
- parent->d_inode->u.umsdos_i.i_emd_dir = demd->d_inode->i_ino;
-
-out_dput:
dput(demd);
out:
return err;
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index ef6e56dc3..c7c94b558 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -50,10 +50,10 @@ void fill_new_filp (struct file *filp, struct dentry *dentry)
void UMSDOS_put_inode (struct inode *inode)
{
PRINTK ((KERN_DEBUG
- "put inode %p (%lu) owner %lu pos %lu dir %lu count=%d\n"
+ "put inode %p (%lu) pos %lu count=%d\n"
,inode, inode->i_ino
- ,inode->u.umsdos_i.i_emd_owner, inode->u.umsdos_i.pos
- ,inode->u.umsdos_i.i_emd_dir, inode->i_count));
+ ,inode->u.umsdos_i.pos
+ ,inode->i_count));
if (inode == pseudo_root) {
printk (KERN_ERR "Umsdos: Oops releasing pseudo_root."
@@ -94,7 +94,6 @@ void umsdos_setup_dir(struct dentry *dir)
printk(KERN_ERR "umsdos_setup_dir: %s/%s not a dir!\n",
dir->d_parent->d_name.name, dir->d_name.name);
- inode->u.umsdos_i.i_emd_dir = 0;
inode->i_op = &umsdos_rdir_inode_operations;
if (umsdos_have_emd(dir)) {
Printk((KERN_DEBUG "umsdos_setup_dir: %s/%s using EMD\n",
@@ -112,14 +111,11 @@ void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos)
struct inode *inode = dentry->d_inode;
struct dentry *demd;
- inode->u.umsdos_i.i_emd_owner = 0;
inode->u.umsdos_i.pos = f_pos;
/* now check the EMD file */
demd = umsdos_get_emd_dentry(dentry->d_parent);
if (!IS_ERR(demd)) {
- if (demd->d_inode)
- inode->u.umsdos_i.i_emd_owner = demd->d_inode->i_ino;
dput(demd);
}
return;
@@ -149,7 +145,6 @@ PRINTK (("umsdos_patch_inode: call umsdos_set_dirinfo_new(%p,%lu)\n",
dentry, f_pos));
umsdos_set_dirinfo_new(dentry, f_pos);
- inode->u.umsdos_i.i_emd_dir = 0;
if (S_ISREG (inode->i_mode)) {
if (MSDOS_SB (inode->i_sb)->cvf_format) {
if (MSDOS_SB (inode->i_sb)->cvf_format->flags & CVF_USE_READPAGE) {
@@ -327,8 +322,6 @@ void UMSDOS_write_inode (struct inode *inode)
{
struct iattr newattrs;
- PRINTK (("UMSDOS_write_inode emd %d (FIXME: missing notify_change)\n",
- inode->u.umsdos_i.i_emd_owner));
fat_write_inode (inode);
newattrs.ia_mtime = inode->i_mtime;
newattrs.ia_atime = inode->i_atime;
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index 8e7780395..444e9ffae 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -6,6 +6,10 @@
*
* Maintain and access the --linux alternate directory file.
*/
+ /*
+ * You are in the maze of twisted functions - half of them shouldn't
+ * be here...
+ */
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -171,18 +175,6 @@ void umsdos_endlookup (struct inode *dir)
#endif
-/*
- * Check whether we can delete from the directory.
- */
-static int is_sticky(struct inode *dir, int uid)
-{
- return !((dir->i_mode & S_ISVTX) == 0 ||
- current->fsuid == uid ||
- current->fsuid == dir->i_uid ||
- capable (CAP_FOWNER));
-}
-
-
static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
int errcod)
{
@@ -258,16 +250,11 @@ static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
goto out;
/* do a real lookup to get the short name dentry */
- fake = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
- info.fake.len, 1);
+ fake = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
ret = PTR_ERR(fake);
if (IS_ERR(fake))
goto out_remove;
- /* keep the short name anonymous ... */
- if (dentry != fake)
- d_drop(fake);
-
/* should not exist yet ... */
ret = -EEXIST;
if (fake->d_inode)
@@ -278,14 +265,8 @@ static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
goto out_remove_dput;
inode = fake->d_inode;
- /*
- * Note! The long and short name might be the same,
- * so check first before doing the instantiate ...
- */
- if (dentry != fake) {
- inode->i_count++;
- d_instantiate (dentry, inode);
- }
+ inode->i_count++;
+ d_instantiate (dentry, inode);
dput(fake);
if (inode->i_count > 1) {
printk(KERN_WARNING
@@ -363,7 +344,7 @@ static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
{
struct inode *old_inode = old_dentry->d_inode;
struct dentry *old, *new, *old_emd;
- int err, ret, rehash = 0;
+ int err, ret;
struct umsdos_info old_info;
struct umsdos_info new_info;
@@ -386,34 +367,11 @@ static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
umsdos_lockcreate2 (old_dir, new_dir);
ret = umsdos_findentry(old_emd->d_parent, &old_info, 0);
- if (ret) {
- printk(KERN_ERR
- "umsdos_rename_f: old entry %s/%s not in EMD, ret=%d\n",
- old_dentry->d_parent->d_name.name, old_info.entry.name,
- ret);
- goto out_unlock;
- }
-
- /* check sticky bit on old_dir */
- ret = -EPERM;
- if (is_sticky(old_dir, old_info.entry.uid)) {
-printk("umsdos_rename_f: %s/%s old sticky bit, fsuid=%d, uid=%d, dir=%d\n",
-old_dentry->d_parent->d_name.name, old_info.entry.name,
-current->fsuid, old_info.entry.uid, old_dir->i_uid);
+ if (ret)
goto out_unlock;
- }
- /*
- * Check whether the new_name already exists, and
- * if so whether we're allowed to replace it.
- */
err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
if (err == 0) {
- /* Are we allowed to replace it? */
- if (is_sticky(new_dir, new_info.entry.uid)) {
-Printk (("sticky set on new "));
- goto out_unlock;
- }
/* check whether it _really_ exists ... */
ret = -EEXIST;
if (new_dentry->d_inode)
@@ -427,108 +385,41 @@ Printk (("sticky set on new "));
S_ISDIR(new_info.entry.mode));
}
-Printk (("new newentry "));
- /* create the new entry ... */
umsdos_ren_init (&new_info, &old_info);
if (flags)
new_info.entry.flags = flags;
ret = umsdos_newentry (new_dentry->d_parent, &new_info);
- if (ret) {
- printk(KERN_WARNING
- "umsdos_rename_f: newentry %s/%s failed, ret=%d\n",
- new_dentry->d_parent->d_name.name, new_info.entry.name,
- ret);
+ if (ret)
goto out_unlock;
- }
/* If we're moving a hardlink, drop it first */
if (old_info.entry.flags & UMSDOS_HLINK) {
- rehash = !list_empty(&old_dentry->d_hash);
d_drop(old_dentry);
-printk("umsdos_rename_f: moving hardlink %s/%s, rehash=%d\n",
-old_dentry->d_parent->d_name.name, old_info.entry.name, rehash);
}
- /* Do a real lookup to get the old short name dentry */
- old = umsdos_lookup_dentry(old_dentry->d_parent, old_info.fake.fname,
- old_info.fake.len, 1);
+ old = umsdos_covered(old_dentry->d_parent, old_info.fake.fname,
+ old_info.fake.len);
ret = PTR_ERR(old);
- if (IS_ERR(old)) {
- printk(KERN_WARNING
- "umsdos_rename_f: lookup old dentry %s/%s, ret=%d\n",
- old_dentry->d_parent->d_name.name, old_info.fake.fname,
- ret);
+ if (IS_ERR(old))
goto out_unlock;
- }
- /* short and long name dentries match? */
- if (old == old_dentry)
- dput(old);
- else {
- /* make sure it's the same inode! */
- ret = -ENOENT;
- if (old->d_inode != old_inode)
- goto out_dput;
- /*
- * A cross-directory move with different short and long
- * names has nasty complications: msdos-fs will need to
- * change inodes, so we must check whether the original
- * dentry is busy, and if the rename succeeds the short
- * dentry will come back with a different inode.
- *
- * To handle this, we drop the dentry and free the inode,
- * and then pick up the new inode after the rename.
- */
- if (old_dir != new_dir) {
- ret = -EBUSY;
- if (old_dentry->d_count > 1) {
-printk("umsdos_rename_f: old dentry %s/%s busy, d_count=%d\n",
-old_dentry->d_parent->d_name.name, old_dentry->d_name.name,old_dentry->d_count);
- goto out_dput;
- }
- d_drop(old_dentry);
- d_delete(old_dentry);
-printk("umsdos_rename_f: cross-dir move, %s/%s dropped\n",
-old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
- }
- }
+ /* make sure it's the same inode! */
+ ret = -ENOENT;
+ if (old->d_inode != old_inode)
+ goto out_dput;
- new = umsdos_lookup_dentry(new_dentry->d_parent, new_info.fake.fname,
- new_info.fake.len, 1);
+ new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname,
+ new_info.fake.len);
ret = PTR_ERR(new);
- if (IS_ERR(new)) {
- printk(KERN_WARNING
- "umsdos_rename_f: lookup new dentry %s/%s, ret=%d\n",
- new_dentry->d_parent->d_name.name, new_info.fake.fname,
- ret);
+ if (IS_ERR(new))
goto out_dput;
- }
-#ifdef UMSDOS_PARANOIA
-if (new->d_inode != new_dentry->d_inode)
-printk("umsdos_rename_f: new %s/%s, inode %p!=%p??\n",
-new->d_parent->d_name.name, new->d_name.name, new->d_inode,new_dentry->d_inode);
-#endif
- /* short and long name dentries match? */
- if (new == new_dentry)
- dput(new);
-#ifdef UMSDOS_DEBUG_VERBOSE
-printk("umsdos_rename_f: msdos_rename %s/%s(%ld) to %s/%s(%ld)\n",
-old->d_parent->d_name.name, old->d_name.name, old->d_inode->i_ino,
-new->d_parent->d_name.name, new->d_name.name,
-new->d_inode ? new->d_inode->i_ino : 0);
-#endif
/* Do the msdos-level rename */
ret = msdos_rename (old_dir, old, new_dir, new);
-Printk(("umsdos_rename_f: now %s/%s, ret=%d\n",
-old->d_parent->d_name.name, old->d_name.name, ret));
- if (new != new_dentry)
- dput(new);
+ dput(new);
/* If the rename failed, remove the new EMD entry */
if (ret != 0) {
-Printk(("umsdos_rename_f: rename failed, ret=%d, removing %s/%s\n",
-ret, new_dentry->d_parent->d_name.name, new_info.entry.name));
umsdos_delentry (new_dentry->d_parent, &new_info,
S_ISDIR (new_info.entry.mode));
goto out_dput;
@@ -550,33 +441,6 @@ ret, new_dentry->d_parent->d_name.name, new_info.entry.name));
}
/*
- * Check whether to update the dcache ... if both
- * old and new dentries match, it's already correct.
- * If the targets were aliases, the old short-name
- * dentry has the original target name.
- */
- if (old_dentry != old) {
- if (!old_dentry->d_inode) {
- struct inode *inode = old->d_inode;
- inode->i_count++;
- d_instantiate(old_dentry, inode);
-printk("umsdos_rename_f: %s/%s gets new ino=%ld\n",
-old_dentry->d_parent->d_name.name, old_dentry->d_name.name, inode->i_ino);
- }
- if (new_dentry == new)
- new_dentry = old;
- goto move_it;
- } else if (new_dentry != new) {
- move_it:
- /* this will rehash the dentry ... */
- d_move(old_dentry, new_dentry);
- }
- /* Check whether the old inode changed ... */
- if (old_dentry->d_inode != old_inode) {
- umsdos_lookup_patch_new(old_dentry, &new_info);
- }
-
- /*
* Update f_pos so notify_change will succeed
* if the file was already in use.
*/
@@ -584,8 +448,7 @@ old_dentry->d_parent->d_name.name, old_dentry->d_name.name, inode->i_ino);
/* dput() the dentry if we haven't already */
out_dput:
- if (old_dentry != old)
- dput(old);
+ dput(old);
out_unlock:
dput(old_emd);
@@ -614,6 +477,9 @@ out:
extern struct inode_operations umsdos_symlink_inode_operations;
+/*
+ * AV. Should be called with dir->i_sem down.
+ */
static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,
const char *symname, int mode, char flags)
{
@@ -745,8 +611,9 @@ dentry->d_parent->d_name.name, hid_info.entry.name, ret);
goto cleanup;
}
/* rename the link to the hidden location ... */
- ret = umsdos_rename_f (olddir, olddentry, olddir, temp,
+ ret = umsdos_rename_f(olddir, olddentry, olddir, temp,
UMSDOS_HIDDEN);
+ d_move(olddentry, temp);
dput(temp);
if (ret) {
printk("umsdos_link: rename to %s/%s failed, ret=%d\n",
@@ -817,9 +684,8 @@ Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n",
olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
/* Do a real lookup to get the short name dentry */
- temp = umsdos_lookup_dentry(olddentry->d_parent,
- old_info.fake.fname,
- old_info.fake.len, 1);
+ temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname,
+ old_info.fake.len);
ret = PTR_ERR(temp);
if (IS_ERR(temp))
goto out_unlock;
@@ -905,16 +771,11 @@ int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
goto out;
/* lookup the short name dentry */
- temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
- info.fake.len, 1);
+ temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
ret = PTR_ERR(temp);
if (IS_ERR(temp))
goto out_remove;
- /* Keep the short name dentry anonymous */
- if (temp != dentry)
- d_drop(temp);
-
/* Make sure the short name doesn't exist */
ret = -EEXIST;
if (temp->d_inode) {
@@ -933,16 +794,9 @@ dentry->d_parent->d_name.name, info.fake.fname);
inode = temp->d_inode;
down(&inode->i_sem);
- /*
- * Note! The long and short name might be the same,
- * so check first before doing the instantiate ...
- */
- if (dentry != temp) {
-if (dentry->d_inode)
-printk("umsdos_mkdir: dentry not negative!\n");
- inode->i_count++;
- d_instantiate(dentry, inode);
- }
+ inode->i_count++;
+ d_instantiate(dentry, inode);
+
/* N.B. this should have an option to create the EMD ... */
umsdos_lookup_patch_new(dentry, &info);
@@ -1042,21 +896,11 @@ demd->d_parent->d_name.name, demd->d_name.name, err);
umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
/* Call findentry to complete the mangling */
umsdos_findentry (dentry->d_parent, &info, 2);
- temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
- info.fake.len, 1);
+ temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
ret = PTR_ERR(temp);
if (IS_ERR(temp))
goto out;
/*
- * If the short name is an alias, dput() it now;
- * otherwise d_drop() it to keep it anonymous.
- */
- if (temp == dentry)
- dput(temp);
- else
- d_drop(temp);
-
- /*
* Attempt to remove the msdos name.
*/
ret = msdos_rmdir (dir, temp);
@@ -1072,8 +916,7 @@ printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
/* dput() temp if we didn't do it above */
out_dput:
- if (temp != dentry)
- dput(temp);
+ dput(temp);
out:
Printk (("umsdos_rmdir %d\n", ret));
@@ -1096,7 +939,7 @@ int UMSDOS_unlink (struct inode *dir, struct dentry *dentry)
{
struct dentry *temp, *link = NULL;
struct inode *inode;
- int ret, rehash = 0;
+ int ret;
struct umsdos_info info;
Printk(("UMSDOS_unlink: entering %s/%s\n",
@@ -1120,14 +963,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name, ret);
Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
- ret = -EPERM;
- /* check sticky bit */
- if (is_sticky(dir, info.entry.uid)) {
-printk("umsdos_unlink: %s/%s is sticky\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
- goto out_unlock;
- }
-
/*
* Note! If this is a hardlink and the names are aliased,
* the short-name lookup will return the hardlink dentry.
@@ -1135,15 +970,11 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
* the original dentry.
*/
if (info.entry.flags & UMSDOS_HLINK) {
- rehash = !list_empty(&dentry->d_hash);
d_drop(dentry);
-Printk(("UMSDOS_unlink: hard link %s/%s, fake=%s, rehash=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname, rehash));
}
/* Do a real lookup to get the short name dentry */
- temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
- info.fake.len, 1);
+ temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
ret = PTR_ERR(temp);
if (IS_ERR(temp))
goto out_unlock;
@@ -1155,13 +986,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname, rehash));
link = umsdos_solve_hlink(dget(temp));
}
- /*
- * If the short and long names are aliased,
- * dput() it now so the dentry isn't busy.
- */
- if (temp == dentry)
- dput(temp);
-
/* Delete the EMD entry */
ret = umsdos_delentry (dentry->d_parent, &info, 0);
if (ret && ret != -ENOENT) {
@@ -1170,7 +994,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname, rehash));
goto out_dput;
}
- ret = msdos_unlink_umsdos (dir, temp);
+ ret = msdos_unlink(dir, temp);
#ifdef UMSDOS_PARANOIA
if (ret)
printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
@@ -1179,12 +1003,9 @@ temp->d_parent->d_name.name, temp->d_name.name, ret);
/* dput() temp if we didn't do it above */
out_dput:
- if (temp != dentry) {
- d_drop(temp);
- dput(temp);
- if (!ret)
- d_delete (dentry);
- }
+ dput(temp);
+ if (!ret)
+ d_delete (dentry);
out_unlock:
umsdos_unlockcreate (dir);
@@ -1247,57 +1068,31 @@ out:
return ret;
}
-
/*
* Rename (move) a file.
*/
int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
- struct dentry *new_target;
int ret;
-#ifdef UMSDOS_DEBUG_VERBOSE
-printk("umsdos_rename: enter, %s/%s(%ld) to %s/%s(%ld)\n",
-old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
-old_dentry->d_inode->i_ino,
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
-new_dentry->d_inode ? new_dentry->d_inode->i_ino : 0);
-#endif
ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
if (ret)
- goto out;
+ return ret;
- /*
- * If the target already exists, delete it first.
- */
+ /*
+ * If the target already exists, delete it first.
+ */
if (new_dentry->d_inode) {
- if (S_ISDIR(new_dentry->d_inode->i_mode))
+ new_dentry->d_count++;
+ if (S_ISDIR(old_dentry->d_inode->i_mode))
ret = UMSDOS_rmdir (new_dir, new_dentry);
else
ret = UMSDOS_unlink (new_dir, new_dentry);
+ dput(new_dentry);
if (ret)
- goto out;
+ return ret;
}
-
- /*
- * If we didn't get a negative dentry, make a copy and hash it.
- */
- new_target = new_dentry;
- if (new_dentry->d_inode) {
-printk("umsdos_rename: %s/%s not negative, hash=%d\n",
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
-!list_empty(&new_dentry->d_hash));
- ret = -ENOMEM;
- new_target = d_alloc(new_dentry->d_parent, &new_dentry->d_name);
- if (!new_target)
- goto out;
- d_add(new_target, NULL);
- }
- ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_target, 0);
- if (new_target != new_dentry)
- dput(new_target);
-
-out:
+ ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0);
return ret;
}
diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
index 10ff145b7..3f5d10953 100644
--- a/fs/umsdos/rdir.c
+++ b/fs/umsdos/rdir.c
@@ -79,9 +79,9 @@ static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir)
* In the real root directory (c:\), the directory ..
* is the pseudo root (c:\linux).
*/
-int umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)
+struct dentry *umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)
{
- int ret;
+ struct dentry *ret;
if (saved_root && dir == saved_root->d_inode && !nopseudo &&
dentry->d_name.len == UMSDOS_PSDROOT_LEN &&
@@ -91,15 +91,16 @@ int umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)
* /linux won't show
*/
- ret = -ENOENT;
+ ret = ERR_PTR(-ENOENT);
goto out;
}
ret = msdos_lookup (dir, dentry);
if (ret) {
printk(KERN_WARNING
- "umsdos_rlookup_x: %s/%s failed, ret=%d\n",
- dentry->d_parent->d_name.name, dentry->d_name.name,ret);
+ "umsdos_rlookup_x: %s/%s failed, ret=%ld\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ PTR_ERR(ret));
goto out;
}
if (dentry->d_inode) {
@@ -119,7 +120,7 @@ out:
}
-int UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry)
+struct dentry *UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry)
{
return umsdos_rlookup_x (dir, dentry, 0);
}
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index d832bd99c..f79ef1b44 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -71,7 +71,7 @@ static int vfat_hashi(struct dentry *parent, struct qstr *qstr);
static int vfat_hash(struct dentry *parent, struct qstr *qstr);
static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
-static int vfat_revalidate(struct dentry *dentry);
+static int vfat_revalidate(struct dentry *dentry, int);
static struct dentry_operations vfat_dentry_ops[4] = {
{
@@ -106,7 +106,7 @@ void vfat_put_super(struct super_block *sb)
MOD_DEC_USE_COUNT;
}
-static int vfat_revalidate(struct dentry *dentry)
+static int vfat_revalidate(struct dentry *dentry, int flags)
{
PRINTK1(("vfat_revalidate: %s\n", dentry->d_name.name));
if (dentry->d_time == dentry->d_parent->d_inode->i_version) {
@@ -506,10 +506,10 @@ static int vfat_find_form(struct inode *dir,char *name)
continue;
if (memcmp(de->name,name,MSDOS_NAME))
continue;
- brelse(bh);
+ fat_brelse(dir->i_sb,bh);
return 0;
}
- brelse(bh);
+ fat_brelse(dir->i_sb,bh);
return -ENOENT;
}
@@ -1140,11 +1140,30 @@ cleanup:
return res;
}
-int vfat_lookup(struct inode *dir,struct dentry *dentry)
+/* Find a hashed dentry for inode; NULL if there are none */
+static struct dentry *find_alias(struct inode *inode)
+{
+ struct list_head *head, *next, *tmp;
+ struct dentry *alias;
+
+ head = &inode->i_dentry;
+ next = inode->i_dentry.next;
+ while (next != head) {
+ tmp = next;
+ next = tmp->next;
+ alias = list_entry(tmp, struct dentry, d_alias);
+ if (!list_empty(&alias->d_hash))
+ return dget(alias);
+ }
+ return NULL;
+}
+
+struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry)
{
int res;
struct vfat_slot_info sinfo;
struct inode *result;
+ struct dentry *alias;
int table;
PRINTK2(("vfat_lookup: name=%s, len=%d\n",
@@ -1161,7 +1180,7 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry)
}
PRINTK3(("vfat_lookup 4.5\n"));
if (!(result = iget(dir->i_sb,sinfo.ino)))
- return -EACCES;
+ return ERR_PTR(-EACCES);
PRINTK3(("vfat_lookup 5\n"));
if (MSDOS_I(result)->i_busy) { /* mkdir in progress */
iput(result);
@@ -1169,6 +1188,15 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry)
table++;
goto error;
}
+ alias = find_alias(result);
+ if (alias) {
+ if (d_invalidate(alias)==0)
+ dput(alias);
+ else {
+ iput(result);
+ return alias;
+ }
+ }
PRINTK3(("vfat_lookup 6\n"));
error:
dentry->d_op = &vfat_dentry_ops[table];
@@ -1397,28 +1425,6 @@ static int vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
return 0;
}
-/* Drop all aliases */
-static void drop_aliases(struct dentry *dentry)
-{
- struct list_head *head, *next, *tmp;
- struct dentry *alias;
-
- PRINTK1(("drop_replace_inodes: dentry=%p, inode=%p\n", dentry, inode));
- head = &dentry->d_inode->i_dentry;
- if (dentry->d_inode) {
- next = dentry->d_inode->i_dentry.next;
- while (next != head) {
- tmp = next;
- next = tmp->next;
- alias = list_entry(tmp, struct dentry, d_alias);
- if (alias == dentry)
- continue;
-
- d_drop(alias);
- }
- }
-}
-
static int vfat_rmdirx(struct inode *dir,struct dentry* dentry)
{
int res;
@@ -1430,12 +1436,6 @@ static int vfat_rmdirx(struct inode *dir,struct dentry* dentry)
if (res >= 0 && sinfo.total_slots > 0) {
if (!list_empty(&dentry->d_hash))
return -EBUSY;
- /* Take care of aliases */
- if (dentry->d_inode->i_count > 1) {
- shrink_dcache_parent(dentry->d_parent);
- if (dentry->d_inode->i_count > 1)
- return -EBUSY;
- }
res = vfat_empty(dentry->d_inode);
if (res)
return res;
@@ -1535,10 +1535,8 @@ int vfat_unlink(struct inode *dir,struct dentry* dentry)
PRINTK1(("vfat_unlink: dentry=%p, inode=%p\n", dentry, dentry->d_inode));
res = vfat_unlinkx (dir,dentry,1);
- if (res >= 0) {
- drop_aliases(dentry);
+ if (res >= 0)
d_delete(dentry);
- }
return res;
}
@@ -1561,7 +1559,6 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
loff_t old_offset,new_offset,old_longname_offset;
int old_slots,old_ino,new_ino,dotdot_ino;
struct inode *old_inode, *new_inode, *dotdot_inode;
- struct dentry *walk;
int res, is_dir, i;
int locked = 0;
struct vfat_slot_info sinfo;
@@ -1570,14 +1567,6 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
old_dentry, old_dentry->d_inode, old_dentry->d_inode->i_ino,
new_dentry, new_dentry->d_inode,
new_dentry->d_inode ? new_dentry->d_inode->i_ino : 0));
- /*
- * POSIX is braindead (surprise, surprise). It requires that rename()
- * should return 0 and do nothing if the target has the same inode as
- * the source. Somebody, get a time machine, return to '89 and tell
- * RMS & Co *not* to do that idiocy, FAST!
- */
- if (old_dentry->d_inode == new_dentry->d_inode)
- return 0;
old_bh = new_bh = NULL;
old_inode = new_inode = NULL;
@@ -1597,24 +1586,8 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
old_inode = old_dentry->d_inode;
is_dir = S_ISDIR(old_inode->i_mode);
- /*
- * Race: we can be hit by another rename after this check.
- * For the time being use fat_lock_creation(), but it's
- * ugly. FIXME.
- */
-
fat_lock_creation(); locked = 1;
- if (is_dir) {
- /* We can't use d_subdir() here. Arrgh. */
- for (walk=new_dentry;walk!=walk->d_parent;walk=walk->d_parent) {
- if (walk->d_inode != old_dentry->d_inode)
- continue;
- res = -EINVAL;
- goto rename_done;
- }
- }
-
if (new_dentry->d_inode) {
/*
* OK, we have to remove the target. We should do it so
@@ -1634,31 +1607,16 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
}
if (is_dir) {
- /*
- * Target is a directory. No other owners will
- * be tolerated.
- */
- res = -EBUSY;
- if (d_invalidate(new_dentry) < 0)
- goto rename_done;
- /*
- * OK, let's try to get rid of other dentries.
- * No need to do it if i_count is 1.
- */
- if (new_inode->i_count>1) {
- shrink_dcache_parent(new_dentry->d_parent);
- if (new_inode->i_count>1)
- goto rename_done;
- }
res = vfat_empty(new_inode);
if (res)
goto rename_done;
- } else {
- drop_aliases(new_dentry);
}
res = vfat_remove_entry(new_dir,&sinfo,new_inode);
if (res)
goto rename_done;
+
+ if (is_dir)
+ new_dir->i_nlink--;
}
/* Serious lossage here. FAT uses braindead inode numbers scheme,
@@ -1670,9 +1628,6 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
* 'busy' stuff on the spot. Later.
*/
- if (is_dir)
- new_dir->i_nlink--;
-
res = vfat_find(new_dir,&new_dentry->d_name,1,is_dir,&sinfo);
if (res < 0) goto rename_done;
@@ -1726,12 +1681,8 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
fat_brelse(sb, dotdot_bh);
}
- if (res >= 0) {
- if (new_inode && is_dir)
- d_rehash(new_dentry);
- d_move(old_dentry, new_dentry);
+ if (res >= 0)
res = 0;
- }
rename_done:
if (locked)